License MIT license
Lines 102
Keywords
desktop (1) keybinding (1) pygtk (2) python (33) python-xlib (1) x (1) xlib (1)
Permissions
Owner: lethalman
Viewable by Everyone
Editable by All Siafoo Users
Hide
Siafoo is here to make coding less frustrating and to save you time. Join Siafoo Now or Learn More

Global keybinding on X using Python Atom Feed 0

In Brief Python code, with no C egg support, for binding a key globally on X. PyGTK is used but Qt could be used as well.... more
# 's
  1# Copyright (C) 2008  Luca Bruno <lethalman88@gmail.com>
2#
3# This a slightly modified version of the globalkeybinding.py file which is part of FreeSpeak.
4#
5# Permission is hereby granted, free of charge, to any person obtaining a copy
6# of this software and associated documentation files (the "Software"), to deal
7# in the Software without restriction, including without limitation the rights
8# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9# copies of the Software, and to permit persons to whom the Software is
10# furnished to do so, subject to the following conditions:
11#
12# The above copyright notice and this permission notice shall be included in
13# all copies or substantial portions of the Software.
14#
15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21# DEALINGS IN THE SOFTWARE.
22
23from Xlib.display import Display
24from Xlib import X
25import gobject
26import gconf
27import gtk.gdk
28import threading
29
30class GlobalKeyBinding (gobject.GObject, threading.Thread):
31 __gsignals__ = {
32 'activate': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()),
33 }
34
35 def __init__ (self, dir, key):
36 gobject.GObject.__init__ (self)
37 threading.Thread.__init__ (self)
38 self.setDaemon (True)
39
40 self.gconf_key = dir+"/"+key
41
42 self.gconf = gconf.client_get_default ()
43 self.gconf.add_dir (dir, gconf.CLIENT_PRELOAD_NONE)
44 self.gconf.notify_add (self.gconf_key, self.on_key_changed)
45
46 self.keymap = gtk.gdk.keymap_get_default ()
47 self.display = Display ()
48 self.screen = self.display.screen ()
49 self.root = self.screen.root
50
51 self.map_modifiers ()
52
53 def map_modifiers (self):
54 gdk_modifiers = (gtk.gdk.CONTROL_MASK, gtk.gdk.SHIFT_MASK, gtk.gdk.MOD1_MASK,
55 gtk.gdk.MOD2_MASK, gtk.gdk.MOD3_MASK, gtk.gdk.MOD4_MASK, gtk.gdk.MOD5_MASK,
56 gtk.gdk.SUPER_MASK, gtk.gdk.HYPER_MASK)
57 self.known_modifiers_mask = 0
58 for modifier in gdk_modifiers:
59 # Do you know how to handle unknown "Mod*" keys?
60 # They are usually Locks and something like that
61 if "Mod" not in gtk.accelerator_name (0, modifier):
62 self.known_modifiers_mask |= modifier
63
64 def on_key_changed (self, *args):
65 self.regrab ()
66
67 def regrab (self):
68 self.ungrab ()
69 self.grab ()
70
71 def grab (self):
72 accelerator = self.gconf.get_string (self.gconf_key)
73 keyval, modifiers = gtk.accelerator_parse (accelerator)
74 if not accelerator or (not keyval and not modifiers):
75 self.keycode = None
76 self.modifiers = None
77 return
78 self.keycode = self.keymap.get_entries_for_keyval(keyval)[0][0]
79 self.modifiers = int (modifiers)
80 return self.root.grab_key (self.keycode, X.AnyModifier, True, X.GrabModeAsync, X.GrabModeSync)
81
82 def ungrab (self):
83 if self.keycode:
84 self.root.ungrab_key (self.keycode, X.AnyModifier, self.root)
85
86 def idle (self):
87 # Clipboard requests will hang without locking the GDK thread
88 gtk.gdk.threads_enter ()
89 self.emit ("activate")
90 gtk.gdk.threads_leave ()
91 return False
92
93 def run (self):
94 self.running = True
95 wait_for_release = False
96 while self.running:
97 event = self.display.next_event ()
98 if event.detail == self.keycode and event.type == X.KeyPress and not wait_for_release:
99 modifiers = event.state & self.known_modifiers_mask
100 if modifiers == self.modifiers:
101 wait_for_release = True
102 self.display.allow_events (X.AsyncKeyboard, event.time)
103 else:
104 self.display.allow_events (X.ReplayKeyboard, event.time)
105 elif event.detail == self.keycode and wait_for_release:
106 if event.type == X.KeyRelease:
107 wait_for_release = False
108 gobject.idle_add (self.idle)
109 self.display.allow_events (X.AsyncKeyboard, event.time)
110 else:
111 self.display.allow_events (X.ReplayKeyboard, event.time)
112
113 def stop (self):
114 self.running = False
115 self.ungrab ()
116 self.display.close ()

Python code, with no C egg support, for binding a key globally on X. PyGTK is used but Qt could be used as well.

# 's
 1# SAMPLE USAGE
2def callback (keybinding):
3 print 'Callback!'
4 gtk.main_quit ()
5
6gtk.gdk.threads_init ()
7keybinding = GlobalKeyBinding ("/apps/appdir", "key_binding")
8keybinding.connect ('activate', callback)
9keybinding.grab ()
10keybinding.start ()
11gtk.main ()

Comments

over 8 years ago (14 Jan 2009 at 09:53 PM) by David Isaacson
Yikes! That's a lot of code for one keybind... somehow not suprising though : )