diff --git a/awesome.c b/awesome.c index bd5881e36..7f217b7e0 100644 --- a/awesome.c +++ b/awesome.c @@ -28,6 +28,7 @@ #include +#include #include #include "awesome.h" @@ -399,6 +400,11 @@ main(int argc, char **argv) if(xcb_connection_has_error(globalconf.connection)) fatal("cannot open display"); + /* check for xtest extension */ + const xcb_query_extension_reply_t *xtest_query; + xtest_query = xcb_get_extension_data(globalconf.connection, &xcb_test_id); + globalconf.have_xtest = xtest_query->present; + /* initiliaze dbus */ a_dbus_init(); diff --git a/awesomeConfig.cmake b/awesomeConfig.cmake index 1cbccb024..dfd6a4454 100644 --- a/awesomeConfig.cmake +++ b/awesomeConfig.cmake @@ -136,6 +136,7 @@ pkg_check_modules(AWESOME_REQUIRED REQUIRED pangocairo>=1.19.3 x11-xcb xcb-randr + xcb-xtest xcb-xinerama xcb-event>=0.3.0 xcb-aux>=0.3.0 diff --git a/client.c b/client.c index 71b6d1c07..589aa9eea 100644 --- a/client.c +++ b/client.c @@ -19,6 +19,7 @@ * */ +#include #include #include @@ -1894,6 +1895,72 @@ luaA_client_buttons(lua_State *L) return luaA_button_array_get(L, buttons); } +/** Send fake events to a client. + * \param L The Lua VM state. + * \return The number of element pushed on stack. + * \luastack + * \lvalue A client. + * \param The event type: key_press, key_release, button_press, button_release + * or motion_notify. + * \param The detail: in case of a key event, this is the keycode to send, in + * case of a button event this is the number of the button. In case of a motion + * event, this is a boolean value which if true make the coordinates relatives. + * \param In case of a motion event, this is the X coordinate. + * \param In case of a motion event, this is the Y coordinate. + */ +static int +luaA_client_fake_input(lua_State *L) +{ + if(!globalconf.have_xtest) + { + luaA_warn(L, "XTest extension is not available, cannot fake input."); + return 0; + } + + client_t **c = luaA_checkudata(L, 1, "client"); + size_t tlen; + const char *stype = luaL_checklstring(L, 2, &tlen); + uint8_t type, detail; + int x = 0, y = 0; + + switch(a_tokenize(stype, tlen)) + { + case A_TK_KEY_PRESS: + type = XCB_KEY_PRESS; + detail = luaL_checknumber(L, 3); /* keycode */ + break; + case A_TK_KEY_RELEASE: + type = XCB_KEY_RELEASE; + detail = luaL_checknumber(L, 3); /* keycode */ + break; + case A_TK_BUTTON_PRESS: + type = XCB_BUTTON_PRESS; + detail = luaL_checknumber(L, 3); /* button number */ + break; + case A_TK_BUTTON_RELEASE: + type = XCB_BUTTON_RELEASE; + detail = luaL_checknumber(L, 3); /* button number */ + break; + case A_TK_MOTION_NOTIFY: + type = XCB_MOTION_NOTIFY; + detail = luaA_checkboolean(L, 3); /* relative to the current position or not */ + x = luaL_checknumber(L, 4); + y = luaL_checknumber(L, 5); + break; + default: + return 0; + } + + xcb_test_fake_input(globalconf.connection, + type, + detail, + XCB_CURRENT_TIME, + (*c)->win, + x, y, + 0); + return 0; +} + /* Client module. * \param L The Lua VM state. * \return The number of pushed elements. @@ -1985,6 +2052,7 @@ const struct luaL_reg awesome_client_meta[] = { "mouse_resize", luaA_client_mouse_resize }, { "mouse_move", luaA_client_mouse_move }, { "unmanage", luaA_client_unmanage }, + { "fake_input", luaA_client_fake_input }, { "__index", luaA_client_index }, { "__newindex", luaA_client_newindex }, { "__eq", luaA_client_eq }, diff --git a/common/tokenize.gperf b/common/tokenize.gperf index 97df714cd..6dfcc4b71 100644 --- a/common/tokenize.gperf +++ b/common/tokenize.gperf @@ -11,6 +11,8 @@ border_padding border_width bottom button +button_press +button_release center char class @@ -42,6 +44,8 @@ icon icon_name image instance +key_press +key_release leader_id left len @@ -59,6 +63,7 @@ Mod2 Mod3 Mod4 Mod5 +motion_notify mouse_enter mouse_leave name diff --git a/structs.h b/structs.h index 97beb40af..8f75b2f2a 100644 --- a/structs.h +++ b/structs.h @@ -306,6 +306,8 @@ struct awesome_t unsigned int capslockmask; /** Check for XRandR extension */ bool have_randr; + /** Check for XTest extension */ + bool have_xtest; /** Clients list */ client_t *clients; /** Embedded windows */