2008-05-28 12:15:00 +02:00
|
|
|
/*
|
|
|
|
* keybinding.c - Key bindings configuration management
|
|
|
|
*
|
|
|
|
* Copyright © 2008 Julien Danjou <julien@danjou.info>
|
Put keybindings in binary searchable arrays.
This patch sorts keybindings in arrays by keycode or keysym to speed up look
up using binary searches. This is a preliminary work to enable more powerful
keybindings stuff, where keybindings can be cascaded or why not, attached to
specific clients.
Interstingly enough, this patch saves 100ko of initial memory (Heap) usage here.
The underlying idea is that we should be able to define keybindings_t as
trees of keybindings_t which would then define key sequences.
The OO approach kind of make sense in fact, since you create a base
keybinding (e.g. reacting on Mod4-w) and then you will probably (with
appropriate apis) be able to populate new submaps from that point more or
less dynamically.
And if you have two keybindings on Mod4-w, then adding them will replace the
previous one. This means that you can fake per-client bindings with e.g.:
k_default = keybindings.new({"Mod4"}, "w", something);
k_mplayer = keybindings.new({"Mod4"}, "w", something_else);
k_default:add()
and in your focus hook:
if /* code for testing if it's mplayer */ then
k_mplayer:add()
else
k_default:add()
end
This would not work before, it does now.
It will take way more sense with submaps of course.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
2008-06-25 01:00:25 +02:00
|
|
|
* Copyright © 2008 Pierre Habouzit <madcoder@debian.org>
|
2008-05-28 12:15:00 +02:00
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License along
|
|
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* XStringToKeysym() */
|
|
|
|
#include <X11/Xlib.h>
|
|
|
|
|
2008-06-30 22:49:11 +02:00
|
|
|
#include "structs.h"
|
Put keybindings in binary searchable arrays.
This patch sorts keybindings in arrays by keycode or keysym to speed up look
up using binary searches. This is a preliminary work to enable more powerful
keybindings stuff, where keybindings can be cascaded or why not, attached to
specific clients.
Interstingly enough, this patch saves 100ko of initial memory (Heap) usage here.
The underlying idea is that we should be able to define keybindings_t as
trees of keybindings_t which would then define key sequences.
The OO approach kind of make sense in fact, since you create a base
keybinding (e.g. reacting on Mod4-w) and then you will probably (with
appropriate apis) be able to populate new submaps from that point more or
less dynamically.
And if you have two keybindings on Mod4-w, then adding them will replace the
previous one. This means that you can fake per-client bindings with e.g.:
k_default = keybindings.new({"Mod4"}, "w", something);
k_mplayer = keybindings.new({"Mod4"}, "w", something_else);
k_default:add()
and in your focus hook:
if /* code for testing if it's mplayer */ then
k_mplayer:add()
else
k_default:add()
end
This would not work before, it does now.
It will take way more sense with submaps of course.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
2008-06-25 01:00:25 +02:00
|
|
|
#include "keybinding.h"
|
2008-06-30 22:49:11 +02:00
|
|
|
|
2008-07-24 16:25:02 +02:00
|
|
|
ARRAY_TYPE(keybinding_t *, keybinding)
|
2008-05-28 12:15:00 +02:00
|
|
|
|
|
|
|
extern awesome_t globalconf;
|
2008-06-30 22:49:11 +02:00
|
|
|
|
2008-06-30 22:49:10 +02:00
|
|
|
static struct {
|
|
|
|
keybinding_array_t by_code;
|
|
|
|
keybinding_array_t by_sym;
|
2008-06-30 22:49:11 +02:00
|
|
|
} keys_g;
|
2008-06-18 18:31:35 +02:00
|
|
|
|
2008-08-17 11:58:09 +02:00
|
|
|
static void
|
|
|
|
keybinding_delete(keybinding_t **kbp)
|
2008-06-25 00:08:40 +02:00
|
|
|
{
|
2008-06-26 13:06:55 +02:00
|
|
|
luaL_unref(globalconf.L, LUA_REGISTRYINDEX, (*kbp)->fct);
|
2008-06-25 00:08:40 +02:00
|
|
|
p_delete(kbp);
|
|
|
|
}
|
|
|
|
|
2008-06-30 22:49:11 +02:00
|
|
|
DO_RCNT(keybinding_t, keybinding, keybinding_delete)
|
|
|
|
ARRAY_FUNCS(keybinding_t *, keybinding, keybinding_unref)
|
|
|
|
DO_LUA_NEW(static, keybinding_t, keybinding, "keybinding", keybinding_ref)
|
|
|
|
DO_LUA_GC(keybinding_t, keybinding, "keybinding", keybinding_unref)
|
|
|
|
|
Put keybindings in binary searchable arrays.
This patch sorts keybindings in arrays by keycode or keysym to speed up look
up using binary searches. This is a preliminary work to enable more powerful
keybindings stuff, where keybindings can be cascaded or why not, attached to
specific clients.
Interstingly enough, this patch saves 100ko of initial memory (Heap) usage here.
The underlying idea is that we should be able to define keybindings_t as
trees of keybindings_t which would then define key sequences.
The OO approach kind of make sense in fact, since you create a base
keybinding (e.g. reacting on Mod4-w) and then you will probably (with
appropriate apis) be able to populate new submaps from that point more or
less dynamically.
And if you have two keybindings on Mod4-w, then adding them will replace the
previous one. This means that you can fake per-client bindings with e.g.:
k_default = keybindings.new({"Mod4"}, "w", something);
k_mplayer = keybindings.new({"Mod4"}, "w", something_else);
k_default:add()
and in your focus hook:
if /* code for testing if it's mplayer */ then
k_mplayer:add()
else
k_default:add()
end
This would not work before, it does now.
It will take way more sense with submaps of course.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
2008-06-25 01:00:25 +02:00
|
|
|
static int
|
|
|
|
keybinding_ev_cmp(xcb_keysym_t keysym, xcb_keycode_t keycode,
|
|
|
|
unsigned long mod, const keybinding_t *k)
|
|
|
|
{
|
|
|
|
if (k->keysym) {
|
|
|
|
if (k->keysym != keysym)
|
|
|
|
return k->keysym > keysym ? 1 : -1;
|
|
|
|
}
|
|
|
|
if (k->keycode) {
|
|
|
|
if (k->keycode != keycode)
|
|
|
|
return k->keycode > keycode ? 1 : -1;
|
|
|
|
}
|
|
|
|
return k->mod == mod ? 0 : (k->mod > mod ? 1 : -1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
keybinding_cmp(const keybinding_t *k1, const keybinding_t *k2)
|
|
|
|
{
|
|
|
|
assert ((k1->keysym && k2->keysym) || (k1->keycode && k2->keycode));
|
|
|
|
assert ((!k1->keysym && !k2->keysym) || (!k1->keycode && !k2->keycode));
|
|
|
|
|
|
|
|
if (k1->keysym != k2->keysym)
|
|
|
|
return k2->keysym > k1->keysym ? 1 : -1;
|
|
|
|
if (k1->keycode != k2->keycode)
|
|
|
|
return k2->keycode > k1->keycode ? 1 : -1;
|
|
|
|
return k1->mod == k2->mod ? 0 : (k2->mod > k1->mod ? 1 : -1);
|
|
|
|
}
|
|
|
|
|
2008-06-30 22:49:10 +02:00
|
|
|
/** Grab key on the root windows.
|
|
|
|
* \param k The keybinding.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
window_root_grabkey(keybinding_t *k)
|
|
|
|
{
|
2008-08-14 22:16:13 +02:00
|
|
|
int phys_screen = 0;
|
|
|
|
int nscreen = xcb_setup_roots_length(xcb_get_setup(globalconf.connection));
|
2008-06-30 22:49:10 +02:00
|
|
|
xcb_screen_t *s;
|
|
|
|
xcb_keycode_t kc;
|
|
|
|
|
|
|
|
if((kc = k->keycode)
|
2008-08-13 10:30:24 +02:00
|
|
|
|| (k->keysym
|
|
|
|
&& (kc = xcb_key_symbols_get_keycode(globalconf.keysyms, k->keysym))))
|
2008-06-30 22:49:10 +02:00
|
|
|
do
|
|
|
|
{
|
|
|
|
s = xutil_screen_get(globalconf.connection, phys_screen);
|
|
|
|
xcb_grab_key(globalconf.connection, true, s->root,
|
|
|
|
k->mod, kc, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);
|
|
|
|
xcb_grab_key(globalconf.connection, true, s->root,
|
|
|
|
k->mod | XCB_MOD_MASK_LOCK, kc, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);
|
|
|
|
xcb_grab_key(globalconf.connection, true, s->root,
|
|
|
|
k->mod | globalconf.numlockmask, kc, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);
|
|
|
|
xcb_grab_key(globalconf.connection, true, s->root,
|
|
|
|
k->mod | globalconf.numlockmask | XCB_MOD_MASK_LOCK, kc, XCB_GRAB_MODE_ASYNC,
|
|
|
|
XCB_GRAB_MODE_ASYNC);
|
|
|
|
phys_screen++;
|
2008-08-14 22:16:13 +02:00
|
|
|
} while(phys_screen < nscreen);
|
2008-06-30 22:49:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Ungrab key on the root windows.
|
|
|
|
* \param k The keybinding.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
window_root_ungrabkey(keybinding_t *k)
|
|
|
|
{
|
2008-08-14 22:16:13 +02:00
|
|
|
int phys_screen = 0;
|
|
|
|
int nscreen = xcb_setup_roots_length(xcb_get_setup(globalconf.connection));
|
2008-06-30 22:49:10 +02:00
|
|
|
xcb_screen_t *s;
|
|
|
|
xcb_keycode_t kc;
|
|
|
|
|
|
|
|
if((kc = k->keycode)
|
|
|
|
|| (k->keysym && (kc = xcb_key_symbols_get_keycode(globalconf.keysyms, k->keysym))))
|
|
|
|
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++;
|
2008-08-14 22:16:13 +02:00
|
|
|
} while(phys_screen < nscreen);
|
2008-06-30 22:49:10 +02:00
|
|
|
}
|
|
|
|
|
2008-06-30 22:49:11 +02:00
|
|
|
static void
|
Put keybindings in binary searchable arrays.
This patch sorts keybindings in arrays by keycode or keysym to speed up look
up using binary searches. This is a preliminary work to enable more powerful
keybindings stuff, where keybindings can be cascaded or why not, attached to
specific clients.
Interstingly enough, this patch saves 100ko of initial memory (Heap) usage here.
The underlying idea is that we should be able to define keybindings_t as
trees of keybindings_t which would then define key sequences.
The OO approach kind of make sense in fact, since you create a base
keybinding (e.g. reacting on Mod4-w) and then you will probably (with
appropriate apis) be able to populate new submaps from that point more or
less dynamically.
And if you have two keybindings on Mod4-w, then adding them will replace the
previous one. This means that you can fake per-client bindings with e.g.:
k_default = keybindings.new({"Mod4"}, "w", something);
k_mplayer = keybindings.new({"Mod4"}, "w", something_else);
k_default:add()
and in your focus hook:
if /* code for testing if it's mplayer */ then
k_mplayer:add()
else
k_default:add()
end
This would not work before, it does now.
It will take way more sense with submaps of course.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
2008-06-25 01:00:25 +02:00
|
|
|
keybinding_register_root(keybinding_t *k)
|
|
|
|
{
|
2008-06-30 22:49:11 +02:00
|
|
|
keybinding_array_t *arr = k->keysym ? &keys_g.by_sym : &keys_g.by_code;
|
Put keybindings in binary searchable arrays.
This patch sorts keybindings in arrays by keycode or keysym to speed up look
up using binary searches. This is a preliminary work to enable more powerful
keybindings stuff, where keybindings can be cascaded or why not, attached to
specific clients.
Interstingly enough, this patch saves 100ko of initial memory (Heap) usage here.
The underlying idea is that we should be able to define keybindings_t as
trees of keybindings_t which would then define key sequences.
The OO approach kind of make sense in fact, since you create a base
keybinding (e.g. reacting on Mod4-w) and then you will probably (with
appropriate apis) be able to populate new submaps from that point more or
less dynamically.
And if you have two keybindings on Mod4-w, then adding them will replace the
previous one. This means that you can fake per-client bindings with e.g.:
k_default = keybindings.new({"Mod4"}, "w", something);
k_mplayer = keybindings.new({"Mod4"}, "w", something_else);
k_default:add()
and in your focus hook:
if /* code for testing if it's mplayer */ then
k_mplayer:add()
else
k_default:add()
end
This would not work before, it does now.
It will take way more sense with submaps of course.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
2008-06-25 01:00:25 +02:00
|
|
|
int l = 0, r = arr->len;
|
|
|
|
|
|
|
|
keybinding_ref(&k);
|
|
|
|
|
|
|
|
while (l < r) {
|
|
|
|
int i = (r + l) / 2;
|
|
|
|
switch (keybinding_cmp(k, arr->tab[i])) {
|
|
|
|
case -1: /* k < arr->tab[i] */
|
|
|
|
r = i;
|
|
|
|
break;
|
|
|
|
case 0: /* k == arr->tab[i] */
|
|
|
|
keybinding_unref(&arr->tab[i]);
|
|
|
|
arr->tab[i] = k;
|
|
|
|
return;
|
|
|
|
case 1: /* k > arr->tab[i] */
|
|
|
|
l = i + 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
keybinding_array_splice(arr, r, 0, &k, 1);
|
|
|
|
window_root_grabkey(k);
|
|
|
|
}
|
|
|
|
|
2008-06-30 22:49:11 +02:00
|
|
|
static void
|
Put keybindings in binary searchable arrays.
This patch sorts keybindings in arrays by keycode or keysym to speed up look
up using binary searches. This is a preliminary work to enable more powerful
keybindings stuff, where keybindings can be cascaded or why not, attached to
specific clients.
Interstingly enough, this patch saves 100ko of initial memory (Heap) usage here.
The underlying idea is that we should be able to define keybindings_t as
trees of keybindings_t which would then define key sequences.
The OO approach kind of make sense in fact, since you create a base
keybinding (e.g. reacting on Mod4-w) and then you will probably (with
appropriate apis) be able to populate new submaps from that point more or
less dynamically.
And if you have two keybindings on Mod4-w, then adding them will replace the
previous one. This means that you can fake per-client bindings with e.g.:
k_default = keybindings.new({"Mod4"}, "w", something);
k_mplayer = keybindings.new({"Mod4"}, "w", something_else);
k_default:add()
and in your focus hook:
if /* code for testing if it's mplayer */ then
k_mplayer:add()
else
k_default:add()
end
This would not work before, it does now.
It will take way more sense with submaps of course.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
2008-06-25 01:00:25 +02:00
|
|
|
keybinding_unregister_root(keybinding_t **k)
|
|
|
|
{
|
2008-06-30 22:49:11 +02:00
|
|
|
keybinding_array_t *arr = (*k)->keysym ? &keys_g.by_sym : &keys_g.by_code;
|
Put keybindings in binary searchable arrays.
This patch sorts keybindings in arrays by keycode or keysym to speed up look
up using binary searches. This is a preliminary work to enable more powerful
keybindings stuff, where keybindings can be cascaded or why not, attached to
specific clients.
Interstingly enough, this patch saves 100ko of initial memory (Heap) usage here.
The underlying idea is that we should be able to define keybindings_t as
trees of keybindings_t which would then define key sequences.
The OO approach kind of make sense in fact, since you create a base
keybinding (e.g. reacting on Mod4-w) and then you will probably (with
appropriate apis) be able to populate new submaps from that point more or
less dynamically.
And if you have two keybindings on Mod4-w, then adding them will replace the
previous one. This means that you can fake per-client bindings with e.g.:
k_default = keybindings.new({"Mod4"}, "w", something);
k_mplayer = keybindings.new({"Mod4"}, "w", something_else);
k_default:add()
and in your focus hook:
if /* code for testing if it's mplayer */ then
k_mplayer:add()
else
k_default:add()
end
This would not work before, it does now.
It will take way more sense with submaps of course.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
2008-06-25 01:00:25 +02:00
|
|
|
int l = 0, r = arr->len;
|
|
|
|
|
|
|
|
while (l < r) {
|
|
|
|
int i = (r + l) / 2;
|
|
|
|
switch (keybinding_cmp(*k, arr->tab[i])) {
|
|
|
|
case -1: /* k < arr->tab[i] */
|
|
|
|
r = i;
|
|
|
|
break;
|
|
|
|
case 0: /* k == arr->tab[i] */
|
|
|
|
keybinding_array_take(arr, i);
|
|
|
|
window_root_ungrabkey(*k);
|
|
|
|
keybinding_unref(k);
|
|
|
|
return;
|
|
|
|
case 1: /* k > arr->tab[i] */
|
|
|
|
l = i + 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-08-13 10:30:24 +02:00
|
|
|
/** Return the keysym from keycode.
|
|
|
|
* \param detail The keycode received.
|
|
|
|
* \param state The modifier state.
|
|
|
|
* \return A keysym.
|
|
|
|
*/
|
|
|
|
xcb_keysym_t
|
|
|
|
key_getkeysym(xcb_keycode_t detail, uint16_t state)
|
|
|
|
{
|
|
|
|
xcb_keysym_t k0, k1;
|
|
|
|
|
|
|
|
/* 'col' (third parameter) is used to get the proper KeySym
|
|
|
|
* according to modifier (XCB doesn't provide an equivalent to
|
|
|
|
* XLookupString()).
|
|
|
|
*
|
|
|
|
* If Mod5 is ON we look into second group.
|
|
|
|
*/
|
|
|
|
if(state & XCB_MOD_MASK_5)
|
|
|
|
{
|
|
|
|
k0 = xcb_key_symbols_get_keysym(globalconf.keysyms, detail, 2);
|
|
|
|
k1 = xcb_key_symbols_get_keysym(globalconf.keysyms, detail, 3);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
k0 = xcb_key_symbols_get_keysym(globalconf.keysyms, detail, 0);
|
|
|
|
k1 = xcb_key_symbols_get_keysym(globalconf.keysyms, detail, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* The numlock modifier is on and the second KeySym is a keypad
|
|
|
|
* KeySym */
|
|
|
|
if((state & globalconf.numlockmask) && xcb_is_keypad_key(k1))
|
|
|
|
{
|
|
|
|
/* The Shift modifier is on, or if the Lock modifier is on and
|
|
|
|
* is interpreted as ShiftLock, use the first KeySym */
|
|
|
|
if((state & XCB_MOD_MASK_SHIFT) ||
|
|
|
|
(state & XCB_MOD_MASK_LOCK && (state & globalconf.shiftlockmask)))
|
|
|
|
return k0;
|
|
|
|
else
|
|
|
|
return k1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* The Shift and Lock modifers are both off, use the first
|
|
|
|
* KeySym */
|
|
|
|
else if(!(state & XCB_MOD_MASK_SHIFT) && !(state & XCB_MOD_MASK_LOCK))
|
|
|
|
return k0;
|
|
|
|
|
|
|
|
/* The Shift modifier is off and the Lock modifier is on and is
|
|
|
|
* interpreted as CapsLock */
|
|
|
|
else if(!(state & XCB_MOD_MASK_SHIFT) &&
|
|
|
|
(state & XCB_MOD_MASK_LOCK && (state & globalconf.capslockmask)))
|
|
|
|
/* The first Keysym is used but if that KeySym is lowercase
|
|
|
|
* alphabetic, then the corresponding uppercase KeySym is used
|
|
|
|
* instead */
|
|
|
|
return k1;
|
|
|
|
|
|
|
|
/* The Shift modifier is on, and the Lock modifier is on and is
|
|
|
|
* interpreted as CapsLock */
|
|
|
|
else if((state & XCB_MOD_MASK_SHIFT) &&
|
|
|
|
(state & XCB_MOD_MASK_LOCK && (state & globalconf.capslockmask)))
|
|
|
|
/* The second Keysym is used but if that KeySym is lowercase
|
|
|
|
* alphabetic, then the corresponding uppercase KeySym is used
|
|
|
|
* instead */
|
|
|
|
return k1;
|
|
|
|
|
|
|
|
/* The Shift modifer is on, or the Lock modifier is on and is
|
|
|
|
* interpreted as ShiftLock, or both */
|
|
|
|
else if((state & XCB_MOD_MASK_SHIFT) ||
|
|
|
|
(state & XCB_MOD_MASK_LOCK && (state & globalconf.shiftlockmask)))
|
|
|
|
return k1;
|
|
|
|
|
|
|
|
return XCB_NO_SYMBOL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
Put keybindings in binary searchable arrays.
This patch sorts keybindings in arrays by keycode or keysym to speed up look
up using binary searches. This is a preliminary work to enable more powerful
keybindings stuff, where keybindings can be cascaded or why not, attached to
specific clients.
Interstingly enough, this patch saves 100ko of initial memory (Heap) usage here.
The underlying idea is that we should be able to define keybindings_t as
trees of keybindings_t which would then define key sequences.
The OO approach kind of make sense in fact, since you create a base
keybinding (e.g. reacting on Mod4-w) and then you will probably (with
appropriate apis) be able to populate new submaps from that point more or
less dynamically.
And if you have two keybindings on Mod4-w, then adding them will replace the
previous one. This means that you can fake per-client bindings with e.g.:
k_default = keybindings.new({"Mod4"}, "w", something);
k_mplayer = keybindings.new({"Mod4"}, "w", something_else);
k_default:add()
and in your focus hook:
if /* code for testing if it's mplayer */ then
k_mplayer:add()
else
k_default:add()
end
This would not work before, it does now.
It will take way more sense with submaps of course.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
2008-06-25 01:00:25 +02:00
|
|
|
keybinding_t *
|
2008-06-30 22:49:10 +02:00
|
|
|
keybinding_find(const xcb_key_press_event_t *ev)
|
Put keybindings in binary searchable arrays.
This patch sorts keybindings in arrays by keycode or keysym to speed up look
up using binary searches. This is a preliminary work to enable more powerful
keybindings stuff, where keybindings can be cascaded or why not, attached to
specific clients.
Interstingly enough, this patch saves 100ko of initial memory (Heap) usage here.
The underlying idea is that we should be able to define keybindings_t as
trees of keybindings_t which would then define key sequences.
The OO approach kind of make sense in fact, since you create a base
keybinding (e.g. reacting on Mod4-w) and then you will probably (with
appropriate apis) be able to populate new submaps from that point more or
less dynamically.
And if you have two keybindings on Mod4-w, then adding them will replace the
previous one. This means that you can fake per-client bindings with e.g.:
k_default = keybindings.new({"Mod4"}, "w", something);
k_mplayer = keybindings.new({"Mod4"}, "w", something_else);
k_default:add()
and in your focus hook:
if /* code for testing if it's mplayer */ then
k_mplayer:add()
else
k_default:add()
end
This would not work before, it does now.
It will take way more sense with submaps of course.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
2008-06-25 01:00:25 +02:00
|
|
|
{
|
2008-06-30 22:49:11 +02:00
|
|
|
const keybinding_array_t *arr = &keys_g.by_sym;
|
2008-08-11 13:27:28 +02:00
|
|
|
int l, r, mod = XUTIL_MASK_CLEAN(ev->state);
|
Put keybindings in binary searchable arrays.
This patch sorts keybindings in arrays by keycode or keysym to speed up look
up using binary searches. This is a preliminary work to enable more powerful
keybindings stuff, where keybindings can be cascaded or why not, attached to
specific clients.
Interstingly enough, this patch saves 100ko of initial memory (Heap) usage here.
The underlying idea is that we should be able to define keybindings_t as
trees of keybindings_t which would then define key sequences.
The OO approach kind of make sense in fact, since you create a base
keybinding (e.g. reacting on Mod4-w) and then you will probably (with
appropriate apis) be able to populate new submaps from that point more or
less dynamically.
And if you have two keybindings on Mod4-w, then adding them will replace the
previous one. This means that you can fake per-client bindings with e.g.:
k_default = keybindings.new({"Mod4"}, "w", something);
k_mplayer = keybindings.new({"Mod4"}, "w", something_else);
k_default:add()
and in your focus hook:
if /* code for testing if it's mplayer */ then
k_mplayer:add()
else
k_default:add()
end
This would not work before, it does now.
It will take way more sense with submaps of course.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
2008-06-25 01:00:25 +02:00
|
|
|
xcb_keysym_t keysym;
|
|
|
|
|
2008-09-10 16:31:12 +02:00
|
|
|
/* get keysym ignoring shift and mod5 */
|
2008-09-10 17:02:07 +02:00
|
|
|
keysym = key_getkeysym(ev->detail, ev->state & ~(XCB_MOD_MASK_SHIFT | XCB_MOD_MASK_5 | XCB_MOD_MASK_LOCK));
|
Put keybindings in binary searchable arrays.
This patch sorts keybindings in arrays by keycode or keysym to speed up look
up using binary searches. This is a preliminary work to enable more powerful
keybindings stuff, where keybindings can be cascaded or why not, attached to
specific clients.
Interstingly enough, this patch saves 100ko of initial memory (Heap) usage here.
The underlying idea is that we should be able to define keybindings_t as
trees of keybindings_t which would then define key sequences.
The OO approach kind of make sense in fact, since you create a base
keybinding (e.g. reacting on Mod4-w) and then you will probably (with
appropriate apis) be able to populate new submaps from that point more or
less dynamically.
And if you have two keybindings on Mod4-w, then adding them will replace the
previous one. This means that you can fake per-client bindings with e.g.:
k_default = keybindings.new({"Mod4"}, "w", something);
k_mplayer = keybindings.new({"Mod4"}, "w", something_else);
k_default:add()
and in your focus hook:
if /* code for testing if it's mplayer */ then
k_mplayer:add()
else
k_default:add()
end
This would not work before, it does now.
It will take way more sense with submaps of course.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
2008-06-25 01:00:25 +02:00
|
|
|
|
|
|
|
again:
|
|
|
|
l = 0;
|
|
|
|
r = arr->len;
|
2008-08-13 10:30:24 +02:00
|
|
|
while (l < r)
|
|
|
|
{
|
Put keybindings in binary searchable arrays.
This patch sorts keybindings in arrays by keycode or keysym to speed up look
up using binary searches. This is a preliminary work to enable more powerful
keybindings stuff, where keybindings can be cascaded or why not, attached to
specific clients.
Interstingly enough, this patch saves 100ko of initial memory (Heap) usage here.
The underlying idea is that we should be able to define keybindings_t as
trees of keybindings_t which would then define key sequences.
The OO approach kind of make sense in fact, since you create a base
keybinding (e.g. reacting on Mod4-w) and then you will probably (with
appropriate apis) be able to populate new submaps from that point more or
less dynamically.
And if you have two keybindings on Mod4-w, then adding them will replace the
previous one. This means that you can fake per-client bindings with e.g.:
k_default = keybindings.new({"Mod4"}, "w", something);
k_mplayer = keybindings.new({"Mod4"}, "w", something_else);
k_default:add()
and in your focus hook:
if /* code for testing if it's mplayer */ then
k_mplayer:add()
else
k_default:add()
end
This would not work before, it does now.
It will take way more sense with submaps of course.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
2008-06-25 01:00:25 +02:00
|
|
|
int i = (r + l) / 2;
|
2008-08-13 10:30:24 +02:00
|
|
|
switch (keybinding_ev_cmp(keysym, ev->detail, mod, arr->tab[i]))
|
|
|
|
{
|
Put keybindings in binary searchable arrays.
This patch sorts keybindings in arrays by keycode or keysym to speed up look
up using binary searches. This is a preliminary work to enable more powerful
keybindings stuff, where keybindings can be cascaded or why not, attached to
specific clients.
Interstingly enough, this patch saves 100ko of initial memory (Heap) usage here.
The underlying idea is that we should be able to define keybindings_t as
trees of keybindings_t which would then define key sequences.
The OO approach kind of make sense in fact, since you create a base
keybinding (e.g. reacting on Mod4-w) and then you will probably (with
appropriate apis) be able to populate new submaps from that point more or
less dynamically.
And if you have two keybindings on Mod4-w, then adding them will replace the
previous one. This means that you can fake per-client bindings with e.g.:
k_default = keybindings.new({"Mod4"}, "w", something);
k_mplayer = keybindings.new({"Mod4"}, "w", something_else);
k_default:add()
and in your focus hook:
if /* code for testing if it's mplayer */ then
k_mplayer:add()
else
k_default:add()
end
This would not work before, it does now.
It will take way more sense with submaps of course.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
2008-06-25 01:00:25 +02:00
|
|
|
case -1: /* ev < arr->tab[i] */
|
|
|
|
r = i;
|
|
|
|
break;
|
|
|
|
case 0: /* ev == arr->tab[i] */
|
|
|
|
return arr->tab[i];
|
|
|
|
case 1: /* ev > arr->tab[i] */
|
|
|
|
l = i + 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2008-08-13 10:30:24 +02:00
|
|
|
if (arr != &keys_g.by_code)
|
|
|
|
{
|
2008-06-30 22:49:11 +02:00
|
|
|
arr = &keys_g.by_code;
|
Put keybindings in binary searchable arrays.
This patch sorts keybindings in arrays by keycode or keysym to speed up look
up using binary searches. This is a preliminary work to enable more powerful
keybindings stuff, where keybindings can be cascaded or why not, attached to
specific clients.
Interstingly enough, this patch saves 100ko of initial memory (Heap) usage here.
The underlying idea is that we should be able to define keybindings_t as
trees of keybindings_t which would then define key sequences.
The OO approach kind of make sense in fact, since you create a base
keybinding (e.g. reacting on Mod4-w) and then you will probably (with
appropriate apis) be able to populate new submaps from that point more or
less dynamically.
And if you have two keybindings on Mod4-w, then adding them will replace the
previous one. This means that you can fake per-client bindings with e.g.:
k_default = keybindings.new({"Mod4"}, "w", something);
k_mplayer = keybindings.new({"Mod4"}, "w", something_else);
k_default:add()
and in your focus hook:
if /* code for testing if it's mplayer */ then
k_mplayer:add()
else
k_default:add()
end
This would not work before, it does now.
It will take way more sense with submaps of course.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
2008-06-25 01:00:25 +02:00
|
|
|
goto again;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2008-05-28 12:15:00 +02:00
|
|
|
static void
|
2008-09-18 10:06:47 +02:00
|
|
|
luaA_keystore(keybinding_t *key, const char *str, ssize_t len)
|
2008-05-28 12:15:00 +02:00
|
|
|
{
|
2008-09-18 10:06:47 +02:00
|
|
|
if(len)
|
2008-08-13 10:30:24 +02:00
|
|
|
{
|
|
|
|
if(*str != '#')
|
2008-09-18 10:06:47 +02:00
|
|
|
{
|
2008-08-13 10:30:24 +02:00
|
|
|
key->keysym = XStringToKeysym(str);
|
2008-09-18 10:54:38 +02:00
|
|
|
if (!key->keysym)
|
|
|
|
{
|
|
|
|
if (len == 1)
|
|
|
|
key->keysym = *str;
|
|
|
|
else
|
|
|
|
warn("there's no keysym named \"%s\"", str);
|
|
|
|
}
|
2008-09-18 10:06:47 +02:00
|
|
|
}
|
2008-08-13 10:30:24 +02:00
|
|
|
else
|
|
|
|
key->keycode = atoi(str + 1);
|
|
|
|
}
|
2008-05-28 12:15:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Define a global key binding. This key binding will always be available.
|
2008-06-10 20:12:51 +02:00
|
|
|
* \param L The Lua VM state.
|
|
|
|
*
|
|
|
|
* \luastack
|
|
|
|
* \lparam A table with modifier keys.
|
|
|
|
* \lparam A key name.
|
|
|
|
* \lparam A function to execute.
|
|
|
|
* \lreturn The keybinding.
|
2008-05-28 12:15:00 +02:00
|
|
|
*/
|
|
|
|
static int
|
|
|
|
luaA_keybinding_new(lua_State *L)
|
|
|
|
{
|
|
|
|
size_t i, len;
|
2008-06-18 18:31:35 +02:00
|
|
|
keybinding_t *k;
|
2008-05-28 12:15:00 +02:00
|
|
|
const char *key;
|
|
|
|
|
2008-06-30 14:01:55 +02:00
|
|
|
/* arg 2 is key mod table */
|
|
|
|
luaA_checktable(L, 2);
|
|
|
|
/* arg 3 is key */
|
2008-09-18 10:06:47 +02:00
|
|
|
key = luaL_checklstring(L, 3, &len);
|
2008-06-30 14:01:55 +02:00
|
|
|
/* arg 4 is cmd to run */
|
|
|
|
luaA_checkfunction(L, 4);
|
2008-05-28 12:15:00 +02:00
|
|
|
|
|
|
|
/* get the last arg as function */
|
|
|
|
k = p_new(keybinding_t, 1);
|
2008-09-18 10:06:47 +02:00
|
|
|
luaA_keystore(k, key, len);
|
2008-08-12 13:23:10 +02:00
|
|
|
luaA_registerfct(L, 4, &k->fct);
|
2008-05-28 12:15:00 +02:00
|
|
|
|
2008-06-30 14:01:55 +02:00
|
|
|
len = lua_objlen(L, 2);
|
2008-05-28 12:15:00 +02:00
|
|
|
for(i = 1; i <= len; i++)
|
|
|
|
{
|
2008-10-01 11:09:57 +02:00
|
|
|
size_t blen;
|
2008-06-30 14:01:55 +02:00
|
|
|
lua_rawgeti(L, 2, i);
|
2008-10-01 11:09:57 +02:00
|
|
|
key = luaL_checklstring(L, -1, &blen);
|
|
|
|
k->mod |= xutil_key_mask_fromstr(key, blen);
|
2008-05-28 12:15:00 +02:00
|
|
|
}
|
|
|
|
|
2008-06-18 18:31:35 +02:00
|
|
|
return luaA_keybinding_userdata_new(L, k);
|
2008-05-28 12:15:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Add a global key binding. This key binding will always be available.
|
2008-06-10 20:12:51 +02:00
|
|
|
* \param L The Lua VM state.
|
|
|
|
*
|
|
|
|
* \luastack
|
2008-09-02 16:52:50 +02:00
|
|
|
* \lvalue A keybinding.
|
2008-05-28 12:15:00 +02:00
|
|
|
*/
|
|
|
|
static int
|
|
|
|
luaA_keybinding_add(lua_State *L)
|
|
|
|
{
|
2008-06-25 00:08:40 +02:00
|
|
|
keybinding_t **k = luaA_checkudata(L, 1, "keybinding");
|
Put keybindings in binary searchable arrays.
This patch sorts keybindings in arrays by keycode or keysym to speed up look
up using binary searches. This is a preliminary work to enable more powerful
keybindings stuff, where keybindings can be cascaded or why not, attached to
specific clients.
Interstingly enough, this patch saves 100ko of initial memory (Heap) usage here.
The underlying idea is that we should be able to define keybindings_t as
trees of keybindings_t which would then define key sequences.
The OO approach kind of make sense in fact, since you create a base
keybinding (e.g. reacting on Mod4-w) and then you will probably (with
appropriate apis) be able to populate new submaps from that point more or
less dynamically.
And if you have two keybindings on Mod4-w, then adding them will replace the
previous one. This means that you can fake per-client bindings with e.g.:
k_default = keybindings.new({"Mod4"}, "w", something);
k_mplayer = keybindings.new({"Mod4"}, "w", something_else);
k_default:add()
and in your focus hook:
if /* code for testing if it's mplayer */ then
k_mplayer:add()
else
k_default:add()
end
This would not work before, it does now.
It will take way more sense with submaps of course.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
2008-06-25 01:00:25 +02:00
|
|
|
keybinding_register_root(*k);
|
2008-05-28 12:15:00 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Remove a global key binding.
|
2008-06-10 20:12:51 +02:00
|
|
|
* \param L The Lua VM state.
|
|
|
|
*
|
|
|
|
* \luastack
|
2008-09-02 16:52:50 +02:00
|
|
|
* \lvalue A keybinding.
|
2008-05-28 12:15:00 +02:00
|
|
|
*/
|
|
|
|
static int
|
|
|
|
luaA_keybinding_remove(lua_State *L)
|
|
|
|
{
|
2008-06-04 18:27:10 +02:00
|
|
|
keybinding_t **k = luaA_checkudata(L, 1, "keybinding");
|
Put keybindings in binary searchable arrays.
This patch sorts keybindings in arrays by keycode or keysym to speed up look
up using binary searches. This is a preliminary work to enable more powerful
keybindings stuff, where keybindings can be cascaded or why not, attached to
specific clients.
Interstingly enough, this patch saves 100ko of initial memory (Heap) usage here.
The underlying idea is that we should be able to define keybindings_t as
trees of keybindings_t which would then define key sequences.
The OO approach kind of make sense in fact, since you create a base
keybinding (e.g. reacting on Mod4-w) and then you will probably (with
appropriate apis) be able to populate new submaps from that point more or
less dynamically.
And if you have two keybindings on Mod4-w, then adding them will replace the
previous one. This means that you can fake per-client bindings with e.g.:
k_default = keybindings.new({"Mod4"}, "w", something);
k_mplayer = keybindings.new({"Mod4"}, "w", something_else);
k_default:add()
and in your focus hook:
if /* code for testing if it's mplayer */ then
k_mplayer:add()
else
k_default:add()
end
This would not work before, it does now.
It will take way more sense with submaps of course.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
2008-06-25 01:00:25 +02:00
|
|
|
keybinding_unregister_root(k);
|
2008-05-28 12:15:00 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Convert a keybinding to a printable string.
|
|
|
|
* \return A string.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
luaA_keybinding_tostring(lua_State *L)
|
|
|
|
{
|
2008-06-04 18:27:10 +02:00
|
|
|
keybinding_t **p = luaA_checkudata(L, 1, "keybinding");
|
2008-05-28 12:15:00 +02:00
|
|
|
lua_pushfstring(L, "[keybinding udata(%p)]", *p);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
const struct luaL_reg awesome_keybinding_methods[] =
|
|
|
|
{
|
2008-06-30 14:01:55 +02:00
|
|
|
{ "__call", luaA_keybinding_new },
|
2008-05-28 12:15:00 +02:00
|
|
|
{ NULL, NULL }
|
|
|
|
};
|
|
|
|
const struct luaL_reg awesome_keybinding_meta[] =
|
|
|
|
{
|
2008-09-02 16:37:12 +02:00
|
|
|
{ "add", luaA_keybinding_add },
|
|
|
|
{ "remove", luaA_keybinding_remove },
|
|
|
|
{ "__tostring", luaA_keybinding_tostring },
|
|
|
|
{ "__gc", luaA_keybinding_gc },
|
2008-05-28 12:15:00 +02:00
|
|
|
{ NULL, NULL },
|
|
|
|
};
|
|
|
|
|