I was looking for some example of global python xlib babe that will work with gtk3, as is done for gtk2 at http://www.siafoo.net/snippet/239 , very similar code here:
from Xlib.display import Display from Xlib import X import gtk.gdk import threading import gobject class GlobalKeyBinding (gobject.GObject, threading.Thread): __gsignals__ = { 'activate': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()), } def __init__ (self): gobject.GObject.__init__ (self) threading.Thread.__init__ (self) self.setDaemon (True) self.keymap = gtk.gdk.keymap_get_default () self.display = Display () self.screen = self.display.screen () self.root = self.screen.root self.map_modifiers () self.keybindings={} self.current_signal=None def map_modifiers (self): gdk_modifiers = (gtk.gdk.CONTROL_MASK, gtk.gdk.SHIFT_MASK, gtk.gdk.MOD1_MASK, gtk.gdk.MOD3_MASK, gtk.gdk.MOD4_MASK, gtk.gdk.MOD5_MASK, gtk.gdk.SUPER_MASK, gtk.gdk.HYPER_MASK) self.known_modifiers_mask = 0 for modifier in gdk_modifiers: self.known_modifiers_mask |= modifier def add_grab_key(self,accelerator,signal): if not accelerator: return keyval,modifiers=gtk.accelerator_parse(accelerator) if not keyval or not modifiers: return keycode=self.keymap.get_entries_for_keyval(keyval)[0][0] self.keybindings[signal]=[accelerator, keycode, int (modifiers)] #grab_key operation forces X to exclusivelly send given keycode (like apostrophe char) to current X client (unless other X client grabbed it before). #`X.AnyModifier' parameter tells to register the keycode for all modifiers, thus Ctrl-', Alt-', Shift-', ' will all be sent to this X client. # given keyval is grabbed by current X client until `ungrab_key' is called. return self.root.grab_key (keycode, X.AnyModifier, True, X.GrabModeAsync, X.GrabModeSync) def ungrab (self): for signal in self.keybindings: # ungrab_key ungrabs given keycode, that was grabbed by `grab_key'. self.root.ungrab_key (self.keybindings[signal][1],X.AnyModifier, self.root) self.keybindings={} def idle (self): if self.current_signal: gtk.gdk.threads_enter () self.emit (self.current_signal) self.current_signal=None gtk.gdk.threads_leave () return False #threading.Thread.start() method invokes this method. def run (self): self.running = True wait_for_release = False while self.running: event = self.display.next_event () # registered keycode(or probably rather event) has been received. if self.current_signal: self.display.allow_events (X.ReplayKeyboard, event.time) continue try: if not wait_for_release and event.type == X.KeyPress: modifiers = event.state & self.known_modifiers_mask print modifiers, event.detail for signal in self.keybindings: if self.keybindings[signal][1] == event.detail and self.keybindings[signal][2] == modifiers: self.this_signal=signal this_keycode = self.keybindings[signal][1] wait_for_release=True break if wait_for_release: self.display.allow_events (X.AsyncKeyboard, event.time) else: self.display.allow_events (X.ReplayKeyboard, event.time) continue elif wait_for_release and event.detail == this_keycode and event.type == X.KeyRelease: wait_for_release = False self.current_signal=self.this_signal self.event_window=event.window gobject.idle_add (self.idle) self.display.allow_events (X.AsyncKeyboard, event.time) else: self.display.allow_events (X.ReplayKeyboard, event.time) except: self.display.allow_events (X.ReplayKeyboard, event.time) def stop (self): print "stopping keybindings thread..." self.running = False self.ungrab () self.display.close () # SAMPLE USAGE def callback (keybinding): print 'Callback!' keybinding.stop() gtk.main_quit () def main(): print "starting..." gtk.gdk.threads_init () keybindings=GlobalKeyBinding() keybindings.add_grab_key('<Control>apostrophe','activate') keybindings.connect('activate',callback) keybindings.start () # let thart the thread gtk.main () main()
Unfortunately, I did not find it, so I decided to override it to use gtk3 (ubuntu 12.04). Below is the result. It does not have runtime errors, but unfortunately it does not receive any data.
from Xlib.display import Display from Xlib import X from gi.repository import Gtk, Gdk, GObject import threading class GlobalKeyBinding (GObject.GObject, threading.Thread): __gsignals__ = { 'activate': (GObject.SignalFlags.RUN_LAST, None, ()), } def __init__ (self): GObject.GObject.__init__ (self) threading.Thread.__init__ (self) self.setDaemon (True) self.keymap = Gdk.Keymap.get_default() self.display = Display () self.screen = self.display.screen () self.root = self.screen.root self.map_modifiers () self.keybindings={} self.current_signal=None def map_modifiers (self): gdk_modifiers = (Gdk.ModifierType.CONTROL_MASK, Gdk.ModifierType.SHIFT_MASK, Gdk.ModifierType.MOD1_MASK, Gdk.ModifierType.MOD3_MASK, Gdk.ModifierType.MOD4_MASK, Gdk.ModifierType.MOD5_MASK, Gdk.ModifierType.SUPER_MASK, Gdk.ModifierType.HYPER_MASK) self.known_modifiers_mask = 0 for modifier in gdk_modifiers: #print modifier,modifier+0 self.known_modifiers_mask |= modifier def add_grab_key(self,accelerator,signal): if not accelerator: return keyval,modifiers=Gtk.accelerator_parse(accelerator) if not keyval or not modifiers: return #keycode=self.keymap.get_entries_for_keyval(keyval)[0][0] success, entries = self.keymap.get_entries_for_keyval(keyval) entry = [(int(i.keycode), i.group, i.level) for i in entries] if not entry: raise TypeError("Invalid key name") keycode=entry[0][0] self.keybindings[signal]=[accelerator, keycode, int (modifiers)] return self.root.grab_key (keycode, X.AnyModifier, True, X.GrabModeAsync, X.GrabModeSync) def ungrab (self): for signal in self.keybindings: self.root.ungrab_key (self.keybindings[signal][1],X.AnyModifier, self.root) self.keybindings={} def idle (self): if self.current_signal: Gdk.threads_enter () self.emit (self.current_signal) self.current_signal=None Gdk.threads_leave () return False def run (self): self.running = True wait_for_release = False while self.running: event = self.display.next_event () if self.current_signal: self.display.allow_events (X.ReplayKeyboard, event.time) continue try: if not wait_for_release and event.type == X.KeyPress: modifiers = event.get_state() & self.known_modifiers_mask print modifiers,event.get_state() for signal in self.keybindings: if self.keybindings[signal][1] == event.detail and self.keybindings[signal][2] == modifiers: self.this_signal=signal this_keycode = self.keybindings[signal][1] wait_for_release=True break if wait_for_release: self.display.allow_events (X.AsyncKeyboard, event.time) else: self.display.allow_events (X.ReplayKeyboard, event.time) continue elif wait_for_release and event.detail == this_keycode and event.type == X.KeyRelease: wait_for_release = False self.current_signal=self.this_signal self.event_window=event.window GObject.idle_add (self.idle) self.display.allow_events (X.AsyncKeyboard, event.time) else: self.display.allow_events (X.ReplayKeyboard, event.time) except: self.display.allow_events (X.ReplayKeyboard, event.time) def stop (self): self.running = False self.ungrab () self.display.close () # SAMPLE USAGE def callback (keybinding): print 'Callback!' keybinding.stop() Gtk.main_quit () def main(): print "starting..." Gdk.threads_init () keybindings=GlobalKeyBinding() keybindings.add_grab_key('<Control>apostrophe','activate') keybindings.connect('activate',callback) print "keybindings go" keybindings.start () # let thart the thread print "gtk go" Gtk.main () main()
Perhaps you have ideas on how to make it work?
Regards Paul