From 14e28f6107d9e9bae81eeee8d0a22abdc256a295 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Mon, 12 Sep 2022 02:23:01 +0200 Subject: Fix key/button state when window loses focus (check state on call to is_**_pressed) --- src/window/window.c | 131 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 88 insertions(+), 43 deletions(-) diff --git a/src/window/window.c b/src/window/window.c index b60c9e4..8acd428 100644 --- a/src/window/window.c +++ b/src/window/window.c @@ -75,8 +75,6 @@ typedef struct { an event for all of them. */ x11_events_circular_buffer events; - bool key_pressed[__MGL_NUM_KEYS__]; - bool mouse_button_pressed[__MGL_NUM_MOUSE_BUTTONS__]; } x11_context; static void x11_context_deinit(x11_context *self); @@ -124,14 +122,6 @@ static int x11_context_init(x11_context *self) { x11_events_circular_buffer_init(&self->events); - for(size_t i = 0; i < __MGL_NUM_KEYS__; ++i) { - self->key_pressed[i] = false; - } - - for(size_t i = 0; i < __MGL_NUM_MOUSE_BUTTONS__; ++i) { - self->mouse_button_pressed[i] = false; - } - return 0; } @@ -177,34 +167,6 @@ static bool x11_context_pop_event(x11_context *self, mgl_event *event) { return x11_events_circular_buffer_pop(&self->events, event); } -/* Returns true if the state changed */ -static bool x11_context_update_key_state(x11_context *self, mgl_key key, bool key_pressed) { - if(self->key_pressed[key] != key_pressed) { - self->key_pressed[key] = key_pressed; - return true; - } else { - return false; - } -} - -/* Returns true if the state changed */ -static bool x11_context_update_mouse_button_state(x11_context *self, mgl_mouse_button button, bool button_pressed) { - if(self->mouse_button_pressed[button] != button_pressed) { - self->mouse_button_pressed[button] = button_pressed; - return true; - } else { - return false; - } -} - -static bool x11_context_is_key_pressed(const x11_context *self, mgl_key key) { - return self->key_pressed[key]; -} - -static bool x11_context_is_mouse_button_pressed(const x11_context *self, mgl_mouse_button button) { - return self->mouse_button_pressed[button]; -} - /* TODO: Use gl OML present for other platforms than nvidia? nvidia doesn't support present yet */ /* TODO: check for glx swap control extension string (GLX_EXT_swap_control, etc) */ @@ -418,6 +380,7 @@ void mgl_window_deinit(mgl_window *self) { self->open = false; } +/* Returns MGL_KEY_UNKNOWN on no match */ static mgl_key x11_keysym_to_mgl_key(KeySym key_sym) { if(key_sym >= XK_A && key_sym <= XK_Z) return MGL_KEY_A + (key_sym - XK_A); @@ -472,6 +435,59 @@ static mgl_key x11_keysym_to_mgl_key(KeySym key_sym) { return MGL_KEY_UNKNOWN; } +/* Returns XK_VoidSymbol on no match */ +static KeySym mgl_key_to_x11_keysym(mgl_key key) { + if(key >= MGL_KEY_A && key <= MGL_KEY_Z) + return XK_A + (key - MGL_KEY_A); + if(key >= MGL_KEY_NUM0 && key <= MGL_KEY_NUM9) + return XK_0 + (key - MGL_KEY_NUM0); + if(key >= MGL_KEY_NUMPAD0 && key <= MGL_KEY_NUMPAD9) + return XK_KP_0 + (key - MGL_KEY_NUMPAD0); + + /* TODO: Fill in the rest */ + switch(key) { + case MGL_KEY_SPACE: return XK_space; + case MGL_KEY_BACKSPACE: return XK_BackSpace; + case MGL_KEY_TAB: return XK_Tab; + case MGL_KEY_ENTER: return XK_Return; + case MGL_KEY_ESCAPE: return XK_Escape; + case MGL_KEY_LCONTROL: return XK_Control_L; + case MGL_KEY_LSHIFT: return XK_Shift_L; + case MGL_KEY_LALT: return XK_Alt_L; + case MGL_KEY_LSYSTEM: return XK_Super_L; + case MGL_KEY_RCONTROL: return XK_Control_R; + case MGL_KEY_RSHIFT: return XK_Shift_R; + case MGL_KEY_RALT: return XK_Alt_R; + case MGL_KEY_RSYSTEM: return XK_Super_R; + case MGL_KEY_DELETE: return XK_Delete; + case MGL_KEY_HOME: return XK_Home; + case MGL_KEY_LEFT: return XK_Left; + case MGL_KEY_UP: return XK_Up; + case MGL_KEY_RIGHT: return XK_Right; + case MGL_KEY_DOWN: return XK_Down; + case MGL_KEY_PAGEUP: return XK_Page_Up; + case MGL_KEY_PAGEDOWN: return XK_Page_Down; + case MGL_KEY_END: return XK_End; + case MGL_KEY_F1: return XK_F1; + case MGL_KEY_F2: return XK_F2; + case MGL_KEY_F3: return XK_F3; + case MGL_KEY_F4: return XK_F4; + case MGL_KEY_F5: return XK_F5; + case MGL_KEY_F6: return XK_F6; + case MGL_KEY_F7: return XK_F7; + case MGL_KEY_F8: return XK_F8; + case MGL_KEY_F9: return XK_F9; + case MGL_KEY_F10: return XK_F10; + case MGL_KEY_F11: return XK_F11; + case MGL_KEY_F12: return XK_F12; + case MGL_KEY_F13: return XK_F13; + case MGL_KEY_F14: return XK_F14; + case MGL_KEY_F15: return XK_F15; + default: return XK_VoidSymbol; + } + return XK_VoidSymbol; +} + static mgl_mouse_button x11_button_to_mgl_button(unsigned int button) { switch(button) { case Button1: return MGL_BUTTON_LEFT; @@ -489,7 +505,6 @@ static void mgl_window_handle_key_event(mgl_window *self, XKeyEvent *xkey, mgl_e event->key.control = ((xkey->state & ControlMask) != 0); event->key.shift = ((xkey->state & ShiftMask) != 0); event->key.system = ((xkey->state & Mod4Mask) != 0); - x11_context_update_key_state(self->context, event->key.code, pressed); } static void mgl_window_handle_text_event(mgl_window *self, XEvent *xev) { @@ -577,7 +592,6 @@ static void mgl_window_on_receive_event(mgl_window *self, XEvent *xev, mgl_event event->mouse_button.button = x11_button_to_mgl_button(xev->xbutton.button); event->mouse_button.x = xev->xbutton.x; event->mouse_button.y = xev->xbutton.y; - x11_context_update_mouse_button_state(self->context, event->mouse_button.button, true); } return; } @@ -586,7 +600,6 @@ static void mgl_window_on_receive_event(mgl_window *self, XEvent *xev, mgl_event event->mouse_button.button = x11_button_to_mgl_button(xev->xbutton.button); event->mouse_button.x = xev->xbutton.x; event->mouse_button.y = xev->xbutton.y; - x11_context_update_mouse_button_state(self->context, event->mouse_button.button, false); return; } case FocusIn: { @@ -780,16 +793,48 @@ bool mgl_window_has_focus(const mgl_window *self) { return self->focused; } +/* TODO: Track keys with events instead, but somehow handle window focus lost */ bool mgl_window_is_key_pressed(const mgl_window *self, mgl_key key) { if(key < 0 || key >= __MGL_NUM_KEYS__) return false; - return x11_context_is_key_pressed(self->context, key); + + mgl_context *context = mgl_get_context(); + const KeySym keysym = mgl_key_to_x11_keysym(key); + if(keysym == XK_VoidSymbol) + return false; + + KeyCode keycode = XKeysymToKeycode(context->connection, keysym); + if(keycode == 0) + return false; + + char keys[32]; + XQueryKeymap(context->connection, keys); + + return (keys[keycode / 8] & (1 << (keycode % 8))) != 0; } +/* TODO: Track keys with events instead, but somehow handle window focus lost */ bool mgl_window_is_mouse_button_pressed(const mgl_window *self, mgl_mouse_button button) { if(button < 0 || button >= __MGL_NUM_MOUSE_BUTTONS__) return false; - return x11_context_is_mouse_button_pressed(self->context, button); + + mgl_context *context = mgl_get_context(); + Window root, child; + int root_x, root_y, win_x, win_y; + + unsigned int buttons_mask = 0; + XQueryPointer(context->connection, DefaultRootWindow(context->connection), &root, &child, &root_x, &root_y, &win_x, &win_y, &buttons_mask); + + switch(button) { + case MGL_BUTTON_LEFT: return buttons_mask & Button1Mask; + case MGL_BUTTON_MIDDLE: return buttons_mask & Button2Mask; + case MGL_BUTTON_RIGHT: return buttons_mask & Button3Mask; + case MGL_BUTTON_XBUTTON1: return false; /* Not supported by x11 */ + case MGL_BUTTON_XBUTTON2: return false; /* Not supported by x11 */ + default: return false; + } + + return false; } void mgl_window_close(mgl_window *self) { -- cgit v1.2.3