aboutsummaryrefslogtreecommitdiffstats
path: root/matchbox2/mb-wm-keys.c
diff options
context:
space:
mode:
Diffstat (limited to 'matchbox2/mb-wm-keys.c')
-rw-r--r--matchbox2/mb-wm-keys.c379
1 files changed, 379 insertions, 0 deletions
diff --git a/matchbox2/mb-wm-keys.c b/matchbox2/mb-wm-keys.c
new file mode 100644
index 0000000..7c32105
--- /dev/null
+++ b/matchbox2/mb-wm-keys.c
@@ -0,0 +1,379 @@
+#include "mb-wm.h"
+#include <ctype.h> /* isalpha etc */
+
+struct MBWMKeys /* FIXME: Probably do want to hide these here */
+{
+ MBWMList *bindings; /* Always points to first binding */
+
+ int MetaMask;
+ int HyperMask;
+ int SuperMask;
+ int AltMask;
+ int ModeMask;
+ int NumLockMask;
+ int ScrollLockMask;
+ int lock_mask;
+
+};
+
+static Bool
+keysym_needs_shift (MBWindowManager *wm, KeySym keysym)
+{
+ int min_kc, max_kc, keycode, col;
+ KeySym k;
+
+ XDisplayKeycodes(wm->xdpy, &min_kc, &max_kc);
+
+ for (keycode = min_kc; keycode <= max_kc; keycode++)
+ for (col = 0;
+ (k = XKeycodeToKeysym (wm->xdpy, keycode, col)) != NoSymbol;
+ col++)
+ if (k == keysym && col == 1)
+ return True;
+
+ return False;
+}
+
+static Bool
+key_binding_set_grab (MBWindowManager *wm,
+ MBWMKeyBinding *key,
+ Bool ungrab)
+{
+ int ignored_mask = 0;
+
+ MBWM_ASSERT (wm->keys != NULL);
+
+ /* Needed to grab all Locked combo's too */
+ while (ignored_mask < (int) wm->keys->lock_mask)
+ {
+ if (ignored_mask & ~(wm->keys->lock_mask))
+ {
+ ++ignored_mask;
+ continue;
+ }
+
+ if (ungrab)
+ {
+ MBWM_DBG("ungrabbing %i , %i",
+ XKeysymToKeycode(wm->xdpy, key->keysym),
+ key->modifier_mask);
+
+ XUngrabKey(wm->xdpy,
+ XKeysymToKeycode(wm->xdpy, key->keysym),
+ key->modifier_mask | ignored_mask,
+ wm->root_win->xwindow);
+ }
+ else
+ {
+ int result;
+
+ mb_wm_util_trap_x_errors();
+
+ MBWM_DBG ("grabbing keycode: %i, keysym %li, mask: %i",
+ XKeysymToKeycode(wm->xdpy, key->keysym),
+ key->keysym,
+ key->modifier_mask | ignored_mask);
+
+ XGrabKey(wm->xdpy, XKeysymToKeycode(wm->xdpy, key->keysym),
+ key->modifier_mask | ignored_mask,
+ wm->root_win->xwindow, True, GrabModeAsync, GrabModeAsync);
+
+ result = mb_wm_util_untrap_x_errors();
+
+ if (result != Success)
+ {
+ if (result == BadAccess)
+ mb_wm_util_warn ("Some other program is already using the key %s with modifiers %x as a binding\n",
+ (XKeysymToString(key->keysym)) ? XKeysymToString (key->keysym) : "unknown",
+ key->modifier_mask | ignored_mask );
+ else
+ mb_wm_util_warn ("Unable to grab the key %s with modifiers %x as a binding\n",
+ (XKeysymToString(key->keysym)) ? XKeysymToString (key->keysym) : "unknown",
+ key->modifier_mask | ignored_mask );
+ return False;
+ }
+ }
+
+ ++ignored_mask;
+ }
+
+ return True;
+}
+
+void
+mb_wm_keys_binding_remove_all (MBWindowManager *wm)
+{
+
+}
+
+void
+mb_wm_keys_binding_remove (MBWindowManager *wm,
+ MBWMKeyBinding *binding)
+{
+
+ key_binding_set_grab (wm, binding, True);
+}
+
+MBWMKeyBinding*
+mb_wm_keys_binding_add (MBWindowManager *wm,
+ KeySym ks,
+ int mask,
+ MBWMKeyPressedFunc press_func,
+ MBWMKeyDestroyFunc destroy_func,
+ void *userdata)
+{
+ MBWMKeyBinding *binding = NULL;
+ MBWMKeys *keys = wm->keys;
+
+ MBWM_ASSERT (wm->keys != NULL);
+
+ binding = mb_wm_util_malloc0(sizeof(MBWMKeyBinding));
+
+ binding->keysym = ks;
+ binding->modifier_mask = mask;
+ binding->pressed = press_func;
+ binding->destroy = destroy_func;
+ binding->userdata = userdata;
+
+ if (key_binding_set_grab (wm, binding, False))
+ {
+ keys->bindings = mb_wm_util_list_append(keys->bindings, binding);
+ return binding;
+ }
+
+ /* Grab failed */
+ free(binding);
+ return NULL;
+}
+
+MBWMKeyBinding*
+mb_wm_keys_binding_add_with_spec (MBWindowManager *wm,
+ const char *keystr,
+ MBWMKeyPressedFunc press_func,
+ MBWMKeyDestroyFunc destroy_func,
+ void *userdata)
+{
+ char *orig, *p, *q, *keydef = NULL;
+ int i = 0, mask = 0;
+ Bool want_shift = False;
+ KeySym ks;
+ MBWMKeys *keys = wm->keys;
+ MBWMKeyBinding *binding = NULL;
+
+ struct { char *def; int mask; } lookup[] =
+ {
+ { "ctrl", ControlMask },
+ { "alt", keys->AltMask },
+ { "meta", keys->MetaMask },
+ { "super",keys->SuperMask },
+ { "hyper",keys->HyperMask },
+ { "mod1", Mod1Mask },
+ { "mod2", Mod2Mask },
+ { "mod3", Mod3Mask },
+ { "mod4", Mod4Mask },
+ { "mod5", Mod5Mask },
+ { "shift",-1 },
+ { NULL, 0 }
+ };
+
+ orig = p = strdup(keystr);
+
+ /* parse '<mod><mod><mod>key' */
+
+ while (*p != '\0')
+ {
+ Bool found = False;
+
+ if (*p == '<')
+ {
+ q = ++p; i = 0;
+
+ while (*q != '\0' && *q != '>')
+ q++;
+
+ if (*q == '\0')
+ goto out; /* Parse error */
+
+ while (lookup[i].def != NULL && !found)
+ {
+ if (!strncasecmp(p, lookup[i].def, q-p) && lookup[i].mask)
+ {
+ if (lookup[i].mask == -1)
+ want_shift = True;
+ else
+ mask |= lookup[i].mask;
+ found = True;
+ }
+ i++;
+ }
+
+ if (found)
+ p = q;
+ else
+ goto out;
+ }
+ else if (!isspace(*p))
+ {
+ keydef = p;
+ break;
+ }
+
+ p++;
+ }
+
+ if (!keydef)
+ goto out;
+
+ MBWM_DBG("keydefinition is %s, want_shift is %i", keydef, want_shift);
+
+ if ((ks = XStringToKeysym(keydef)) == (KeySym)NULL)
+ {
+ if (islower(keydef[0])) /* Try again, changing case */
+ keydef[0] = toupper(keydef[0]);
+ else
+ keydef[0] = tolower(keydef[0]);
+
+ if ((ks = XStringToKeysym(keydef)) == (KeySym)NULL)
+ {
+ mb_wm_util_warn ("Cant find keysym for %s", keydef);
+ goto out;
+ }
+ }
+
+ if (keysym_needs_shift(wm, ks) || want_shift)
+ mask |= ShiftMask;
+
+ /* If we grab keycode 0, we end up grabbing the entire keyboard.. */
+ if (XKeysymToKeycode(wm->xdpy, ks) == 0 && mask == 0)
+ {
+ MBWM_DBG("Cant find a keycode for keysym %li", ks);
+ goto out;
+ }
+
+ binding = mb_wm_keys_binding_add (wm, ks, mask,
+ press_func, destroy_func, userdata);
+
+ out:
+
+ free (orig);
+ return binding;
+}
+
+void /* FIXME: rename */
+mb_wm_keys_press (MBWindowManager *wm,
+ KeySym keysym,
+ int modifier_mask)
+{
+ MBWMList *iter;
+ MBWMKeyBinding *binding;
+
+ if (!wm->keys)
+ return;
+
+ MBWM_DBG ("Looking up keysym <%li>, ( mask %i )", keysym, modifier_mask);
+
+ iter = wm->keys->bindings;
+
+ while (iter)
+ {
+ int ignored_mask = 0;
+
+ binding = (MBWMKeyBinding*)iter->data;
+
+ MBWM_DBG ("Checking up keysym <%li>, ( mask %i )",
+ binding->keysym,
+ binding->modifier_mask);
+
+ /* FIXME: Assumes multiple bindings per key */
+ while (ignored_mask < (int) wm->keys->lock_mask)
+ {
+ if (ignored_mask & ~(wm->keys->lock_mask))
+ {
+ ++ignored_mask;
+ continue;
+ }
+
+ if (binding->pressed
+ && binding->keysym == keysym
+ && binding->modifier_mask|ignored_mask == modifier_mask)
+ {
+ binding->pressed(wm, binding, binding->userdata);
+ break;
+ }
+
+ ++ignored_mask;
+ }
+
+ iter = mb_wm_util_list_next(iter);
+ }
+}
+
+
+Bool
+mb_wm_keys_init(MBWindowManager *wm)
+{
+ int mod_idx, mod_key, col, kpm;
+ XModifierKeymap *mod_map;
+ MBWMKeys *keys;
+
+ mod_map = XGetModifierMapping(wm->xdpy);
+
+ keys = wm->keys = mb_wm_util_malloc0(sizeof(MBWMKeys));
+
+ /* Figure out modifier masks */
+
+ kpm = mod_map->max_keypermod;
+ for (mod_idx = 0; mod_idx < 8; mod_idx++)
+ for (mod_key = 0; mod_key < kpm; mod_key++)
+ {
+ KeySym last_sym = 0;
+ for (col = 0; col < 4; col += 2)
+ {
+ KeyCode code = mod_map->modifiermap[mod_idx * kpm + mod_key];
+ KeySym sym = (code ? XKeycodeToKeysym(wm->xdpy, code, col) : 0);
+
+ if (sym == last_sym) continue;
+ last_sym = sym;
+
+ switch (sym)
+ {
+ case XK_Mode_switch:
+ /* XXX store_modifier("Mode_switch", mode_bit); */
+ break;
+ case XK_Meta_L:
+ case XK_Meta_R:
+ keys->MetaMask |= (1 << mod_idx);
+ break;
+ case XK_Super_L:
+ case XK_Super_R:
+ keys->SuperMask |= (1 << mod_idx);
+ break;
+ case XK_Hyper_L:
+ case XK_Hyper_R:
+ keys->HyperMask |= (1 << mod_idx);
+ break;
+ case XK_Alt_L:
+ case XK_Alt_R:
+ keys->AltMask |= (1 << mod_idx);
+ break;
+ case XK_Num_Lock:
+ keys->NumLockMask |= (1 << mod_idx);
+ break;
+ case XK_Scroll_Lock:
+ keys->ScrollLockMask |= (1 << mod_idx);
+ break;
+ }
+ }
+ }
+
+ /* XXX check this. assume alt <=> meta if only either set */
+ if (!keys->AltMask) keys->AltMask = keys->MetaMask;
+ if (!keys->MetaMask) keys->MetaMask = keys->AltMask;
+
+ keys->lock_mask = keys->ScrollLockMask | keys->NumLockMask | LockMask;
+
+ if (mod_map) XFreeModifiermap(mod_map);
+
+ return True;
+}
+