From 7e946f68d9f8ec7c880664b437edbbaa5d49ac10 Mon Sep 17 00:00:00 2001 From: Dana Jansens Date: Fri, 4 May 2007 01:10:03 +0000 Subject: [PATCH] make the modifier key code a lot better... 1) it can handle more user cases. 2) it can handle binding more modifier keys with their keysym names like Hyper and Super. W is a shortcut for Super, cuz the windows key is generally bound to it. 3) if you change your keymap bindings and reconfigure openbox it will learn your changes. and i dunno.. its just nice and stuff now.. you can actually read it I think.. --- Makefile.am | 2 + openbox/event.c | 75 +++---------------------- openbox/grab.c | 20 ++++--- openbox/modkeys.c | 133 ++++++++++++++++++++++++++++++++++++++++++++ openbox/modkeys.h | 54 ++++++++++++++++++ openbox/openbox.c | 4 ++ openbox/translate.c | 42 ++++++++++---- 7 files changed, 243 insertions(+), 87 deletions(-) create mode 100644 openbox/modkeys.c create mode 100644 openbox/modkeys.h diff --git a/Makefile.am b/Makefile.am index e7802d48..9bef49a5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -182,6 +182,8 @@ openbox_openbox_SOURCES = \ openbox/menu.c \ openbox/menu.h \ openbox/misc.h \ + openbox/modkeys.c \ + openbox/modkeys.h \ openbox/mouse.c \ openbox/mouse.h \ openbox/moveresize.c \ diff --git a/openbox/event.c b/openbox/event.c index cbc9aaf8..d4ac2176 100644 --- a/openbox/event.c +++ b/openbox/event.c @@ -31,6 +31,7 @@ #include "menu.h" #include "menuframe.h" #include "keyboard.h" +#include "modkeys.h" #include "mouse.h" #include "mainloop.h" #include "framerender.h" @@ -93,21 +94,7 @@ static gboolean menu_hide_delay_func(gpointer data); /* The time for the current event being processed */ Time event_curtime = CurrentTime; -/*! The value of the mask for the NumLock modifier */ -guint NumLockMask; -/*! The value of the mask for the ScrollLock modifier */ -guint ScrollLockMask; -/*! The key codes for the modifier keys */ -static XModifierKeymap *modmap; -/*! Table of the constant modifier masks */ -static const gint mask_table[] = { - ShiftMask, LockMask, ControlMask, Mod1Mask, - Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask -}; -static gint mask_table_size; - static guint ignore_enter_focus = 0; - static gboolean menu_can_hide; #ifdef USE_SM @@ -136,31 +123,6 @@ void event_startup(gboolean reconfig) { if (reconfig) return; - mask_table_size = sizeof(mask_table) / sizeof(mask_table[0]); - - /* get lock masks that are defined by the display (not constant) */ - modmap = XGetModifierMapping(ob_display); - g_assert(modmap); - if (modmap && modmap->max_keypermod > 0) { - size_t cnt; - const size_t size = mask_table_size * modmap->max_keypermod; - /* get the values of the keyboard lock modifiers - Note: Caps lock is not retrieved the same way as Scroll and Num - lock since it doesn't need to be. */ - const KeyCode num_lock = XKeysymToKeycode(ob_display, XK_Num_Lock); - const KeyCode scroll_lock = XKeysymToKeycode(ob_display, - XK_Scroll_Lock); - - for (cnt = 0; cnt < size; ++cnt) { - if (! modmap->modifiermap[cnt]) continue; - - if (num_lock == modmap->modifiermap[cnt]) - NumLockMask = mask_table[cnt / modmap->max_keypermod]; - if (scroll_lock == modmap->modifiermap[cnt]) - ScrollLockMask = mask_table[cnt / modmap->max_keypermod]; - } - } - ob_main_loop_x_add(ob_main_loop, event_process, NULL, NULL); #ifdef USE_SM @@ -179,7 +141,6 @@ void event_shutdown(gboolean reconfig) #endif client_remove_destructor(focus_delay_client_dest); - XFreeModifiermap(modmap); } static Window event_get_window(XEvent *e) @@ -271,54 +232,34 @@ static void event_set_curtime(XEvent *e) event_curtime = t; } -#define STRIP_MODS(s) \ - s &= ~(LockMask | NumLockMask | ScrollLockMask), \ - /* kill off the Button1Mask etc, only want the modifiers */ \ - s &= (ControlMask | ShiftMask | Mod1Mask | \ - Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask) \ - static void event_hack_mods(XEvent *e) { #ifdef XKB XkbStateRec xkb_state; #endif - KeyCode *kp; - gint i, k; switch (e->type) { case ButtonPress: case ButtonRelease: - STRIP_MODS(e->xbutton.state); + e->xbutton.state = modkeys_only_modifier_masks(e->xbutton.state); break; case KeyPress: - STRIP_MODS(e->xkey.state); + e->xkey.state = modkeys_only_modifier_masks(e->xkey.state); break; case KeyRelease: - STRIP_MODS(e->xkey.state); - /* remove from the state the mask of the modifier being released, if - it is a modifier key being released (this is a little ugly..) */ + e->xkey.state = modkeys_only_modifier_masks(e->xkey.state); #ifdef XKB if (XkbGetState(ob_display, XkbUseCoreKbd, &xkb_state) == Success) { e->xkey.state = xkb_state.compat_state; break; } #endif - kp = modmap->modifiermap; - for (i = 0; i < mask_table_size; ++i) { - for (k = 0; k < modmap->max_keypermod; ++k) { - if (*kp == e->xkey.keycode) { /* found the keycode */ - /* remove the mask for it */ - e->xkey.state &= ~mask_table[i]; - /* cause the first loop to break; */ - i = mask_table_size; - break; /* get outta here! */ - } - ++kp; - } - } + /* remove from the state the mask of the modifier key being released, + if it is a modifier key being released that is */ + e->xkey.state &= ~modkeys_keycode_to_mask(e->xkey.keycode); break; case MotionNotify: - STRIP_MODS(e->xmotion.state); + e->xmotion.state = modkeys_only_modifier_masks(e->xmotion.state); /* compress events */ { XEvent ce; diff --git a/openbox/grab.c b/openbox/grab.c index eaf65f6b..3e1066ba 100644 --- a/openbox/grab.c +++ b/openbox/grab.c @@ -18,6 +18,7 @@ */ #include "grab.h" +#include "modkeys.h" #include "openbox.h" #include "event.h" #include "xerror.h" @@ -135,17 +136,20 @@ gint grab_server(gboolean grab) void grab_startup(gboolean reconfig) { guint i = 0; + guint num, caps, scroll; - if (reconfig) return; + num = modkeys_key_to_mask(OB_MODKEY_KEY_NUMLOCK); + caps = modkeys_key_to_mask(OB_MODKEY_KEY_CAPSLOCK); + scroll = modkeys_key_to_mask(OB_MODKEY_KEY_SCROLLLOCK); mask_list[i++] = 0; - mask_list[i++] = LockMask; - mask_list[i++] = NumLockMask; - mask_list[i++] = LockMask | NumLockMask; - mask_list[i++] = ScrollLockMask; - mask_list[i++] = ScrollLockMask | LockMask; - mask_list[i++] = ScrollLockMask | NumLockMask; - mask_list[i++] = ScrollLockMask | LockMask | NumLockMask; + mask_list[i++] = num; + mask_list[i++] = caps; + mask_list[i++] = scroll; + mask_list[i++] = num | caps; + mask_list[i++] = num | scroll; + mask_list[i++] = caps | scroll; + mask_list[i++] = num | caps | scroll; g_assert(i == MASK_LIST_SIZE); } diff --git a/openbox/modkeys.c b/openbox/modkeys.c new file mode 100644 index 00000000..4f0ddca9 --- /dev/null +++ b/openbox/modkeys.c @@ -0,0 +1,133 @@ +/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*- + + modkeys.c for the Openbox window manager + Copyright (c) 2007 Dana Jansens + + 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. + + See the COPYING file for a copy of the GNU General Public License. +*/ + +#include "modkeys.h" +#include "openbox.h" + +#include + +/* These masks are constants and the modifier keys are bound to them as + anyone sees fit: + ShiftMask (1<<0), LockMask (1<<1), ControlMask (1<<2), Mod1Mask (1<<3), + Mod2Mask (1<<4), Mod3Mask (1<<5), Mod4Mask (1<<6), Mod5Mask (1<<7) +*/ +#define NUM_MASKS 8 +#define ALL_MASKS 0xf /* an or'ing of all 8 keyboard masks */ + +/* Get the bitflag for the n'th modifier mask */ +#define nth_mask(n) (1 << n) + +static void set_modkey_mask(guchar mask, KeySym sym); + +static XModifierKeymap *modmap; +/* This is a bitmask of the different masks for each modifier key */ +static guchar modkeys_keys[OB_MODKEY_NUM_KEYS]; + +void modkeys_startup(gboolean reconfigure) +{ + /* keycodes for the modifier keys which will be bound to the masks */ + gint i, j, k; + + modmap = XGetModifierMapping(ob_display); + g_assert(modmap->max_keypermod > 0); + + /* reset the keys to not be bound to any masks */ + for (i = 0; i < OB_MODKEY_NUM_KEYS; ++i) + modkeys_keys[i] = 0; + + /* go through each of the modifier masks (eg ShiftMask, CapsMask...) */ + for (i = 0; i < NUM_MASKS; ++i) { + /* go through each keycode that is bound to the mask */ + for (j = 0; j < modmap->max_keypermod; ++j) { + KeySym sym; + /* get a keycode that is bound to the mask (i) */ + KeyCode keycode = modmap->modifiermap[i*modmap->max_keypermod + j]; + /* go through each keysym bound to the given keycode */ + for (k = 0; ; ++k) { + sym = XKeycodeToKeysym(ob_display, keycode, k); + if (sym == NoSymbol) break; + + /* bind the key to the mask (e.g. Alt_L => Mod1Mask) */ + set_modkey_mask(nth_mask(i), sym); + } + } + } +} + +void modkeys_shutdown(gboolean reconfigure) +{ + XFreeModifiermap(modmap); +} + +guint modkeys_keycode_to_mask(guint keycode) +{ + gint i, j; + guint mask = 0; + + if (keycode == NoSymbol) return 0; + + /* go through each of the modifier masks (eg ShiftMask, CapsMask...) */ + for (i = 0; i < NUM_MASKS; ++i) { + /* go through each keycode that is bound to the mask */ + for (j = 0; j < modmap->max_keypermod; ++j) { + /* compare with a keycode that is bound to the mask (i) */ + if (modmap->modifiermap[i*modmap->max_keypermod + j] == keycode) + mask |= nth_mask(i); + } + } + return mask; +} + +guint modkeys_only_modifier_masks(guint mask) +{ + mask &= ALL_MASKS; + /* strip off these lock keys. they shouldn't affect key bindings */ + mask &= ~modkeys_key_to_mask(OB_MODKEY_KEY_CAPSLOCK); + mask &= ~modkeys_key_to_mask(OB_MODKEY_KEY_NUMLOCK); + mask &= ~modkeys_key_to_mask(OB_MODKEY_KEY_SCROLLLOCK); + return mask; +} + +guint modkeys_key_to_mask(ObModkeysKey key) +{ + return modkeys_keys[key]; +} + +static void set_modkey_mask(guchar mask, KeySym sym) +{ + /* find what key this is, and bind it to the mask */ + + if (sym == XK_Num_Lock) + modkeys_keys[OB_MODKEY_KEY_NUMLOCK] |= mask; + else if (sym == XK_Scroll_Lock) + modkeys_keys[OB_MODKEY_KEY_SCROLLLOCK] |= mask; + else if (sym == XK_Caps_Lock) + modkeys_keys[OB_MODKEY_KEY_CAPSLOCK] |= mask; + else if (sym == XK_Shift_L || sym == XK_Shift_R) + modkeys_keys[OB_MODKEY_KEY_SHIFT] |= mask; + else if (sym == XK_Control_L || sym == XK_Control_R) + modkeys_keys[OB_MODKEY_KEY_CONTROL] |= mask; + else if (sym == XK_Super_L || sym == XK_Super_R) + modkeys_keys[OB_MODKEY_KEY_SUPER] |= mask; + else if (sym == XK_Hyper_L || sym == XK_Hyper_R) + modkeys_keys[OB_MODKEY_KEY_HYPER] |= mask; + else if (sym == XK_Alt_L || sym == XK_Alt_R) + modkeys_keys[OB_MODKEY_KEY_ALT] |= mask; + else if (sym == XK_Meta_L || sym == XK_Meta_R) + modkeys_keys[OB_MODKEY_KEY_META] |= mask; +} diff --git a/openbox/modkeys.h b/openbox/modkeys.h new file mode 100644 index 00000000..cfa95b04 --- /dev/null +++ b/openbox/modkeys.h @@ -0,0 +1,54 @@ +/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*- + + masks.h for the Openbox window manager + Copyright (c) 2007 Dana Jansens + + 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. + + See the COPYING file for a copy of the GNU General Public License. +*/ + +#ifndef ob__modkeys_h +#define ob__modkeys_h + +#include + +/*! These keys are bound to the modifier masks in any fashion */ +typedef enum { + OB_MODKEY_KEY_CAPSLOCK, + OB_MODKEY_KEY_NUMLOCK, + OB_MODKEY_KEY_SCROLLLOCK, + OB_MODKEY_KEY_SHIFT, + OB_MODKEY_KEY_CONTROL, + OB_MODKEY_KEY_SUPER, + OB_MODKEY_KEY_HYPER, + OB_MODKEY_KEY_META, + OB_MODKEY_KEY_ALT, + + OB_MODKEY_NUM_KEYS +} ObModkeysKey; + +void modkeys_startup(gboolean reconfigure); +void modkeys_shutdown(gboolean reconfigure); + +/*! Get the modifier masks for a keycode. (eg. a keycode bound to Alt_L could + return a mask of (Mod1Mask | Mask3Mask)) */ +guint modkeys_keycode_to_mask(guint keycode); + +/*! Strip off all modifiers except for the modifier keys. This strips stuff + like Button1Mask, and also LockMask, NumLockMask, and ScrollLockMask */ +guint modkeys_only_modifier_masks(guint mask); + +/*! Get the modifier masks for a modifier key. This includes both the left and + right keys when there are both. */ +guint modkeys_key_to_mask(ObModkeysKey key); + +#endif diff --git a/openbox/openbox.c b/openbox/openbox.c index 9de780dd..052929a5 100644 --- a/openbox/openbox.c +++ b/openbox/openbox.c @@ -21,6 +21,7 @@ #include "openbox.h" #include "session.h" #include "dock.h" +#include "modkeys.h" #include "event.h" #include "menu.h" #include "client.h" @@ -215,6 +216,8 @@ gint main(gint argc, gchar **argv) xmlDocPtr doc; xmlNodePtr node; + modkeys_startup(reconfigure); + /* startup the parsing so everything can register sections of the rc */ i = parse_startup(); @@ -320,6 +323,7 @@ gint main(gint argc, gchar **argv) window_shutdown(reconfigure); event_shutdown(reconfigure); config_shutdown(); + modkeys_shutdown(reconfigure); } while (reconfigure); } diff --git a/openbox/translate.c b/openbox/translate.c index a7cac557..1ef8e7d5 100644 --- a/openbox/translate.c +++ b/openbox/translate.c @@ -19,6 +19,7 @@ #include "openbox.h" #include "mouse.h" +#include "modkeys.h" #include "gettext.h" #include #include @@ -26,20 +27,37 @@ static guint translate_modifier(gchar *str) { - if (!g_ascii_strcasecmp("Mod1", str) || - !g_ascii_strcasecmp("A", str)) return Mod1Mask; - else if (!g_ascii_strcasecmp("Mod2", str)) return Mod2Mask; - else if (!g_ascii_strcasecmp("Mod3", str) || - !g_ascii_strcasecmp("M", str)) return Mod3Mask; - else if (!g_ascii_strcasecmp("Mod4", str) || - !g_ascii_strcasecmp("W", str)) return Mod4Mask; - else if (!g_ascii_strcasecmp("Mod5", str)) return Mod5Mask; + guint mask = 0; + + if (!g_ascii_strcasecmp("Mod1", str)) mask = Mod1Mask; + else if (!g_ascii_strcasecmp("Mod2", str)) mask = Mod2Mask; + else if (!g_ascii_strcasecmp("Mod3", str)) mask = Mod3Mask; + else if (!g_ascii_strcasecmp("Mod4", str)) mask = Mod4Mask; + else if (!g_ascii_strcasecmp("Mod5", str)) mask = Mod5Mask; + else if (!g_ascii_strcasecmp("Control", str) || - !g_ascii_strcasecmp("C", str)) return ControlMask; + !g_ascii_strcasecmp("C", str)) + mask = modkeys_key_to_mask(OB_MODKEY_KEY_CONTROL); + else if (!g_ascii_strcasecmp("Alt", str) || + !g_ascii_strcasecmp("A", str)) + mask = modkeys_key_to_mask(OB_MODKEY_KEY_ALT); + else if (!g_ascii_strcasecmp("Meta", str) || + !g_ascii_strcasecmp("M", str)) + mask = modkeys_key_to_mask(OB_MODKEY_KEY_META); + /* W = windows key, is linked to the Super_L/R buttons */ + else if (!g_ascii_strcasecmp("Super", str) || + !g_ascii_strcasecmp("W", str)) + mask = modkeys_key_to_mask(OB_MODKEY_KEY_SUPER); else if (!g_ascii_strcasecmp("Shift", str) || - !g_ascii_strcasecmp("S", str)) return ShiftMask; - g_message(_("Invalid modifier key '%s' in key/pointer binding"), str); - return 0; + !g_ascii_strcasecmp("S", str)) + mask = modkeys_key_to_mask(OB_MODKEY_KEY_SHIFT); + else if (!g_ascii_strcasecmp("Hyper", str) || + !g_ascii_strcasecmp("H", str)) + mask = modkeys_key_to_mask(OB_MODKEY_KEY_HYPER); + else + g_message(_("Invalid modifier key '%s' in key/pointer binding"), str); + + return mask; } gboolean translate_button(const gchar *str, guint *state, guint *button) -- 2.39.2