From bd8158495e059baa0e8ba525b813254451447f4a Mon Sep 17 00:00:00 2001 From: Uli Schlachter Date: Sat, 20 Aug 2011 15:39:49 +0200 Subject: [PATCH] Support more than 5 mouse buttons X11 only let's you query the state of mouse button 1 to 5. However, it can generate ButtonPress and ButtonRelease events for up to 256 mouse buttons. Instead of asking the server which buttons are pressed, we will now remember the button state from those ButtonPress and ButtonRelease events. Currently this let's us keep track of up to 32 mouse buttons. Signed-off-by: Uli Schlachter --- event.c | 35 ++++++++++++++++++++++++++++++++++- globalconf.h | 2 ++ mouse.c | 34 +++++++++++++++------------------- mouse.h | 3 +-- mousegrabber.c | 12 ------------ mousegrabber.h | 1 - 6 files changed, 52 insertions(+), 35 deletions(-) diff --git a/event.c b/event.c index 4dfe2889..3028e32d 100644 --- a/event.c +++ b/event.c @@ -113,7 +113,7 @@ event_handle_mousegrabber(int x, int y, uint16_t mask) if(globalconf.mousegrabber != LUA_REFNIL) { lua_rawgeti(globalconf.L, LUA_REGISTRYINDEX, globalconf.mousegrabber); - mousegrabber_handleevent(globalconf.L, x, y, mask); + luaA_mouse_pushstatus(globalconf.L, x, y); if(lua_pcall(globalconf.L, 1, 1, 0)) { warn("error running function: %s", lua_tostring(globalconf.L, -1)); @@ -156,6 +156,37 @@ event_emit_button(xcb_button_press_event_t *ev) luaA_object_emit_signal(globalconf.L, -5, name, 4); } +/** Update the global button state + * \param response_type XCB_BUTTON_PRESS or XCB_BUTTON_RELEASE + * \param button Button being changed + */ +static void +event_update_button_state(uint8_t response_type, uint8_t button) +{ + /* There is no button 0! */ + const unsigned int max_button = sizeof(globalconf.buttons_pressed) * 8; + uint32_t mask = 1 << (button - 1); + + if (button > max_button) { + warn("Button %d pressed, but we only support %d buttons", button, max_button); + return; + } + + switch(response_type) + { + case XCB_BUTTON_PRESS: + /* Set the (button-1)-st bit */ + globalconf.buttons_pressed |= mask; + break; + case XCB_BUTTON_RELEASE: + /* Clear the (button-1)-st bit */ + globalconf.buttons_pressed &= ~mask; + break; + default: + fatal("Invalid event type"); + } +} + /** The button press event handler. * \param ev The event. */ @@ -167,6 +198,8 @@ event_handle_button(xcb_button_press_event_t *ev) globalconf.timestamp = ev->time; + event_update_button_state(ev->response_type, ev->detail); + if(event_handle_mousegrabber(ev->root_x, ev->root_y, 1 << (ev->detail - 1 + 8))) return; diff --git a/globalconf.h b/globalconf.h index 3d78cfb6..27ba5104 100644 --- a/globalconf.h +++ b/globalconf.h @@ -64,6 +64,8 @@ typedef struct button_array_t buttons; /** Modifiers masks */ uint16_t numlockmask, shiftlockmask, capslockmask, modeswitchmask; + /** Bitmask for currently pressed buttons */ + uint32_t buttons_pressed; /** Check for XTest extension */ bool have_xtest; /** Clients list */ diff --git a/mouse.c b/mouse.c index a1779aa1..6c685644 100644 --- a/mouse.c +++ b/mouse.c @@ -32,11 +32,10 @@ * \param x will be set to the Pointer-x-coordinate relative to window * \param y will be set to the Pointer-y-coordinate relative to window * \param child Will be set to the window under the pointer. - * \param mask will be set to the current buttons state * \return true on success, false if an error occurred **/ -bool -mouse_query_pointer(xcb_window_t window, int16_t *x, int16_t *y, xcb_window_t *child, uint16_t *mask) +static bool +mouse_query_pointer(xcb_window_t window, int16_t *x, int16_t *y, xcb_window_t *child) { xcb_query_pointer_cookie_t query_ptr_c; xcb_query_pointer_reply_t *query_ptr_r; @@ -49,8 +48,6 @@ mouse_query_pointer(xcb_window_t window, int16_t *x, int16_t *y, xcb_window_t *c *x = query_ptr_r->win_x; *y = query_ptr_r->win_y; - if(mask) - *mask = query_ptr_r->mask; if(child) *child = query_ptr_r->child; @@ -67,11 +64,11 @@ mouse_query_pointer(xcb_window_t window, int16_t *x, int16_t *y, xcb_window_t *c * \return True on success, false if an error occurred. */ static bool -mouse_query_pointer_root(int16_t *x, int16_t *y, xcb_window_t *child, uint16_t *mask) +mouse_query_pointer_root(int16_t *x, int16_t *y, xcb_window_t *child) { xcb_window_t root = globalconf.screen->root; - if(mouse_query_pointer(root, x, y, child, mask)) + if(mouse_query_pointer(root, x, y, child)) { return true; } @@ -106,7 +103,7 @@ luaA_mouse_index(lua_State *L) if(a_strcmp(attr, "screen") == 0) { - if(!mouse_query_pointer_root(&mouse_x, &mouse_y, NULL, NULL)) + if(!mouse_query_pointer_root(&mouse_x, &mouse_y, NULL)) return 0; screen = screen_getbycoord(mouse_x, mouse_y); @@ -150,7 +147,7 @@ luaA_mouse_newindex(lua_State *L) * \param mask The button mask. */ int -luaA_mouse_pushstatus(lua_State *L, int x, int y, uint16_t mask) +luaA_mouse_pushstatus(lua_State *L, int x, int y) { lua_createtable(L, 0, 2); lua_pushnumber(L, x); @@ -160,15 +157,15 @@ luaA_mouse_pushstatus(lua_State *L, int x, int y, uint16_t mask) lua_createtable(L, 5, 0); - int i = 1; - - for(uint16_t maski = XCB_BUTTON_MASK_1; maski <= XCB_BUTTON_MASK_5; maski <<= 1) + const int max_button = sizeof(globalconf.buttons_pressed) * 8; + int mask = 1; + for (int i = 1; i <= max_button; i++, mask <<= 1) { - if(mask & maski) + if(globalconf.buttons_pressed & mask) lua_pushboolean(L, true); else lua_pushboolean(L, false); - lua_rawseti(L, -2, i++); + lua_rawseti(L, -2, i); } lua_setfield(L, -2, "buttons"); return 1; @@ -181,7 +178,6 @@ luaA_mouse_pushstatus(lua_State *L, int x, int y, uint16_t mask) static int luaA_mouse_coords(lua_State *L) { - uint16_t mask; int x, y; int16_t mouse_x, mouse_y; @@ -190,7 +186,7 @@ luaA_mouse_coords(lua_State *L) luaA_checktable(L, 1); bool ignore_enter_notify = (lua_gettop(L) == 2 && luaA_checkboolean(L, 2)); - if(!mouse_query_pointer_root(&mouse_x, &mouse_y, NULL, &mask)) + if(!mouse_query_pointer_root(&mouse_x, &mouse_y, NULL)) return 0; x = luaA_getopt_number(L, 1, "x", mouse_x); @@ -207,10 +203,10 @@ luaA_mouse_coords(lua_State *L) lua_pop(L, 1); } - if(!mouse_query_pointer_root(&mouse_x, &mouse_y, NULL, &mask)) + if(!mouse_query_pointer_root(&mouse_x, &mouse_y, NULL)) return 0; - return luaA_mouse_pushstatus(L, mouse_x, mouse_y, mask); + return luaA_mouse_pushstatus(L, mouse_x, mouse_y); } /** Get the client which is under the pointer. @@ -225,7 +221,7 @@ luaA_mouse_object_under_pointer(lua_State *L) int16_t mouse_x, mouse_y; xcb_window_t child; - if(!mouse_query_pointer_root(&mouse_x, &mouse_y, &child, NULL)) + if(!mouse_query_pointer_root(&mouse_x, &mouse_y, &child)) return 0; drawin_t *drawin; diff --git a/mouse.h b/mouse.h index db690984..2a310a70 100644 --- a/mouse.h +++ b/mouse.h @@ -26,8 +26,7 @@ #include #include -bool mouse_query_pointer(xcb_window_t, int16_t *, int16_t *, xcb_window_t *, uint16_t *); -int luaA_mouse_pushstatus(lua_State *, int, int, uint16_t); +int luaA_mouse_pushstatus(lua_State *, int, int); #endif // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80 diff --git a/mousegrabber.c b/mousegrabber.c index f603b3e4..5cac8e91 100644 --- a/mousegrabber.c +++ b/mousegrabber.c @@ -59,18 +59,6 @@ mousegrabber_grab(xcb_cursor_t cursor) return false; } -/** Handle mouse motion events. - * \param L Lua stack to push the pointer motion. - * \param x The received mouse event x component. - * \param y The received mouse event y component. - * \param mask The received mouse event bit mask. - */ -void -mousegrabber_handleevent(lua_State *L, int x, int y, uint16_t mask) -{ - luaA_mouse_pushstatus(L, x, y, mask); -} - /** Grab the mouse pointer and list motions, calling callback function at each * motion. The callback function must return a boolean value: true to * continue grabbing, false to stop. diff --git a/mousegrabber.h b/mousegrabber.h index 87f8d7c6..04eee314 100644 --- a/mousegrabber.h +++ b/mousegrabber.h @@ -26,7 +26,6 @@ #include int luaA_mousegrabber_stop(lua_State *); -void mousegrabber_handleevent(lua_State *, int, int, uint16_t); #endif // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80