/** * Intercept a KeyRelease-KeyPress sequence and ignore */ static bool Sys_XRepeatPress( XEvent *event ) { XEvent peekevent; bool repeated = false; int lookupRet; char buf[5]; KeySym keysym; if ( Sys_XPendingInput() ) { XPeekEvent( dpy, &peekevent ); if ((peekevent.type == KeyPress) && (peekevent.xkey.keycode == event->xkey.keycode) && (peekevent.xkey.time == event->xkey.time)) { repeated = true; XNextEvent( dpy, &peekevent ); // emit an SE_CHAR for the repeat lookupRet = XLookupString( (XKeyEvent*)&peekevent, buf, sizeof(buf), &keysym, NULL ); if (lookupRet > 0) { Posix_QueEvent( SE_CHAR, buf[ 0 ], 0, 0, NULL); } else { // shouldn't we be doing a release/press in this order rather? // ( doesn't work .. but that's what I would have expected to do though ) Posix_QueEvent( SE_KEY, s_scantokey[peekevent.xkey.keycode], true, 0, NULL); Posix_QueEvent( SE_KEY, s_scantokey[peekevent.xkey.keycode], false, 0, NULL); } } } return repeated; }
/* called during frame loops, pacifier updates etc. this is only for console input polling and misc mouse grab tasks the actual mouse and keyboard input is in the Sys_Poll logic */ void Sys_GenerateEvents( void ) { char *s; if ( ( s = Posix_ConsoleInput() ) ) { char *b; int len; len = strlen( s ) + 1; b = (char *)Mem_Alloc( len ); strcpy( b, s ); Posix_QueEvent( SE_CONSOLE, 0, 0, len, b ); } }
/* ========================== Posix_PollInput ========================== */ void Posix_PollInput() { static char buf[16]; static XEvent event; static XKeyEvent *key_event = (XKeyEvent*)&event; int lookupRet; int b, dx, dy; KeySym keysym; if ( !dpy ) { return; } // NOTE: Sys_GetEvent only calls when there are no events left // but here we pump all X events that have accumulated // pump one by one? or use threaded input? while ( XPending( dpy ) ) { XNextEvent( dpy, &event ); switch (event.type) { case KeyPress: #ifdef XEVT_DBG if (key_event->keycode > 0x7F) common->DPrintf("WARNING: KeyPress keycode > 0x7F"); #endif key_event->keycode &= 0x7F; #ifdef XEVT_DBG2 printf("SE_KEY press %d\n", key_event->keycode); #endif Posix_QueEvent( SE_KEY, s_scantokey[key_event->keycode], true, 0, NULL); lookupRet = XLookupString(key_event, buf, sizeof(buf), &keysym, NULL); if (lookupRet > 0) { char s = buf[0]; #ifdef XEVT_DBG if (buf[1]!=0) common->DPrintf("WARNING: got XLookupString buffer '%s' (%d)\n", buf, strlen(buf)); #endif #ifdef XEVT_DBG2 printf("SE_CHAR %s\n", buf); #endif Posix_QueEvent( SE_CHAR, s, 0, 0, NULL); } if (!Posix_AddKeyboardPollEvent( s_scantokey[key_event->keycode], true )) return; break; case KeyRelease: if (Sys_XRepeatPress(&event)) { #ifdef XEVT_DBG2 printf("RepeatPress\n"); #endif continue; } #ifdef XEVT_DBG if (key_event->keycode > 0x7F) common->DPrintf("WARNING: KeyRelease keycode > 0x7F"); #endif key_event->keycode &= 0x7F; #ifdef XEVT_DBG2 printf("SE_KEY release %d\n", key_event->keycode); #endif Posix_QueEvent( SE_KEY, s_scantokey[key_event->keycode], false, 0, NULL); if (!Posix_AddKeyboardPollEvent( s_scantokey[key_event->keycode], false )) return; break; case ButtonPress: if (event.xbutton.button == 4) { Posix_QueEvent( SE_KEY, K_MWHEELUP, true, 0, NULL); if (!Posix_AddMousePollEvent( M_DELTAZ, 1 )) return; } else if (event.xbutton.button == 5) { Posix_QueEvent( SE_KEY, K_MWHEELDOWN, true, 0, NULL); if (!Posix_AddMousePollEvent( M_DELTAZ, -1 )) return; } else { b = -1; if (event.xbutton.button == 1) { b = 0; // K_MOUSE1 } else if (event.xbutton.button == 2) { b = 2; // K_MOUSE3 } else if (event.xbutton.button == 3) { b = 1; // K_MOUSE2 } else if (event.xbutton.button == 6) { b = 3; // K_MOUSE4 } else if (event.xbutton.button == 7) { b = 4; // K_MOUSE5 } if (b == -1 || b > 4) { common->DPrintf("X ButtonPress %d not supported\n", event.xbutton.button); } else { Posix_QueEvent( SE_KEY, K_MOUSE1 + b, true, 0, NULL); if (!Posix_AddMousePollEvent( M_ACTION1 + b, true )) return; } } break; case ButtonRelease: if (event.xbutton.button == 4) { Posix_QueEvent( SE_KEY, K_MWHEELUP, false, 0, NULL); } else if (event.xbutton.button == 5) { Posix_QueEvent( SE_KEY, K_MWHEELDOWN, false, 0, NULL); } else { b = -1; if (event.xbutton.button == 1) { b = 0; } else if (event.xbutton.button == 2) { b = 2; } else if (event.xbutton.button == 3) { b = 1; } else if (event.xbutton.button == 6) { b = 3; // K_MOUSE4 } else if (event.xbutton.button == 7) { b = 4; // K_MOUSE5 } if (b == -1 || b > 4) { common->DPrintf("X ButtonRelease %d not supported\n", event.xbutton.button); } else { Posix_QueEvent( SE_KEY, K_MOUSE1 + b, false, 0, NULL); if (!Posix_AddMousePollEvent( M_ACTION1 + b, false )) return; } } break; case MotionNotify: if (!mouse_active) break; if (in_dgamouse.GetBool()) { dx = event.xmotion.x_root; dy = event.xmotion.y_root; Posix_QueEvent( SE_MOUSE, dx, dy, 0, NULL); // if we overflow here, we'll get a warning, but the delta will be completely processed anyway Posix_AddMousePollEvent( M_DELTAX, dx ); if (!Posix_AddMousePollEvent( M_DELTAY, dy )) return; } else { // if it's a center motion, we've just returned from our warp // FIXME: we generate mouse delta on wrap return, but that lags us quite a bit from the initial event.. if (event.xmotion.x == glConfig.vidWidth / 2 && event.xmotion.y == glConfig.vidHeight / 2) { mwx = glConfig.vidWidth / 2; mwy = glConfig.vidHeight / 2; Posix_QueEvent( SE_MOUSE, mx, my, 0, NULL); Posix_AddMousePollEvent( M_DELTAX, mx ); if (!Posix_AddMousePollEvent( M_DELTAY, my )) return; mx = my = 0; break; } dx = ((int) event.xmotion.x - mwx); dy = ((int) event.xmotion.y - mwy); mx += dx; my += dy; mwx = event.xmotion.x; mwy = event.xmotion.y; XWarpPointer(dpy,None,win,0,0,0,0, (glConfig.vidWidth/2),(glConfig.vidHeight/2)); } break; } } }