client: implements per-client key bindings
Signed-off-by: Julien Danjou <julien@danjou.info>
This commit is contained in:
parent
bf44ae1e03
commit
d9c868b627
213
awesomerc.lua.in
213
awesomerc.lua.in
|
@ -168,7 +168,6 @@ root.buttons({
|
||||||
-- }}}
|
-- }}}
|
||||||
|
|
||||||
-- {{{ Key bindings
|
-- {{{ Key bindings
|
||||||
|
|
||||||
-- Bind keyboard digits
|
-- Bind keyboard digits
|
||||||
-- Compute the maximum number of digit we need, limited to 9
|
-- Compute the maximum number of digit we need, limited to 9
|
||||||
keynumber = 0
|
keynumber = 0
|
||||||
|
@ -176,120 +175,135 @@ for s = 1, screen.count() do
|
||||||
keynumber = math.min(9, math.max(#tags[s], keynumber));
|
keynumber = math.min(9, math.max(#tags[s], keynumber));
|
||||||
end
|
end
|
||||||
|
|
||||||
|
globalkeys = {}
|
||||||
|
clientkeys = {}
|
||||||
|
|
||||||
for i = 1, keynumber do
|
for i = 1, keynumber do
|
||||||
key({ modkey }, i,
|
table.insert(globalkeys,
|
||||||
function ()
|
key({ modkey }, i,
|
||||||
local screen = mouse.screen
|
function ()
|
||||||
if tags[screen][i] then
|
local screen = mouse.screen
|
||||||
awful.tag.viewonly(tags[screen][i])
|
if tags[screen][i] then
|
||||||
end
|
awful.tag.viewonly(tags[screen][i])
|
||||||
end):add()
|
end
|
||||||
key({ modkey, "Control" }, i,
|
end))
|
||||||
function ()
|
table.insert(globalkeys,
|
||||||
local screen = mouse.screen
|
key({ modkey, "Control" }, i,
|
||||||
if tags[screen][i] then
|
function ()
|
||||||
tags[screen][i].selected = not tags[screen][i].selected
|
local screen = mouse.screen
|
||||||
end
|
if tags[screen][i] then
|
||||||
end):add()
|
tags[screen][i].selected = not tags[screen][i].selected
|
||||||
key({ modkey, "Shift" }, i,
|
end
|
||||||
function ()
|
end))
|
||||||
if client.focus and tags[client.focus.screen][i] then
|
table.insert(globalkeys,
|
||||||
awful.client.movetotag(tags[client.focus.screen][i])
|
key({ modkey, "Shift" }, i,
|
||||||
end
|
function ()
|
||||||
end):add()
|
if client.focus and tags[client.focus.screen][i] then
|
||||||
key({ modkey, "Control", "Shift" }, i,
|
awful.client.movetotag(tags[client.focus.screen][i])
|
||||||
function ()
|
end
|
||||||
if client.focus and tags[client.focus.screen][i] then
|
end))
|
||||||
awful.client.toggletag(tags[client.focus.screen][i])
|
table.insert(globalkeys,
|
||||||
end
|
key({ modkey, "Control", "Shift" }, i,
|
||||||
end):add()
|
function ()
|
||||||
|
if client.focus and tags[client.focus.screen][i] then
|
||||||
|
awful.client.toggletag(tags[client.focus.screen][i])
|
||||||
|
end
|
||||||
|
end))
|
||||||
end
|
end
|
||||||
|
|
||||||
key({ modkey }, "Left", awful.tag.viewprev):add()
|
table.insert(globalkeys, key({ modkey }, "Left", awful.tag.viewprev))
|
||||||
key({ modkey }, "Right", awful.tag.viewnext):add()
|
table.insert(globalkeys, key({ modkey }, "Right", awful.tag.viewnext))
|
||||||
key({ modkey }, "Escape", awful.tag.history.restore):add()
|
table.insert(globalkeys, key({ modkey }, "Escape", awful.tag.history.restore))
|
||||||
|
|
||||||
|
table.insert(globalkeys, key({ modkey }, "j", function () awful.client.focus.byidx(1); if client.focus then client.focus:raise() end end))
|
||||||
|
table.insert(globalkeys, key({ modkey }, "k", function () awful.client.focus.byidx(-1); if client.focus then client.focus:raise() end end))
|
||||||
|
table.insert(globalkeys, key({ modkey, "Shift" }, "j", function () awful.client.swap.byidx(1) end))
|
||||||
|
table.insert(globalkeys, key({ modkey, "Shift" }, "k", function () awful.client.swap.byidx(-1) end))
|
||||||
|
|
||||||
|
table.insert(globalkeys, key({ modkey, "Control" }, "j", function () awful.screen.focus(1) end))
|
||||||
|
table.insert(globalkeys, key({ modkey, "Control" }, "k", function () awful.screen.focus(-1) end))
|
||||||
|
|
||||||
|
table.insert(globalkeys, key({ modkey }, "Tab", function () awful.client.focus.history.previous(); if client.focus then client.focus:raise() end end))
|
||||||
|
|
||||||
|
table.insert(globalkeys, key({ modkey }, "u", awful.client.urgent.jumpto))
|
||||||
|
|
||||||
-- Standard program
|
-- Standard program
|
||||||
key({ modkey }, "Return", function () awful.util.spawn(terminal) end):add()
|
table.insert(globalkeys, key({ modkey }, "Return", function () awful.util.spawn(terminal) end))
|
||||||
|
|
||||||
key({ modkey, "Control" }, "r", function ()
|
table.insert(globalkeys, key({ modkey, "Control" }, "r", function ()
|
||||||
mypromptbox[mouse.screen].text =
|
mypromptbox[mouse.screen].text =
|
||||||
awful.util.escape(awful.util.restart())
|
awful.util.escape(awful.util.restart())
|
||||||
end):add()
|
end))
|
||||||
key({ modkey, "Shift" }, "q", awesome.quit):add()
|
table.insert(globalkeys, key({ modkey, "Shift" }, "q", awesome.quit))
|
||||||
|
|
||||||
-- Client manipulation
|
-- Client manipulation
|
||||||
key({ modkey }, "m", function () if client.focus then client.focus.maximized_horizontal = not client.focus.maximized_horizontal
|
table.insert(clientkeys, key({ modkey }, "m", function (c) c.maximized_horizontal = not c.maximized_horizontal
|
||||||
client.focus.maximized_vertical = not client.focus.maximized_vertical end end):add()
|
c.maximized_vertical = not c.maximized_vertical end))
|
||||||
key({ modkey }, "f", function () if client.focus then client.focus.fullscreen = not client.focus.fullscreen end end):add()
|
table.insert(clientkeys, key({ modkey }, "f", function (c) c.fullscreen = not c.fullscreen end))
|
||||||
key({ modkey, "Shift" }, "c", function () if client.focus then client.focus:kill() end end):add()
|
table.insert(clientkeys, key({ modkey, "Shift" }, "c", function (c) c:kill() end))
|
||||||
key({ modkey }, "j", function () awful.client.focus.byidx(1); if client.focus then client.focus:raise() end end):add()
|
table.insert(clientkeys, key({ modkey, "Control" }, "space", awful.client.floating.toggle))
|
||||||
key({ modkey }, "k", function () awful.client.focus.byidx(-1); if client.focus then client.focus:raise() end end):add()
|
table.insert(clientkeys, key({ modkey, "Control" }, "Return", function (c) c:swap(awful.client.getmaster()) end))
|
||||||
key({ modkey, "Shift" }, "j", function () awful.client.swap.byidx(1) end):add()
|
table.insert(clientkeys, key({ modkey }, "o", awful.client.movetoscreen))
|
||||||
key({ modkey, "Shift" }, "k", function () awful.client.swap.byidx(-1) end):add()
|
table.insert(clientkeys, key({ modkey, "Shift" }, "r", function (c) c:redraw() end))
|
||||||
key({ modkey, "Control" }, "j", function () awful.screen.focus(1) end):add()
|
table.insert(clientkeys, key({ modkey, "Ctrl" }, "i", function (c)
|
||||||
key({ modkey, "Control" }, "k", function () awful.screen.focus(-1) end):add()
|
local s = c.screen
|
||||||
key({ modkey, "Control" }, "space", awful.client.floating.toggle):add()
|
if mypromptbox[s].text then
|
||||||
key({ modkey, "Control" }, "Return", function () if client.focus then client.focus:swap(awful.client.getmaster()) end end):add()
|
mypromptbox[s].text = nil
|
||||||
key({ modkey }, "o", awful.client.movetoscreen):add()
|
else
|
||||||
key({ modkey }, "Tab", function () awful.client.focus.history.previous(); if client.focus then client.focus:raise() end end):add()
|
mypromptbox[s].text = nil
|
||||||
key({ modkey }, "u", awful.client.urgent.jumpto):add()
|
if c.class then
|
||||||
key({ modkey, "Shift" }, "r", function () if client.focus then client.focus:redraw() end end):add()
|
mypromptbox[s].text = "Class: " .. c.class .. " "
|
||||||
|
end
|
||||||
|
if c.instance then
|
||||||
|
mypromptbox[s].text = mypromptbox[s].text .. "Instance: ".. c.instance .. " "
|
||||||
|
end
|
||||||
|
if c.role then
|
||||||
|
mypromptbox[s].text = mypromptbox[s].text .. "Role: ".. crole
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end))
|
||||||
|
|
||||||
-- Layout manipulation
|
-- Layout manipulation
|
||||||
key({ modkey }, "l", function () awful.tag.incmwfact(0.05) end):add()
|
table.insert(globalkeys, key({ modkey }, "l", function () awful.tag.incmwfact(0.05) end))
|
||||||
key({ modkey }, "h", function () awful.tag.incmwfact(-0.05) end):add()
|
table.insert(globalkeys, key({ modkey }, "h", function () awful.tag.incmwfact(-0.05) end))
|
||||||
key({ modkey, "Shift" }, "h", function () awful.tag.incnmaster(1) end):add()
|
table.insert(globalkeys, key({ modkey, "Shift" }, "h", function () awful.tag.incnmaster(1) end))
|
||||||
key({ modkey, "Shift" }, "l", function () awful.tag.incnmaster(-1) end):add()
|
table.insert(globalkeys, key({ modkey, "Shift" }, "l", function () awful.tag.incnmaster(-1) end))
|
||||||
key({ modkey, "Control" }, "h", function () awful.tag.incncol(1) end):add()
|
table.insert(globalkeys, key({ modkey, "Control" }, "h", function () awful.tag.incncol(1) end))
|
||||||
key({ modkey, "Control" }, "l", function () awful.tag.incncol(-1) end):add()
|
table.insert(globalkeys, key({ modkey, "Control" }, "l", function () awful.tag.incncol(-1) end))
|
||||||
key({ modkey }, "space", function () awful.layout.inc(layouts, 1) end):add()
|
table.insert(globalkeys, key({ modkey }, "space", function () awful.layout.inc(layouts, 1) end))
|
||||||
key({ modkey, "Shift" }, "space", function () awful.layout.inc(layouts, -1) end):add()
|
table.insert(globalkeys, key({ modkey, "Shift" }, "space", function () awful.layout.inc(layouts, -1) end))
|
||||||
|
|
||||||
-- Prompt
|
-- Prompt
|
||||||
key({ modkey }, "F1", function ()
|
table.insert(globalkeys, key({ modkey }, "F1", function ()
|
||||||
awful.prompt.run({ prompt = "Run: " }, mypromptbox[mouse.screen],
|
awful.prompt.run({ prompt = "Run: " },
|
||||||
awful.util.spawn, awful.completion.bash,
|
mypromptbox[mouse.screen],
|
||||||
awful.util.getdir("cache") .. "/history")
|
awful.util.spawn, awful.completion.bash,
|
||||||
end):add()
|
awful.util.getdir("cache") .. "/history")
|
||||||
key({ modkey }, "F4", function ()
|
end))
|
||||||
awful.prompt.run({ prompt = "Run Lua code: " }, mypromptbox[mouse.screen],
|
table.insert(globalkeys, key({ modkey }, "F4", function ()
|
||||||
awful.util.eval, awful.prompt.bash,
|
awful.prompt.run({ prompt = "Run Lua code: " },
|
||||||
awful.util.getdir("cache") .. "/history_eval")
|
mypromptbox[mouse.screen],
|
||||||
end):add()
|
awful.util.eval, awful.prompt.bash,
|
||||||
|
awful.util.getdir("cache") .. "/history_eval")
|
||||||
key({ modkey, "Ctrl" }, "i", function ()
|
end))
|
||||||
local s = mouse.screen
|
|
||||||
if mypromptbox[s].text then
|
|
||||||
mypromptbox[s].text = nil
|
|
||||||
elseif client.focus then
|
|
||||||
mypromptbox[s].text = nil
|
|
||||||
if client.focus.class then
|
|
||||||
mypromptbox[s].text = "Class: " .. client.focus.class .. " "
|
|
||||||
end
|
|
||||||
if client.focus.instance then
|
|
||||||
mypromptbox[s].text = mypromptbox[s].text .. "Instance: ".. client.focus.instance .. " "
|
|
||||||
end
|
|
||||||
if client.focus.role then
|
|
||||||
mypromptbox[s].text = mypromptbox[s].text .. "Role: ".. client.focus.role
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end):add()
|
|
||||||
|
|
||||||
-- Client awful tagging: this is useful to tag some clients and then do stuff like move to tag on them
|
-- Client awful tagging: this is useful to tag some clients and then do stuff like move to tag on them
|
||||||
key({ modkey }, "t", awful.client.togglemarked):add()
|
table.insert(clientkeys, key({ modkey }, "t", awful.client.togglemarked))
|
||||||
|
|
||||||
for i = 1, keynumber do
|
for i = 1, keynumber do
|
||||||
key({ modkey, "Shift" }, "F" .. i,
|
table.insert(globalkeys, key({ modkey, "Shift" }, "F" .. i,
|
||||||
function ()
|
function ()
|
||||||
local screen = mouse.screen
|
local screen = mouse.screen
|
||||||
if tags[screen][i] then
|
if tags[screen][i] then
|
||||||
for k, c in pairs(awful.client.getmarked()) do
|
for k, c in pairs(awful.client.getmarked()) do
|
||||||
awful.client.movetotag(tags[screen][i], c)
|
awful.client.movetotag(tags[screen][i], c)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end):add()
|
end))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Set keys
|
||||||
|
root.keys(globalkeys)
|
||||||
-- }}}
|
-- }}}
|
||||||
|
|
||||||
-- {{{ Hooks
|
-- {{{ Hooks
|
||||||
|
@ -374,6 +388,9 @@ awful.hooks.manage.register(function (c, startup)
|
||||||
-- Do this after tag mapping, so you don't see it on the wrong tag for a split second.
|
-- Do this after tag mapping, so you don't see it on the wrong tag for a split second.
|
||||||
client.focus = c
|
client.focus = c
|
||||||
|
|
||||||
|
-- Set key bindings
|
||||||
|
c:keys(clientkeys)
|
||||||
|
|
||||||
-- Set the windows at the slave,
|
-- Set the windows at the slave,
|
||||||
-- i.e. put it at the end of others instead of setting it master.
|
-- i.e. put it at the end of others instead of setting it master.
|
||||||
-- awful.client.setslave(c)
|
-- awful.client.setslave(c)
|
||||||
|
|
25
client.c
25
client.c
|
@ -1897,6 +1897,30 @@ luaA_client_buttons(lua_State *L)
|
||||||
return luaA_button_array_get(L, buttons);
|
return luaA_button_array_get(L, buttons);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Get or set keys bindings for a client.
|
||||||
|
* \param L The Lua VM state.
|
||||||
|
* \return The number of element pushed on stack.
|
||||||
|
* \luastack
|
||||||
|
* \lvalue A client.
|
||||||
|
* \lparam An array of key bindings objects, or nothing.
|
||||||
|
* \return The array of key bindings objects of this client.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
luaA_client_keys(lua_State *L)
|
||||||
|
{
|
||||||
|
client_t **c = luaA_checkudata(L, 1, "client");
|
||||||
|
keybindings_t *keys = &(*c)->keys;
|
||||||
|
|
||||||
|
if(lua_gettop(L) == 2)
|
||||||
|
{
|
||||||
|
luaA_key_array_set(L, 2, keys);
|
||||||
|
xcb_ungrab_key(globalconf.connection, XCB_GRAB_ANY, (*c)->win, XCB_BUTTON_MASK_ANY);
|
||||||
|
window_grabkeys((*c)->win, keys);
|
||||||
|
}
|
||||||
|
|
||||||
|
return luaA_key_array_get(L, keys);
|
||||||
|
}
|
||||||
|
|
||||||
/** Send fake events to a client.
|
/** Send fake events to a client.
|
||||||
* \param L The Lua VM state.
|
* \param L The Lua VM state.
|
||||||
* \return The number of element pushed on stack.
|
* \return The number of element pushed on stack.
|
||||||
|
@ -2045,6 +2069,7 @@ const struct luaL_reg awesome_client_meta[] =
|
||||||
{ "isvisible", luaA_client_isvisible },
|
{ "isvisible", luaA_client_isvisible },
|
||||||
{ "geometry", luaA_client_geometry },
|
{ "geometry", luaA_client_geometry },
|
||||||
{ "buttons", luaA_client_buttons },
|
{ "buttons", luaA_client_buttons },
|
||||||
|
{ "keys", luaA_client_keys },
|
||||||
{ "tags", luaA_client_tags },
|
{ "tags", luaA_client_tags },
|
||||||
{ "kill", luaA_client_kill },
|
{ "kill", luaA_client_kill },
|
||||||
{ "swap", luaA_client_swap },
|
{ "swap", luaA_client_swap },
|
||||||
|
|
57
event.c
57
event.c
|
@ -542,6 +542,8 @@ event_handle_key(void *data __attribute__ ((unused)),
|
||||||
xcb_connection_t *connection __attribute__ ((unused)),
|
xcb_connection_t *connection __attribute__ ((unused)),
|
||||||
xcb_key_press_event_t *ev)
|
xcb_key_press_event_t *ev)
|
||||||
{
|
{
|
||||||
|
client_t *c;
|
||||||
|
|
||||||
if(globalconf.keygrabber != LUA_REFNIL)
|
if(globalconf.keygrabber != LUA_REFNIL)
|
||||||
{
|
{
|
||||||
lua_rawgeti(globalconf.L, LUA_REGISTRYINDEX, globalconf.keygrabber);
|
lua_rawgeti(globalconf.L, LUA_REGISTRYINDEX, globalconf.keygrabber);
|
||||||
|
@ -557,9 +559,32 @@ event_handle_key(void *data __attribute__ ((unused)),
|
||||||
}
|
}
|
||||||
lua_pop(globalconf.L, 1); /* pop returned value or function if not called */
|
lua_pop(globalconf.L, 1); /* pop returned value or function if not called */
|
||||||
}
|
}
|
||||||
|
else if((c = client_getbywin(ev->event)))
|
||||||
|
{
|
||||||
|
keyb_t *k = key_find(&c->keys, ev);
|
||||||
|
|
||||||
|
if(k)
|
||||||
|
switch(ev->response_type)
|
||||||
|
{
|
||||||
|
case XCB_KEY_PRESS:
|
||||||
|
if(k->press != LUA_REFNIL)
|
||||||
|
{
|
||||||
|
luaA_client_userdata_new(globalconf.L, c);
|
||||||
|
luaA_dofunction(globalconf.L, k->press, 1, 0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case XCB_KEY_RELEASE:
|
||||||
|
if(k->release != LUA_REFNIL)
|
||||||
|
{
|
||||||
|
luaA_client_userdata_new(globalconf.L, c);
|
||||||
|
luaA_dofunction(globalconf.L, k->release, 1, 0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
keyb_t *k = key_find(ev);
|
keyb_t *k = key_find(&globalconf.keys, ev);
|
||||||
|
|
||||||
if(k)
|
if(k)
|
||||||
switch(ev->response_type)
|
switch(ev->response_type)
|
||||||
|
@ -746,9 +771,6 @@ event_handle_mappingnotify(void *data,
|
||||||
if(ev->request == XCB_MAPPING_MODIFIER
|
if(ev->request == XCB_MAPPING_MODIFIER
|
||||||
|| ev->request == XCB_MAPPING_KEYBOARD)
|
|| ev->request == XCB_MAPPING_KEYBOARD)
|
||||||
{
|
{
|
||||||
int nscreen = xcb_setup_roots_length(xcb_get_setup(connection));
|
|
||||||
int phys_screen = 0;
|
|
||||||
|
|
||||||
/* Send the request to get the NumLock, ShiftLock and CapsLock masks */
|
/* Send the request to get the NumLock, ShiftLock and CapsLock masks */
|
||||||
xmapping_cookie = xcb_get_modifier_mapping_unchecked(globalconf.connection);
|
xmapping_cookie = xcb_get_modifier_mapping_unchecked(globalconf.connection);
|
||||||
|
|
||||||
|
@ -761,23 +783,22 @@ event_handle_mappingnotify(void *data,
|
||||||
globalconf.keysyms, &globalconf.numlockmask,
|
globalconf.keysyms, &globalconf.numlockmask,
|
||||||
&globalconf.shiftlockmask, &globalconf.capslockmask);
|
&globalconf.shiftlockmask, &globalconf.capslockmask);
|
||||||
|
|
||||||
do
|
int nscreen = xcb_setup_roots_length(xcb_get_setup(connection));
|
||||||
{
|
|
||||||
xcb_screen_t *s = xutil_screen_get(globalconf.connection, phys_screen);
|
|
||||||
/* yes XCB_BUTTON_MASK_ANY is also for grab_key even if it's look
|
|
||||||
* weird */
|
|
||||||
xcb_ungrab_key(connection, XCB_GRAB_ANY, s->root, XCB_BUTTON_MASK_ANY);
|
|
||||||
phys_screen++;
|
|
||||||
} while(phys_screen < nscreen);
|
|
||||||
|
|
||||||
/* regrab everything */
|
/* regrab everything */
|
||||||
key_array_t *arr = &globalconf.keys.by_sym;
|
for(int phys_screen = 0; phys_screen < nscreen; phys_screen++)
|
||||||
for(int i = 0; i < arr->len; i++)
|
{
|
||||||
window_root_grabkey(arr->tab[i]);
|
xcb_screen_t *s = xutil_screen_get(globalconf.connection, phys_screen);
|
||||||
|
/* yes XCB_BUTTON_MASK_ANY is also for grab_key even if it's look weird */
|
||||||
|
xcb_ungrab_key(connection, XCB_GRAB_ANY, s->root, XCB_BUTTON_MASK_ANY);
|
||||||
|
window_grabkeys(s->root, &globalconf.keys);
|
||||||
|
}
|
||||||
|
|
||||||
arr = &globalconf.keys.by_code;
|
for(client_t *c = globalconf.clients; c; c = c->next)
|
||||||
for(int i = 0; i < arr->len; i++)
|
{
|
||||||
window_root_grabkey(arr->tab[i]);
|
xcb_ungrab_key(connection, XCB_GRAB_ANY, c->win, XCB_BUTTON_MASK_ANY);
|
||||||
|
window_grabkeys(c->win, &c->keys);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
181
key.c
181
key.c
|
@ -40,6 +40,20 @@ ARRAY_FUNCS(keyb_t *, key, key_unref)
|
||||||
DO_LUA_NEW(static, keyb_t, key, "key", key_ref)
|
DO_LUA_NEW(static, keyb_t, key, "key", key_ref)
|
||||||
DO_LUA_GC(keyb_t, key, "key", key_unref)
|
DO_LUA_GC(keyb_t, key, "key", key_unref)
|
||||||
|
|
||||||
|
static void
|
||||||
|
keybindings_init(keybindings_t *kb)
|
||||||
|
{
|
||||||
|
key_array_init(&kb->by_code);
|
||||||
|
key_array_init(&kb->by_sym);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
keybindings_wipe(keybindings_t *kb)
|
||||||
|
{
|
||||||
|
key_array_wipe(&kb->by_code);
|
||||||
|
key_array_wipe(&kb->by_sym);
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
key_ev_cmp(xcb_keysym_t keysym, xcb_keycode_t keycode,
|
key_ev_cmp(xcb_keysym_t keysym, xcb_keycode_t keycode,
|
||||||
unsigned long mod, const keyb_t *k)
|
unsigned long mod, const keyb_t *k)
|
||||||
|
@ -68,68 +82,45 @@ key_cmp(const keyb_t *k1, const keyb_t *k2)
|
||||||
return k1->mod == k2->mod ? 0 : (k2->mod > k1->mod ? 1 : -1);
|
return k1->mod == k2->mod ? 0 : (k2->mod > k1->mod ? 1 : -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Grab key on the root windows.
|
/** Grab key on a window.
|
||||||
|
* \param win The window.
|
||||||
* \param k The key.
|
* \param k The key.
|
||||||
*/
|
*/
|
||||||
void
|
static void
|
||||||
window_root_grabkey(keyb_t *k)
|
window_grabkey(xcb_window_t win, keyb_t *k)
|
||||||
{
|
{
|
||||||
int phys_screen = 0;
|
|
||||||
int nscreen = xcb_setup_roots_length(xcb_get_setup(globalconf.connection));
|
|
||||||
xcb_screen_t *s;
|
|
||||||
xcb_keycode_t kc;
|
xcb_keycode_t kc;
|
||||||
|
|
||||||
if((kc = k->keycode)
|
if((kc = k->keycode)
|
||||||
|| (k->keysym
|
|| (k->keysym
|
||||||
&& (kc = xcb_key_symbols_get_keycode(globalconf.keysyms, k->keysym))))
|
&& (kc = xcb_key_symbols_get_keycode(globalconf.keysyms, k->keysym))))
|
||||||
do
|
{
|
||||||
{
|
xcb_grab_key(globalconf.connection, true, win,
|
||||||
s = xutil_screen_get(globalconf.connection, phys_screen);
|
k->mod, kc, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);
|
||||||
xcb_grab_key(globalconf.connection, true, s->root,
|
xcb_grab_key(globalconf.connection, true, win,
|
||||||
k->mod, kc, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);
|
k->mod | XCB_MOD_MASK_LOCK, kc, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);
|
||||||
xcb_grab_key(globalconf.connection, true, s->root,
|
xcb_grab_key(globalconf.connection, true, win,
|
||||||
k->mod | XCB_MOD_MASK_LOCK, kc, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);
|
k->mod | globalconf.numlockmask, kc, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);
|
||||||
xcb_grab_key(globalconf.connection, true, s->root,
|
xcb_grab_key(globalconf.connection, true, win,
|
||||||
k->mod | globalconf.numlockmask, kc, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);
|
k->mod | globalconf.numlockmask | XCB_MOD_MASK_LOCK, kc, XCB_GRAB_MODE_ASYNC,
|
||||||
xcb_grab_key(globalconf.connection, true, s->root,
|
XCB_GRAB_MODE_ASYNC);
|
||||||
k->mod | globalconf.numlockmask | XCB_MOD_MASK_LOCK, kc, XCB_GRAB_MODE_ASYNC,
|
}
|
||||||
XCB_GRAB_MODE_ASYNC);
|
|
||||||
phys_screen++;
|
|
||||||
} while(phys_screen < nscreen);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Ungrab key on the root windows.
|
void
|
||||||
* \param k The key.
|
window_grabkeys(xcb_window_t win, keybindings_t *keys)
|
||||||
*/
|
|
||||||
static void
|
|
||||||
window_root_ungrabkey(keyb_t *k)
|
|
||||||
{
|
{
|
||||||
int phys_screen = 0;
|
for(int i = 0; i < keys->by_code.len; i++)
|
||||||
int nscreen = xcb_setup_roots_length(xcb_get_setup(globalconf.connection));
|
window_grabkey(win, keys->by_code.tab[i]);
|
||||||
xcb_screen_t *s;
|
|
||||||
xcb_keycode_t kc;
|
|
||||||
|
|
||||||
if((kc = k->keycode)
|
for(int i = 0; i < keys->by_sym.len; i++)
|
||||||
|| (k->keysym && (kc = xcb_key_symbols_get_keycode(globalconf.keysyms, k->keysym))))
|
window_grabkey(win, keys->by_sym.tab[i]);
|
||||||
do
|
|
||||||
{
|
|
||||||
s = xutil_screen_get(globalconf.connection, phys_screen);
|
|
||||||
xcb_ungrab_key(globalconf.connection, kc, s->root,
|
|
||||||
k->mod);
|
|
||||||
xcb_ungrab_key(globalconf.connection, kc, s->root,
|
|
||||||
k->mod | XCB_MOD_MASK_LOCK);
|
|
||||||
xcb_ungrab_key(globalconf.connection, kc, s->root,
|
|
||||||
k->mod | globalconf.numlockmask);
|
|
||||||
xcb_ungrab_key(globalconf.connection, kc, s->root,
|
|
||||||
k->mod | globalconf.numlockmask | XCB_MOD_MASK_LOCK);
|
|
||||||
phys_screen++;
|
|
||||||
} while(phys_screen < nscreen);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
key_register_root(keyb_t *k)
|
key_register(keybindings_t *keys, keyb_t *k)
|
||||||
{
|
{
|
||||||
key_array_t *arr = k->keysym ? &globalconf.keys.by_sym : &globalconf.keys.by_code;
|
key_array_t *arr = k->keysym ? &keys->by_sym : &keys->by_code;
|
||||||
int l = 0, r = arr->len;
|
int l = 0, r = arr->len;
|
||||||
|
|
||||||
key_ref(&k);
|
key_ref(&k);
|
||||||
|
@ -151,31 +142,6 @@ key_register_root(keyb_t *k)
|
||||||
}
|
}
|
||||||
|
|
||||||
key_array_splice(arr, r, 0, &k, 1);
|
key_array_splice(arr, r, 0, &k, 1);
|
||||||
window_root_grabkey(k);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
key_unregister_root(keyb_t **k)
|
|
||||||
{
|
|
||||||
key_array_t *arr = (*k)->keysym ? &globalconf.keys.by_sym : &globalconf.keys.by_code;
|
|
||||||
int l = 0, r = arr->len;
|
|
||||||
|
|
||||||
while (l < r) {
|
|
||||||
int i = (r + l) / 2;
|
|
||||||
switch (key_cmp(*k, arr->tab[i])) {
|
|
||||||
case -1: /* k < arr->tab[i] */
|
|
||||||
r = i;
|
|
||||||
break;
|
|
||||||
case 0: /* k == arr->tab[i] */
|
|
||||||
key_array_take(arr, i);
|
|
||||||
window_root_ungrabkey(*k);
|
|
||||||
key_unref(k);
|
|
||||||
return;
|
|
||||||
case 1: /* k > arr->tab[i] */
|
|
||||||
l = i + 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Return the keysym from keycode.
|
/** Return the keysym from keycode.
|
||||||
|
@ -256,9 +222,9 @@ key_getkeysym(xcb_keycode_t detail, uint16_t state)
|
||||||
|
|
||||||
|
|
||||||
keyb_t *
|
keyb_t *
|
||||||
key_find(const xcb_key_press_event_t *ev)
|
key_find(keybindings_t *keys, const xcb_key_press_event_t *ev)
|
||||||
{
|
{
|
||||||
const key_array_t *arr = &globalconf.keys.by_sym;
|
const key_array_t *arr = &keys->by_sym;
|
||||||
int l, r, mod = XUTIL_MASK_CLEAN(ev->state);
|
int l, r, mod = XUTIL_MASK_CLEAN(ev->state);
|
||||||
xcb_keysym_t keysym;
|
xcb_keysym_t keysym;
|
||||||
|
|
||||||
|
@ -283,9 +249,9 @@ key_find(const xcb_key_press_event_t *ev)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (arr != &globalconf.keys.by_code)
|
if(arr != &keys->by_code)
|
||||||
{
|
{
|
||||||
arr = &globalconf.keys.by_code;
|
arr = &keys->by_code;
|
||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -360,6 +326,55 @@ luaA_key_new(lua_State *L)
|
||||||
return luaA_key_userdata_new(L, k);
|
return luaA_key_userdata_new(L, k);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Set a key array with a Lua table.
|
||||||
|
* \param L The Lua VM state.
|
||||||
|
* \param idx The index of the Lua table.
|
||||||
|
* \param keys The array key to fill.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
luaA_key_array_set(lua_State *L, int idx, keybindings_t *keys)
|
||||||
|
{
|
||||||
|
luaA_checktable(L, idx);
|
||||||
|
|
||||||
|
for(int i = 0; i < keys->by_code.len; i++);
|
||||||
|
|
||||||
|
for(int i = 0; i < keys->by_sym.len; i++);
|
||||||
|
|
||||||
|
keybindings_wipe(keys);
|
||||||
|
|
||||||
|
keybindings_init(keys);
|
||||||
|
|
||||||
|
lua_pushnil(L);
|
||||||
|
while(lua_next(L, idx))
|
||||||
|
{
|
||||||
|
keyb_t **k = luaA_checkudata(L, -1, "key");
|
||||||
|
key_register(keys, *k);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Push an array of key as an Lua table onto the stack.
|
||||||
|
* \param L The Lua VM state.
|
||||||
|
* \param keys The key array to push.
|
||||||
|
* \return The number of elements pushed on stack.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
luaA_key_array_get(lua_State *L, keybindings_t *keys)
|
||||||
|
{
|
||||||
|
luaA_otable_new(L);
|
||||||
|
for(int i = 0; i < keys->by_code.len; i++)
|
||||||
|
{
|
||||||
|
luaA_key_userdata_new(L, keys->by_code.tab[i]);
|
||||||
|
lua_rawseti(L, -2, i + 1);
|
||||||
|
}
|
||||||
|
for(int i = 0; i < keys->by_sym.len; i++)
|
||||||
|
{
|
||||||
|
luaA_key_userdata_new(L, keys->by_sym.tab[i]);
|
||||||
|
lua_rawseti(L, -2, i + 1);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/** Add a global key binding. This key binding will always be available.
|
/** Add a global key binding. This key binding will always be available.
|
||||||
* \param L The Lua VM state.
|
* \param L The Lua VM state.
|
||||||
*
|
*
|
||||||
|
@ -369,8 +384,19 @@ luaA_key_new(lua_State *L)
|
||||||
static int
|
static int
|
||||||
luaA_key_add(lua_State *L)
|
luaA_key_add(lua_State *L)
|
||||||
{
|
{
|
||||||
|
luaA_deprecate(L, "root.keys");
|
||||||
keyb_t **k = luaA_checkudata(L, 1, "key");
|
keyb_t **k = luaA_checkudata(L, 1, "key");
|
||||||
key_register_root(*k);
|
int nscreen = xcb_setup_roots_length(xcb_get_setup(globalconf.connection));
|
||||||
|
|
||||||
|
key_register(&globalconf.keys, *k);
|
||||||
|
|
||||||
|
for(int phys_screen = 0; phys_screen < nscreen; phys_screen++)
|
||||||
|
{
|
||||||
|
xcb_screen_t *s = xutil_screen_get(globalconf.connection, phys_screen);
|
||||||
|
xcb_ungrab_key(globalconf.connection, XCB_GRAB_ANY, s->root, XCB_BUTTON_MASK_ANY);
|
||||||
|
window_grabkeys(s->root, &globalconf.keys);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -383,8 +409,7 @@ luaA_key_add(lua_State *L)
|
||||||
static int
|
static int
|
||||||
luaA_key_remove(lua_State *L)
|
luaA_key_remove(lua_State *L)
|
||||||
{
|
{
|
||||||
keyb_t **k = luaA_checkudata(L, 1, "key");
|
luaA_deprecate(L, "root.keys");
|
||||||
key_unregister_root(k);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
15
key.h
15
key.h
|
@ -44,9 +44,20 @@ typedef struct keyb_t
|
||||||
|
|
||||||
ARRAY_TYPE(keyb_t *, key)
|
ARRAY_TYPE(keyb_t *, key)
|
||||||
|
|
||||||
keyb_t *key_find(const xcb_key_press_event_t *);
|
/** Key bindings */
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
key_array_t by_code;
|
||||||
|
key_array_t by_sym;
|
||||||
|
} keybindings_t;
|
||||||
|
|
||||||
|
keyb_t *key_find(keybindings_t *, const xcb_key_press_event_t *);
|
||||||
xcb_keysym_t key_getkeysym(xcb_keycode_t, uint16_t);
|
xcb_keysym_t key_getkeysym(xcb_keycode_t, uint16_t);
|
||||||
void window_root_grabkey(keyb_t *);
|
|
||||||
|
void luaA_key_array_set(lua_State *, int, keybindings_t *);
|
||||||
|
int luaA_key_array_get(lua_State *, keybindings_t *);
|
||||||
|
|
||||||
|
void window_grabkeys(xcb_window_t, keybindings_t *);
|
||||||
|
|
||||||
int luaA_key_new(lua_State *);
|
int luaA_key_new(lua_State *);
|
||||||
|
|
||||||
|
|
42
luaa.c
42
luaa.c
|
@ -84,24 +84,51 @@ static ev_io csio = { .fd = -1 };
|
||||||
|
|
||||||
#define XDG_CONFIG_HOME_DEFAULT "/.config"
|
#define XDG_CONFIG_HOME_DEFAULT "/.config"
|
||||||
|
|
||||||
/** Get or
|
/** Get or set global key bindings.
|
||||||
|
* This binding will be available when you'll press keys on root window.
|
||||||
|
* \param L The Lua VM state.
|
||||||
|
* \return The number of element pushed on stack.
|
||||||
|
* \luastack
|
||||||
|
* \lvalue A client.
|
||||||
|
* \lparam An array of key bindings objects, or nothing.
|
||||||
|
* \return The array of key bindings objects of this client.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
luaA_root_keys(lua_State *L)
|
||||||
|
{
|
||||||
|
if(lua_gettop(L) == 1)
|
||||||
|
{
|
||||||
|
luaA_key_array_set(L, 1, &globalconf.keys);
|
||||||
|
|
||||||
|
int nscreen = xcb_setup_roots_length(xcb_get_setup(globalconf.connection));
|
||||||
|
|
||||||
|
for(int phys_screen = 0; phys_screen < nscreen; phys_screen++)
|
||||||
|
{
|
||||||
|
xcb_screen_t *s = xutil_screen_get(globalconf.connection, phys_screen);
|
||||||
|
xcb_ungrab_key(globalconf.connection, XCB_GRAB_ANY, s->root, XCB_BUTTON_MASK_ANY);
|
||||||
|
window_grabkeys(s->root, &globalconf.keys);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return luaA_key_array_get(L, &globalconf.keys);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get or set global mouse bindings.
|
||||||
* This binding will be available when you'll click on root window.
|
* This binding will be available when you'll click on root window.
|
||||||
* \param L The Lua VM state.
|
* \param L The Lua VM state.
|
||||||
* \return The number of element pushed on stack.
|
* \return The number of element pushed on stack.
|
||||||
* \luastack
|
* \luastack
|
||||||
* \lvalue A client.
|
* \lvalue A client.
|
||||||
* \lparam An array of mouse button bindings objects, or nothing.
|
* \lparam An array of mouse button bindings objects, or nothing.
|
||||||
* \return The array of mouse button bindings objects of this client.
|
* \return The array of mouse button bindings objects.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
luaA_root_buttons(lua_State *L)
|
luaA_root_buttons(lua_State *L)
|
||||||
{
|
{
|
||||||
button_array_t *buttons = &globalconf.buttons;
|
|
||||||
|
|
||||||
if(lua_gettop(L) == 1)
|
if(lua_gettop(L) == 1)
|
||||||
luaA_button_array_set(L, 1, buttons);
|
luaA_button_array_set(L, 1, &globalconf.buttons);
|
||||||
|
|
||||||
return luaA_button_array_get(L, buttons);
|
return luaA_button_array_get(L, &globalconf.buttons);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get or set global mouse bindings (DEPRECATED).
|
/** Get or set global mouse bindings (DEPRECATED).
|
||||||
|
@ -111,7 +138,7 @@ luaA_root_buttons(lua_State *L)
|
||||||
* \luastack
|
* \luastack
|
||||||
* \lvalue A client.
|
* \lvalue A client.
|
||||||
* \lparam An array of mouse button bindings objects, or nothing.
|
* \lparam An array of mouse button bindings objects, or nothing.
|
||||||
* \return The array of mouse button bindings objects of this client.
|
* \return The array of mouse button bindings objects.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
luaA_buttons(lua_State *L)
|
luaA_buttons(lua_State *L)
|
||||||
|
@ -808,6 +835,7 @@ luaA_init(void)
|
||||||
static const struct luaL_reg root_lib[] =
|
static const struct luaL_reg root_lib[] =
|
||||||
{
|
{
|
||||||
{ "buttons", luaA_root_buttons },
|
{ "buttons", luaA_root_buttons },
|
||||||
|
{ "keys", luaA_root_keys },
|
||||||
{ NULL, NULL }
|
{ NULL, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
12
structs.h
12
structs.h
|
@ -218,6 +218,8 @@ struct client_t
|
||||||
wibox_t *titlebar;
|
wibox_t *titlebar;
|
||||||
/** Button bindings */
|
/** Button bindings */
|
||||||
button_array_t buttons;
|
button_array_t buttons;
|
||||||
|
/** Key bindings */
|
||||||
|
keybindings_t keys;
|
||||||
/** Icon */
|
/** Icon */
|
||||||
image_t *icon;
|
image_t *icon;
|
||||||
/** Size hints */
|
/** Size hints */
|
||||||
|
@ -290,13 +292,9 @@ struct awesome_t
|
||||||
int nscreen;
|
int nscreen;
|
||||||
/** True if xinerama is active */
|
/** True if xinerama is active */
|
||||||
bool xinerama_is_active;
|
bool xinerama_is_active;
|
||||||
/** Key bindings */
|
/** Root window key bindings */
|
||||||
struct
|
keybindings_t keys;
|
||||||
{
|
/** Root window mouse bindings */
|
||||||
key_array_t by_code;
|
|
||||||
key_array_t by_sym;
|
|
||||||
} keys;
|
|
||||||
/** Mouse bindings list */
|
|
||||||
button_array_t buttons;
|
button_array_t buttons;
|
||||||
/** Numlock mask */
|
/** Numlock mask */
|
||||||
unsigned int numlockmask;
|
unsigned int numlockmask;
|
||||||
|
|
Loading…
Reference in New Issue