static void handle_key(XGenericEventCookie *cookie) { XIDeviceEvent *ev = (XIDeviceEvent *)cookie->data; qboolean down = cookie->evtype == XI_KeyPress; int keycode = ev->detail; unsigned time = Sys_XTimeToSysTime(ev->time); // Ignore shift_level for game key press KeySym keysym = XkbKeycodeToKeysym(x11display.dpy, keycode, 0, 0); int key = XLateKey( keysym ); // Set or clear 1 in the shift_level bitmask if ( keysym == XK_Shift_L || keysym == XK_Shift_R ) shift_level ^= (-down ^ shift_level) & 1; // Set or clear 2 in the shift_level bitmask else if( keysym == XK_ISO_Level3_Shift ) shift_level ^= (-down ^ shift_level) & 2; Key_Event(key, down, time); if( down ) { // Use shift_level for chat and console input qwchar wc = keysym2ucs(XkbKeycodeToKeysym(x11display.dpy, keycode, 0, shift_level)); if( wc == -1 && key > K_NUMLOCK && key <= KP_EQUAL ) wc = ( qwchar )key; // Convert ctrl-c / ctrl-v combinations to the expected events if( Key_IsDown(K_LCTRL) || Key_IsDown(K_RCTRL) ) { if( key == 'v' ) { key = CTRLV; wc = CTRLV; } else if( key == 'c' ) { key = CTRLC; wc = CTRLC; } } Key_CharEvent( key, wc ); } }
/* * IN_Android_OnInputEvent */ static int32_t IN_Android_OnInputEvent( struct android_app *app, AInputEvent *event ) { int32_t type = AInputEvent_getType( event ); int64_t time; if( type == AINPUT_EVENT_TYPE_KEY ) { int32_t keycode = AKeyEvent_getKeyCode( event ); int key; if( keycode >= ( sizeof( s_android_scantokey ) / sizeof( s_android_scantokey[0] ) ) ) return 0; if( ( keycode >= AKEYCODE_DPAD_UP ) && ( keycode <= AKEYCODE_DPAD_RIGHT ) && ( AInputEvent_getSource( event ) == AINPUT_SOURCE_KEYBOARD ) ) { key = keycode + ( K_UPARROW - AKEYCODE_DPAD_UP ); } else { key = s_android_scantokey[keycode]; } if( !key ) return 0; time = AKeyEvent_getEventTime( event ) / ( ( int64_t )1000000 ); switch( AKeyEvent_getAction( event ) ) { case AKEY_EVENT_ACTION_DOWN: case AKEY_EVENT_ACTION_MULTIPLE: if( ( key == K_ESCAPE ) && IN_Android_HideSoftKeyboard() ) // Instead of broken AInputQueue_preDispatchEvent. return 1; Key_Event( key, true, time ); if( Key_IsDown( K_LCTRL ) || Key_IsDown( K_RCTRL ) ) { if( key == 'v' ) Key_CharEvent( KC_CTRLV, KC_CTRLV ); else if( key == 'c' ) Key_CharEvent( KC_CTRLC, KC_CTRLC ); else Key_CharEvent( key, IN_Android_KeyEvent2UCS( event ) ); } else { Key_CharEvent( key, IN_Android_KeyEvent2UCS( event ) ); } break; case AKEY_EVENT_ACTION_UP: Key_Event( key, false, time ); break; } return 1; } if( type == AINPUT_EVENT_TYPE_MOTION ) { int32_t action = AMotionEvent_getAction( event ); int32_t source = AInputEvent_getSource( event ); int x, y; time = AMotionEvent_getEventTime( event ) / ( ( int64_t )1000000 ); switch( source ) { case AINPUT_SOURCE_TOUCHSCREEN: { touchevent_t type; size_t i, pointerCount = 0, p; switch( action & AMOTION_EVENT_ACTION_MASK ) { case AMOTION_EVENT_ACTION_DOWN: case AMOTION_EVENT_ACTION_POINTER_DOWN: type = TOUCH_DOWN; pointerCount = 1; break; case AMOTION_EVENT_ACTION_POINTER_UP: type = TOUCH_UP; pointerCount = 1; break; case AMOTION_EVENT_ACTION_MOVE: type = TOUCH_MOVE; pointerCount = AMotionEvent_getPointerCount( event ); break; case AMOTION_EVENT_ACTION_UP: case AMOTION_EVENT_ACTION_CANCEL: case AMOTION_EVENT_ACTION_OUTSIDE: type = TOUCH_UP; pointerCount = AMotionEvent_getPointerCount( event ); break; } p = action >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; for( i = 0; i < pointerCount; ++i, ++p ) { if( IN_Android_EventToWindowCoordinates( event, p, &x, &y ) ) CL_TouchEvent( AMotionEvent_getPointerId( event, p ), type, x, y, time ); } } break; case AINPUT_SOURCE_JOYSTICK: { float hatXValue = AMotionEvent_getAxisValue( event, AMOTION_EVENT_AXIS_HAT_X, 0 ); float hatYValue = AMotionEvent_getAxisValue( event, AMOTION_EVENT_AXIS_HAT_Y, 0 ); int hatX = 0, hatY = 0; static int oldHatX = 0, oldHatY = 0; bool leftTrigger, rightTrigger; static bool oldLeftTrigger = false, oldRightTrigger = false; in_android_thumbsticks[0] = AMotionEvent_getAxisValue( event, AMOTION_EVENT_AXIS_X, 0 ); in_android_thumbsticks[1] = AMotionEvent_getAxisValue( event, AMOTION_EVENT_AXIS_Y, 0 ); in_android_thumbsticks[2] = AMotionEvent_getAxisValue( event, AMOTION_EVENT_AXIS_Z, 0 ); in_android_thumbsticks[3] = AMotionEvent_getAxisValue( event, AMOTION_EVENT_AXIS_RZ, 0 ); hatX = ( hatXValue > 0.5f ) - ( hatXValue < -0.5f ); hatY = ( hatYValue > 0.5f ) - ( hatYValue < -0.5f ); if( hatX != oldHatX ) { if( oldHatX ) Key_Event( K_DPAD_LEFT + ( oldHatX > 0 ), false, time ); if( hatX ) Key_Event( K_DPAD_LEFT + ( hatX > 0 ), true, time ); oldHatX = hatX; } if( hatY != oldHatY ) { if( oldHatY ) Key_Event( K_DPAD_UP + ( oldHatY > 0 ), false, time ); if( hatY ) Key_Event( K_DPAD_UP + ( hatY > 0 ), true, time ); oldHatY = hatY; } leftTrigger = ( AMotionEvent_getAxisValue( event, AMOTION_EVENT_AXIS_BRAKE, 0 ) > ( 30.0f / 255.0f ) ) || ( AMotionEvent_getAxisValue( event, AMOTION_EVENT_AXIS_LTRIGGER, 0 ) > ( 30.0f / 255.0f ) ); rightTrigger = ( AMotionEvent_getAxisValue( event, AMOTION_EVENT_AXIS_GAS, 0 ) > ( 30.0f / 255.0f ) ) || ( AMotionEvent_getAxisValue( event, AMOTION_EVENT_AXIS_RTRIGGER, 0 ) > ( 30.0f / 255.0f ) ); if( leftTrigger != oldLeftTrigger ) { Key_Event( K_LTRIGGER, leftTrigger, time ); oldLeftTrigger = leftTrigger; } if( rightTrigger != oldRightTrigger ) { Key_Event( K_RTRIGGER, rightTrigger, time ); oldRightTrigger = rightTrigger; } } break; case AINPUT_SOURCE_MOUSE: { switch( action & AMOTION_EVENT_ACTION_MASK ) { case AMOTION_EVENT_ACTION_DOWN: case AMOTION_EVENT_ACTION_UP: { static int32_t oldButtonState = 0; int32_t buttonState = AMotionEvent_getButtonState( event ); int32_t buttonsDown = buttonState & ~oldButtonState, buttonsUp = oldButtonState & ~buttonState; int32_t buttonsChanged = buttonsDown | buttonsUp; int button; oldButtonState = buttonState; for( button = 0; buttonsChanged >> button; button++ ) { if( buttonsChanged & ( 1 << button ) ) Key_MouseEvent( K_MOUSE1 + button, ( buttonsDown & ( 1 << button ) ) ? true : false, time ); } } break; case AMOTION_EVENT_ACTION_HOVER_MOVE: case AMOTION_EVENT_ACTION_MOVE: if( IN_Android_EventToWindowCoordinates( event, 0, &x, &y ) ) CL_MouseSet( x, y, false ); break; case AMOTION_EVENT_ACTION_SCROLL: { float scroll = AMotionEvent_getAxisValue( event, AMOTION_EVENT_AXIS_VSCROLL, 0 ); if( scroll > 0.0f ) { Key_Event( K_MWHEELUP, true, time ); Key_Event( K_MWHEELUP, false, time ); } else if( scroll < 0.0f ) { Key_Event( K_MWHEELDOWN, true, time ); Key_Event( K_MWHEELDOWN, false, time ); } } break; } } break; } return 1; }
static void IN_HandleEvents( void ) { Uint16 *wtext = NULL; SDL_PumpEvents(); SDL_Event event; while( SDL_PollEvent( &event ) ) { switch( event.type ) { case SDL_KEYDOWN: key_event( &event.key, true ); // Emulate copy/paste #if defined( __APPLE__ ) #define KEYBOARD_COPY_PASTE_MODIFIER KMOD_GUI #else #define KEYBOARD_COPY_PASTE_MODIFIER KMOD_CTRL #endif if( event.key.keysym.sym == SDLK_c ) { if( event.key.keysym.mod & KEYBOARD_COPY_PASTE_MODIFIER ) { Key_CharEvent( KC_CTRLC, KC_CTRLC ); } } else if( event.key.keysym.sym == SDLK_v ) { if( event.key.keysym.mod & KEYBOARD_COPY_PASTE_MODIFIER ) { Key_CharEvent( KC_CTRLV, KC_CTRLV ); } } break; case SDL_KEYUP: key_event( &event.key, false ); break; case SDL_TEXTINPUT: // SDL_iconv_utf8_ucs2 uses "UCS-2-INTERNAL" as tocode and fails to convert text on Linux // where SDL_iconv uses system iconv. So we force needed encoding directly #if SDL_BYTEORDER == SDL_LIL_ENDIAN #define UCS_2_INTERNAL "UCS-2LE" #else #define UCS_2_INTERNAL "UCS-2BE" #endif wtext = (Uint16 *)SDL_iconv_string( UCS_2_INTERNAL, "UTF-8", event.text.text, SDL_strlen( event.text.text ) + 1 ); if( wtext ) { wchar_t charkey = wtext[0]; int key = ( charkey <= 255 ) ? charkey : 0; Key_CharEvent( key, charkey ); SDL_free( wtext ); } break; case SDL_MOUSEMOTION: mouse_motion_event( &event.motion ); break; case SDL_MOUSEBUTTONDOWN: mouse_button_event( &event.button, true ); break; case SDL_MOUSEBUTTONUP: mouse_button_event( &event.button, false ); break; case SDL_MOUSEWHEEL: mouse_wheel_event( &event.wheel ); break; case SDL_QUIT: Cbuf_ExecuteText( EXEC_NOW, "quit" ); break; case SDL_WINDOWEVENT: switch( event.window.event ) { case SDL_WINDOWEVENT_SHOWN: AppActivate( true ); break; case SDL_WINDOWEVENT_HIDDEN: AppActivate( false ); break; case SDL_WINDOWEVENT_CLOSE: break; case SDL_WINDOWEVENT_FOCUS_GAINED: input_focus = true; break; case SDL_WINDOWEVENT_FOCUS_LOST: input_focus = false; break; case SDL_WINDOWEVENT_MOVED: // FIXME: move this somewhere else Cvar_SetValue( "vid_xpos", event.window.data1 ); Cvar_SetValue( "vid_ypos", event.window.data2 ); vid_xpos->modified = false; vid_ypos->modified = false; break; } break; } } }
// main window procedure STATIC LONG WINAPI Win_MainWndProc ( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { switch( uMsg ) { case WM_MOUSEWHEEL: if( win.mouse.initialized == WIN_MOUSE_LEGACY ) { mouse_wheel_event( ( short )HIWORD( wParam ) ); } break; case WM_MOUSEHWHEEL: if( win.mouse.initialized == WIN_MOUSE_LEGACY ) { mouse_hwheel_event( ( short )HIWORD( wParam ) ); } break; case WM_NCMOUSEMOVE: if( win.mouse.initialized ) { // don't hide cursor IN_MouseEvent( -1, -1 ); } break; case WM_MOUSEMOVE: if( win.mouse.initialized ) { int x = ( short )LOWORD( lParam ); int y = ( short )HIWORD( lParam ); IN_MouseEvent( x, y ); } // fall through case WM_LBUTTONDOWN: case WM_LBUTTONUP: case WM_RBUTTONDOWN: case WM_RBUTTONUP: case WM_MBUTTONDOWN: case WM_MBUTTONUP: case WM_XBUTTONDOWN: case WM_XBUTTONUP: if( win.mouse.initialized == WIN_MOUSE_LEGACY ) { legacy_mouse_event( wParam ); } break; case WM_HOTKEY: return FALSE; case WM_INPUT: if( wParam == RIM_INPUT && win.mouse.initialized == WIN_MOUSE_RAW ) { raw_input_event( ( HANDLE )lParam ); } break; case WM_CLOSE: PostQuitMessage( 0 ); return FALSE; case WM_ACTIVATE: Win_Activate( wParam ); break; case WM_WINDOWPOSCHANGING: if( !( win.flags & QVF_FULLSCREEN ) ) { WINDOWPOS *pos = ( WINDOWPOS * )lParam; if( !( pos->flags & SWP_NOSIZE ) ) { resizing_event( hWnd, pos ); } } break; case WM_SIZE: if( wParam == SIZE_RESTORED && !( win.flags & QVF_FULLSCREEN ) ) { int w = ( short )LOWORD( lParam ); int h = ( short )HIWORD( lParam ); win.rc.width = w; win.rc.height = h; win.mode_changed |= MODE_SIZE; } break; case WM_MOVE: if( !( win.flags & QVF_FULLSCREEN ) ) { int x = ( short )LOWORD( lParam ); int y = ( short )HIWORD( lParam ); RECT r; // adjust for non-client area get_nc_area_size( hWnd, &r ); win.rc.x = x + r.left; win.rc.y = y + r.top; win.mode_changed |= MODE_POS; } break; case WM_SYSCOMMAND: switch( wParam & 0xFFF0 ) { case SC_SCREENSAVE: return FALSE; case SC_MAXIMIZE: if( !vid_fullscreen->integer ) { VID_ToggleFullscreen(); } return FALSE; } break; case WM_KEYDOWN: case WM_SYSKEYDOWN: legacy_key_event( wParam, lParam, qtrue ); return FALSE; case WM_KEYUP: case WM_SYSKEYUP: legacy_key_event( wParam, lParam, qfalse ); return FALSE; case WM_SYSCHAR: case WM_CHAR: #if USE_CHAR_EVENTS Key_CharEvent( wParam ); #endif return FALSE; default: break; } // pass all unhandled messages to DefWindowProc return DefWindowProc( hWnd, uMsg, wParam, lParam ); }
static void HandleEvents( void ) { XEvent event; qboolean dowarp = qfalse, was_focused = focus; int mwx = x11display.win_width / 2; int mwy = x11display.win_height / 2; char *p; int key = 0; int time = 0; assert( x11display.dpy && x11display.win ); #ifdef WSW_EVDEV if( mouse_active && m_evdev_num ) { evdev_read(); } else #endif if( mouse_active && !dgamouse ) { int root_x, root_y, win_x, win_y; unsigned int mask; Window root, child; if( XQueryPointer( x11display.dpy, x11display.win, &root, &child, &root_x, &root_y, &win_x, &win_y, &mask ) ) { mx += ( (int)win_x - mwx ); my += ( (int)win_y - mwy ); mwx = win_x; mwy = win_y; if( mx || my ) dowarp = qtrue; if( ignore_one ) { mx = my = 0; ignore_one = qfalse; } } } while( XPending( x11display.dpy ) ) { XNextEvent( x11display.dpy, &event ); switch( event.type ) { case KeyPress: time = Sys_XTimeToSysTime(event.xkey.time); p = XLateKey( &event.xkey, &key ); if( key ) Key_Event( key, qtrue, time ); while ( p && *p ) { qwchar wc = Q_GrabWCharFromUtf8String( (const char **)&p ); Key_CharEvent( key, wc ); } break; case KeyRelease: if( repeated_press( &event ) ) break; // don't send release events when repeating time = Sys_XTimeToSysTime(event.xkey.time); XLateKey( &event.xkey, &key ); Key_Event( key, event.type == KeyPress, time ); break; case MotionNotify: #ifdef WSW_EVDEV if( mouse_active && dgamouse && !m_evdev_num ) #else if( mouse_active && dgamouse ) #endif { mx += event.xmotion.x_root; my += event.xmotion.y_root; if( ignore_one ) { mx = my = 0; ignore_one = qfalse; } } break; case ButtonPress: if( ( cls.key_dest == key_console ) && !in_grabinconsole->integer ) break; #ifdef WSW_EVDEV if( m_evdev_num ) break; #endif time = Sys_XTimeToSysTime(event.xkey.time); if( event.xbutton.button == 1 ) Key_MouseEvent( K_MOUSE1, 1, time ); else if( event.xbutton.button == 2 ) Key_MouseEvent( K_MOUSE3, 1, time ); else if( event.xbutton.button == 3 ) Key_MouseEvent( K_MOUSE2, 1, time ); else if( event.xbutton.button == 4 ) Key_Event( K_MWHEELUP, 1, time ); else if( event.xbutton.button == 5 ) Key_Event( K_MWHEELDOWN, 1, time ); else if( event.xbutton.button >= 6 && event.xbutton.button <= 10 ) Key_MouseEvent( K_MOUSE4+event.xbutton.button-6, 1, time ); break; case ButtonRelease: if( ( cls.key_dest == key_console ) && !in_grabinconsole->integer ) break; #ifdef WSW_EVDEV if( m_evdev_num ) break; #endif time = Sys_XTimeToSysTime(event.xkey.time); if( event.xbutton.button == 1 ) Key_MouseEvent( K_MOUSE1, 0, time ); else if( event.xbutton.button == 2 ) Key_MouseEvent( K_MOUSE3, 0, time ); else if( event.xbutton.button == 3 ) Key_MouseEvent( K_MOUSE2, 0, time ); else if( event.xbutton.button == 4 ) Key_Event( K_MWHEELUP, 0, time ); else if( event.xbutton.button == 5 ) Key_Event( K_MWHEELDOWN, 0, time ); else if( event.xbutton.button >= 6 && event.xbutton.button <= 10 ) Key_MouseEvent( K_MOUSE4+event.xbutton.button-6, 0, time ); break; case FocusIn: if( x11display.ic ) XSetICFocus(x11display.ic); if( !focus ) { focus = qtrue; } break; case FocusOut: if( x11display.ic ) XUnsetICFocus(x11display.ic); if( focus ) { Key_ClearStates(); focus = qfalse; } break; case ClientMessage: if( event.xclient.data.l[0] == x11display.wmDeleteWindow ) Cbuf_ExecuteText( EXEC_NOW, "quit" ); break; case MapNotify: mapped = qtrue; if( x11display.modeset ) { if ( x11display.dpy && x11display.win ) { XSetInputFocus( x11display.dpy, x11display.win, RevertToPointerRoot, CurrentTime ); x11display.modeset = qfalse; } } if( input_active ) { uninstall_grabs(); install_grabs(); } break; case ConfigureNotify: VID_AppActivate( qtrue, qfalse ); break; case PropertyNotify: if( event.xproperty.window == x11display.win ) { if ( event.xproperty.atom == x11display.wmState ) { qboolean was_minimized = minimized; _X11_CheckWMSTATE(); if( minimized != was_minimized ) { // FIXME: find a better place for this?.. CL_SoundModule_Activate( !minimized ); } } } break; } } if( dowarp ) { XWarpPointer( x11display.dpy, None, x11display.win, 0, 0, 0, 0, x11display.win_width/2, x11display.win_height/2 ); } // set fullscreen or windowed mode upon focus in/out events if: // a) lost focus in fullscreen -> windowed // b) received focus -> fullscreen if a) if( ( focus != was_focused ) ) { if( x11display.features.wmStateFullscreen ) { if( !focus && Cvar_Value( "vid_fullscreen" ) ) { go_fullscreen_on_focus = qtrue; Cbuf_ExecuteText( EXEC_APPEND, "vid_fullscreen 0\n" ); } else if( focus && go_fullscreen_on_focus ) { go_fullscreen_on_focus = qfalse; Cbuf_ExecuteText( EXEC_APPEND, "vid_fullscreen 1\n" ); } } } }