使用Python gtk3在X上进行全局键绑定

我正在寻找一些Python xlib全局键绑定的例子,它可以和gtk3一起工作,就像在http://www.siafoo.net/snippet/239上为gtk2所做的那样。 这里非常类似的代码:

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's thart the thread gtk.main () main() 

不幸的是我没有find一个,所以我决定重新实现它使用gtk3(Ubuntu的12.04)。 以下是结果。 它没有运行时错误,但不幸的是,它不抓住任何input。

 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's thart the thread print "gtk go" Gtk.main () main() 

也许你有一些想法如何使其工作?

最好的问候,保罗

Solutions Collecting From Web of "使用Python gtk3在X上进行全局键绑定"

嘿,我执行相同的代码,工作很好,你可以试试这个。 但没有保修。 如果您发现缺少的部分,请告诉我。

 # -*- coding: utf-8; -*- # Copyright (C) 2013 Özcan Esen <ozcanesen@gmail.com> # Copyright (C) 2008 Luca Bruno <lethalman88@gmail.com> # # This a slightly modified version of the globalkeybinding.py file which is part of FreeSpeak. # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. from Xlib.display import Display from Xlib import X, error #import GObject #import gtk.gdk from gi.repository import Gtk, Gdk, GObject, GLib import threading from config import ConfigManager class GlobalKeyBinding(GObject.GObject, threading.Thread): __gsignals__ = { 'activate':(GObject.SIGNAL_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.ignored_masks = self.get_mask_combinations(X.LockMask | X.Mod2Mask | X.Mod5Mask) self.map_modifiers() def map_modifiers(self): gdk_modifiers =(Gdk.ModifierType.CONTROL_MASK, Gdk.ModifierType.SHIFT_MASK, Gdk.ModifierType.MOD1_MASK, Gdk.ModifierType.MOD2_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: if "Mod" not in Gtk.accelerator_name(0, modifier): self.known_modifiers_mask |= modifier def grab(self): Gdk.threads_enter() accelerator = ConfigManager.get_conf('global-key') Gdk.threads_leave() keyval, modifiers = Gtk.accelerator_parse(accelerator) if not accelerator or(not keyval and not modifiers): self.keycode = None self.modifiers = None return self.keycode= self.keymap.get_entries_for_keyval(keyval)[1][0].keycode self.modifiers = int(modifiers) catch = error.CatchError(error.BadAccess) for ignored_mask in self.ignored_masks: mod = modifiers | ignored_mask result = self.root.grab_key(self.keycode, mod, True, X.GrabModeAsync, X.GrabModeSync, onerror=catch) self.display.sync() if catch.get_error(): return False return True def ungrab(self): if self.keycode: self.root.ungrab_key(self.keycode, X.AnyModifier, self.root) def get_mask_combinations(self, mask): return [x for x in xrange(mask+1) if not (x & ~mask)] def idle(self): Gdk.threads_enter() self.emit("activate") Gdk.threads_leave() return False def run(self): self.running = True wait_for_release = False while self.running: event = self.display.next_event() self.current_event_time = event.time if event.detail == self.keycode and event.type == X.KeyPress and not wait_for_release: modifiers = event.state & self.known_modifiers_mask if modifiers == self.modifiers: wait_for_release = True self.display.allow_events(X.AsyncKeyboard, event.time) else: self.display.allow_events(X.ReplayKeyboard, event.time) elif event.detail == self.keycode and wait_for_release: if event.type == X.KeyRelease: wait_for_release = False GLib.idle_add(self.idle) self.display.allow_events(X.AsyncKeyboard, event.time) else: self.display.allow_events(X.ReplayKeyboard, event.time) def stop(self): self.running = False self.ungrab() self.display.close()