1 /* vim:set et sts=4 sw=4:
2 valac --pkg gtk+-2.0 --pkg x11 --pkg gdk-x11-2.0 --pkg gee-1.0 keybinding-manager.vala
6 * This class is in charge to grab keybindings on the X11 display
7 * and filter X11-events and passing on such events to the registed
10 * @author Oliver Sauder <os@esite.ch>
13 extern bool grab_keycode (Gdk.Display display,
17 extern bool ungrab_keycode (Gdk.Display display,
21 public class KeybindingManager : GLib.Object {
23 * list of binded keybindings
25 private GLib.List<Keybinding> m_bindings = new GLib.List<Keybinding>();
27 private static KeybindingManager m_instance = null;
29 public static const uint MODIFIER_FILTER =
30 Gdk.ModifierType.MODIFIER_MASK & ~(
31 Gdk.ModifierType.LOCK_MASK | // Caps Lock
32 // Gdk.ModifierType.MOD1_MASK | // Alt
33 Gdk.ModifierType.MOD2_MASK | // Num Lock
34 // Gdk.ModifierType.MOD3_MASK |
35 // Gdk.ModifierType.MOD4_MASK | // Super, Hyper
36 // Gdk.ModifierType.MOD5_MASK | //
37 Gdk.ModifierType.BUTTON1_MASK |
38 Gdk.ModifierType.BUTTON2_MASK |
39 Gdk.ModifierType.BUTTON3_MASK |
40 Gdk.ModifierType.BUTTON4_MASK |
41 Gdk.ModifierType.BUTTON5_MASK |
42 Gdk.ModifierType.SUPER_MASK |
43 Gdk.ModifierType.HYPER_MASK |
44 Gdk.ModifierType.META_MASK);
47 * Helper class to store keybinding
49 private class Keybinding {
50 public Keybinding(uint keysym,
51 Gdk.ModifierType modifiers,
52 KeybindingHandlerFunc handler) {
54 this.modifiers = modifiers;
55 this.handler = handler;
58 public uint keysym { get; set; }
59 public Gdk.ModifierType modifiers { get; set; }
60 public unowned KeybindingHandlerFunc handler { get; set; }
64 * Keybinding func needed to bind key to handler
66 * @param event passing on gdk event
68 public delegate void KeybindingHandlerFunc(Gdk.Event event);
71 private KeybindingManager() {
72 Gdk.Event.handler_set(event_handler);
76 * Bind accelerator to given handler
80 * @param handler handler called when given accelerator is pressed
82 public bool bind(uint keysym,
83 Gdk.ModifierType modifiers,
84 KeybindingHandlerFunc handler) {
85 unowned X.Display display = Gdk.x11_get_default_xdisplay();
87 int keycode = display.keysym_to_keycode(keysym);
92 grab_keycode (Gdk.Display.get_default(), keysym, modifiers);
95 Keybinding binding = new Keybinding(keysym, modifiers, handler);
96 m_bindings.append(binding);
102 * Unbind given accelerator.
107 public void unbind(uint keysym,
108 Gdk.ModifierType modifiers) {
109 // unbind all keys with given accelerator
110 GLib.List<Keybinding> remove_bindings = new GLib.List<Keybinding>();
111 foreach(Keybinding binding in m_bindings) {
112 if (binding.keysym == keysym && binding.modifiers == modifiers) {
113 ungrab_keycode (Gdk.Display.get_default(),
116 remove_bindings.append(binding);
120 // remove unbinded keys
121 foreach (Keybinding binding in remove_bindings)
122 m_bindings.remove (binding);
125 public static KeybindingManager get_instance () {
126 if (m_instance == null)
127 m_instance = new KeybindingManager ();
131 public static Gdk.ModifierType get_primary_modifier (uint binding_mask) {
132 const Gdk.ModifierType[] masks = {
133 Gdk.ModifierType.MOD5_MASK,
134 Gdk.ModifierType.MOD4_MASK,
135 Gdk.ModifierType.MOD3_MASK,
136 Gdk.ModifierType.MOD2_MASK,
137 Gdk.ModifierType.MOD1_MASK,
138 Gdk.ModifierType.CONTROL_MASK,
139 Gdk.ModifierType.SHIFT_MASK,
140 Gdk.ModifierType.LOCK_MASK
142 foreach (Gdk.ModifierType mask in masks) {
143 if ((binding_mask & mask) == mask)
149 public static bool primary_modifier_still_pressed(Gdk.Event event,
150 uint primary_modifier) {
151 Gdk.EventKey keyevent = event.key;
152 if (primary_modifier == 0)
155 Gdk.Device device = event.get_device();
157 if (device.get_source() == Gdk.InputSource.KEYBOARD)
158 pointer = device.get_associated_device();
163 pointer.get_state(keyevent.window, null, out modifier);
164 if ((primary_modifier & modifier) == primary_modifier)
170 public static uint keyval_to_modifier (uint keyval) {
172 case 0xffe3: /* Control_L */
173 case 0xffe4: /* Control_R */
174 return Gdk.ModifierType.CONTROL_MASK;
175 case 0xffe1: /* Shift_L */
176 case 0xffe2: /* Shift_R */
177 return Gdk.ModifierType.SHIFT_MASK;
178 case 0xffe5: /* Caps_Lock */
179 return Gdk.ModifierType.LOCK_MASK;
180 case 0xffe9: /* Alt_L */
181 case 0xffea: /* Alt_R */
182 return Gdk.ModifierType.MOD1_MASK;
183 case 0xffe7: /* Meta_L */
184 case 0xffe8: /* Meta_R */
185 return Gdk.ModifierType.META_MASK;
186 case 0xffeb: /* Super_L */
187 case 0xffec: /* Super_R */
188 return Gdk.ModifierType.SUPER_MASK;
189 case 0xffed: /* Hyper_L */
190 case 0xffee: /* Hyper_R */
191 return Gdk.ModifierType.HYPER_MASK;
197 private void event_handler(Gdk.Event event) {
199 if (event.any.window != Gdk.get_default_root_window()) {
203 if (event.type == Gdk.EventType.KEY_PRESS) {
204 uint modifiers = event.key.state & MODIFIER_FILTER;
205 foreach (var binding in m_bindings) {
206 if (event.key.keyval != binding.keysym ||
207 modifiers != binding.modifiers)
209 binding.handler(event);
214 Gtk.main_do_event(event);
219 public static int main (string[] args)
223 KeybindingManager manager = new KeybindingManager();
224 manager.bind("<Ctrl><Alt>V", test);
230 private static void test()
232 debug("hotkey pressed");