namespace NeoLayoutViewer{ /** * Modification of http://www.linux-nantes.org/~fmonnier/ocaml/Xlib/doc/Xlib.html by * Oliver Sauder */ public class KeybindingManager : GLib.Object { private NeoWindow neo_win; /** * list of binded keybindings */ private Gee.List bindings = new Gee.ArrayList(); private Gee.List modifier_bindings = new Gee.ArrayList(); /** * locked modifiers used to grab all keys whatever lock key * is pressed. */ private static uint[] lock_modifiers = { 0, Gdk.ModifierType.MOD2_MASK, // NUM_LOCK Gdk.ModifierType.LOCK_MASK, // CAPS_LOCK Gdk.ModifierType.MOD5_MASK, // SCROLL_LOCK Gdk.ModifierType.MOD2_MASK|Gdk.ModifierType.LOCK_MASK, Gdk.ModifierType.MOD2_MASK|Gdk.ModifierType.MOD5_MASK, Gdk.ModifierType.LOCK_MASK|Gdk.ModifierType.MOD5_MASK, Gdk.ModifierType.MOD2_MASK|Gdk.ModifierType.LOCK_MASK|Gdk.ModifierType.MOD5_MASK }; /** * Helper class to store keybinding */ private class Keybinding { public Keybinding(string accelerator, int keycode, Gdk.ModifierType modifiers, KeybindingHandlerFunc handler) { this.accelerator = accelerator; this.keycode = keycode; this.modifiers = modifiers; this.handler = handler; } public string accelerator { get; set; } public int keycode { get; set; } public Gdk.ModifierType modifiers { get; set; } public KeybindingHandlerFunc handler { get; set; } } /** * Helper class to store second set of keybindings (modifier) */ private class ModifierKeybinding { public ModifierKeybinding(string accelerator, int keycode, Gdk.ModifierType modifiers, int ebene, KeybindingHandlerFunc handler) { this.accelerator = accelerator; this.keycode = keycode; this.ebene = ebene; this.modifiers = modifiers; this.handler = handler; } public string accelerator { get; set; } public int keycode { get; set; } public int ebene { get; set; } public Gdk.ModifierType modifiers { get; set; } public KeybindingHandlerFunc handler { get; set; } } /** * Keybinding func needed to bind key to handler * * @param event passing on gdk event */ public delegate void KeybindingHandlerFunc(Gdk.Event event); public KeybindingManager(NeoWindow neo_win) { this.neo_win = neo_win; // init filter to retrieve X.Events Gdk.Window rootwin = Gdk.get_default_root_window(); if(rootwin != null) { rootwin.add_filter(event_filter); } //some tests /* X.Display display = Gdk.x11_drawable_get_xdisplay(rootwin); X.ModifierKeymap modmap = display.get_modifier_mapping (); debug("Max mod: %i\n".printf(modmap.max_keypermod)); for(int i=0; i remove_bindings = new Gee.ArrayList(); foreach(Keybinding binding in bindings) { if(str_equal(accelerator, binding.accelerator)) { foreach(uint lock_modifier in lock_modifiers) { display.ungrab_key(binding.keycode, binding.modifiers, xid); } remove_bindings.add(binding); } } // remove unbinded keys bindings.remove_all(remove_bindings); } public void unbind2(int keycode) { //debug("Unbinding key\n "); Gdk.Window rootwin = Gdk.get_default_root_window(); unowned X.Display display = Gdk.x11_drawable_get_xdisplay(rootwin); X.ID xid = Gdk.x11_drawable_get_xid(rootwin); // unbind all keys with given accelerator Gee.List remove_bindings = new Gee.ArrayList(); foreach(ModifierKeybinding binding in modifier_bindings) { if(keycode == binding.keycode) { display.ungrab_key(binding.keycode, binding.modifiers, xid); remove_bindings.add(binding); } } // remove unbinded keys bindings.remove_all(remove_bindings); } /** * Event filter method needed to fetch X.Events */ public Gdk.FilterReturn event_filter(Gdk.XEvent gdk_xevent, Gdk.Event gdk_event) { Gdk.FilterReturn filter_return = Gdk.FilterReturn.CONTINUE; //Gdk.FilterReturn filter_return = Gdk.FilterReturn.REMOVE; void* pointer = &gdk_xevent; X.Event* xevent = (X.Event*) pointer; if(xevent->type == X.EventType.KeyPress) { foreach(Keybinding binding in bindings) { // remove NumLock, CapsLock and ScrollLock from key state uint event_mods = xevent.xkey.state & ~ (lock_modifiers[7]); if(xevent->xkey.keycode == binding.keycode && event_mods == binding.modifiers) { // call all handlers with pressed key and modifiers binding.handler(gdk_event); } } } if(xevent->type == X.EventType.KeyPress) { uint event_mods = xevent.xkey.state; foreach(ModifierKeybinding binding in modifier_bindings) { if(xevent->xkey.keycode == binding.keycode) { //neo_win.external_key_press(binding.ebene,(int)event_mods); neo_win.active_modifier[binding.ebene] = 1; neo_win.redraw(); // call all handlers with pressed key and modifiers binding.handler(gdk_event); //send_event_again(Gdk.get_default_root_window(), binding, *xevent); } } } if(xevent->type == X.EventType.KeyRelease) { uint event_mods = xevent.xkey.state; foreach(ModifierKeybinding binding in modifier_bindings) { if(xevent->xkey.keycode == binding.keycode) { //neo_win.external_key_release(0,(int)event_mods); neo_win.active_modifier[binding.ebene] = 0; neo_win.redraw(); // call all handlers with pressed key and modifiers binding.handler(gdk_event); //send_event_again(Gdk.get_default_root_window(), binding, *xevent); } } } debug("Filter %u\n".printf(xevent.xkey.keycode)); send_event_again(Gdk.get_default_root_window(), *xevent); return filter_return; } private void send_event_again(Gdk.Window rootwin, X.Event xevent){ if(rootwin != null) { unowned X.Display display = Gdk.x11_drawable_get_xdisplay(rootwin); X.ID xid = Gdk.x11_drawable_get_xid(rootwin); foreach(ModifierKeybinding binding in modifier_bindings){ display.ungrab_key(binding.keycode, binding.modifiers, xid); } //rootwin.remove_filter(event_filter); debug("Send Event again %u\n".printf(xevent.xkey.state)); display.send_event(xevent.xkey.window,true,xevent.xkey.state,ref xevent); //rootwin.add_filter(event_filter); foreach(ModifierKeybinding binding in modifier_bindings){ // display.grab_key(binding.keycode, 0, xid, false, X.GrabMode.Async, X.GrabMode.Async); } } } } }