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 <psychon@znc.in>
This commit is contained in:
parent
d9e4c1e866
commit
bd8158495e
35
event.c
35
event.c
|
@ -113,7 +113,7 @@ event_handle_mousegrabber(int x, int y, uint16_t mask)
|
||||||
if(globalconf.mousegrabber != LUA_REFNIL)
|
if(globalconf.mousegrabber != LUA_REFNIL)
|
||||||
{
|
{
|
||||||
lua_rawgeti(globalconf.L, LUA_REGISTRYINDEX, globalconf.mousegrabber);
|
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))
|
if(lua_pcall(globalconf.L, 1, 1, 0))
|
||||||
{
|
{
|
||||||
warn("error running function: %s", lua_tostring(globalconf.L, -1));
|
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);
|
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.
|
/** The button press event handler.
|
||||||
* \param ev The event.
|
* \param ev The event.
|
||||||
*/
|
*/
|
||||||
|
@ -167,6 +198,8 @@ event_handle_button(xcb_button_press_event_t *ev)
|
||||||
|
|
||||||
globalconf.timestamp = ev->time;
|
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)))
|
if(event_handle_mousegrabber(ev->root_x, ev->root_y, 1 << (ev->detail - 1 + 8)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -64,6 +64,8 @@ typedef struct
|
||||||
button_array_t buttons;
|
button_array_t buttons;
|
||||||
/** Modifiers masks */
|
/** Modifiers masks */
|
||||||
uint16_t numlockmask, shiftlockmask, capslockmask, modeswitchmask;
|
uint16_t numlockmask, shiftlockmask, capslockmask, modeswitchmask;
|
||||||
|
/** Bitmask for currently pressed buttons */
|
||||||
|
uint32_t buttons_pressed;
|
||||||
/** Check for XTest extension */
|
/** Check for XTest extension */
|
||||||
bool have_xtest;
|
bool have_xtest;
|
||||||
/** Clients list */
|
/** Clients list */
|
||||||
|
|
34
mouse.c
34
mouse.c
|
@ -32,11 +32,10 @@
|
||||||
* \param x will be set to the Pointer-x-coordinate relative to window
|
* \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 y will be set to the Pointer-y-coordinate relative to window
|
||||||
* \param child Will be set to the window under the pointer.
|
* \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
|
* \return true on success, false if an error occurred
|
||||||
**/
|
**/
|
||||||
bool
|
static bool
|
||||||
mouse_query_pointer(xcb_window_t window, int16_t *x, int16_t *y, xcb_window_t *child, uint16_t *mask)
|
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_cookie_t query_ptr_c;
|
||||||
xcb_query_pointer_reply_t *query_ptr_r;
|
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;
|
*x = query_ptr_r->win_x;
|
||||||
*y = query_ptr_r->win_y;
|
*y = query_ptr_r->win_y;
|
||||||
if(mask)
|
|
||||||
*mask = query_ptr_r->mask;
|
|
||||||
if(child)
|
if(child)
|
||||||
*child = query_ptr_r->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.
|
* \return True on success, false if an error occurred.
|
||||||
*/
|
*/
|
||||||
static bool
|
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;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -106,7 +103,7 @@ luaA_mouse_index(lua_State *L)
|
||||||
|
|
||||||
if(a_strcmp(attr, "screen") == 0)
|
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;
|
return 0;
|
||||||
|
|
||||||
screen = screen_getbycoord(mouse_x, mouse_y);
|
screen = screen_getbycoord(mouse_x, mouse_y);
|
||||||
|
@ -150,7 +147,7 @@ luaA_mouse_newindex(lua_State *L)
|
||||||
* \param mask The button mask.
|
* \param mask The button mask.
|
||||||
*/
|
*/
|
||||||
int
|
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_createtable(L, 0, 2);
|
||||||
lua_pushnumber(L, x);
|
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);
|
lua_createtable(L, 5, 0);
|
||||||
|
|
||||||
int i = 1;
|
const int max_button = sizeof(globalconf.buttons_pressed) * 8;
|
||||||
|
int mask = 1;
|
||||||
for(uint16_t maski = XCB_BUTTON_MASK_1; maski <= XCB_BUTTON_MASK_5; maski <<= 1)
|
for (int i = 1; i <= max_button; i++, mask <<= 1)
|
||||||
{
|
{
|
||||||
if(mask & maski)
|
if(globalconf.buttons_pressed & mask)
|
||||||
lua_pushboolean(L, true);
|
lua_pushboolean(L, true);
|
||||||
else
|
else
|
||||||
lua_pushboolean(L, false);
|
lua_pushboolean(L, false);
|
||||||
lua_rawseti(L, -2, i++);
|
lua_rawseti(L, -2, i);
|
||||||
}
|
}
|
||||||
lua_setfield(L, -2, "buttons");
|
lua_setfield(L, -2, "buttons");
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -181,7 +178,6 @@ luaA_mouse_pushstatus(lua_State *L, int x, int y, uint16_t mask)
|
||||||
static int
|
static int
|
||||||
luaA_mouse_coords(lua_State *L)
|
luaA_mouse_coords(lua_State *L)
|
||||||
{
|
{
|
||||||
uint16_t mask;
|
|
||||||
int x, y;
|
int x, y;
|
||||||
int16_t mouse_x, mouse_y;
|
int16_t mouse_x, mouse_y;
|
||||||
|
|
||||||
|
@ -190,7 +186,7 @@ luaA_mouse_coords(lua_State *L)
|
||||||
luaA_checktable(L, 1);
|
luaA_checktable(L, 1);
|
||||||
bool ignore_enter_notify = (lua_gettop(L) == 2 && luaA_checkboolean(L, 2));
|
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;
|
return 0;
|
||||||
|
|
||||||
x = luaA_getopt_number(L, 1, "x", mouse_x);
|
x = luaA_getopt_number(L, 1, "x", mouse_x);
|
||||||
|
@ -207,10 +203,10 @@ luaA_mouse_coords(lua_State *L)
|
||||||
lua_pop(L, 1);
|
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 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.
|
/** 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;
|
int16_t mouse_x, mouse_y;
|
||||||
xcb_window_t child;
|
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;
|
return 0;
|
||||||
|
|
||||||
drawin_t *drawin;
|
drawin_t *drawin;
|
||||||
|
|
3
mouse.h
3
mouse.h
|
@ -26,8 +26,7 @@
|
||||||
#include <xcb/xcb.h>
|
#include <xcb/xcb.h>
|
||||||
#include <lua.h>
|
#include <lua.h>
|
||||||
|
|
||||||
bool mouse_query_pointer(xcb_window_t, int16_t *, int16_t *, xcb_window_t *, uint16_t *);
|
int luaA_mouse_pushstatus(lua_State *, int, int);
|
||||||
int luaA_mouse_pushstatus(lua_State *, int, int, uint16_t);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
||||||
|
|
|
@ -59,18 +59,6 @@ mousegrabber_grab(xcb_cursor_t cursor)
|
||||||
return false;
|
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
|
/** Grab the mouse pointer and list motions, calling callback function at each
|
||||||
* motion. The callback function must return a boolean value: true to
|
* motion. The callback function must return a boolean value: true to
|
||||||
* continue grabbing, false to stop.
|
* continue grabbing, false to stop.
|
||||||
|
|
|
@ -26,7 +26,6 @@
|
||||||
#include <xcb/xcb.h>
|
#include <xcb/xcb.h>
|
||||||
|
|
||||||
int luaA_mousegrabber_stop(lua_State *);
|
int luaA_mousegrabber_stop(lua_State *);
|
||||||
void mousegrabber_handleevent(lua_State *, int, int, uint16_t);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
||||||
|
|
Loading…
Reference in New Issue