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
Bored? Check out the Recent Activity on Siafoo 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 7 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 : )