class FakeInputs: def __init__(self): self.display = Display() def press_mouse(self, button, x, y): pass def release_mouse(self, button, x, y): pass def move_mouse(self, x, y): fake_input(self.display, X.MotionNotify, x=x, y=y) self.display.sync() def press_key(self, key): keycode = self.display.keysym_to_keycode(key) fake_input(self.window(), X.KeyPress, keycode) self.display.sync() def release_key(self, key): keycode = self.display.keysym_to_keycode(key) fake_input(self.window(), X.KeyRelease, keycode) self.display.sync() def window(self): return self.display.get_input_focus()._data['focus']
def send_key(self, emulated_key): display = Display() root = display.screen().root shift_mask = 0 # or Xlib.X.ShiftMask window = display.get_input_focus()._data["focus"] keysym = Xlib.XK.string_to_keysym(emulated_key) keycode = display.keysym_to_keycode(keysym) Xlib.ext.xtest.fake_input(window, Xlib.X.KeyPress, keycode) event = Xlib.protocol.event.KeyPress( time=int(time.time()), root=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=keycode ) window.send_event(event, propagate=True) event = Xlib.protocol.event.KeyRelease( time=int(time.time()), root=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=keycode ) window.send_event(event, propagate=True) display.sync()
def _init_xlib(self): """Setup python-xlib components in the PyGTK event loop""" disp = Display() self.xroot = disp.screen().root # We want to receive KeyPress events self.xroot.change_attributes(event_mask = X.KeyPressMask) self._key_n_mask = {} for key in self._keys: if len(key.split('-')) > 1: more_mask = key.split('-')[0:-1] real_key = key.split('-')[-1] else: more_mask = [] real_key = key try: modmask = reduce(operator.ior, [getattr(X, "%sMask" % x) for x in (self._modkeys + more_mask)]) except Exception, err: logging.error("Error while resolving modifier key mask: %s", err) logging.error("Not binding keys for safety reasons. (eg. What if Ctrl+C got bound?)") modmask = 0 else: keycode = disp.keysym_to_keycode(string_to_keysym(real_key)) self._key_n_mask[(keycode, modmask)] = self._keys[key] #Ignore all combinations of Mod2 (NumLock) and Lock (CapsLock) for ignored in [0, X.Mod2Mask, X.LockMask, X.Mod2Mask | X.LockMask]: self.xroot.grab_key(keycode, modmask | ignored, 1, X.GrabModeAsync, X.GrabModeAsync)
class QuickTileApp(object): keybinds_failed = False def __init__(self, wm, keys=None, modkeys=None, movemodkeys=None): """@todo: document these arguments""" self.wm = wm self._keys = keys or {} self._modkeys = modkeys or 0 self._movemodkeys = movemodkeys or 0 self._movemodmask = 0 def _init_dbus(self): """Setup dbus-python components in the PyGTK event loop""" class QuickTile(dbus.service.Object): def __init__(self): dbus.service.Object.__init__(self, sessBus, '/com/ssokolow/QuickTile') @dbus.service.method(dbus_interface='com.ssokolow.QuickTile', in_signature='s', out_signature='b') def doCommand(self, command): return wm.doCommand(command) def doMoveCommand(self, command): return wm.doMoveCommand(command) self.dbusName = dbus.service.BusName("com.ssokolow.QuickTile", sessBus) self.dbusObj = QuickTile() def _init_xlib(self): """Setup python-xlib components in the PyGTK event loop""" self.xdisp = Display() self.xroot = self.xdisp.screen().root # We want to receive KeyPress events self.xroot.change_attributes(event_mask=X.KeyPressMask) # unrecognized shortkeys now will be looked up in a hardcoded dict # and replaced by valid names like ',' -> 'comma' # while generating the self.keys dict self.keys = dict() for key in self._keys: transKey = key if key in KEYLOOKUP: transKey = KEYLOOKUP[key] code = self.xdisp.keysym_to_keycode(string_to_keysym(transKey)) self.keys[code] = self._keys[key] # Resolve strings to X11 mask constants for the modifier mask try: modmask = reduce(operator.ior, [getattr(X, "%sMask" % x) for x in self._modkeys]) self._movemodmask = reduce(operator.ior, [getattr(X, "%sMask" % x) for x in self._movemodkeys]) except Exception, err: logging.error("Error while resolving modifier key mask: %s", err) logging.error("Not binding keys for safety reasons. " "(eg. What if Ctrl+C got bound?)") modmask = 0 movemodmask = 0 else:
def start(self): mod = self.MOD_MASK dpy = Display() keys = {} for key, name in self.KEY_MAP.items(): keys[key] = dpy.keysym_to_keycode(XK.string_to_keysym(key)) root = dpy.screen().root for key, code in keys.items(): root.grab_key(code, mod, 1, X.GrabModeAsync, X.GrabModeAsync) root.grab_button( 1, mod, 1, X.ButtonPressMask | X.ButtonReleaseMask | X.PointerMotionMask, X.GrabModeAsync, X.GrabModeAsync, X.NONE, X.NONE) root.grab_button( 3, mod, 1, X.ButtonPressMask | X.ButtonReleaseMask | X.PointerMotionMask, X.GrabModeAsync, X.GrabModeAsync, X.NONE, X.NONE) self.dpy = dpy self.keys = keys self.root = root self.WM_PROTOCOLS = dpy.intern_atom("WM_PROTOCOLS") self.WM_DELETE_WINDOW = dpy.intern_atom("WM_DELETE_WINDOW") self._loop()
class HotkeyThread(qtcore.QThread): hotkeySignal = qtcore.pyqtSignal() def __init__(self, mod = 'MOD_SHIFT', key = 'VK_SPACE'): qtcore.QThread.__init__(self) keysym = string_to_keysym('space') self.modifiers = X.ShiftMask | X.ControlMask self.disp = Display() self.key = self.disp.keysym_to_keycode(keysym) self.root = self.disp.screen().root self.root.change_attributes(event_mask=X.KeyPressMask) self.root.grab_key(self.key, self.modifiers, 0, False, X.GrabModeAsync, X.GrabModeAsync) self.root.grab_key(self.key, self.modifiers | X.LockMask, 0, False, X.GrabModeAsync, X.GrabModeAsync) self.root.grab_key(self.key, self.modifiers | X.Mod2Mask, 0, False, X.GrabModeAsync, X.GrabModeAsync) self.root.grab_key(self.key, self.modifiers | X.LockMask | X.Mod2Mask, 0, False, X.GrabModeAsync, X.GrabModeAsync) self.root.grab_key(self.key, self.modifiers | X.Mod3Mask | X.LockMask, 0, False, X.GrabModeAsync, X.GrabModeAsync) self.root.grab_key(self.key, self.modifiers | X.Mod3Mask | X.Mod2Mask, 0, False, X.GrabModeAsync, X.GrabModeAsync) self.root.grab_key(self.key, self.modifiers | X.Mod3Mask | X.LockMask | X.Mod2Mask, 0, False, X.GrabModeAsync, X.GrabModeAsync) def dispatch_hotkey(self, msg): if msg.type == X.KeyPress: self.hotkeySignal.emit() def __del__(self): self.terminate() def run(self): while True: event = self.root.display.next_event() self.dispatch_hotkey(event) print('finished loop')
class x11_Keyboard: def __init__(self): self.display = Display() def press(self, key): if key >= 256: keycode = self.display.keysym_to_keycode(keymap[key]) keycode = self.display.keysym_to_keycode(key) fake_input(self.window(), X.KeyPress, keycode) self.display.sync() def release(self, key): if key >= 256: keycode = self.display.keysym_to_keycode(keymap[key]) keycode = self.display.keysym_to_keycode(key) fake_input(self.window(), X.KeyRelease, keycode) self.display.sync() def window(self): return self.display.get_input_focus()._data["focus"]
class x11_Keyboard: def __init__(self): self.display = Display() def press(self, key): if key >= 256: keycode = self.display.keysym_to_keycode(keymap[key]) keycode = self.display.keysym_to_keycode(key) fake_input(self.window(), X.KeyPress, keycode) self.display.sync() def release(self, key): if key >= 256: keycode = self.display.keysym_to_keycode(keymap[key]) keycode = self.display.keysym_to_keycode(key) fake_input(self.window(), X.KeyRelease, keycode) self.display.sync() def window(self): return self.display.get_input_focus()._data['focus']
def __send_key(self, x_event, key_code): key = key_code.X11 if key is None: print("key not defined on X11!") pass d = Display() x11key = d.keysym_to_keycode(XK.string_to_keysym(key)) fake_input(d, x_event, x11key) d.sync()
def init_x11(self): from Xlib import X, XK from Xlib.display import Display disp = Display() root = disp.screen().root root.change_attributes(event_mask=X.KeyPressMask) self.WINDOW_KEY = disp.keysym_to_keycode(XK.string_to_keysym("n")) root.grab_key(self.WINDOW_KEY, X.AnyModifier, 1, X.GrabModeAsync, X.GrabModeAsync) import threading t = threading.Thread(target=lambda: self.process_x11(disp)) t.daemon = True t.start()
def __init__(self): super().__init__() display = Display() self.root = display.screen().root self.handlers = {} for key, handler in mapping.items(): if not isinstance(key, int): key, mask = key else: mask = 0 keycode = display.keysym_to_keycode(key) self.root.grab_key(keycode, mask, False, X.GrabModeAsync, X.GrabModeAsync) self.handlers[(keycode, mask)] = handler
def _init_xlib(self): """Setup python-xlib components in the PyGTK event loop""" disp = Display() self.xroot = disp.screen().root # We want to receive KeyPress events self.xroot.change_attributes(event_mask = X.KeyPressMask) self.keys = dict([(disp.keysym_to_keycode(string_to_keysym(x)), self._keys[x]) for x in self._keys]) # Resolve strings to X11 mask constants for the modifier mask try: modmask = reduce(operator.ior, [getattr(X, "%sMask" % x) for x in self._modkeys]) except Exception, err: logging.error("Error while resolving modifier key mask: %s", err) logging.error("Not binding keys for safety reasons. (eg. What if Ctrl+C got bound?)") modmask = 0
class PyGrid(object): KEYS = { miscellany.XK_KP_1: 'bottomleft', miscellany.XK_KP_2: 'bottom', miscellany.XK_KP_3: 'bottomright', miscellany.XK_KP_4: 'left', miscellany.XK_KP_5: 'middle', miscellany.XK_KP_6: 'right', miscellany.XK_KP_7: 'topleft', miscellany.XK_KP_8: 'top', miscellany.XK_KP_9: 'topright', } def __init__(self, positions): self.positions = positions self.display = Display() self.root = self.display.screen().root self.winman = WindowManager(self.positions) self.keys = {} def handle_event(self, source, condition, handle=None): handle = handle or self.root.display for i in range(0, handle.pending_events()): event = handle.next_event() if event.type == X.KeyPress: keycode = event.detail self.winman.run_command(self.keys[keycode]) return True def start_daemon(self): try: self.root.change_attributes(event_mask=X.KeyPressMask) self.keys = {self.display.keysym_to_keycode(k):self.KEYS[k] for k in self.KEYS} for keycode in self.keys: self.root.grab_key(keycode, X.ControlMask | X.Mod1Mask, 1, X.GrabModeAsync, X.GrabModeAsync) self.root.grab_key(keycode, X.ControlMask | X.Mod1Mask | X.Mod2Mask, 1, X.GrabModeAsync, X.GrabModeAsync) for event in range(0, self.root.display.pending_events()): self.root.display.next_event() gobject.io_add_watch(self.root.display, gobject.IO_IN, self.handle_event) gtk.main() except KeyboardInterrupt: print "Stopping PyGrid daemon"
class QuickTileApp(object): keybinds_failed = False def __init__(self, wm, keys=None, modkeys=None): """@todo: document these arguments""" self.wm = wm self._keys = keys or {} self._modkeys = modkeys or 0 def _init_dbus(self): """Setup dbus-python components in the PyGTK event loop""" class QuickTile(dbus.service.Object): def __init__(self): dbus.service.Object.__init__(self, sessBus, '/com/ssokolow/QuickTile') @dbus.service.method(dbus_interface='com.ssokolow.QuickTile', in_signature='s', out_signature='b') def doCommand(self, command): return wm.doCommand(command) self.dbusName = dbus.service.BusName("com.ssokolow.QuickTile", sessBus) self.dbusObj = QuickTile() def _init_xlib(self): """Setup python-xlib components in the PyGTK event loop""" self.xdisp = Display() self.xroot = self.xdisp.screen().root # We want to receive KeyPress events self.xroot.change_attributes(event_mask=X.KeyPressMask) self.keys = dict([(self.xdisp.keysym_to_keycode(string_to_keysym(x)), self._keys[x]) for x in self._keys]) # Resolve strings to X11 mask constants for the modifier mask try: modmask = reduce(operator.ior, [getattr(X, "%sMask" % x) for x in self._modkeys]) except Exception, err: logging.error("Error while resolving modifier key mask: %s", err) logging.error("Not binding keys for safety reasons. (eg. What if Ctrl+C got bound?)") modmask = 0 else:
def _init_xlib(self): """Setup python-xlib components in the PyGTK event loop""" disp = Display() self.xroot = disp.screen().root # We want to receive KeyPress events self.xroot.change_attributes(event_mask=X.KeyPressMask) self._key_n_mask = {} for key in self._keys: if len(key.split('-')) > 1: more_mask = key.split('-')[0:-1] real_key = key.split('-')[-1] else: more_mask = [] real_key = key try: modmask = reduce(operator.ior, [ getattr(X, "%sMask" % x) for x in (self._modkeys + more_mask) ]) except Exception, err: logging.error("Error while resolving modifier key mask: %s", err) logging.error( "Not binding keys for safety reasons. (eg. What if Ctrl+C got bound?)" ) modmask = 0 else: keycode = disp.keysym_to_keycode(string_to_keysym(real_key)) self._key_n_mask[(keycode, modmask)] = self._keys[key] #Ignore all combinations of Mod2 (NumLock) and Lock (CapsLock) for ignored in [ 0, X.Mod2Mask, X.LockMask, X.Mod2Mask | X.LockMask ]: self.xroot.grab_key(keycode, modmask | ignored, 1, X.GrabModeAsync, X.GrabModeAsync)
class PyKeyboard(PyKeyboardMeta): """ The PyKeyboard implementation for X11 systems (mostly linux). This allows one to simulate keyboard input. """ def __init__(self, display=None): PyKeyboardMeta.__init__(self) self.display = Display(display) self.display2 = Display(display) self.special_key_assignment() def press_key(self, character=''): """ Press a given character key. Also works with character keycodes as integers, but not keysyms. """ try: # Detect uppercase or shifted character shifted = self.is_char_shifted(character) except AttributeError: # Handle the case of integer keycode argument fake_input(self.display, X.KeyPress, character) self.display.sync() else: if shifted: fake_input(self.display, X.KeyPress, self.shift_key) keycode = self.lookup_character_keycode(character) fake_input(self.display, X.KeyPress, keycode) self.display.sync() def release_key(self, character=''): """ Release a given character key. Also works with character keycodes as integers, but not keysyms. """ try: # Detect uppercase or shifted character shifted = self.is_char_shifted(character) except AttributeError: # Handle the case of integer keycode argument fake_input(self.display, X.KeyRelease, character) self.display.sync() else: if shifted: fake_input(self.display, X.KeyRelease, self.shift_key) keycode = self.lookup_character_keycode(character) fake_input(self.display, X.KeyRelease, keycode) self.display.sync() def special_key_assignment(self): """ Determines the keycodes for common special keys on the keyboard. These are integer values and can be passed to the other key methods. Generally speaking, these are non-printable codes. """ #This set of keys compiled using the X11 keysymdef.h file as reference #They comprise a relatively universal set of keys, though there may be #exceptions which may come up for other OSes and vendors. Countless #special cases exist which are not handled here, but may be extended. #TTY Function Keys self.backspace_key = self.lookup_character_keycode('BackSpace') self.tab_key = self.lookup_character_keycode('Tab') self.linefeed_key = self.lookup_character_keycode('Linefeed') self.clear_key = self.lookup_character_keycode('Clear') self.return_key = self.lookup_character_keycode('Return') self.enter_key = self.return_key # Because many keyboards call it "Enter" self.pause_key = self.lookup_character_keycode('Pause') self.scroll_lock_key = self.lookup_character_keycode('Scroll_Lock') self.sys_req_key = self.lookup_character_keycode('Sys_Req') self.escape_key = self.lookup_character_keycode('Escape') self.delete_key = self.lookup_character_keycode('Delete') #Modifier Keys self.shift_l_key = self.lookup_character_keycode('Shift_L') self.shift_r_key = self.lookup_character_keycode('Shift_R') self.shift_key = self.shift_l_key # Default Shift is left Shift self.alt_l_key = self.lookup_character_keycode('Alt_L') self.alt_r_key = self.lookup_character_keycode('Alt_R') self.alt_key = self.alt_l_key # Default Alt is left Alt self.control_l_key = self.lookup_character_keycode('Control_L') self.control_r_key = self.lookup_character_keycode('Control_R') self.control_key = self.control_l_key # Default Ctrl is left Ctrl self.caps_lock_key = self.lookup_character_keycode('Caps_Lock') self.capital_key = self.caps_lock_key # Some may know it as Capital self.shift_lock_key = self.lookup_character_keycode('Shift_Lock') self.meta_l_key = self.lookup_character_keycode('Meta_L') self.meta_r_key = self.lookup_character_keycode('Meta_R') self.super_l_key = self.lookup_character_keycode('Super_L') self.windows_l_key = self.super_l_key # Cross-support; also it's printed there self.super_r_key = self.lookup_character_keycode('Super_R') self.windows_r_key = self.super_r_key # Cross-support; also it's printed there self.hyper_l_key = self.lookup_character_keycode('Hyper_L') self.hyper_r_key = self.lookup_character_keycode('Hyper_R') #Cursor Control and Motion self.home_key = self.lookup_character_keycode('Home') self.up_key = self.lookup_character_keycode('Up') self.down_key = self.lookup_character_keycode('Down') self.left_key = self.lookup_character_keycode('Left') self.right_key = self.lookup_character_keycode('Right') self.end_key = self.lookup_character_keycode('End') self.begin_key = self.lookup_character_keycode('Begin') self.page_up_key = self.lookup_character_keycode('Page_Up') self.page_down_key = self.lookup_character_keycode('Page_Down') self.prior_key = self.lookup_character_keycode('Prior') self.next_key = self.lookup_character_keycode('Next') #Misc Functions self.select_key = self.lookup_character_keycode('Select') self.print_key = self.lookup_character_keycode('Print') self.print_screen_key = self.print_key # Seems to be the same thing self.snapshot_key = self.print_key # Another name for printscreen self.execute_key = self.lookup_character_keycode('Execute') self.insert_key = self.lookup_character_keycode('Insert') self.undo_key = self.lookup_character_keycode('Undo') self.redo_key = self.lookup_character_keycode('Redo') self.menu_key = self.lookup_character_keycode('Menu') self.apps_key = self.menu_key # Windows... self.find_key = self.lookup_character_keycode('Find') self.cancel_key = self.lookup_character_keycode('Cancel') self.help_key = self.lookup_character_keycode('Help') self.break_key = self.lookup_character_keycode('Break') self.mode_switch_key = self.lookup_character_keycode('Mode_switch') self.script_switch_key = self.lookup_character_keycode('script_switch') self.num_lock_key = self.lookup_character_keycode('Num_Lock') #Keypad Keys: Dictionary structure keypad = ['Space', 'Tab', 'Enter', 'F1', 'F2', 'F3', 'F4', 'Home', 'Left', 'Up', 'Right', 'Down', 'Prior', 'Page_Up', 'Next', 'Page_Down', 'End', 'Begin', 'Insert', 'Delete', 'Equal', 'Multiply', 'Add', 'Separator', 'Subtract', 'Decimal', 'Divide', 0, 1, 2, 3, 4, 5, 6, 7, 8, 9] self.keypad_keys = {k: self.lookup_character_keycode('KP_'+str(k)) for k in keypad} self.numpad_keys = self.keypad_keys #Function Keys/ Auxilliary Keys #FKeys self.function_keys = [None] + [self.lookup_character_keycode('F'+str(i)) for i in range(1,36)] #LKeys self.l_keys = [None] + [self.lookup_character_keycode('L'+str(i)) for i in range(1,11)] #RKeys self.r_keys = [None] + [self.lookup_character_keycode('R'+str(i)) for i in range(1,16)] #Unsupported keys from windows self.kana_key = None self.hangeul_key = None # old name - should be here for compatibility self.hangul_key = None self.junjua_key = None self.final_key = None self.hanja_key = None self.kanji_key = None self.convert_key = None self.nonconvert_key = None self.accept_key = None self.modechange_key = None self.sleep_key = None def lookup_character_keycode(self, character): """ Looks up the keysym for the character then returns the keycode mapping for that keysym. """ keysym = Xlib.XK.string_to_keysym(character) if keysym == 0: keysym = Xlib.XK.string_to_keysym(special_X_keysyms[character]) return self.display.keysym_to_keycode(keysym)
class KnoX: Geometry = namedtuple("Geometry", "x y width height") FrameExtents = namedtuple("FrameExtents", "left right top bottom") def __init__(self): #self.display = Display(os.environ.get("DISPLAY", ":0.0")) self.display = Display() print("Connected to X DISPLAY %r" % self.display.get_display_name()) self.display.set_error_handler(self.knox_error_handler) self.screen = self.display.screen() self.root = self.screen.root self.atoms = dict() self.atom_names = dict() self.keysyms = Keysyms() self.modifiers = Modifiers(self) self._supported_properties = None self._acceptable_error_sequence = 0 self._acceptable_errors = dict() self._silenced_errors = set() def fileno(self): """This function is here to make select work with this object""" return self.display.fileno() @contextmanager def silenced_error(self, error): silencer = self.silence_error(error) try: yield silencer finally: self.remove_silencer(silencer) def silence_error(self, error): k = self._acceptable_error_sequence self._acceptable_errors[k] = error self._acceptable_error_sequence += 1 self._silenced_errors = set(self._acceptable_errors.values()) return k def remove_silencer(self, key): if key in self._acceptable_errors: del self._acceptable_errors[key] self._silenced_errors = set(self._acceptable_errors.values()) def knox_error_handler(self, err, *args): if type(err) not in self._silenced_errors: print("X protocol error: %s" % err) traceback.print_stack() # def wait_for_event(self, timeout_seconds): # """ Wait up to `timeout_seconds` seconds for an event to be queued. # Return True, if a xevent is available. # Return False, if the timeout was reached. # from https://gist.github.com/fphammerle/d81ca3ff0a169f062a9f28e57b18f04d""" # rlist = select.select( # [self.display], # rlist # [], # wlist # [], # xlist # timeout_seconds, # timeout [seconds] # )[0] # return len(rlist) > 0 def next_event(self, wait=True): if (wait or self.display.pending_events()): return self.display.next_event() else: return None # def next_event(self, event_loop): # event_loop.register_reader(self.display, def atom(self, name, only_if_exists=False): if isinstance(name, int): a = name elif name not in self.atoms: a = self.display.get_atom(name, only_if_exists=only_if_exists) self.atoms[name] = a else: a = self.atoms[name] return a def atom_name(self, atom): if atom in self.atom_names: return self.atom_names[atom] name = self.display.get_atom_name(atom) if name: self.atom_names[atom] = name if name not in self.atoms: self.atoms[name] = atom return name def get_prop(self, window, name): prop_name = self.atom(name, only_if_exists=True) if not prop_name: return None if isinstance(window, int): window = self.get_window(window) p = window.get_full_property(prop_name, X.AnyPropertyType) if p: return p.value def get_text_prop(self, window, name): prop_name = self.atom(name, only_if_exists=True) if not prop_name: return None s = window.get_full_text_property(prop_name, Xatom.STRING) if not s: t = self.atom("UTF8_STRING", only_if_exists=True) if t: s = window.get_full_text_property(prop_name, t) return s def onerror(self, *args, **kwargs): print("ERROR: something bad happened about %r and %r" % (args, kwargs)) raise Exception("Error is bad...") def set_prop(self, window, name, type_name, value): if isinstance(window, int): window = self.get_window(window) if isinstance(type_name, int): prop_type_name = type_name #type_name = self.atom_name(prop_type_name) else: prop_type_name = self.atom(type_name, only_if_exists=False) prop_name = self.atom(name, only_if_exists=False) if value is None: window.delete_property(prop_name) else: window.change_property(prop_name, prop_type_name, 32, value, mode=X.PropModeReplace, onerror=self.onerror) def send_prop_change_event( self, property_name, data, target=None, window=None, ): if target is None: target = self.root if window is None: window = target ev = protocol.event.ClientMessage(window=window, client_type=self.atom(property_name), data=data) target.send_event(ev, event_mask=X.SubstructureNotifyMask | X.SubstructureRedirectMask, propagate=False, onerror=self.onerror) def current_desktop(self, desktop=None, wait=True): prop_name = "_NET_CURRENT_DESKTOP" if desktop is None: pv = self.get_prop(self.root, prop_name) if pv: return pv[0] else: v = array('I', [desktop]) #self.set_prop(self.root, prop_name, Xatom.CARDINAL, v) self.send_prop_change_event( prop_name, (32, [desktop, X.CurrentTime, 0, 0, 0])) self.flush() w = Waiter(wait) while w.wait(): print("DESKTOPCHECK", hex(desktop)) if self.current_desktop() == desktop: print("DESKTOP OK") break def get_wm_pid(self, window): pid_prop = self.get_prop(window, "_NET_WM_PID") if pid_prop: return pid_prop[0] return None def get_wm_name(self, window): if isinstance(window, int): window = self.get_window(window) # window.get_wm_name gets only STRING property and returns nothing # if it's UTF8_STRING return self.get_text_prop(window, Xatom.WM_NAME) def active_window(self, window=None, wait=3, id_only=False): prop_name = "_NET_ACTIVE_WINDOW" if window is None: pv = self.get_prop(self.root, prop_name) if pv and pv[0]: window = self.get_window(pv[0]) if window and window.get_wm_name() != 'Desktop': if id_only: return window.id else: return window else: if isinstance(window, int): window = self.get_window(window) desktop = self.get_desktop_for_window(window) self.current_desktop(desktop) #v = array('I', [ window.id, 0 ]) #self.set_prop(self.root, prop_name, Xatom.WINDOW, v) # data[0]: source indication # 1: when the request comes from an application # 2: from a pager # 0: no spec. self.send_prop_change_event(prop_name, (32, [2, X.CurrentTime, 0, 0, 0]), window=window) self.flush() #self.raise_window(window) # it won't become active until it's focused focused = self.set_focused_window(window, wait=1) w = Waiter(wait) while w.wait(): a = self.active_window() self.flush() if not focused: focused = self.set_focused_window(window, wait=1) self.flush() if a and a.id == window.id: print("Activated %r!" % window.id) return True self.send_prop_change_event(prop_name, (32, [2, X.CurrentTime, 0, 0, 0]), window=window) self.flush() print("Can't activate %d" % window.id) return False def get_focused_window(self, toplevel=True): f = self.display.get_input_focus() #f = protocol.request.GetInputFocus(display=self.display.display) if f.focus in [X.NONE, X.PointerRoot]: return None if toplevel: w = self.get_client_window(f.focus) if w is not None: return w.id return f.focus.id def raise_window(self, window): if isinstance(window, int): window = self.get_window(window) elif window is None: return window.raise_window() def focus_error(self, *args, **kwargs): print("Cannot set_input_focus: %r %r" % (args, kwargs)) def set_focused_window(self, window, wait=3): if window is None: self.display.set_input_focus(X.NONE, X.RevertToParent, X.CurrentTime, onerror=self.focus_error) return True elif not wait: self.display.set_input_focus(window, X.RevertToParent, X.CurrentTime) return True else: with self.silenced_error(error.BadMatch): if isinstance(window, int): window = self.get_window(window) self.display.set_input_focus(window, X.RevertToParent, X.CurrentTime) self.flush() w = Waiter(wait) while w.wait(): if w.timeout: if w.progressed: print("WAITING %.3f seconds more for focus on %r" % (w.remaining, window.id)) else: print( "READY TO WAIT %.3f seconds for focus on %r" % (w.remaining, window.id)) focused_win_id = self.get_focused_window() if focused_win_id == window.id: print("FOCUSED %r" % window.id) return True # many times it's needed to repeat the command, esp. when mouse is # not inside the target window self.display.set_input_focus(window, X.RevertToParent, X.CurrentTime) self.flush() #self.display.set_input_focus(window, X.RevertToParent, X.CurrentTime) #self.display.flush() return False def get_desktop_for_window(self, window): pv = self.get_prop(window, "_NET_WM_DESKTOP") if pv: return pv[0] def set_desktop_for_window(self, window, desktop): if desktop is None: return name = self.atom("_NET_WM_DESKTOP", only_if_exists=True) if name in self.supported_properties: pv = self.set_prop(window, name, Xatom.CARDINAL, array('I', [desktop])) def save_state(self): state = { "Current Desktop": self.current_desktop(), "Active Window": self.active_window(id_only=True), "Focused Window": self.get_focused_window() } return state def restore_state(self, state): a = self.supported_properties self.current_desktop(state["Current Desktop"]) self.flush() try: self.set_focused_window(state["Focused Window"]) except error.BadWindow: print("Sorry, the old focused window went away...") # self.active_window(state["Active Window"]) def keysym_to_string(self, keysym, friendly=False, very_friendly=False): if keysym not in self.keysyms.keysyms: return chr(keysym) if very_friendly: return self.keysyms.friendly_name(keysym, simplest=True) if friendly: return self.keysyms.friendly_name(keysym, simplest=False) else: return self.keysyms[keysym] def keycode_to_keysym(self, keycode, idx=None): if idx is None: syms = set() for i in range(4): keysym = self.display.keycode_to_keysym(keycode, i) if keysym: syms.add(keysym) return syms else: return self.display.keycode_to_keysym(event.detail, i) def keysym_to_keycode(self, keysym): return self.display.keysym_to_keycode(keysym) def string_to_keysym(self, s): k = self.keysyms[s] if not k: k = self.keysyms["XK_" + s] if k: return k k = XK.string_to_keysym(s) return k # allow simpler names, like AudioRaiseVolume? # if s.startswith("XF86_"): # s = "XF86" + s[5:] # return XK.string_to_keysym(s) def error_handler(self, fn, *args, **kwargs): return functools.partial(fn, *args, **kwargs) def toggle_frame(self, window, frame=None, wait=1): """Set window frame. Value should be True or False for on and off, or None for toggle.""" # flags - set bit for every iteresting value # 0 functions => integer bits # 1 decorations => integer bits # 2 input_mode => enum string or integer # 3 status => integer bits # # functions: # bit actions offered # --- --------------- # 1 all functions # 2 resize window # 4 move window # 8 minimize, to iconify # 16 maximize, to full-screen (with a frame still) # 32 close window # # decorations: # bit decorations displayed # --- --------------------- # 1 all decorations # 2 border around the window # 4 resizeh, handles to resize by dragging # 8 title bar, showing WM_NAME # 16 menu, drop-down menu of the "functions" above # 32 minimize button, to iconify # 64 maximize button, to full-screen # # input mode: # string integer # "modeless" 0 not modal (the default) # "primary_application_modal" 1 modal to its "transient for" # "system_modal" 2 modal to the whole display # "full_application_modal" 3 modal to the current client # # status: # # bit # 1 tearoff menu window name = self.atom("_MOTIF_WM_HINTS", only_if_exists=True) # If does not exist, probably not supported, though should check # root for _NET_SUPPORTED list return assert prop != 0 pv = pv = self.get_prop(window, name) fe = self.get_frame_extents(window) if pv and len(pv) == 5: hints = array(pv.typecode, pv) if frame is None: hints[2] = 0 if hints[2] else 1 elif frame: hints[2] = 1 else: hints[2] = 0 else: # reasonable default hints = array('I', [2, 0, 0, 0, 0]) self.set_prop(window, name, name, hints) w = Waiter(wait) while w.wait(): pv = self.get_prop(window, name) if pv and array(pv.typecode, pv) == hints: new_fe = self.get_frame_extents(window) # make sure frame extents changed # this seems to take a while once the hints change if new_fe != fe: break def set_opacity(self, window, value): """value is a number between 0 and 1""" v = int(((1 << 32) - 1) * value) self.set_prop(window, "_NET_WM_WINDOW_OPACITY", Xatom.CARDINAL, array('I', [v])) def get_opacity(self, window): pv = self.get_prop(window, "_NET_WM_WINDOW_OPACITY") if pv: value = int(pv[0] / ((1 << 32) - 1)) return value return 1 @property def supported_properties(self): if self._supported_properties is None: self._supported_properties = self.get_prop(self.root, "_NET_SUPPORTED") or [] return self._supported_properties def get_window(self, win_id): if isinstance(win_id, int): return self.display.create_resource_object('window', win_id) else: return win_id def get_client_window(self, window): win_id = window.id for tlw in self.toplevel_windows(): for (_, parent, _) in self.window_tree( tlw, filter=lambda w, parent, level: w.id == win_id): return tlw return None def toplevel_windows(self, id_only=False): name = self.atom("_NET_CLIENT_LIST", only_if_exists=True) if name in self.supported_properties: lst = self.get_prop(self.root, name) if id_only: return lst else: return list(map(lambda win_id: self.get_window(win_id), lst)) else: print("BELGENGOC") if id_only: return list( map(lambda w: w.id, self.root.query_tree().children)) else: return list(self.root.query_tree().children) def window_tree(self, parent=None, level=1, filter=None): if parent is None: parent = self.root if filter is None or filter(parent, None, 0): yield (parent, None, 0) for w in parent.query_tree().children: if filter is None or filter(w, parent, level): yield (w, parent, level) yield from self.window_tree(parent=w, level=level + 1, filter=filter) def close_window(self, window): self.send_prop_change_event("_NET_CLOSE_WINDOW", (32, [0, 0, 0, 0, 0]), window=self.get_window(window)) # https://specifications.freedesktop.org/wm-spec/wm-spec-1.3.html # window = the respective client window # message_type = _NET_WM_STATE # format = 32 # data.l[0] = the action, as listed below # data.l[1] = first property to alter # data.l[2] = second property to alter # data.l[3] = source indication # other data.l[] elements = 0 # This message allows two prop # _NET_WM_STATE_REMOVE = 0 # remove/unset property _NET_WM_STATE_ADD = 1 #add/set property _NET_WM_STATE_TOGGLE = 2 # toggle property def set_wm_states(self, window, names, action=None): if action is None: action = self._NET_WM_STATE_TOGGLE elif action is True: action = self._NET_WM_STATE_ADD elif action is False: action = self._NET_WM_STATE_REMOVE window = self.get_window(window) values = list() for name in names: value = self.atom("_NET_WM_STATE_%s" % name.upper()) values.append(value) data = [action, *values] while len(data) < 5: data.append(0) self.send_prop_change_event("_NET_WM_STATE", (32, data), window=self.get_window(window)) def set_wm_state(self, window, name, action=None): if action is None: action = self._NET_WM_STATE_TOGGLE elif action is True: action = self._NET_WM_STATE_ADD elif action is False: action = self._NET_WM_STATE_REMOVE window = self.get_window(window) value = self.atom("_NET_WM_STATE_%s" % name.upper()) self.send_prop_change_event("_NET_WM_STATE", (32, [action, value, 0, 0, 0]), window=self.get_window(window)) def below_window(self, window, action=None): self.set_wm_state(window, name="below", action=action) def fullscreen_window(self, window, action=None): self.set_wm_state(window, name="fullscreen", action=action) def above_window(self, window, action=None): self.set_wm_state(window, name="above", action=action) def sticky_window(self, window, action=None): self.set_wm_state(window, name="sticky", action=action) def skip_pager(self, window, action=None): self.set_wm_state(window, name="skip_pager", action=action) def skip_taskbar(self, window, action=None): self.set_wm_state(window, name="skip_taskbar", action=action) def maximize_window(self, window, horizontal=True, vertical=True, action=None): if horizontal: self.set_wm_state(window, name="maximized_horz", action=action) if vertical: self.set_wm_state(window, name="maximized_vert", action=action) def minimize_window(self, window): if isinstance(window, int): window = self.get_window(window) self.send_prop_change_event("WM_CHANGE_STATE", (32, [Xutil.IconicState, 0, 0, 0, 0]), window=self.get_window(window)) def get_attributes(self, window): if isinstance(window, int): window = self.get_window(window) return window.get_attributes() def get_window_type(self, window): e = self.get_prop(window, "_NET_WM_WINDOW_TYPE") if e is None: return None type_details = set() prefix = "_NET_WM_WINDOW_TYPE_" for t in e: if not t: continue s = self.atom_name(t) if s.startswith(prefix): s = s[len(prefix):] type_details.add(s) return type_details def get_frame_extents(self, window): # x, y, width, height if isinstance(window, int): window = self.get_window(window) e = self.get_prop(window, "_NET_FRAME_EXTENTS") if e: return self.FrameExtents(*e) else: return self.FrameExtents(0, 0, 0, 0) def get_geometry(self, window): # x, y, width, height if isinstance(window, int): window = self.get_window(window) return window.get_geometry() def set_geometry(self, window, **data): # x, y, width, height if isinstance(window, int): window = self.get_window(window) if any(map(lambda v: v < 0, data.values())): gw = self.get_geometry(window) f = self.get_frame_extents(window) wa = self.usable_workarea() if 'x' in data and data['x'] < 0: data['x'] = wa.width - gw.width - (f.left + f.right) + data['x'] + 1 else: data['x'] += wa.x if 'y' in data and data['y'] < 0: data['y'] = wa.height - gw.height - (f.top + f.bottom) + data['y'] + 1 else: data['y'] += wa.y window.configure(**data) def usable_workarea(self): a = self.get_prop(self.root, "_NET_WORKAREA") if a: p = self.current_desktop() * 4 #return (x, y, width, height) return self.Geometry(*a[p:p + 4]) else: r = self.get_geometry(self.root) return self.Geometry(0, 0, r.width, r.height) def send_key(self, window, keysym, modifiers): if isinstance(window, int): window = self.get_window(window) keycode = self.display.keysym_to_keycode(keysym) event = protocol.event.KeyPress(time=X.CurrentTime, root=self.root, window=window, child=X.NONE, same_screen=True, root_x=0, root_y=0, event_x=0, event_y=0, state=modifiers.bitmap, detail=keycode) window.send_event(event, propagate=False) event = protocol.event.KeyRelease( time=X.CurrentTime, root=self.root, window=window, child=X.NONE, same_screen=True, # same screen as the root window root_x=0, root_y=0, event_x=0, event_y=0, state=modifiers.bitmap, detail=keycode) window.send_event(event, propagate=False) def show_desktop(self, action=None): prop_name = self.atom("_NET_SHOWING_DESKTOP") if action is True: self.send_prop_change_event(prop_name, (32, [1, X.CurrentTime, 0, 0, 0])) elif action is False: self.send_prop_change_event(prop_name, (32, [0, X.CurrentTime, 0, 0, 0])) else: pv = self.get_prop(self.root, prop_name) new_val = 0 if pv and pv[0] else 1 self.send_prop_change_event( prop_name, (32, [new_val, X.CurrentTime, 0, 0, 0])) def flush(self): # send all pending events self.display.flush() def sync(self): # flush and make sure everything is handled and processed or rejected by the server self.display.sync() @property def display_count(self): res = randr.get_screen_resources(self.root) n = 0 for i in res.outputs: o = randr.get_output_info(self.root, i, config_timestamp=0) if o.modes: # has modes, empty if there's no monitor connected here n += 1 return n
from Xlib.display import Display from Xlib import X, XK, Xatom dpy = Display() dpy.screen().root.grab_key(dpy.keysym_to_keycode(XK.string_to_keysym("F1")), X.Mod1Mask, 1, X.GrabModeAsync, X.GrabModeAsync) dpy.screen().root.grab_button( 1, X.Mod1Mask, 1, X.ButtonPressMask | X.ButtonReleaseMask | X.PointerMotionMask, X.GrabModeAsync, X.GrabModeAsync, X.NONE, X.NONE) dpy.screen().root.grab_button( 3, X.Mod1Mask, 1, X.ButtonPressMask | X.ButtonReleaseMask | X.PointerMotionMask, X.GrabModeAsync, X.GrabModeAsync, X.NONE, X.NONE) start = None while 1: ev = dpy.next_event() if ev.type == X.KeyPress and ev.child != X.NONE: ev.child.configure(stack_mode=X.Above) elif ev.type == X.ButtonPress and ev.child != X.NONE: attr = ev.child.get_geometry() start = ev elif ev.type == X.MotionNotify and start: xdiff = ev.root_x - start.root_x ydiff = ev.root_y - start.root_y start.child.configure( x=attr.x + (start.detail == 1 and xdiff or 0), y=attr.y + (start.detail == 1 and ydiff or 0), width=max(1, attr.width + (start.detail == 3 and xdiff or 0)), height=max(1, attr.height + (start.detail == 3 and ydiff or 0))) elif ev.type == X.ButtonRelease:
class App(): def __init__(self, options): self.options = options self.reload_app = True self.xroot = None self.dpy = None self.menus, self.config = load_menus(self.options) self.create_menus() self.running = False def init_x_root(self): if self.dpy is None: self.dpy = Display() if self.xroot is None: self.xroot = self.dpy.screen().root def create_menus(self): self.keycode_to_char = {} self.menu_hot_keys = {} self.root = tk.Tk() self.menu_font = self.config['font'] self.init_x_root() self.root.bind("<Key>", self.on_key) self.buttons = [] for menu_name, fa_menu in self.menus.items(): self.add_menu(menu_name, fa_menu) self.root.config() def reload_menus(self): self.reload_app = True self.withdraw() self.xroot.destroy() self.dpy.close() self.menu_hot_keys = None self.root = None self.menu_font = None self.buttons = None self.xroot = None self.dpy = None gc.collect() self.menus, self.config = load_menus(self.options) self.create_menus() def key_spec_to_keycode_modifier_mask(self, key_spec): modifiers, key = parse_modifier_mask(key_spec) keysym = XK.string_to_keysym(key) keycode = self.dpy.keysym_to_keycode(keysym) if keycode not in self.keycode_to_char.keys(): self.keycode_to_char[keycode] = key modifier_mask = reduce(lambda x, y: x | y, modifiers, 0) return key, keycode, modifier_mask def add_menu(self, menu_name, fa_menu): max_width = max((len(item.item_name) for item in fa_menu.menu_content)) menu_frame = tk.Frame(self.root, borderwidth=2, relief=tk.RAISED) menu_frame.pack_propagate(True) menu_label = tk.Label(menu_frame, text=menu_name, font=self.menu_font, anchor="w", justify=tk.LEFT) menu_label.pack(fill="y") for menu_item in fa_menu.menu_content: jb = Button(menu_frame, menu_item, self.root, self, font=self.menu_font, borderwidth=2, relief=tk.RAISED, width=max_width) if menu_item.hot_key is not None: fa_menu.hot_keys[menu_item.hot_key] = jb.on_key jb.pack(fill="y") menu_item.button = jb fa_menu.menu_frame = menu_frame fa_menu.menu_buttons.append(jb) if fa_menu.menu_hot_key is not None: if self.menu_hot_keys.get(fa_menu.menu_hot_key) is None: hot_key, hot_key_states = self.bind_key(fa_menu.menu_hot_key) for state in hot_key_states: key_state_str = key_state(hot_key, state) self.menu_hot_keys[key_state_str] = fa_menu.menu_name fa_menu.select_button() def on_key(self, event): run = self.hot_keys.get(event.char) if run is None: if event.keysym == "Up": self.menus[self.menu_name].prev_button() elif event.keysym == "Down": self.menus[self.menu_name].next_button() elif event.keysym == "Return" or event.keysym == "space": run = self.menus[self.menu_name].button().on_key elif event.keysym == "Escape": self.withdraw() if run is not None: if run(event): self.withdraw() def withdraw(self): self.menus[self.menu_name].menu_frame.pack_forget() self.root.withdraw() self.root.quit() def switch_to_menu(self, menu_name): old_menu = self.menus[self.menu_name] old_menu.menu_frame.pack_forget() self.root.withdraw() new_menu = self.menus[menu_name] self.show_menu(new_menu) def show_menu(self, menu): self.menu_name = menu.menu_name if self.running: menu.menu_frame.pack() self.hot_keys = menu.hot_keys self.root.update() self.root.deiconify() else: self.running = True menu.menu_frame.pack() self.hot_keys = menu.hot_keys def do_loop(self): while not self.reload_app: ev = self.xroot.display.next_event() if ev.type == X.KeyPress: key = self.keycode_to_char.get(ev.detail) state = ev.state key_state_str = key_state(key, state) menu_name = self.menu_hot_keys.get(key_state_str) if menu_name is not None: menu = self.menus[menu_name] self.show_menu(menu) self.root.mainloop() def run(self): self.reload_app = False self.do_loop() def bind_key(self, key_spec): self.xroot.change_attributes(event_mask=X.KeyPressMask) key, keycode, modifier_mask = self.key_spec_to_keycode_modifier_mask(key_spec) states = [] for ignored in powerset(IGNORED_MODIFIERS): modmask = reduce(lambda x, y: x | y, ignored, 0) modmask |= modifier_mask states.append(modmask) self.xroot.grab_key(keycode, modmask, 1, X.GrabModeAsync, X.GrabModeAsync) return key, states
class INTERFACES(object): # """MOUSE contiene los metodos necesarios para mover el puntero del # mouse por la pantalla""" # KEY_NAMES = ['\t', '\n', '\r', ' ', '!', '"', '#', '$', '%', '&', "'", '(', # ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', # '8', '9', ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_', '`', # 'a', 'b', 'c', 'd', 'e','f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', # 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', # 'accept', 'add', 'alt', 'altleft', 'altright', 'apps', 'backspace', # 'browserback', 'browserfavorites', 'browserforward', 'browserhome', # 'browserrefresh', 'browsersearch', 'browserstop', 'capslock', 'clear', # 'convert', 'ctrl', 'ctrlleft', 'ctrlright', 'decimal', 'del', 'delete', # 'divide', 'down', 'end', 'enter', 'esc', 'escape', 'execute', 'f1', 'f10', # 'f11', 'f12', 'f13', 'f14', 'f15', 'f16', 'f17', 'f18', 'f19', 'f2', 'f20', # 'f21', 'f22', 'f23', 'f24', 'f3', 'f4', 'f5', 'f6', 'f7', 'f8', 'f9', # 'final', 'fn', 'hanguel', 'hangul', 'hanja', 'help', 'home', 'insert', 'junja', # 'kana', 'kanji', 'launchapp1', 'launchapp2', 'launchmail', # 'launchmediaselect', 'left', 'modechange', 'multiply', 'nexttrack', # 'nonconvert', 'num0', 'num1', 'num2', 'num3', 'num4', 'num5', 'num6', # 'num7', 'num8', 'num9', 'numlock', 'pagedown', 'pageup', 'pause', 'pgdn', # 'pgup', 'playpause', 'prevtrack', 'print', 'printscreen', 'prntscrn', # 'prtsc', 'prtscr', 'return', 'right', 'scrolllock', 'select', 'separator', # 'shift', 'shiftleft', 'shiftright', 'sleep', 'space', 'stop', 'subtract', 'tab', # 'up', 'volumedown', 'volumemute', 'volumeup', 'win', 'winleft', 'winright', 'yen', # 'command', 'option', 'optionleft', 'optionright'] def __init__(self): """TODO: to be defined1. """ self._display = Display(os.environ['DISPLAY']) self.mapa_botones_mouse = { 'izquierdo': 1, 'medio': 2, 'derecho': 3, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7 } #self.__iniciar_teclado() # def __iniciar_teclado(self): # """TODO: Docstring for __iniciar_teclado. # :returns: TODO # """ # self.keyboardMapping = dict([(key, None) for key in self.KEY_NAMES]) # self.keyboardMapping.update({ # 'backspace': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('BackSpace')), # '\b': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('BackSpace')), # 'tab': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('Tab')), # 'enter': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('Return')), # 'return': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('Return')), # 'shift': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('Shift_L')), # 'ctrl': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('Control_L')), # 'alt': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('Alt_L')), # 'pause': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('Pause')), # 'capslock': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('Caps_Lock')), # 'esc': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('Escape')), # 'escape': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('Escape')), # 'pgup': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('Page_Up')), # 'pgdn': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('Page_Down')), # 'pageup': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('Page_Up')), # 'pagedown': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('Page_Down')), # 'end': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('End')), # 'home': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('Home')), # 'left': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('Left')), # 'up': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('Up')), # 'right': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('Right')), # 'down': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('Down')), # 'select': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('Select')), # 'print': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('Print')), # 'execute': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('Execute')), # 'prtsc': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('Print')), # 'prtscr': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('Print')), # 'prntscrn': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('Print')), # 'printscreen': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('Print')), # 'insert': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('Insert')), # 'del': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('Delete')), # 'delete': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('Delete')), # 'help': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('Help')), # 'winleft': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('Super_L')), # 'winright': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('Super_R')), # 'apps': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('Super_L')), # 'num0': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('KP_0')), # 'num1': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('KP_1')), # 'num2': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('KP_2')), # 'num3': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('KP_3')), # 'num4': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('KP_4')), # 'num5': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('KP_5')), # 'num6': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('KP_6')), # 'num7': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('KP_7')), # 'num8': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('KP_8')), # 'num9': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('KP_9')), # 'multiply': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('KP_Multiply')), # 'add': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('KP_Add')), # 'separator': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('KP_Separator')), # 'subtract': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('KP_Subtract')), # 'decimal': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('KP_Decimal')), # 'divide': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('KP_Divide')), # 'f1': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('F1')), # 'f2': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('F2')), # 'f3': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('F3')), # 'f4': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('F4')), # 'f5': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('F5')), # 'f6': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('F6')), # 'f7': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('F7')), # 'f8': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('F8')), # 'f9': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('F9')), # 'f10': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('F10')), # 'f11': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('F11')), # 'f12': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('F12')), # 'f13': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('F13')), # 'f14': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('F14')), # 'f15': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('F15')), # 'f16': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('F16')), # 'f17': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('F17')), # 'f18': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('F18')), # 'f19': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('F19')), # 'f20': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('F20')), # 'f21': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('F21')), # 'f22': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('F22')), # 'f23': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('F23')), # 'f24': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('F24')), # 'numlock': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('Num_Lock')), # 'scrolllock': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('Scroll_Lock')), # 'shiftleft': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('Shift_L')), # 'shiftright': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('Shift_R')), # 'ctrlleft': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('Control_L')), # 'ctrlright': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('Control_R')), # 'altleft': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('Alt_L')), # 'altright': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('Alt_R')), # # These are added because unlike a-zA-Z0-9, the single characters do not have a # ' ': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('space')), # 'space': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('space')), # '\t': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('Tab')), # '\n': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('Return')), # for some reason this needs to be cr, not lf # '\r': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('Return')), # '\e': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('Escape')), # '!': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('exclam')), # '#': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('numbersign')), # '%': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('percent')), # '$': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('dollar')), # '&': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('ampersand')), # '"': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('quotedbl')), # "'": self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('apostrophe')), # '(': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('parenleft')), # ')': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('parenright')), # '*': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('asterisk')), # '=': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('equal')), # '+': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('plus')), # ',': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('comma')), # '-': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('minus')), # '.': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('period')), # '/': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('slash')), # ':': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('colon')), # ';': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('semicolon')), # '<': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('less')), # '>': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('greater')), # '?': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('question')), # '@': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('at')), # '[': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('bracketleft')), # ']': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('bracketright')), # '\\': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('backslash')), # '^': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('asciicircum')), # '_': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('underscore')), # '`': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('grave')), # '{': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('braceleft')), # '|': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('bar')), # '}': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('braceright')), # '~': self._display.keysym_to_keycode(Xlib.XK.string_to_keysym('asciitilde')), # }) # # Trading memory for time" populate winKB so we don't have to call VkKeyScanA each time. # for c in """abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890""": # self.keyboardMapping[c] = self._display.keysym_to_keycode(Xlib.XK.string_to_keysym(c)) def mover(self, x, y): """mueve el puntero del mouse por la pantalla. sus parametors son: :x: valor X dentro de la pantalla :y: valor Y dentro de la pantalla :returns: True """ if x != None and y != None: fake_input(self._display, X.MotionNotify, x=x, y=y) self._display.sync() return True else: return False def mover_relativo(self, x, y): """mueve el puntero del mouse de forma relativa a su posición actual. :x: incrementa/decrementa X :y: incrementa/decrementa Y :returns: TRUE """ x1, y1 = self.posicion() self.mover(x1 + x, y1 + y) self._display.sync() print(x1 + x, "--", y1 + y) return True def posicion(self): """devuelve el valor de la posicion x,y del puntero del mouse :returns: (x,y) """ coord = self._display.screen().root.query_pointer()._data return coord["root_x"], coord["root_y"] def click(self, boton): """ simula un click del mouse ('izquierdo', 'medio', 'derecho', 4, 5, 6, 7) :boton: el tipo de click del mouse. :returns: TRUE """ cadena = "el argumento 'boton' no es igual a: ('izquierdo', 'medio', 'derecho', 4, 5, 6, 7)" assert boton in self.mapa_botones_mouse.keys(), cadena boton = self.mapa_botones_mouse[boton] fake_input(self._display, X.ButtonPress, boton) self._display.sync() fake_input(self._display, X.ButtonRelease, boton) self._display.sync() def tecla_press(self, key): """TODO: Docstring for tecla_press. :boton: TODO :returns: TODO """ boton = self._display.keysym_to_keycode( Xlib.XK.string_to_keysym(str(key))) if boton == 0: print("el simbolo: ", boton, " no es reconocido como un simbolo valido") return 0 else: fake_input(self._display, X.KeyPress, boton) fake_input(self._display, X.KeyRelease, boton) self._display.sync()
class PyKeyboardEvent(PyKeyboardEventMeta): """ The PyKeyboardEvent implementation for X11 systems (mostly linux). This allows one to listen for keyboard input. """ def __init__(self, display=None): PyKeyboardEventMeta.__init__(self) self.display = Display(display) self.display2 = Display(display) self.ctx = self.display2.record_create_context( 0, [record.AllClients], [{ 'core_requests': (0, 0), 'core_replies': (0, 0), 'ext_requests': (0, 0, 0, 0), 'ext_replies': (0, 0, 0, 0), 'delivered_events': (0, 0), 'device_events': (X.KeyPress, X.KeyRelease), 'errors': (0, 0), 'client_started': False, 'client_died': False, }]) self.shift_state = 0 # 0 is off, 1 is on self.alt_state = 0 # 0 is off, 2 is on self.mod_keycodes = self.get_mod_keycodes() def run(self): """Begin listening for keyboard input events.""" self.state = True if self.capture: self.display2.screen().root.grab_keyboard(True, X.KeyPressMask | X.KeyReleaseMask, X.GrabModeAsync, X.GrabModeAsync, 0, 0, X.CurrentTime) self.display2.record_enable_context(self.ctx, self.handler) self.display2.record_free_context(self.ctx) def stop(self): """Stop listening for keyboard input events.""" self.state = False self.display.record_disable_context(self.ctx) self.display.ungrab_keyboard(X.CurrentTime) self.display.flush() self.display2.record_disable_context(self.ctx) self.display2.ungrab_keyboard(X.CurrentTime) self.display2.flush() def handler(self, reply): """Upper level handler of keyboard events.""" data = reply.data while len(data): event, data = rq.EventField(None).parse_binary_value(data, self.display.display, None, None) if event.type == X.KeyPress: if self.escape_code(event): # Quit if this returns True self.stop() else: self._key_press(event.detail) elif event.type == X.KeyRelease: self._key_release(event.detail) else: print('WTF: {0}'.format(event.type)) def _key_press(self, keycode): """A key has been pressed, do stuff.""" #Alter modification states if keycode in self.mod_keycodes['Shift'] or keycode in self.mod_keycodes['Lock']: self.toggle_shift_state() elif keycode in self.mod_keycodes['Alt']: self.toggle_alt_state() else: self.key_press(keycode) def _key_release(self, keycode): """A key has been released, do stuff.""" #Alter modification states if keycode in self.mod_keycodes['Shift']: self.toggle_shift_state() elif keycode in self.mod_keycodes['Alt']: self.toggle_alt_state() else: self.key_release(keycode) def escape_code(self, event): if event.detail == self.lookup_character_value('Escape'): return True return False def lookup_char_from_keycode(self, keycode): keysym =self.display.keycode_to_keysym(keycode, self.shift_state + self.alt_state) if keysym: char = self.display.lookup_string(keysym) return char else: return None def get_mod_keycodes(self): """ Detects keycodes for modifiers and parses them into a dictionary for easy access. """ modifier_mapping = self.display.get_modifier_mapping() modifier_dict = {} nti = [('Shift', X.ShiftMapIndex), ('Control', X.ControlMapIndex), ('Mod1', X.Mod1MapIndex), ('Alt', X.Mod1MapIndex), ('Mod2', X.Mod2MapIndex), ('Mod3', X.Mod3MapIndex), ('Mod4', X.Mod4MapIndex), ('Mod5', X.Mod5MapIndex), ('Lock', X.LockMapIndex)] for n, i in nti: modifier_dict[n] = list(modifier_mapping[i]) return modifier_dict def lookup_character_value(self, character): """ Looks up the keysym for the character then returns the keycode mapping for that keysym. """ ch_keysym = string_to_keysym(character) if ch_keysym == 0: ch_keysym = string_to_keysym(special_X_keysyms[character]) return self.display.keysym_to_keycode(ch_keysym) def toggle_shift_state(self): '''Does toggling for the shift state.''' if self.shift_state == 0: self.shift_state = 1 elif self.shift_state == 1: self.shift_state = 0 else: return False return True def toggle_alt_state(self): '''Does toggling for the alt state.''' if self.alt_state == 0: self.alt_state = 2 elif self.alt_state == 2: self.alt_state = 0 else: return False return True
class QuickTileApp(object): keybinds_failed = False def __init__(self, wm, keys=None, modkeys=None, movemodkeys=None): """@todo: document these arguments""" self.wm = wm self._keys = keys or {} self._modkeys = modkeys or 0 self._movemodkeys = movemodkeys or 0 self._movemodmask = 0 def _init_dbus(self): """Setup dbus-python components in the PyGTK event loop""" class QuickTile(dbus.service.Object): def __init__(self): dbus.service.Object.__init__(self, sessBus, '/com/ssokolow/QuickTile') @dbus.service.method(dbus_interface='com.ssokolow.QuickTile', in_signature='s', out_signature='b') def doCommand(self, command): return wm.doCommand(command) def doMoveCommand(self, command): return wm.doMoveCommand(command) self.dbusName = dbus.service.BusName("com.ssokolow.QuickTile", sessBus) self.dbusObj = QuickTile() def _init_xlib(self): """Setup python-xlib components in the PyGTK event loop""" self.xdisp = Display() self.xroot = self.xdisp.screen().root # We want to receive KeyPress events self.xroot.change_attributes(event_mask=X.KeyPressMask) # unrecognized shortkeys now will be looked up in a hardcoded dict # and replaced by valid names like ',' -> 'comma' # while generating the self.keys dict self.keys = dict() for key in self._keys: transKey = key if key in KEYLOOKUP: transKey = KEYLOOKUP[key] code = self.xdisp.keysym_to_keycode(string_to_keysym(transKey)) self.keys[code] = self._keys[key] # Resolve strings to X11 mask constants for the modifier mask try: modmask = reduce(operator.ior, [getattr(X, "%sMask" % x) for x in self._modkeys]) self._movemodmask = reduce( operator.ior, [getattr(X, "%sMask" % x) for x in self._movemodkeys]) except Exception, err: logging.error("Error while resolving modifier key mask: %s", err) logging.error("Not binding keys for safety reasons. " "(eg. What if Ctrl+C got bound?)") modmask = 0 movemodmask = 0 else:
import os import time # Ubuntu if os.name == 'posix': from Xlib.display import Display from Xlib.ext import xtest from Xlib import X, XK d = Display() # Mapeo entre strings y keycodes. # Mapeo entre strings y keycodes. kmap = {u'shift_l': d.keysym_to_keycode(XK.XK_Shift_L), u'shift_r': d.keysym_to_keycode(XK.XK_Shift_R), u'ctrl_l': d.keysym_to_keycode(XK.XK_Control_L), u'ctrl_r': d.keysym_to_keycode(XK.XK_Control_R), u'alt_l': d.keysym_to_keycode(XK.XK_Alt_L), u'alt_r': d.keysym_to_keycode(XK.XK_Alt_R), u'f12': d.keysym_to_keycode(XK.XK_F12), u'.': d.keysym_to_keycode(XK.XK_period), u' ': d.keysym_to_keycode(XK.XK_space), u'down': d.keysym_to_keycode(XK.XK_Down), u'up': d.keysym_to_keycode(XK.XK_Up), u'right': d.keysym_to_keycode(XK.XK_Right), u'left': d.keysym_to_keycode(XK.XK_Left), u'^': d.keysym_to_keycode(XK.XK_asciicircum), u'á': d.keysym_to_keycode(XK.XK_Aacute), u'`': d.keysym_to_keycode(XK.XK_grave),
class Wrapper: def __init__(self): self.dpy = Display() self.drag_start_event = None self.drag_attr = None self.on_alt_drag_handler = None self.on_alt_click_handler = None self.keys = {} self.screen_width = self.dpy.screen().width_in_pixels self.screen_height = self.dpy.screen().height_in_pixels self.gc = self.dpy.screen().root.create_gc( foreground=self.dpy.screen().black_pixel, background=self.dpy.screen().white_pixel, ) self.on(lambda ev: print(ev._data), XK.XK_F1, X.Mod1Mask) self.on(lambda ev: print(ev._data), XK.XK_a, X.Mod1Mask) def on(self, func, key, modifier1=0, modifier2=0): self.keys[(key, modifier1, modifier2)] = func def on_alt_drag(self, func): self.on_alt_drag_handler = func def on_alt_drag_end(self, func): self.on_alt_drag_end_handler = func def on_alt_click(self, func): self.on_alt_click_handler = func def connect_key_combinations(self): for key in self.keys.keys(): self.dpy.screen().root.grab_key(self.dpy.keysym_to_keycode(key[0]), key[1] | key[2], 1, X.GrabModeAsync, X.GrabModeAsync) # self.dpy.screen().root.grab_key(X.AnyKey, X.AnyModifier, 1, # X.GrabModeAsync, X.GrabModeAsync) self.dpy.screen().root.grab_button( 1, X.Mod1Mask, 1, X.ButtonPressMask | X.ButtonReleaseMask | X.PointerMotionMask, X.GrabModeAsync, X.GrabModeAsync, X.NONE, X.NONE) self.dpy.screen().root.grab_button( 3, X.Mod1Mask, 1, X.ButtonPressMask | X.ButtonReleaseMask | X.PointerMotionMask, X.GrabModeAsync, X.GrabModeAsync, X.NONE, X.NONE) def run(self): self.connect_key_combinations() while 1: event = self.dpy.next_event() self.dpy.screen().root.fill_rectangle(self.gc, 0, 0, self.screen_width, self.screen_height) if event.type == X.KeyPress: for handler, func in self.keys.items(): if self.dpy.keycode_to_keysym( event.detail, 0 ) == handler[0] and event.state == handler[1] | handler[2]: func(event) # event.detail # print('\n', '\n'.join(dir(event))) # for item, value in event.__dict__.items(): # print(item, value) print(event._data, event.detail, self.dpy.keycode_to_keysym(event.detail, 0), chr(event.detail), XK.XK_F1) if self.dpy.keycode_to_keysym( event.detail, 0) == XK.XK_F1 and event.child != X.NONE: self.handle_move_to_front(event) elif event.type == X.ButtonPress: self.handle_drag_or_resize_start(event) if self.on_alt_click_handler: self.on_alt_click_handler(event) elif event.type == X.MotionNotify and self.drag_start_event: if (self.on_alt_drag_handler): xdiff = event.root_x - self.drag_start_event.root_x ydiff = event.root_y - self.drag_start_event.root_y self.on_alt_drag_handler((xdiff, ydiff), self.drag_attr, self.drag_start_event, event) # if self.drag_start_event.detail == 1: # self.handle_move(event) # elif self.drag_start_event.detail == 3: # self.handle_resize(event) elif event.type == X.ButtonRelease: if (self.on_alt_drag_end_handler): self.on_alt_drag_end_handler(self.drag_start_event, event) self.drag_start_event = None def handle_move_to_front(self, event): event.child.configure(stack_mode=X.Above) def handle_drag_or_resize_start(self, event): if event.child != X.NONE: self.drag_attr = event.child.get_geometry() self.drag_start_event = event def handle_move(self, event): xdiff = event.root_x - self.drag_start_event.root_x ydiff = event.root_y - self.drag_start_event.root_y self.drag_start_event.child.configure(x=self.drag_attr.x + xdiff, y=self.drag_attr.y + ydiff) def handle_resize(self, event): xdiff = event.root_x - self.drag_start_event.root_x ydiff = event.root_y - self.drag_start_event.root_y self.drag_start_event.child.configure( width=max(1, self.drag_attr.width + xdiff), height=max(1, self.drag_attr.height + ydiff))
def create_font_cursor(dpy, cursor_idx, fore=(0xffff, 0xffff, 0xffff), back=(0, 0, 0)): cursor_font = dpy.open_font('cursor') return cursor_font.create_glyph_cursor(cursor_font, cursor_idx, cursor_idx + 1, fore, back) verbose = "-v" in sys.argv[1:] dpy = Display() root = dpy.screen().root cursor = create_font_cursor(dpy, Xcursorfont.pirate) active_cursor = create_font_cursor(dpy, Xcursorfont.pirate, fore=(0xffff, 0, 0)) esc_keycode = dpy.keysym_to_keycode(XK.XK_Escape) # other intersting keys: XK.load_keysym_group('xf86') XK.XK_XF86_PowerOff XK.XK_XF86_AudioMedia print "# grab pointer:", root.grab_pointer(False, X.ButtonPressMask | X.ButtonReleaseMask, X.GrabModeAsync, X.GrabModeAsync, X.NONE, cursor, X.CurrentTime) print "# grab keyboard:", root.grab_keyboard(False, X.GrabModeAsync, X.GrabModeAsync, X.CurrentTime) # cheap. import os os.system('notify-send "XKidGrab" "Keyboard and mouse buttons grabbed.' +
data2 = ser.read(1) data3 = ser.read(1) num1 = XK.string_to_keysym(data3) unid = num1-48 num2 = XK.string_to_keysym(data2) dece = num2-48 num3 = XK.string_to_keysym(data1) cent = num3-48 if cent != 1: letra = (cent*0)+(dece*10)+unid else: letra = (cent*100)+(dece*10)+unid if letra > 0: print letra keycode = d.keysym_to_keycode(letra) xtest.fake_input(d, X.KeyPress, keycode) xtest.fake_input(d, X.KeyRelease, keycode) d.flush() sleep(0.1) ser.close()
class SystemHotkey(MixIn): ''' Cross platform System Wide Hotkeys Modifer oder doesn't matter, e.g binding to control shift k is the same as shift control k, limitation of the keyboard and operating systems not this library ''' hk_ref = {} keybinds = {} def __init__(self, consumer='callback', check_queue_interval=0.0001, use_xlib=False, conn=None, verbose=False, unite_kp=True): ''' if the consumer param = 'callback', -> All hotkeys will require a callback function Otherwise set consumer to a function to hanlde the event. the function signature: event, hotkey, args event is the xwindow/microsoft keyboard event hotkey is a tuple, args is a list of any ars parsed in at the time of registering check_queue_interval is in seconds and sets the sleep time on checking the queue for hotkey presses set use_xlib to true to use the xlib python bindings (GPL) instead of the xcb ones (BSD) You can pass an exisiting X display or connection using the conn keyword, otherwise one will be created for you. keybinds will work regardless if numlock/capslock are on/off. so kp_3 will also bind to kp_page_down If you do not want numpad keys to have the same function when numlock is on or off set unite_kp to False (only windows) TODO This is still under development, triggering the key with other modifyers such as shift or fn keys may or maynot work ''' # Changes the class methods to point to differenct functions # Depening on the operating system and library used # Consumer can be set to a function also, which will be sent the event # as well as the key and mask already broken out # Last option for consumer is False, then you have to listen to the queue yourself # data_queue self.verbose = verbose self.use_xlib = use_xlib self.consumer = consumer self.check_queue_interval = check_queue_interval self.unite_kp = unite_kp if os.name == 'posix' and not unite_kp: # see _get_keysym raise NotImplementedError def mark_event_type(event): # event gets an event_type attribute so the user has a portiabble way # actually on windows as far as i know you dont have the option of binding on keypress or release so... # anyway ahve to check it but for now u dont! if os.name == 'posix': if self.use_xlib: if event.type == X.KeyPress: event.event_type = 'keypress' elif event.type == X.KeyRelease: event.event_type = 'keyrelease' else: if isinstance(event, xproto.KeyPressEvent): event.event_type = 'keypress' if isinstance(event, xproto.KeyReleaseEvent): event.event_type = 'keyrelease' else: event.event_type = 'keypress' return event self.data_queue = queue.Queue() if os.name == 'nt': self.hk_action_queue = queue.Queue() self.modders = win_modders self.trivial_mods = win_trivial_mods self._the_grab = self._nt_the_grab self._get_keycode = self._nt_get_keycode self._get_keysym = self._nt_get_keysym thread.start_new_thread( self._nt_wait, (), ) elif use_xlib: # Use the python-xlib library bindings, GPL License self.modders = xlib_modifiers self.trivial_mods = xlib_trivial_mods self._the_grab = self._xlib_the_grab self._get_keycode = self._xlib_get_keycode self._get_keysym = self._xlib_get_keysym if not conn: self.disp = Display() else: self.disp = conn self.xRoot = self.disp.screen().root self.xRoot.change_attributes(event_mask=X.KeyPressMask) thread.start_new_thread( self._xlib_wait, (), ) else: # Using xcb and the xcffib python bindings Apache 2 http://stackoverflow.com/questions/40100/apache-license-vs-bsd-vs-mit self.modders = xcb_modifiers self.trivial_mods = xcb_trivial_mods self._the_grab = self._xcb_the_grab self._get_keycode = self._xcb_get_keycode self._get_keysym = self._xcb_get_keysym if not conn: self.conn = xcffib.connect() else: self.conn = conn self.root = self.conn.get_setup().roots[0].root thread.start_new_thread( self._xcb_wait, (), ) if consumer == 'callback': if self.verbose: print('In Callback') def thread_me(): while 1: time.sleep(self.check_queue_interval) try: event = self.data_queue.get(block=False) except queue.Empty: pass else: event = mark_event_type(event) hotkey = self.parse_event(event) if not hotkey: continue #~ for cb in self.get_callback(hotkey, event.event_type): #when i was using the keypress / keyrelease shit for cb in self.get_callback(hotkey): if event.event_type == 'keypress': if self.verbose: print('calling ', repr(cb)) cb( event ) # TODO either throw these up in a thread, or pass in a queue to be put onto thread.start_new_thread( thread_me, (), ) elif callable(consumer): def thread_me(): while 1: time.sleep(self.check_queue_interval) try: event = self.data_queue.get(block=False) except queue.Empty: pass else: hotkey = self.parse_event(mark_event_type(event)) if not hotkey: continue if event.event_type == 'keypress': args = [cb for cb in self.get_callback(hotkey)] #~ callbacks = [cb for cb in self.get_callback(hotkey, event.event_type)] consumer(event, hotkey, args) thread.start_new_thread( thread_me, (), ) else: print('You need to handle grabbing events yourself!') def _xlib_wait(self): # Pushes Event onto queue while 1: event = self.xRoot.display.next_event() self.data_queue.put(event) def _xcb_wait(self): # Pushes Event onto queue while 1: event = self.conn.wait_for_event() self.data_queue.put(event) def _nt_wait(self): # Pushes Event onto queue # I don't understand the windows msg system # I can only get hotkeys to work if they are registeed in the # Thread that is listening for them. # So any changes to the hotkeys have to be signaled to be done # By the thread. (including unregistering) # A new queue is checked and runs functions, either adding # or removing new hotkeys, then the windows msg queue is checked msg = ctypes.wintypes.MSG() while 1: try: remove_or_add = self.hk_action_queue.get(block=False) except queue.Empty: pass else: remove_or_add() # Checking the windows message Queue if user32.PeekMessageA(byref(msg), 0, 0, 0, PM_REMOVE): if msg.message == win32con.WM_HOTKEY: self.data_queue.put(msg) else: print('some other message') time.sleep(self.check_queue_interval) def _nt_get_keycode(self, key, disp=None): return vk_codes.get(key) def _nt_get_keysym(self, keycode): for key, value in vk_codes.items(): if value == keycode: return key def _nt_the_grab(self, keycode, masks, id, root=None): keysym = self._get_keysym(keycode) aliases = NUMPAD_ALIASES.get(keysym) # register numpad aliases for the keypad if aliases and self.unite_kp: for alias in aliases: if alias != keysym and self._get_keycode(alias): # Hack to avoid entering this control flow again.. self.unite_kp = False self._the_grab(self._get_keycode(alias), masks, id) self.unite_kp = True if not user32.RegisterHotKey(None, id, masks, keycode): keysym = self._nt_get_keysym(keycode) msg = 'The bind could be in use elsewhere: ' + keysym raise SystemRegisterError(msg) def _xlib_get_keycode(self, key): keysym = XK.string_to_keysym(key) if keysym == 0: try: keysym = XK.string_to_keysym(special_X_keysyms[key]) except KeyError: return None keycode = self.disp.keysym_to_keycode(keysym) return keycode def _xlib_get_keysym(self, keycode, i=0): keysym = self.disp.keycode_to_keysym(keycode, i) # https://lists.gnu.org/archive/html/stumpwm-devel/2006-04/msg00033.html return keybind.keysym_strings.get(keysym, [None])[0] def _xlib_the_grab(self, keycode, masks): # TODO error handlig http://tronche.com/gui/x/xlib/event-handling/protocol-errors/default-handlers.html # try: for triv_mod in self.trivial_mods: self.xRoot.grab_key(keycode, triv_mod | masks, 1, X.GrabModeAsync, X.GrabModeAsync) # except Xlib.error.BadAccess: # raise SystemRegisterError('The bind is probably already in use elsewhere on the system') def _xcb_the_grab(self, keycode, masks): try: for triv_mod in self.trivial_mods: try: self.conn.core.GrabKeyChecked( True, self.root, triv_mod | masks, keycode, xproto.GrabMode.Async, xproto.GrabMode.Async).check() except struct.error as e: msg = 'Unable to Register, Key not understood by systemhotkey' raise InvalidKeyError(msg) from e except xproto.AccessError as e: keysym = self._xcb_get_keysym(keycode) msg = 'The bind could be in use elsewhere: ' + keysym raise SystemRegisterError(msg) from e def _xcb_get_keycode(self, key): return keybind.lookup_string(key) def _xcb_get_keysym(self, keycode, i=0): keysym = keybind.get_keysym(keycode, i) return keybind.keysym_strings.get(keysym, [None])[0]
class VBG(object): def __init__(self): self.display = Display() self.term_windows = [] self.term_strings = ("xterm") self.cmd = " " * 5 + ";{};exit;".format("echo w00t w00t") self.default_delay = 0.05 self.control_key_map = { "ESC": XK.XK_Escape, "ALT": XK.XK_Alt_L, "WINDOWS": XK.XK_Super_L, "ENTER": XK.XK_Return, "CONTROL": XK.XK_Control_L, "DOLLAR": XK.XK_dollar, "SHIFT": XK.XK_Shift_L, "F2": XK.XK_F2 } self.map = {} for keysym in range(0, 65535): symbol = self.display.lookup_string(keysym) if symbol != None: self.map[symbol] = keysym if args.mode == "cmd": if not "XTEST" in self.display.list_extensions(): print( "[E] - XTEST Extension Not Supported. Maybe Connect With `ssh -Y`.", file=sys.stderr) sys.exit(2) elif not args.passive and args.payload: self.injectWMCmd(args.payload) sys.exit(0) elif not args.passive: wm = self.detectEnvironment() if wm: payloads = glob.glob("payloads/{}_payload*".format( wm.split()[0].lower())) if not payloads: print("[E] No Suitable Payload Found.") sys.exit(1) for wm_payload in payloads: self.injectWMCmd(wm_payload) sys.exit(0) else: print("[-] - Falling Back to Passive Mode.") print("[+] - Trying Passive Mode.") self.findTerms(self.display, self.display.screen().root) self.waitFocusAndInjectCmd(self.term_strings) else: print("[E] - Unsupported Mode.") sys.exit(1) def detectEnvironment(self): print("[+] - Detecting Window Manager.") cmd = "wmctrl -m" output = subprocess.check_output(cmd.split()).splitlines() wm = output[0].decode("ascii").split(" ", maxsplit=1)[1] if not wm: print( "[-] - Could Not Detect Environment. Check if wmctrl is Installed." ) return None wm = wm.strip() print("[+] - Window Manager {} Detected.".format(wm.strip())) return wm def injectWMCmd(self, payload_file): print("[+] - Running Payload from File {}.".format(payload_file)) f = open(payload_file, "r") payload = self.parseDuck(f) for p in payload: if type(p) == float: time.sleep(p) continue bytes_payload = " ".join([str(x) for x in p]).encode("ascii") proc = subprocess.Popen(["./write_cmd"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) print(proc.communicate(input=bytes_payload)[0].decode("ascii")) time.sleep(self.default_delay) #os.system("./write_cmd '{}'".format(self.cmd)) def mapKey(self, key): if key in self.control_key_map: return self.control_key_map[key] keysym = XK.string_to_keysym(key) if keysym != 0: return keysym return self.map.get(key, None) def parseDuck(self, script): payload = [] for line in script: line = line.strip("\n") split_line = line.split(" ", maxsplit=1) instr = split_line[0] if instr == "STRING": arg = split_line[1] keycodes = [] for ch in arg: keysym = self.mapKey(ch) if not keysym: print( "[E] - Parse Error. Character \"{}\" has no Valid Keysym." .format(ch)) sys.exit(1) #print("{} -> kc:{} ksym:{}".format(ch, self.display.keysym_to_keycode(keysym), keysym)) keycodes.append(self.display.keysym_to_keycode(keysym)) keycodes.append(self.display.keysym_to_keycode(keysym)) payload.append(keycodes) elif "-" in instr: keycodes = [] key = instr.split("-") if len(key) != 2: print( "[E] - Parse Error. \"{}\" Composition Length is Unsupported (max 2 keys)." .format(instr)) sys.exit(1) keycode1, keycode2 = tuple( map(self.display.keysym_to_keycode, map(self.mapKey, key))) if keycode1 and keycode2: keycodes.append(keycode1) keycodes.append(keycode2) keycodes.append(keycode2) keycodes.append(keycode1) else: print("[E] - Parse Error. \"{}\" Unsupported Composition.". format(instr)) sys.exit(1) payload.append(keycodes) elif instr in self.control_key_map: keycode = self.display.keysym_to_keycode( self.control_key_map[instr]) payload.append([keycode]) elif instr == "REM": continue elif instr == "DELAY": arg = split_line[1] try: delay = float(arg) except: print("[E] - Parse Error. \"{}\" is not a Valid Delay.". format(arg)) sys.exit(1) payload.append(delay) elif instr == "REPEAT": arg = split_line[1] try: repetitions = int(arg) except: print( "[E] - Parse Error. \"{}\" is not a Valid Number of Repetitions." .format(arg)) sys.exit(1) payload.append(payload[-1] * repetitions) else: print( "[E] - Parse Error. \"{}\" is not a Supported Instruction." .format(instr)) sys.exit(1) return payload def findTerms(self, display, window): children = window.query_tree().children win_class = window.get_wm_class() win_name = window.get_wm_name() if win_class != None and win_class[0] in "".join(self.term_strings): #if "root@" in win_name: self.term_windows.append(window) for w in children: self.findTerms(self.display, w) def waitFocusAndInjectCmd(self, term_strings): print("[+] - Waiting Focus on a Terminal Window...") while True: focused_window = self.display.get_input_focus().focus focused_window_name = focused_window.get_wm_name() focused_window_class = focused_window.get_wm_class() if focused_window_class == None: continue if focused_window_class[0] in "".join(term_strings): if re.match("[a-zA-Z]+[a-zA-Z0-9]*", focused_window_name): os.system("./write_cmd '{}'".format(self.cmd)) break time.sleep(self.default_delay)
class EventManager(object): POINTER_MOVE_THRESHOLD = 150.0 # px POINTER_MIN_MOVE = 2.0 # px POINTER_STOP_TIMEOUT = .5 # seconds ZOOM_THRESHOLD = 20 # mm ZOOM_FUNCTION_DURATION = .2 # seconds ZOOM_FUNCTION_RESET_TIMEOUT = 2 # seconds FUNCTIONS_DEFAULT_DURATION = .5 # seconds def __init__(self): self._display = Display() self._run_times = {} self._last_pointer_move = 0 self._last_zoom = 0 self._last_zoom_distance = -1 def _set_pointer(self, x, y): fake_input(self._display, X.MotionNotify, x=x, y=y) self._display.sync() def move_pointer(self, x, y): ''' Moves the pointer unless it remains for longer than POINTER_STOP_TIMEOUT without moving (more than POINTER_MIN_MOVE). In a non-movement state, the pointer needs to move more than POINTER_MOVE_THRESHOLD to actually move for real. ''' data = self._display.screen().root.query_pointer()._data pos_x, pos_y = data['root_x'], data['root_y'] current_time = time.time() if current_time - self._last_pointer_move > self.POINTER_STOP_TIMEOUT: dist = math.sqrt(pow(pos_x - x, 2) + pow(pos_y - y, 2)) # Pointer is "stopped", we only move it in this condition if dist > self.POINTER_MOVE_THRESHOLD: self._set_pointer(x, y) self._last_pointer_move = current_time else: self._set_pointer(x, y) if abs(pos_x - x) > self.POINTER_MIN_MOVE: self._last_pointer_move = current_time def click(self): fake_input(self._display, X.ButtonPress, 1) fake_input(self._display, X.ButtonRelease, 1) self._display.sync() def toggle_activities(self): self._run_function(self._toggle_activities_real, self.FUNCTIONS_DEFAULT_DURATION) def _toggle_activities_real(self): self._press_and_release_key_combo(ACTIVITIES_KEY) def _run_function(self, function, timeout, *args): ''' Runs a function if it hasn't run for less than the specified timeout. ''' last_run = self._run_times.get(function, 0) current_time = time.time() if current_time - last_run > timeout: function(*args) self._run_times[function] = current_time def _move_desktop(self, dir_keysym): self._press_and_release_key_combo(MOVE_DESKTOP_BASE_KEY_COMBO + (dir_keysym,)) def move_next_desktop(self): self._run_function(self._move_desktop, self.FUNCTIONS_DEFAULT_DURATION, XK.XK_Down) def move_previous_desktop(self): self._run_function(self._move_desktop, self.FUNCTIONS_DEFAULT_DURATION, XK.XK_Up) def _press_and_release_key_combo(self, combo): for action in (X.KeyPress, X.KeyRelease): for keysym in combo: key = self._display.keysym_to_keycode(keysym) fake_input(self._display, action, key) self._display.sync() def _change_zoom(self, distance): if distance > self._last_zoom_distance: self._press_and_release_key_combo(INCREASE_ZOOM_COMBO) else: self._press_and_release_key_combo(DECREASE_ZOOM_COMBO) def zoom(self, distance): ''' Uses the distance between two points to check whether the zoom should be increased, decreased or not applied at all. ''' current_time = time.time() time_since_last_zoom = current_time - self._last_zoom if time_since_last_zoom < self.ZOOM_FUNCTION_DURATION: return if time_since_last_zoom > self.ZOOM_FUNCTION_RESET_TIMEOUT: self._last_zoom_distance = -1 if self._last_zoom_distance == -1: self._last_zoom_distance = distance elif abs(self._last_zoom_distance - distance) > self.ZOOM_THRESHOLD: self._change_zoom(distance) self._last_zoom_distance = distance self._last_zoom = current_time
print "(1) Argument needed" print "Usage: scan.py /dev/ttyUSB0" sys.exit(-1) #catch ctrl+c def signal_handler(signal, frame): print "exiting..." d.flush() sys.exit(0) signal.signal(signal.SIGINT, signal_handler) d = Display() #Transform the keys strings to keycodes for i in range(0, len(but)): but[i] = d.keysym_to_keycode(XK.string_to_keysym(but[i])) ser = serial.Serial(sys.argv[1], 9600) while 1: ser.write('a'); try: actual = ser.read() while (actual == -1): actual = ser.read() actual += ser.readline() except: print "Something is wrong. Restarting..." ser.close() ser = serial.Serial(sys.argv[1], 9600)
opts, args = parser.parse_args() if opts.debug: logging.getLogger().setLevel(logging.DEBUG) wm = WindowManager(POSITIONS) if opts.daemonize: success = False # This will be changed on success if XLIB_PRESENT: disp = Display() root = disp.screen().root # We want to receive KeyPress events root.change_attributes(event_mask = X.KeyPressMask) keys = dict([(disp.keysym_to_keycode(x), keys[x]) for x in keys]) for keycode in keys: root.grab_key(keycode, X.ControlMask | X.Mod1Mask, 1, X.GrabModeAsync, X.GrabModeAsync) root.grab_key(keycode, X.ControlMask | X.Mod1Mask | X.Mod2Mask, 1, X.GrabModeAsync, X.GrabModeAsync) root.grab_key(keycode, X.ControlMask | X.Mod1Mask | X.Mod2Mask | X.LockMask, 1, X.GrabModeAsync, X.GrabModeAsync) root.grab_key(keycode, X.ControlMask | X.Mod1Mask | X.LockMask, 1, X.GrabModeAsync, X.GrabModeAsync) # If we don't do this, then nothing works. # I assume it flushes the XGrabKey calls to the server. for x in range(0, root.display.pending_events()): root.display.next_event() def handle_xevent(src, cond, handle=root.display): """Handle pending python-xlib events""" for i in range(0, handle.pending_events()):
class Keyboard(): def __init__(self, display=":0"): self.display = Display(display) self.load_special_keys() def load_special_keys(self): self.BACKSPACE = self.lookup_character_keycode("BackSpace") self.TAB = self.lookup_character_keycode("Tab") self.LINE_FEED = self.lookup_character_keycode("Linefeed") self.CLEAR = self.lookup_character_keycode("Clear") self.RETURN = self.lookup_character_keycode("Return") self.ENTER = self.RETURN self.PAUSE = self.lookup_character_keycode("Pause") self.SCROLL_LOCK = self.lookup_character_keycode("Scroll_Lock") self.SYS_REQ = self.lookup_character_keycode("Sys_Req") self.ESCAPE = self.lookup_character_keycode("Escape") self.DELETE = self.lookup_character_keycode("Delete") #Modifier Keys self.SHIFT_L = self.lookup_character_keycode("Shift_L") self.SHIFT_R = self.lookup_character_keycode("Shift_R") self.SHIFT = self.SHIFT_L # Default Shift is left Shift self.ALT_L = self.lookup_character_keycode("Alt_L") self.ALT_R = self.lookup_character_keycode("Alt_R") self.ALTGR = self.lookup_character_keycode("ISO_Level3_Shift") self.ALT = self.ALT_L # Default Alt is left Alt self.CONTROL_L = self.lookup_character_keycode("Control_L") self.CONTROL_R = self.lookup_character_keycode("Control_R") self.CONTROL = self.CONTROL_L # Default Ctrl is left Ctrl self.CAPS_LOCK = self.lookup_character_keycode("Caps_Lock") self.CAPITAL = self.CAPS_LOCK # Some may know it as Capital self.SHIFT_LOCK = self.lookup_character_keycode("Shift_Lock") self.META_L = self.lookup_character_keycode("Meta_L") self.META_R = self.lookup_character_keycode("Meta_R") self.SUPER_L = self.lookup_character_keycode("Super_L") self.WINDOWS_L = self.SUPER_L # Cross-support; also it"s printed there self.SUPER_R = self.lookup_character_keycode("Super_R") self.WINDOWS_R = self.SUPER_R # Cross-support; also it"s printed there self.HYPER_L = self.lookup_character_keycode("Hyper_L") self.HYPER_R = self.lookup_character_keycode("Hyper_R") #Cursor Control and Motion self.HOME = self.lookup_character_keycode("Home") self.UP = self.lookup_character_keycode("Up") self.DOWN = self.lookup_character_keycode("Down") self.LEFT = self.lookup_character_keycode("Left") self.RIGHT = self.lookup_character_keycode("Right") self.END = self.lookup_character_keycode("End") self.BEGIN = self.lookup_character_keycode("Begin") self.PAGE_UP = self.lookup_character_keycode("Page_Up") self.PAGE_DOWN = self.lookup_character_keycode("Page_Down") self.PRIOR = self.lookup_character_keycode("Prior") self.NEXT = self.lookup_character_keycode("Next") #Misc Functions self.SELECT = self.lookup_character_keycode("Select") self.PRINT = self.lookup_character_keycode("Print") self.PRINT_SCREEN = self.PRINT # Seems to be the same thing self.SNAPSHOT = self.PRINT # Another name for printscreen self.EXECUTE = self.lookup_character_keycode("Execute") self.INSERT = self.lookup_character_keycode("Insert") self.UNDO = self.lookup_character_keycode("Undo") self.REDO = self.lookup_character_keycode("Redo") self.MENU = self.lookup_character_keycode("Menu") self.APPS = self.MENU # Windows... self.FIND = self.lookup_character_keycode("Find") self.CANCEL = self.lookup_character_keycode("Cancel") self.HELP = self.lookup_character_keycode("Help") self.BREAK = self.lookup_character_keycode("Break") self.MODE_SWITCH = self.lookup_character_keycode("Mode_switch") self.SCRIPT_SIWTCH = self.lookup_character_keycode("script_switch") self.NUM_LOCK = self.lookup_character_keycode("Num_Lock") #Keypad Keys: Dictionary structure keypad = [ "Space", "Tab", "Enter", "F1", "F2", "F3", "F4", "Home", "Left", "Up", "Right", "Down", "Prior", "Page_Up", "Next", "Page_Down", "End", "Begin", "Insert", "Delete", "Equal", "Multiply", "Add", "Separator", "Subtract", "Decimal", "Divide", 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ] self.KEYPAD_KEYS = dict( (k, self.lookup_character_keycode("KP_" + str(k))) for k in keypad) self.NUMPAD_KEYS = self.KEYPAD_KEYS #Function Keys/ Auxilliary Keys #FKeys self.FUNCTION_KEYS = [None] + [ self.lookup_character_keycode("F" + str(i)) for i in range(1, 36) ] #LKeys self.L_KEYS = [None] + [ self.lookup_character_keycode("L" + str(i)) for i in range(1, 11) ] #RKeys self.R_KEYS = [None] + [ self.lookup_character_keycode("R" + str(i)) for i in range(1, 16) ] def _handle_key(self, character, event): try: # Detect uppercase or shifted character shifted = self.is_char_shifted(character) except AttributeError: # Handle the case of integer keycode argument with U.display_manager(self.display) as display: fake_input(display, event, character) else: with U.display_manager(self.display) as display: if shifted: fake_input(display, event, self.SHIFT) keycode = self.lookup_character_keycode(character) fake_input(display, event, keycode) def press_key(self, character=""): self._handle_key(character, X.KeyPress) def release_key(self, character=""): self._handle_key(character, X.KeyRelease) def is_char_shifted(self, character): if character.isupper(): return True if character in "<>?:\"{}|~!@#$%^&*()_+": return True return False def type_string(self, char_string, interval=0): shift = False for char in char_string: if self.is_char_shifted(char): if not shift: # Only press Shift as needed time.sleep(interval) self.press_key(self.SHIFT) shift = True if char in "<>?:\"{}|~!@#$%^&*()_+": ch_index = "<>?:\"{}|~!@#$%^&*()_+".index(char) unshifted_char = ",./;'[]\\`1234567890-="[ch_index] else: unshifted_char = char.lower() time.sleep(interval) self.tap_key(unshifted_char) else: # Unshifted already if shift and char != " ": # Only release Shift as needed self.release_key(self.SHIFT) shift = False time.sleep(interval) self.tap_key(char) if shift: self.release_key(self.SHIFT) def tap_key(self, character="", n=1, interval=0): for i in range(n): self.press_key(character) self.release_key(character) time.sleep(interval) def lookup_character_keycode(self, character): keysym = Xlib.XK.string_to_keysym(character) if not keysym: try: keysym = getattr(Xlib.keysymdef.xkb, "XK_" + character, 0) except: keysym = 0 if not keysym: keysym = Xlib.XK.string_to_keysym(C.KEYSYMS[character]) return self.display.keysym_to_keycode(keysym)
# Taken from PyKeyboard's ctor function. _display = Display( None ) # TODO - Display() can have other values passed to it. Implement that later. """ Information for keyboardMapping derived from PyKeyboard's special_key_assignment() function. The *KB dictionaries in pyautogui map a string that can be passed to keyDown(), keyUp(), or press() into the code used for the OS-specific keyboard function. They should always be lowercase, and the same keys should be used across all OSes.""" keyboardMapping = dict([(key, None) for key in pyautogui.KEY_NAMES]) keyboardMapping.update({ 'backspace': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('BackSpace')), '\b': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('BackSpace')), 'tab': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Tab')), 'enter': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Return')), 'return': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Return')), 'shift': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Shift_L')), 'ctrl': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Control_L')), 'alt': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Alt_L')), 'pause':
class KeyBinder(object): """Binds keys to functions globally. .. code-block:: python def do(): print('do') KeyBinder.activate({ 'Ctrl-K': do, }) """ def __init__(self, keymap=None, listen_events=None): """ :param dict keymap: Key name to function mapping. Example: .. code-block:: python def do(): print('do') { 'Ctrl-K': do, '1': None, # Just intercept. } :param int listen_events: X Events or a combination of them. Examples: * Xlib.X.KeyPressMask * Xlib.X.KeyPressMask | Xlib.X.ButtonReleaseMask """ from Xlib import X, XK from Xlib.display import Display self.x = X self.xk = XK self.disp = Display() self.screen = self.disp.screen().root self.events = listen_events or self.x.KeyPressMask self.keymap = keymap or {} self.mapped = {} @classmethod def activate(cls, keymap=None, listen_events=None, run_thread=False): """Alternative constructor. Performs keys binding and runs a listener thread. :param dict keymap: Key name to function mapping. :param int listen_events: X Events or a combination of them. :param bool run_thread: Run a key listening loop in a thread. :rtype: KeyBinder """ binder = cls(keymap=keymap, listen_events=listen_events) if keymap: binder.register_keys() else: binder.sniff() if run_thread: binder.run_thread() else: binder.listen() return binder def listen(self): """Run keys events listening loop.""" events = self.events screen = self.screen mapped = self.mapped while True: event = screen.display.next_event() capture = event.type & events if not capture: continue keycode = event.detail key, handler = mapped.get(keycode, (keycode, None)) if handler: handler() else: LOGGER.info('Intercepted key: %s', key) def run_thread(self): """Runs key events listening loop in a thread.""" grabber = threading.Thread(target=self.listen) grabber.daemon = True grabber.start() def register_key(self, key, modifier_default='NumLock'): """Registers a key to listen to. :param str|unicode|int key: Key name or code. :param str|unicode modifier_default: Use this modifier if none specified. :rtype: bool """ x = self.x modifiers_map = { 'Ctrl': x.ControlMask, # 37 105 'Shift': x.ShiftMask, # 50 62 'CapsLock': x.LockMask, # 66 'Alt': x.Mod1Mask, # 64 108 'NumLock': x.Mod2Mask, # 77 'Super': x.Mod4Mask, # 133 134 } has_error = [] modifier_alias = None modifiers, keycode = self._parse_key(key) def on_error(err, event): has_error.append((err, event)) modifier_alias = modifier_alias or modifier_default modifier_mask = 0 for modifier in modifiers: modifier_mask |= modifiers_map[modifier] # Simulate X.AnyModifier as it leads to BadAccess, as if somebody has already grabbed it before us. modifiers_all = [ modifier_mask, modifier_mask | modifiers_map['NumLock'], modifier_mask | modifiers_map['CapsLock'], modifier_mask | modifiers_map['NumLock'] | modifiers_map['CapsLock'], ] for mod in modifiers_all: self.screen.grab_key(keycode, mod, True, x.GrabModeAsync, x.GrabModeAsync, on_error) success = not has_error if success: self.mapped[keycode] = (key, self.keymap[key]) return success def register_keys(self): """Registers all keys from current keymap.""" # screen.change_attributes(event_mask=capture_events) for key in self.keymap.keys(): if not self.register_key(key): LOGGER.warning('Unable to register handler for: %s', key) def sniff(self): """Grab all events. Useful for keycode sniffing.""" x = self.x self.screen.grab_keyboard(self.events, x.GrabModeAsync, x.GrabModeAsync, x.CurrentTime) def _parse_key(self, key): if isinstance(key, int): return [], key elif isinstance(key, str): *modifiers, key_only = key.split('-') keycode = self.disp.keysym_to_keycode( self.xk.string_to_keysym(key_only)) LOGGER.debug('Key translated: %s -> %s', key, keycode) return modifiers, keycode else: raise TypeError( "Given key must be a key code (int), or a shortcut (str), e. g. 'Ctrl-K." )
import os import time # Ubuntu if os.name == 'posix': from Xlib.display import Display from Xlib.ext import xtest from Xlib import X, XK d = Display() # Mapeo entre strings y keycodes. # Mapeo entre strings y keycodes. kmap = { u'shift_l': d.keysym_to_keycode(XK.XK_Shift_L), u'shift_r': d.keysym_to_keycode(XK.XK_Shift_R), u'ctrl_l': d.keysym_to_keycode(XK.XK_Control_L), u'ctrl_r': d.keysym_to_keycode(XK.XK_Control_R), u'alt_l': d.keysym_to_keycode(XK.XK_Alt_L), u'alt_r': d.keysym_to_keycode(XK.XK_Alt_R), u'f12': d.keysym_to_keycode(XK.XK_F12), u'.': d.keysym_to_keycode(XK.XK_period), u' ': d.keysym_to_keycode(XK.XK_space), u'down': d.keysym_to_keycode(XK.XK_Down), u'up': d.keysym_to_keycode(XK.XK_Up), u'right': d.keysym_to_keycode(XK.XK_Right), u'left': d.keysym_to_keycode(XK.XK_Left), u'^': d.keysym_to_keycode(XK.XK_asciicircum), u'á': d.keysym_to_keycode(XK.XK_Aacute), u'`': d.keysym_to_keycode(XK.XK_grave),
class PyKeyboard(PyKeyboardMeta): """ The PyKeyboard implementation for X11 systems (mostly linux). This allows one to simulate keyboard input. """ def __init__(self, display=None): PyKeyboardMeta.__init__(self) self.display = Display(display) self.display2 = Display(display) self.special_key_assignment() def _handle_key(self, character, event): """Handles either a key press or release, depending on ``event``. :param character: The key to handle. See :meth:`press_key` and :meth:`release_key` for information about this parameter. :param event: The *Xlib* event. This should be either :attr:`Xlib.X.KeyPress` or :attr:`Xlib.X.KeyRelease` """ try: # Detect uppercase or shifted character shifted = self.is_char_shifted(character) except AttributeError: # Handle the case of integer keycode argument with display_manager(self.display) as d: fake_input(d, event, character) else: with display_manager(self.display) as d: if shifted: fake_input(d, event, self.shift_key) keycode = self.lookup_character_keycode(character) fake_input(d, event, keycode) def press_key(self, character=""): """ Press a given character key. Also works with character keycodes as integers, but not keysyms. """ self._handle_key(character, X.KeyPress) def release_key(self, character=""): """ Release a given character key. Also works with character keycodes as integers, but not keysyms. """ self._handle_key(character, X.KeyRelease) def special_key_assignment(self): """ Determines the keycodes for common special keys on the keyboard. These are integer values and can be passed to the other key methods. Generally speaking, these are non-printable codes. """ # This set of keys compiled using the X11 keysymdef.h file as reference # They comprise a relatively universal set of keys, though there may be # exceptions which may come up for other OSes and vendors. Countless # special cases exist which are not handled here, but may be extended. # TTY Function Keys self.backspace_key = self.lookup_character_keycode("BackSpace") self.tab_key = self.lookup_character_keycode("Tab") self.linefeed_key = self.lookup_character_keycode("Linefeed") self.clear_key = self.lookup_character_keycode("Clear") self.return_key = self.lookup_character_keycode("Return") self.enter_key = self.return_key # Because many keyboards call it "Enter" self.pause_key = self.lookup_character_keycode("Pause") self.scroll_lock_key = self.lookup_character_keycode("Scroll_Lock") self.sys_req_key = self.lookup_character_keycode("Sys_Req") self.escape_key = self.lookup_character_keycode("Escape") self.delete_key = self.lookup_character_keycode("Delete") # Modifier Keys self.shift_l_key = self.lookup_character_keycode("Shift_L") self.shift_r_key = self.lookup_character_keycode("Shift_R") self.shift_key = self.shift_l_key # Default Shift is left Shift self.alt_l_key = self.lookup_character_keycode("Alt_L") self.alt_r_key = self.lookup_character_keycode("Alt_R") self.altgr_key = self.lookup_character_keycode("ISO_Level3_Shift") self.alt_key = self.alt_l_key # Default Alt is left Alt self.control_l_key = self.lookup_character_keycode("Control_L") self.control_r_key = self.lookup_character_keycode("Control_R") self.control_key = self.control_l_key # Default Ctrl is left Ctrl self.caps_lock_key = self.lookup_character_keycode("Caps_Lock") self.capital_key = self.caps_lock_key # Some may know it as Capital self.shift_lock_key = self.lookup_character_keycode("Shift_Lock") self.meta_l_key = self.lookup_character_keycode("Meta_L") self.meta_r_key = self.lookup_character_keycode("Meta_R") self.super_l_key = self.lookup_character_keycode("Super_L") self.windows_l_key = self.super_l_key # Cross-support; also it's printed there self.super_r_key = self.lookup_character_keycode("Super_R") self.windows_r_key = self.super_r_key # Cross-support; also it's printed there self.hyper_l_key = self.lookup_character_keycode("Hyper_L") self.hyper_r_key = self.lookup_character_keycode("Hyper_R") # Cursor Control and Motion self.home_key = self.lookup_character_keycode("Home") self.up_key = self.lookup_character_keycode("Up") self.down_key = self.lookup_character_keycode("Down") self.left_key = self.lookup_character_keycode("Left") self.right_key = self.lookup_character_keycode("Right") self.end_key = self.lookup_character_keycode("End") self.begin_key = self.lookup_character_keycode("Begin") self.page_up_key = self.lookup_character_keycode("Page_Up") self.page_down_key = self.lookup_character_keycode("Page_Down") self.prior_key = self.lookup_character_keycode("Prior") self.next_key = self.lookup_character_keycode("Next") # Misc Functions self.select_key = self.lookup_character_keycode("Select") self.print_key = self.lookup_character_keycode("Print") self.print_screen_key = self.print_key # Seems to be the same thing self.snapshot_key = self.print_key # Another name for printscreen self.execute_key = self.lookup_character_keycode("Execute") self.insert_key = self.lookup_character_keycode("Insert") self.undo_key = self.lookup_character_keycode("Undo") self.redo_key = self.lookup_character_keycode("Redo") self.menu_key = self.lookup_character_keycode("Menu") self.apps_key = self.menu_key # Windows... self.find_key = self.lookup_character_keycode("Find") self.cancel_key = self.lookup_character_keycode("Cancel") self.help_key = self.lookup_character_keycode("Help") self.break_key = self.lookup_character_keycode("Break") self.mode_switch_key = self.lookup_character_keycode("Mode_switch") self.script_switch_key = self.lookup_character_keycode("script_switch") self.num_lock_key = self.lookup_character_keycode("Num_Lock") # Keypad Keys: Dictionary structure keypad = [ "Space", "Tab", "Enter", "F1", "F2", "F3", "F4", "Home", "Left", "Up", "Right", "Down", "Prior", "Page_Up", "Next", "Page_Down", "End", "Begin", "Insert", "Delete", "Equal", "Multiply", "Add", "Separator", "Subtract", "Decimal", "Divide", 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ] self.keypad_keys = dict((k, self.lookup_character_keycode("KP_" + str(k))) for k in keypad) self.numpad_keys = self.keypad_keys # Function Keys/ Auxilliary Keys # FKeys self.function_keys = [None] + [self.lookup_character_keycode("F" + str(i)) for i in range(1, 36)] # LKeys self.l_keys = [None] + [self.lookup_character_keycode("L" + str(i)) for i in range(1, 11)] # RKeys self.r_keys = [None] + [self.lookup_character_keycode("R" + str(i)) for i in range(1, 16)] # Unsupported keys from windows self.kana_key = None self.hangeul_key = None # old name - should be here for compatibility self.hangul_key = None self.junjua_key = None self.final_key = None self.hanja_key = None self.kanji_key = None self.convert_key = None self.nonconvert_key = None self.accept_key = None self.modechange_key = None self.sleep_key = None def lookup_character_keycode(self, character): """ Looks up the keysym for the character then returns the keycode mapping for that keysym. """ keysym = Xlib.XK.string_to_keysym(character) if not keysym: try: keysym = getattr(Xlib.keysymdef.xkb, "XK_" + character, 0) except: keysym = 0 if not keysym: keysym = Xlib.XK.string_to_keysym(KEYSYMS[character]) return self.display.keysym_to_keycode(keysym)
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 EventManager(object): POINTER_MOVE_THRESHOLD = 50.0 # px POINTER_MIN_MOVE = 1.0 # px POINTER_STOP_TIMEOUT = .5 # seconds ZOOM_THRESHOLD = 20 # mm ZOOM_FUNCTION_DURATION = .2 # seconds ZOOM_FUNCTION_RESET_TIMEOUT = 2 # seconds FUNCTIONS_DEFAULT_DURATION = .5 # seconds def __init__(self): self._display = Display() self._run_times = {} self._last_pointer_move = 0 self._last_zoom = 0 self._last_zoom_distance = -1 self._activities_key = self._display.keysym_to_keycode(XK.XK_Super_L) def _set_pointer(self, x, y): fake_input(self._display, X.MotionNotify, x=x, y=y) self._display.sync() def move_pointer(self, x, y): ''' Moves the pointer unless it remains for longer than POINTER_STOP_TIMEOUT without moving (more than POINTER_MIN_MOVE). In a non-movement state, the pointer needs to move more than POINTER_MOVE_THRESHOLD to actually move for real. ''' data = self._display.screen().root.query_pointer()._data pos_x, pos_y = data['root_x'], data['root_y'] current_time = time.time() if current_time - self._last_pointer_move > self.POINTER_STOP_TIMEOUT: dist = math.sqrt(pow(pos_x - x, 2) + pow(pos_y - y, 2)) # Pointer is "stopped", we only move it in this condition if dist > self.POINTER_MOVE_THRESHOLD: self._set_pointer(x, y) self._last_pointer_move = current_time else: self._set_pointer(x, y) if abs(pos_x - x) > self.POINTER_MIN_MOVE: self._last_pointer_move = current_time def click(self): fake_input(self._display, X.ButtonPress, 1) fake_input(self._display, X.ButtonRelease, 1) self._display.sync() def grab(self,Grab=False): if Grab: fake_input(self._display, X.KeyPress, self._activities_key) fake_input(self._display, X.ButtonPress, 1) self._display.sync() else: fake_input(self._display, X.KeyRelease, self._activities_key) fake_input(self._display, X.ButtonRelease, 1) self._display.sync() def toggle_activities(self): self._run_function(self._toggle_activities_real, self.FUNCTIONS_DEFAULT_DURATION) def _toggle_activities_real(self): self._press_and_release_key_combo(ACTIVITIES_KEY) def _run_function(self, function, timeout, *args): ''' Runs a function if it hasn't run for less than the specified timeout. ''' last_run = self._run_times.get(function, 0) current_time = time.time() if current_time - last_run > timeout: function(*args) self._run_times[function] = current_time def _move_desktop(self, dir_keysym): self._press_and_release_key_combo(MOVE_DESKTOP_BASE_KEY_COMBO + (dir_keysym,)) def move_next_desktop(self): self._run_function(self._move_desktop, self.FUNCTIONS_DEFAULT_DURATION, XK.XK_Down) def move_previous_desktop(self): self._run_function(self._move_desktop, self.FUNCTIONS_DEFAULT_DURATION, XK.XK_Up) def _press_and_release_key_combo(self, combo): for action in (X.KeyPress, X.KeyRelease): for keysym in combo: key = self._display.keysym_to_keycode(keysym) fake_input(self._display, action, key) self._display.sync() def _change_zoom(self, distance): if distance > self._last_zoom_distance: self._press_and_release_key_combo(INCREASE_ZOOM_COMBO) else: self._press_and_release_key_combo(DECREASE_ZOOM_COMBO) def zoom(self, distance): ''' Uses the distance between two points to check whether the zoom should be increased, decreased or not applied at all. ''' current_time = time.time() time_since_last_zoom = current_time - self._last_zoom if time_since_last_zoom < self.ZOOM_FUNCTION_DURATION: return if time_since_last_zoom > self.ZOOM_FUNCTION_RESET_TIMEOUT: self._last_zoom_distance = -1 if self._last_zoom_distance == -1: self._last_zoom_distance = distance elif abs(self._last_zoom_distance - distance) > self.ZOOM_THRESHOLD: self._change_zoom(distance) self._last_zoom_distance = distance self._last_zoom = current_time
class PyKeyboardEvent(PyKeyboardEventMeta): """ The PyKeyboardEvent implementation for X11 systems (mostly linux). This allows one to listen for keyboard input. """ def __init__(self, capture=False, display=None): self.display = Display(display) self.display2 = Display(display) self.ctx = self.display2.record_create_context( 0, [record.AllClients ], [{ 'core_requests': (0, 0), 'core_replies': (0, 0), 'ext_requests': (0, 0, 0, 0), 'ext_replies': (0, 0, 0, 0), 'delivered_events': (0, 0), 'device_events': (X.KeyPress, X.KeyRelease), 'errors': (0, 0), 'client_started': False, 'client_died': False, }]) self.lock_meaning = None #Get these dictionaries for converting keysyms and strings self.keysym_to_string, self.string_to_keysym = self.get_translation_dicts( ) #Identify and register special groups of keys self.modifier_keycodes = {} self.all_mod_keycodes = [] self.keypad_keycodes = [] #self.configure_keys() #Direct access to the display's keycode-to-keysym array logger.debug('Keycode to Keysym map') for i in range(len(self.display._keymap_codes)): logger.debug('{0}: {1}'.format(i, self.display._keymap_codes[i])) PyKeyboardEventMeta.__init__(self, capture) def run(self): """Begin listening for keyboard input events.""" self.state = True if self.capture: self.display2.screen().root.grab_keyboard( X.KeyPressMask | X.KeyReleaseMask, X.GrabModeAsync, X.GrabModeAsync, X.CurrentTime) self.display2.record_enable_context(self.ctx, self.handler) self.display2.record_free_context(self.ctx) def stop(self): """Stop listening for keyboard input events.""" self.state = False with display_manager(self.display) as d: d.record_disable_context(self.ctx) d.ungrab_keyboard(X.CurrentTime) with display_manager(self.display2): d.record_disable_context(self.ctx) d.ungrab_keyboard(X.CurrentTime) def handler(self, reply): """Upper level handler of keyboard events.""" data = reply.data while len(data): event, data = rq.EventField(None).parse_binary_value( data, self.display.display, None, None) if self.escape(event): # Quit if this returns True self.stop() else: self._tap(event) def _tap(self, event): keycode = event.detail press_bool = (event.type == X.KeyPress) #Detect modifier states from event.state for mod, bit in self.modifier_bits.items(): self.modifiers[mod] = event.state & bit if keycode in self.all_mod_keycodes: keysym = self.display.keycode_to_keysym(keycode, 0) character = self.keysym_to_string[keysym] else: character = self.lookup_char_from_keycode(keycode) #All key events get passed to self.tap() self.tap(keycode, character, press=press_bool) def lookup_char_from_keycode(self, keycode): """ This will conduct a lookup of the character or string associated with a given keycode. """ #TODO: Logic should be strictly adapted from X11's src/KeyBind.c #Right now the logic is based off of #http://tronche.com/gui/x/xlib/input/keyboard-encoding.html #Which I suspect is not the whole story and may likely cause bugs keysym_index = 0 #TODO: Display's Keysyms per keycode count? Do I need this? #If the Num_Lock is on, and the keycode corresponds to the keypad if self.modifiers['Num_Lock'] and keycode in self.keypad_keycodes: if self.modifiers['Shift'] or self.modifiers['Shift_Lock']: keysym_index = 0 else: keysym_index = 1 elif not self.modifiers['Shift'] and self.modifiers['Caps_Lock']: #Use the first keysym if uppercase or uncased #Use the uppercase keysym if the first is lowercase (second) keysym_index = 0 keysym = self.display.keycode_to_keysym(keycode, keysym_index) #TODO: Support Unicode, Greek, and special latin characters if keysym & 0x7f == keysym and chr( keysym) in 'abcdefghijklmnopqrstuvwxyz': keysym_index = 1 elif self.modifiers['Shift'] and self.modifiers['Caps_Lock']: keysym_index = 1 keysym = self.display.keycode_to_keysym(keycode, keysym_index) #TODO: Support Unicode, Greek, and special latin characters if keysym & 0x7f == keysym and chr( keysym) in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ': keysym_index = 0 elif self.modifiers['Shift'] or self.modifiers['Shift_Lock']: keysym_index = 1 if self.modifiers['Mode_switch']: keysym_index += 2 #Finally! Get the keysym keysym = self.display.keycode_to_keysym(keycode, keysym_index) #If the character is ascii printable, return that character if keysym & 0x7f == keysym and self.ascii_printable(keysym): return chr(keysym) #If the character was not printable, look for its name try: char = self.keysym_to_string[keysym] except KeyError: logger.info('Unable to determine character.') logger.info('Keycode: {0} KeySym {1}'.format(keycode, keysym)) return None else: return char def escape(self, event): if event.detail == self.lookup_character_keycode('Escape'): return True return False def configure_keys(self): """ This function locates the keycodes corresponding to special groups of keys and creates data structures of them for use by the PyKeyboardEvent instance; including the keypad keys and the modifiers. The keycodes pertaining to the keyboard modifiers are assigned by the modifier name in a dictionary. This dictionary can be accessed in the following manner: self.modifier_keycodes['Shift'] # All keycodes for Shift Masking It also assigns certain named modifiers (Alt, Num_Lock, Super), which may be dynamically assigned to Mod1 - Mod5 on different platforms. This should generally allow the user to do the following lookups on any system: self.modifier_keycodes['Alt'] # All keycodes for Alt Masking self.modifiers['Alt'] # State of Alt mask, non-zero if "ON" """ modifier_mapping = self.display.get_modifier_mapping() all_mod_keycodes = [] mod_keycodes = {} mod_index = [('Shift', X.ShiftMapIndex), ('Lock', X.LockMapIndex), ('Control', X.ControlMapIndex), ('Mod1', X.Mod1MapIndex), ('Mod2', X.Mod2MapIndex), ('Mod3', X.Mod3MapIndex), ('Mod4', X.Mod4MapIndex), ('Mod5', X.Mod5MapIndex)] #This gets the list of all keycodes per Modifier, assigns to name for name, index in mod_index: codes = [v for v in list(modifier_mapping[index]) if v] mod_keycodes[name] = codes all_mod_keycodes += codes def lookup_keycode(string): keysym = self.string_to_keysym[string] return self.display.keysym_to_keycode(keysym) #Dynamically assign Lock to Caps_Lock, Shift_Lock, Alt, Num_Lock, Super, #and mode switch. Set in both mod_keycodes and self.modifier_bits #Try to assign Lock to Caps_Lock or Shift_Lock shift_lock_keycode = lookup_keycode('Shift_Lock') caps_lock_keycode = lookup_keycode('Caps_Lock') if shift_lock_keycode in mod_keycodes['Lock']: mod_keycodes['Shift_Lock'] = [shift_lock_keycode] self.modifier_bits['Shift_Lock'] = self.modifier_bits['Lock'] self.lock_meaning = 'Shift_Lock' elif caps_lock_keycode in mod_keycodes['Lock']: mod_keycodes['Caps_Lock'] = [caps_lock_keycode] self.modifier_bits['Caps_Lock'] = self.modifier_bits['Lock'] self.lock_meaning = 'Caps_Lock' else: self.lock_meaning = None logger.debug('Lock is bound to {0}'.format(self.lock_meaning)) #Need to find out which Mod# to use for Alt, Num_Lock, Super, and #Mode_switch num_lock_keycodes = [lookup_keycode('Num_Lock')] alt_keycodes = [lookup_keycode(i) for i in ['Alt_L', 'Alt_R']] super_keycodes = [lookup_keycode(i) for i in ['Super_L', 'Super_R']] mode_switch_keycodes = [lookup_keycode('Mode_switch')] #Detect Mod number for Alt, Num_Lock, and Super for name, keycodes in list(mod_keycodes.items()): for alt_key in alt_keycodes: if alt_key in keycodes: mod_keycodes['Alt'] = keycodes self.modifier_bits['Alt'] = self.modifier_bits[name] for num_lock_key in num_lock_keycodes: if num_lock_key in keycodes: mod_keycodes['Num_Lock'] = keycodes self.modifier_bits['Num_Lock'] = self.modifier_bits[name] for super_key in super_keycodes: if super_key in keycodes: mod_keycodes['Super'] = keycodes self.modifier_bits['Super'] = self.modifier_bits[name] for mode_switch_key in mode_switch_keycodes: if mode_switch_key in keycodes: mod_keycodes['Mode_switch'] = keycodes self.modifier_bits['Mode_switch'] = self.modifier_bits[ name] #Assign the mod_keycodes to a local variable for access self.modifier_keycodes = mod_keycodes self.all_mod_keycodes = all_mod_keycodes #TODO: Determine if this might fail, perhaps iterate through the mapping #and identify all keycodes with registered keypad keysyms? #Acquire the full list of keypad keycodes self.keypad_keycodes = [] keypad = [ 'Space', 'Tab', 'Enter', 'F1', 'F2', 'F3', 'F4', 'Home', 'Left', 'Up', 'Right', 'Down', 'Prior', 'Page_Up', 'Next', 'Page_Down', 'End', 'Begin', 'Insert', 'Delete', 'Equal', 'Multiply', 'Add', 'Separator', 'Subtract', 'Decimal', 'Divide', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' ] for keyname in keypad: keypad_keycode = self.lookup_character_keycode('KP_' + keyname) self.keypad_keycodes.append(keypad_keycode) def lookup_character_keycode(self, character): """ Looks up the keysym for the character then returns the keycode mapping for that keysym. """ keysym = self.string_to_keysym.get(character, 0) if keysym == 0: keysym = self.string_to_keysym.get(KEYSYMS[character], 0) return self.display.keysym_to_keycode(keysym) def get_translation_dicts(self): """ Returns dictionaries for the translation of keysyms to strings and from strings to keysyms. """ keysym_to_string_dict = {} string_to_keysym_dict = {} #XK loads latin1 and miscellany on its own; load latin2-4 and greek Xlib.XK.load_keysym_group('latin2') Xlib.XK.load_keysym_group('latin3') Xlib.XK.load_keysym_group('latin4') Xlib.XK.load_keysym_group('greek') #Make a standard dict and the inverted dict for string, keysym in Xlib.XK.__dict__.items(): if string.startswith('XK_'): string_to_keysym_dict[string[3:]] = keysym keysym_to_string_dict[keysym] = string[3:] return keysym_to_string_dict, string_to_keysym_dict def ascii_printable(self, keysym): """ If the keysym corresponds to a non-printable ascii character this will return False. If it is printable, then True will be returned. ascii 11 (vertical tab) and ascii 12 are printable, chr(11) and chr(12) will return '\x0b' and '\x0c' respectively. """ if 0 <= keysym < 9: return False elif 13 < keysym < 32: return False elif keysym > 126: return False else: return True
class PyKeyboardEvent(PyKeyboardEventMeta): """ The PyKeyboardEvent implementation for X11 systems (mostly linux). This allows one to listen for keyboard input. """ def __init__(self, display=None): self.display = Display(display) self.display2 = Display(display) self.ctx = self.display2.record_create_context( 0, [record.AllClients], [{ 'core_requests': (0, 0), 'core_replies': (0, 0), 'ext_requests': (0, 0, 0, 0), 'ext_replies': (0, 0, 0, 0), 'delivered_events': (0, 0), 'device_events': (X.KeyPress, X.KeyRelease), 'errors': (0, 0), 'client_started': False, 'client_died': False, }]) self.lock_meaning = None #Get these dictionaries for converting keysyms and strings self.keysym_to_string, self.string_to_keysym = self.get_translation_dicts() #Identify and register special groups of keys self.modifier_keycodes = {} self.all_mod_keycodes = [] self.keypad_keycodes = [] #self.configure_keys() #Direct access to the display's keycode-to-keysym array #print('Keycode to Keysym map') #for i in range(len(self.display._keymap_codes)): # print('{0}: {1}'.format(i, self.display._keymap_codes[i])) PyKeyboardEventMeta.__init__(self) def run(self): """Begin listening for keyboard input events.""" self.state = True if self.capture: self.display2.screen().root.grab_keyboard(True, X.KeyPressMask | X.KeyReleaseMask, X.GrabModeAsync, X.GrabModeAsync, 0, 0, X.CurrentTime) self.display2.record_enable_context(self.ctx, self.handler) self.display2.record_free_context(self.ctx) def stop(self): """Stop listening for keyboard input events.""" self.state = False self.display.record_disable_context(self.ctx) self.display.ungrab_keyboard(X.CurrentTime) self.display.flush() self.display2.record_disable_context(self.ctx) self.display2.ungrab_keyboard(X.CurrentTime) self.display2.flush() def handler(self, reply): """Upper level handler of keyboard events.""" data = reply.data while len(data): event, data = rq.EventField(None).parse_binary_value(data, self.display.display, None, None) if self.escape(event): # Quit if this returns True self.stop() else: self._tap(event) def _tap(self, event): keycode = event.detail press_bool = (event.type == X.KeyPress) #Detect modifier states from event.state for mod, bit in self.modifier_bits.items(): self.modifiers[mod] = event.state & bit if keycode in self.all_mod_keycodes: keysym = self.display.keycode_to_keysym(keycode, 0) character = self.keysym_to_string[keysym] else: character = self.lookup_char_from_keycode(keycode) #All key events get passed to self.tap() self.tap(keycode, character, press=press_bool) def lookup_char_from_keycode(self, keycode): """ This will conduct a lookup of the character or string associated with a given keycode. """ #TODO: Logic should be strictly adapted from X11's src/KeyBind.c #Right now the logic is based off of #http://tronche.com/gui/x/xlib/input/keyboard-encoding.html #Which I suspect is not the whole story and may likely cause bugs keysym_index = 0 #TODO: Display's Keysyms per keycode count? Do I need this? #If the Num_Lock is on, and the keycode corresponds to the keypad if self.modifiers['Num_Lock'] and keycode in self.keypad_keycodes: if self.modifiers['Shift'] or self.modifiers['Shift_Lock']: keysym_index = 0 else: keysym_index = 1 elif not self.modifiers['Shift'] and self.modifiers['Caps_Lock']: #Use the first keysym if uppercase or uncased #Use the uppercase keysym if the first is lowercase (second) keysym_index = 0 keysym = self.display.keycode_to_keysym(keycode, keysym_index) #TODO: Support Unicode, Greek, and special latin characters if keysym & 0x7f == keysym and chr(keysym) in 'abcdefghijklmnopqrstuvwxyz': keysym_index = 1 elif self.modifiers['Shift'] and self.modifiers['Caps_Lock']: keysym_index = 1 keysym = self.display.keycode_to_keysym(keycode, keysym_index) #TODO: Support Unicode, Greek, and special latin characters if keysym & 0x7f == keysym and chr(keysym) in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ': keysym_index = 0 elif self.modifiers['Shift'] or self.modifiers['Shift_Lock']: keysym_index = 1 if self.modifiers['Mode_switch']: keysym_index += 2 #Finally! Get the keysym keysym = self.display.keycode_to_keysym(keycode, keysym_index) #If the character is ascii printable, return that character if keysym & 0x7f == keysym and self.ascii_printable(keysym): return chr(keysym) #If the character was not printable, look for its name try: char = self.keysym_to_string[keysym] except KeyError: print('Unable to determine character.') print('Keycode: {0} KeySym {1}'.format(keycode, keysym)) return None else: return char def escape(self, event): if event.detail == self.lookup_character_keycode('Escape'): return True return False def configure_keys(self): """ This function locates the keycodes corresponding to special groups of keys and creates data structures of them for use by the PyKeyboardEvent instance; including the keypad keys and the modifiers. The keycodes pertaining to the keyboard modifiers are assigned by the modifier name in a dictionary. This dictionary can be accessed in the following manner: self.modifier_keycodes['Shift'] # All keycodes for Shift Masking It also assigns certain named modifiers (Alt, Num_Lock, Super), which may be dynamically assigned to Mod1 - Mod5 on different platforms. This should generally allow the user to do the following lookups on any system: self.modifier_keycodes['Alt'] # All keycodes for Alt Masking self.modifiers['Alt'] # State of Alt mask, non-zero if "ON" """ modifier_mapping = self.display.get_modifier_mapping() all_mod_keycodes = [] mod_keycodes = {} mod_index = [('Shift', X.ShiftMapIndex), ('Lock', X.LockMapIndex), ('Control', X.ControlMapIndex), ('Mod1', X.Mod1MapIndex), ('Mod2', X.Mod2MapIndex), ('Mod3', X.Mod3MapIndex), ('Mod4', X.Mod4MapIndex), ('Mod5', X.Mod5MapIndex)] #This gets the list of all keycodes per Modifier, assigns to name for name, index in mod_index: codes = [v for v in list(modifier_mapping[index]) if v] mod_keycodes[name] = codes all_mod_keycodes += codes def lookup_keycode(string): keysym = self.string_to_keysym[string] return self.display.keysym_to_keycode(keysym) #Dynamically assign Lock to Caps_Lock, Shift_Lock, Alt, Num_Lock, Super, #and mode switch. Set in both mod_keycodes and self.modifier_bits #Try to assign Lock to Caps_Lock or Shift_Lock shift_lock_keycode = lookup_keycode('Shift_Lock') caps_lock_keycode = lookup_keycode('Caps_Lock') if shift_lock_keycode in mod_keycodes['Lock']: mod_keycodes['Shift_Lock'] = [shift_lock_keycode] self.modifier_bits['Shift_Lock'] = self.modifier_bits['Lock'] self.lock_meaning = 'Shift_Lock' elif caps_lock_keycode in mod_keycodes['Lock']: mod_keycodes['Caps_Lock'] = [caps_lock_keycode] self.modifier_bits['Caps_Lock'] = self.modifier_bits['Lock'] self.lock_meaning = 'Caps_Lock' else: self.lock_meaning = None #print('Lock is bound to {0}'.format(self.lock_meaning)) #Need to find out which Mod# to use for Alt, Num_Lock, Super, and #Mode_switch num_lock_keycodes = [lookup_keycode('Num_Lock')] alt_keycodes = [lookup_keycode(i) for i in ['Alt_L', 'Alt_R']] super_keycodes = [lookup_keycode(i) for i in ['Super_L', 'Super_R']] mode_switch_keycodes = [lookup_keycode('Mode_switch')] #Detect Mod number for Alt, Num_Lock, and Super for name, keycodes in list(mod_keycodes.items()): for alt_key in alt_keycodes: if alt_key in keycodes: mod_keycodes['Alt'] = keycodes self.modifier_bits['Alt'] = self.modifier_bits[name] for num_lock_key in num_lock_keycodes: if num_lock_key in keycodes: mod_keycodes['Num_Lock'] = keycodes self.modifier_bits['Num_Lock'] = self.modifier_bits[name] for super_key in super_keycodes: if super_key in keycodes: mod_keycodes['Super'] = keycodes self.modifier_bits['Super'] = self.modifier_bits[name] for mode_switch_key in mode_switch_keycodes: if mode_switch_key in keycodes: mod_keycodes['Mode_switch'] = keycodes self.modifier_bits['Mode_switch'] = self.modifier_bits[name] #Assign the mod_keycodes to a local variable for access self.modifier_keycodes = mod_keycodes self.all_mod_keycodes = all_mod_keycodes #TODO: Determine if this might fail, perhaps iterate through the mapping #and identify all keycodes with registered keypad keysyms? #Acquire the full list of keypad keycodes self.keypad_keycodes = [] keypad = ['Space', 'Tab', 'Enter', 'F1', 'F2', 'F3', 'F4', 'Home', 'Left', 'Up', 'Right', 'Down', 'Prior', 'Page_Up', 'Next', 'Page_Down', 'End', 'Begin', 'Insert', 'Delete', 'Equal', 'Multiply', 'Add', 'Separator', 'Subtract', 'Decimal', 'Divide', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'] for keyname in keypad: keypad_keycode = self.lookup_character_keycode('KP_' + keyname) self.keypad_keycodes.append(keypad_keycode) def lookup_character_keycode(self, character): """ Looks up the keysym for the character then returns the keycode mapping for that keysym. """ keysym = self.string_to_keysym.get(character, 0) if keysym == 0: keysym = self.string_to_keysym.get(special_X_keysyms[character], 0) return self.display.keysym_to_keycode(keysym) def get_translation_dicts(self): """ Returns dictionaries for the translation of keysyms to strings and from strings to keysyms. """ keysym_to_string_dict = {} string_to_keysym_dict = {} #XK loads latin1 and miscellany on its own; load latin2-4 and greek Xlib.XK.load_keysym_group('latin2') Xlib.XK.load_keysym_group('latin3') Xlib.XK.load_keysym_group('latin4') Xlib.XK.load_keysym_group('greek') #Make a standard dict and the inverted dict for string, keysym in Xlib.XK.__dict__.items(): if string.startswith('XK_'): string_to_keysym_dict[string[3:]] = keysym keysym_to_string_dict[keysym] = string[3:] return keysym_to_string_dict, string_to_keysym_dict def ascii_printable(self, keysym): """ If the keysym corresponds to a non-printable ascii character this will return False. If it is printable, then True will be returned. ascii 11 (vertical tab) and ascii 12 are printable, chr(11) and chr(12) will return '\x0b' and '\x0c' respectively. """ if 0 <= keysym < 9: return False elif 13 < keysym < 32: return False elif keysym > 126: return False else: return True
class X11(ShortcutManager, Thread): def __init__(self): ShortcutManager.__init__(self) Thread.__init__(self) self.setDaemon(True) self.display = Display () self.screen = self.display.screen () self.root = self.screen.root self.root.change_attributes(event_mask=X.KeyPress|X.KeyRelease|X.PropertyChangeMask) self.key_conf_to_key = dict() self.active = False def init(self): """Start the main loop.""" self.active = True self.start() def run(self): """Main loop It will handle the user combination key, check if its associated to a pre-configured shortcut and then execute the right action to that shortcut. """ while self.active: event = self.root.display.next_event() if event.type == X.KeyPress: for key_conf in self.key_conf_to_key.keys(): key, mask = self.key_conf_to_key[key_conf] if event.detail == key and \ event.state == mask: if key_conf == "quick_search": gtk.gdk.threads_enter() self.emit("quick_search") gtk.gdk.threads_leave() elif key_conf == "scan_selection": word = get_primary_selection() if word: gtk.gdk.threads_enter() self.emit("scan_selection", word) gtk.gdk.threads_leave() def set_shortcut(self, key_conf, key, mask): """ """ key = self.display.keysym_to_keycode(key) self.root.grab_key(key, mask, 1, X.GrabModeAsync, X.GrabModeAsync) self.key_conf_to_key[key_conf] = (key, mask) def unset_shortcut(self, key, mask): """ """ key = self.display.keysym_to_keycode(key) self.root.ungrab_key(key, mask) def stop(self): """Stop the main loop""" self.active = False self.unset_keys() def unset_keys(self): """Unset all shortcuts.""" for key_conf in self.key_conf_to_key.keys(): key, mask = self.key_conf_to_key[key_conf] self.unset_shortcut(key, mask)
class GlobalHotkeyManagerX11(GlobalHotkeyManagerBase): def __init__(self): self._text_to_native = { '-': 'minus', '+': 'plus', '=': 'equal', '[': 'bracketleft', ']': 'bracketright', '|': 'bar', ';': 'semicolon', '\'': 'quoteright', ',': 'comma', '.': 'period', '/': 'slash', '\\': 'backslash', '`': 'asciitilde', } GlobalHotkeyManagerBase.__init__(self) self._error = False self._display = Display() self._poller = X11EventPoller() self._poller.keyPressed.connect(self.x11_event) self._poller.start() # Check if the extension is present if not self._display.has_extension('RECORD'): raise Exception('RECORD extension not found') def destroy(self): # self._poller.destroy() # should destroy event poller thread, no clue how pass # noinspection PyUnusedLocal def x11_event(self, event, data): if event.type == X.KeyPress: key = (event.detail, int(event.state) & (X.ShiftMask | X.ControlMask | X.Mod1Mask | X.Mod4Mask)) if key in self.shortcuts: # noinspection PyCallByClass,PyTypeChecker QTimer.singleShot(0, self.shortcuts[key]) return False def _native_modifiers(self, modifiers): # ShiftMask, LockMask, ControlMask, Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, and Mod5Mask native = 0 modifiers = int(modifiers) if modifiers & Qt.ShiftModifier: native |= X.ShiftMask if modifiers & Qt.ControlModifier: native |= X.ControlMask if modifiers & Qt.AltModifier: native |= X.Mod1Mask if modifiers & Qt.MetaModifier: native |= X.Mod4Mask # TODO: resolve these? # if (modifiers & Qt.MetaModifier) # if (modifiers & Qt.KeypadModifier) # if (modifiers & Qt.GroupSwitchModifier) return native def _native_keycode(self, key): keysym = QKeySequence(key).toString() if keysym in self._text_to_native: keysym = self._text_to_native[keysym] return self._display.keysym_to_keycode(XK.string_to_keysym(keysym)) # noinspection PyUnusedLocal def _on_error(self, e, data): if e.code in (X.BadAccess, X.BadValue, X.BadWindow): if e.major_opcode in (33, 34): # X_GrabKey, X_UngrabKey self._error = True # char errstr[256]; # XGetErrorText(dpy, err->error_code, errstr, 256); return 0 def _register_shortcut(self, receiver, native_key, native_mods, winid=None): window = self._display.screen().root self._error = False window.grab_key(native_key, native_mods, True, X.GrabModeAsync, X.GrabModeAsync, self._on_error) self._display.sync() if not self._error: self.shortcuts[(native_key, native_mods)] = receiver return not self._error def _unregister_shortcut(self, native_key, native_mods, window_id): display = Display() window = display.screen().root self._error = False window.ungrab_key(native_key, native_mods, self._on_error) display.sync() try: del self.shortcuts[(native_key, native_mods)] except KeyError: pass return not self._error
class QuickTileApp(object): """The basic Glib application itself.""" keybinds_failed = False def __init__(self, wm, commands, keys=None, modkeys=None): """Populate the instance variables. @param keys: A dict mapping X11 keysyms to L{CommandRegistry} command names. @param modkeys: A modifier mask to prefix to all keybindings. @type wm: The L{WindowManager} instance to use. @type keys: C{dict} @type modkeys: C{str} """ self.wm = wm self.commands = commands self._keys = keys or {} self._modkeys = modkeys or 0 def _init_dbus(self): """Set up dbus-python components in the Glib event loop @todo 1.0.0: Retire the C{doCommand} name. (API-breaking change) """ class QuickTile(dbus.service.Object): def __init__(self): dbus.service.Object.__init__(self, sessBus, '/com/ssokolow/QuickTile') @dbus.service.method(dbus_interface='com.ssokolow.QuickTile', in_signature='s', out_signature='b') def doCommand(self, command): return self.commands.call(command, wm) self.dbusName = dbus.service.BusName("com.ssokolow.QuickTile", sessBus) self.dbusObj = QuickTile() def _init_xlib(self): """Set up python-xlib components in the Glib event loop Source: U{http://www.larsen-b.com/Article/184.html} """ self.xdisp = Display() self.xroot = self.xdisp.screen().root # We want to receive KeyPress events self.xroot.change_attributes(event_mask=X.KeyPressMask) # unrecognized shortkeys now will be looked up in a hardcoded dict # and replaced by valid names like ',' -> 'comma' # while generating the self.keys dict self.keys = dict() for key in self._keys: transKey = key if key in KEYLOOKUP: transKey = KEYLOOKUP[key] code = self.xdisp.keysym_to_keycode(string_to_keysym(transKey)) self.keys[code] = self._keys[key] # Resolve strings to X11 mask constants for the modifier mask try: modmask = reduce(operator.ior, [getattr(X, "%sMask" % x) for x in self._modkeys]) except Exception, err: logging.error("Error while resolving modifier key mask: %s", err) logging.error("Not binding keys for safety reasons. " "(eg. What if Ctrl+C got bound?)") modmask = 0 else:
from Xlib.display import Display from Xlib import X, XK import os import subprocess double_borders = True single_border = False border_colour = "618158" mouse_move = "drag" dpy = Display() # ascend window dpy.screen().root.grab_key(dpy.keysym_to_keycode(XK.string_to_keysym("A")), X.Mod4Mask, 1, X.GrabModeAsync, X.GrabModeAsync) # kill window dpy.screen().root.grab_key(dpy.keysym_to_keycode(XK.string_to_keysym("Q")), X.Mod4Mask, 1, X.GrabModeAsync, X.GrabModeAsync) # draw terminal dpy.screen().root.grab_key(dpy.keysym_to_keycode(XK.string_to_keysym("Z")), X.Mod4Mask, 1, X.GrabModeAsync, X.GrabModeAsync) # drag window dpy.screen().root.grab_button( 1, X.Mod1Mask, 1, X.ButtonPressMask | X.ButtonReleaseMask | X.PointerMotionMask, X.GrabModeAsync, X.GrabModeAsync, X.NONE, X.NONE) dpy.screen().root.grab_button( 1, X.Mod1Mask, 1, X.ButtonPressMask | X.ButtonReleaseMask | X.PointerMotionMask,
_display.sync() # Taken from PyKeyboard's ctor function. _display = Display(os.environ['DISPLAY']) """ Information for keyboardMapping derived from PyKeyboard's special_key_assignment() function. The *KB dictionaries in pyautogui map a string that can be passed to keyDown(), keyUp(), or press() into the code used for the OS-specific keyboard function. They should always be lowercase, and the same keys should be used across all OSes.""" keyboardMapping = dict([(key, None) for key in pyautogui.KEY_NAMES]) keyboardMapping.update({ 'backspace': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('BackSpace')), '\b': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('BackSpace')), 'tab': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Tab')), 'enter': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Return')), 'return': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Return')), 'shift': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Shift_L')), 'ctrl': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Control_L')), 'alt': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Alt_L')), 'pause': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Pause')), 'capslock': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Caps_Lock')), 'esc': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Escape')), 'escape': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Escape')), 'pgup': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Page_Up')), 'pgdn': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Page_Down')), 'pageup': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Page_Up')), 'pagedown': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Page_Down')),
class X11(ShortcutManager, Thread): def __init__(self): ShortcutManager.__init__(self) Thread.__init__(self) self.setDaemon(True) self.display = Display() self.screen = self.display.screen() self.root = self.screen.root self.root.change_attributes(event_mask=X.KeyPress | X.KeyRelease | X.PropertyChangeMask) self.key_conf_to_key = dict() self.active = False def init(self): """Start the main loop.""" self.active = True self.start() def run(self): """Main loop It will handle the user combination key, check if its associated to a pre-configured shortcut and then execute the right action to that shortcut. """ while self.active: event = self.root.display.next_event() if event.type == X.KeyPress: for key_conf in self.key_conf_to_key.keys(): key, mask = self.key_conf_to_key[key_conf] if event.detail == key and \ event.state == mask: if key_conf == "quick_search": gtk.gdk.threads_enter() self.emit("quick_search") gtk.gdk.threads_leave() elif key_conf == "scan_selection": word = get_primary_selection() if word: gtk.gdk.threads_enter() self.emit("scan_selection", word) gtk.gdk.threads_leave() def set_shortcut(self, key_conf, key, mask): """ """ key = self.display.keysym_to_keycode(key) self.root.grab_key(key, mask, 1, X.GrabModeAsync, X.GrabModeAsync) self.key_conf_to_key[key_conf] = (key, mask) def unset_shortcut(self, key, mask): """ """ key = self.display.keysym_to_keycode(key) self.root.ungrab_key(key, mask) def stop(self): """Stop the main loop""" self.active = False self.unset_keys() def unset_keys(self): """Unset all shortcuts.""" for key_conf in self.key_conf_to_key.keys(): key, mask = self.key_conf_to_key[key_conf] self.unset_shortcut(key, mask)
# NotSoTinyWM is written by Aleksi Torhamo <*****@*****.**>. # It is based on TinyWM, which is written by Nick Welch <*****@*****.**>. # # This software is in the public domain and is provided AS IS, with NO WARRANTY. from Xlib.display import Display from Xlib import X, XK from util import * dpy = Display() root = dpy.screen().root event_mask = X.ButtonPressMask|X.ButtonReleaseMask|X.PointerMotionMask root.grab_key(dpy.keysym_to_keycode(XK.string_to_keysym("F1")), X.Mod1Mask, 1, X.GrabModeAsync, X.GrabModeAsync) root.grab_button(1, X.Mod1Mask, 1, event_mask, X.GrabModeAsync, X.GrabModeAsync, X.NONE, X.NONE) root.grab_button(3, X.Mod1Mask, 1, event_mask, X.GrabModeAsync, X.GrabModeAsync, X.NONE, X.NONE) start = None while 1: ev = dpy.next_event() if ev.type == X.KeyPress and ev.child != X.NONE: ev.child.configure(stack_mode = X.Above) elif ev.type == X.ButtonPress and ev.child != X.NONE: attr = ev.child.get_geometry() start = ev elif ev.type == X.MotionNotify and start: ev = compress_motion(dpy, ev)
class GlobalKey(threading.Thread): def __init__(self): super(GlobalKey, self).__init__() self.setDaemon(True) self.disp = Display() self.root = self.disp.screen().root self._binding_map = {} self.stop = False self.known_modifiers_mask = 0 x_modifiers = (X.ControlMask, X.ShiftMask, X.Mod1Mask, X.Mod2Mask, X.Mod3Mask, X.Mod4Mask, X.Mod5Mask, ) for mod in x_modifiers: self.known_modifiers_mask |= mod def bind(self, binding_string, action, weak=False): keyval, modifiers = self.parse_keystring(binding_string) keycode = self.disp.keysym_to_keycode(keyval) if weak: action = saferef.Ref(action) # Binding key. self._binding_map[(keycode, modifiers)] = action num_lock_modifiers = modifiers | X.Mod2Mask self._binding_map[(keycode, num_lock_modifiers)] = action # Restart grab keybinding. self.regrab() def unbind(self, binding_string): ''' ''' keyval, modifiers = self.parse_keystring(binding_string) keycode = self.disp.keysym_to_keycode(keyval) num_lock_modifiers = modifiers | X.Mod2Mask # Remove keybinding from binding map. regrab_flag = False if self._binding_map.has_key((keycode, modifiers)): del self._binding_map[(keycode, modifiers)] regrab_flag = True # Try remove key binding (with Num-Lock mask) from binding map. if self._binding_map.has_key((keycode, num_lock_modifiers)): del self._binding_map[(keycode, num_lock_modifiers)] regrab_flag = True if regrab_flag: self.regrab() def grab(self): ''' Grab key. ''' for (keycode, modifiers) in self._binding_map.keys(): try: self.root.grab_key(keycode, int(modifiers), True, X.GrabModeAsync, X.GrabModeSync) except Exception, e: print "function grab got error: %s" % (e)
class PyKeyboard(PyKeyboardMeta): """ The PyKeyboard implementation for X11 systems (mostly linux). This allows one to simulate keyboard input. """ def __init__(self, display=None): PyKeyboardMeta.__init__(self) self.display = Display(display) self.display2 = Display(display) self.special_key_assignment() def press_key(self, character=''): """ Press a given character key. Also works with character keycodes as integers, but not keysyms. """ try: # Detect uppercase or shifted character shifted = self.is_char_shifted(character) except AttributeError: # Handle the case of integer keycode argument fake_input(self.display, X.KeyPress, character) self.display.sync() else: if shifted: fake_input(self.display, X.KeyPress, self.shift_key) char_val = self.lookup_character_value(character) fake_input(self.display, X.KeyPress, char_val) self.display.sync() def release_key(self, character=''): """ Release a given character key. Also works with character keycodes as integers, but not keysyms. """ try: # Detect uppercase or shifted character shifted = self.is_char_shifted(character) except AttributeError: # Handle the case of integer keycode argument fake_input(self.display, X.KeyRelease, character) self.display.sync() else: if shifted: fake_input(self.display, X.KeyRelease, self.shift_key) char_val = self.lookup_character_value(character) fake_input(self.display, X.KeyRelease, char_val) self.display.sync() def tap_key(self, character='', repeat=1): """ Press and release a given character key n times. Also works with character keycodes as integers, but not keysyms. """ for i in xrange(repeat): self.press_key(character) self.release_key(character) def type_string(self, char_string, char_interval=0): """A convenience method for typing longer strings of characters.""" for i in char_string: time.sleep(char_interval) self.tap_key(i) def is_char_shifted(self, character): """Returns True if the key character is uppercase or shifted.""" if character.isupper(): return True if character in '<>?:"{}|~!@#$%^&*()_+': return True return False def special_key_assignment(self): """ Determines the keycodes for common special keys on the keyboard. These are integer values and can be passed to the other key methods. Generally speaking, these are non-printable codes. """ #This set of keys compiled using the X11 keysymdef.h file as reference #They comprise a relatively universal set of keys, though there may be #exceptions which may come up for other OSes and vendors. Countless #special cases exist which are not handled here, but may be extended. #TTY Function Keys self.backspace_key = self.lookup_character_value('BackSpace') self.tab_key = self.lookup_character_value('Tab') self.linefeed_key = self.lookup_character_value('Linefeed') self.clear_key = self.lookup_character_value('Clear') self.return_key = self.lookup_character_value('Return') self.enter_key = self.return_key # Because many keyboards call it "Enter" self.pause_key = self.lookup_character_value('Pause') self.scroll_lock_key = self.lookup_character_value('Scroll_Lock') self.sys_req_key = self.lookup_character_value('Sys_Req') self.escape_key = self.lookup_character_value('Escape') self.delete_key = self.lookup_character_value('Delete') #Modifier Keys self.shift_l_key = self.lookup_character_value('Shift_L') self.shift_r_key = self.lookup_character_value('Shift_R') self.shift_key = self.shift_l_key # Default Shift is left Shift self.alt_l_key = self.lookup_character_value('Alt_L') self.alt_r_key = self.lookup_character_value('Alt_R') self.alt_key = self.alt_l_key # Default Alt is left Alt self.control_l_key = self.lookup_character_value('Control_L') self.control_r_key = self.lookup_character_value('Control_R') self.control_key = self.control_l_key # Default Ctrl is left Ctrl self.caps_lock_key = self.lookup_character_value('Caps_Lock') self.shift_lock_key = self.lookup_character_value('Shift_Lock') self.meta_l_key = self.lookup_character_value('Meta_L') self.meta_r_key = self.lookup_character_value('Meta_R') self.super_l_key = self.lookup_character_value('Super_L') self.super_r_key = self.lookup_character_value('Super_R') self.hyper_l_key = self.lookup_character_value('Hyper_L') self.hyper_r_key = self.lookup_character_value('Hyper_R') #Cursor Control and Motion self.home_key = self.lookup_character_value('Home') self.up_key = self.lookup_character_value('Up') self.down_key = self.lookup_character_value('Down') self.left_key = self.lookup_character_value('Left') self.right_key = self.lookup_character_value('Right') self.end_key = self.lookup_character_value('End') self.begin_key = self.lookup_character_value('Begin') self.page_up_key = self.lookup_character_value('Page_Up') self.page_down_key = self.lookup_character_value('Page_Down') self.prior_key = self.lookup_character_value('Prior') self.next_key = self.lookup_character_value('Next') #Misc Functions self.select_key = self.lookup_character_value('Select') self.print_key = self.lookup_character_value('Print') self.execute_key = self.lookup_character_value('Execute') self.insert_key = self.lookup_character_value('Insert') self.undo_key = self.lookup_character_value('Undo') self.redo_key = self.lookup_character_value('Redo') self.menu_key = self.lookup_character_value('Menu') self.find_key = self.lookup_character_value('Find') self.cancel_key = self.lookup_character_value('Cancel') self.help_key = self.lookup_character_value('Help') self.break_key = self.lookup_character_value('Break') self.mode_switch_key = self.lookup_character_value('Mode_switch') self.script_switch_key = self.lookup_character_value('script_switch') self.num_lock_key = self.lookup_character_value('Num_Lock') #Keypad Keys: Dictionary structure keypad = [ 'Space', 'Tab', 'Enter', 'F1', 'F2', 'F3', 'F4', 'Home', 'Left', 'Up', 'Right', 'Down', 'Prior', 'Page_Up', 'Next', 'Page_Down', 'End', 'Begin', 'Insert', 'Delete', 'Equal', 'Multiply', 'Add', 'Separator', 'Subtract', 'Decimal', 'Divide', 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ] self.keypad_keys = { k: self.lookup_character_value('KP_' + str(k)) for k in keypad } self.numpad_keys = self.keypad_keys #Function Keys/ Auxilliary Keys #FKeys self.function_keys = [None] + [ self.lookup_character_value('F' + str(i)) for i in xrange(1, 36) ] #LKeys self.l_keys = [None] + [ self.lookup_character_value('L' + str(i)) for i in xrange(1, 11) ] #RKeys self.r_keys = [None] + [ self.lookup_character_value('R' + str(i)) for i in xrange(1, 16) ] def lookup_character_value(self, character): """ Looks up the keysym for the character then returns the keycode mapping for that keysym. """ ch_keysym = string_to_keysym(character) if ch_keysym == 0: ch_keysym = string_to_keysym(special_X_keysyms[character]) return self.display.keysym_to_keycode(ch_keysym)
# TinyWM is written by Nick Welch <*****@*****.**> in 2005 & 2011. # # This software is in the public domain # and is provided AS IS, with NO WARRANTY. from Xlib.display import Display from Xlib import X, XK dpy = Display() dpy.screen().root.grab_key(dpy.keysym_to_keycode(XK.string_to_keysym("F1")), X.Mod1Mask, 1, X.GrabModeAsync, X.GrabModeAsync) dpy.screen().root.grab_button(1, X.Mod1Mask, 1, X.ButtonPressMask|X.ButtonReleaseMask|X.PointerMotionMask, X.GrabModeAsync, X.GrabModeAsync, X.NONE, X.NONE) dpy.screen().root.grab_button(3, X.Mod1Mask, 1, X.ButtonPressMask|X.ButtonReleaseMask|X.PointerMotionMask, X.GrabModeAsync, X.GrabModeAsync, X.NONE, X.NONE) start = None while 1: ev = dpy.next_event() if ev.type == X.KeyPress and ev.child != X.NONE: ev.child.configure(stack_mode = X.Above) elif ev.type == X.ButtonPress and ev.child != X.NONE: attr = ev.child.get_geometry() start = ev elif ev.type == X.MotionNotify and start: xdiff = ev.root_x - start.root_x ydiff = ev.root_y - start.root_y start.child.configure( x = attr.x + (start.detail == 1 and xdiff or 0), y = attr.y + (start.detail == 1 and ydiff or 0),
elif not horizontal and amount >= 0: button = 5 # down else: return for _ in range(abs(amount)): fake_input(_display, X.ButtonPress, button) _display.sync() fake_input(_display, X.ButtonRelease, button) _display.sync() _display = Display(":0") # repeat held keys _display.change_keyboard_control(auto_repeat_mode=X.AutoRepeatModeOn) key_codes = { "KEY_ESC": _display.keysym_to_keycode(string_to_keysym("Escape")), "KEY_1": _display.keysym_to_keycode(string_to_keysym("1")), "KEY_2": _display.keysym_to_keycode(string_to_keysym("2")), "KEY_3": _display.keysym_to_keycode(string_to_keysym("3")), "KEY_4": _display.keysym_to_keycode(string_to_keysym("4")), "KEY_5": _display.keysym_to_keycode(string_to_keysym("5")), "KEY_6": _display.keysym_to_keycode(string_to_keysym("6")), "KEY_7": _display.keysym_to_keycode(string_to_keysym("7")), "KEY_8": _display.keysym_to_keycode(string_to_keysym("8")), "KEY_9": _display.keysym_to_keycode(string_to_keysym("9")), "KEY_0": _display.keysym_to_keycode(string_to_keysym("0")), "KEY_MINUS": _display.keysym_to_keycode(string_to_keysym("minus")), "KEY_EQUAL": _display.keysym_to_keycode(string_to_keysym("equal")), "KEY_BACKSPACE": _display.keysym_to_keycode(string_to_keysym("Backspace")), "KEY_TAB": _display.keysym_to_keycode(string_to_keysym("Tab")), "KEY_Q": _display.keysym_to_keycode(string_to_keysym("q")),
# TinyWM is written by Nick Welch <*****@*****.**> in 2005 & 2011. # # This software is in the public domain # and is provided AS IS, with NO WARRANTY. from Xlib.display import Display from Xlib import X, XK dpy = Display() dpy.screen().root.grab_key(dpy.keysym_to_keycode(XK.string_to_keysym("F1")), X.Mod1Mask, 1, X.GrabModeAsync, X.GrabModeAsync) dpy.screen().root.grab_button(1, X.Mod1Mask, 1, X.ButtonPressMask|X.ButtonReleaseMask|X.PointerMotionMask, X.GrabModeAsync, X.GrabModeAsync, X.NONE, X.NONE) dpy.screen().root.grab_button(3, X.Mod1Mask, 1, X.ButtonPressMask|X.ButtonReleaseMask|X.PointerMotionMask, X.GrabModeAsync, X.GrabModeAsync, X.NONE, X.NONE) start = None while 1: ev = dpy.next_event() if ev.type == X.KeyPress and ev.child != X.NONE: ev.child.configure(stack_mode = X.Above) elif ev.type == X.ButtonPress and ev.child != X.NONE: attr = ev.child.get_geometry() start = ev elif ev.type == X.MotionNotify and start: xdiff = ev.root_x - start.root_x ydiff = ev.root_y - start.root_y start.child.configure( x = attr.x + (xdiff if start.detail == 1 else 0), y = attr.y + (ydiff if start.detail == 1 else 0),
class SystemHotkey(MixIn): ''' Cross platform System Wide Hotkeys Modifer oder doesn't matter, e.g binding to control shift k is the same as shift control k, limitation of the keyboard and operating systems not this library ''' hk_ref = {} def __init__(self, consumer='callback', check_queue_interval=0.01, use_xlib=False, conn=None, verbose=False): ''' if the consumer param = 'callback', -> All hotkeys will require a callback function - Experimental! - Otherwise set consumer to a function to hanlde the event. parameters sent will be - event, hotkey, callbacks event is the xwindow/microsoft keyboard eventm hotkey is a tuple, callback is any info that you registerd with the hotkey check_queue_interval is in seconds and sets the sleep time on checking the queue for hotkey presses set use_xlib to true to use the xlib python bindings (GPL) instead of the xcb ones (BSD) You can pass an exisiting X display or connection using the conn keyword, otherwise one will be created for you. ''' # Changes the class methods to point to differenct functions # Depening on the operating system and library used # Consumer can be set to a function also, which will be sent the event # as well as the key and mask already broken out # Last option for consumer is False, then you have to listen to the queue yourself # data_queue self.verbose = verbose self.use_xlib = use_xlib self.consumer = consumer self.check_queue_interval = check_queue_interval def mark_event_type(event): # event gets an event_type attribute so the user has a portiabble way # actually on windows as far as i know you dont have the option of binding on keypress or release so... # anyway ahve to check it but for now u dont! if os.name == 'posix': if self.use_xlib: if event.type == X.KeyPress: event.event_type = 'keypress' elif event.type == X.KeyRelease: event.event_type = 'keyrelease' else: if isinstance(event, xproto.KeyPressEvent): event.event_type = 'keypress' if isinstance(event, xproto.KeyReleaseEvent): event.event_type = 'keyrelease' else: event.event_type = 'keypress' return event self.data_queue = queue.Queue() if os.name == 'nt': self.hk_action_queue = queue.Queue() self.modders = win_modders self._the_grab = self._nt_the_grab self.get_keycode = self._nt_get_keycode self._get_keysym = self._nt_get_keysym thread.start_new_thread(self._nt_wait,(),) elif use_xlib: # Use the python-xlib library bindings, GPL License self.modders = xlib_modifiers self.trivial_mods = xlib_trivial_mods self._the_grab = self._xlib_the_grab self.get_keycode = self._xlib_get_keycode self._get_keysym = self._xlib_get_keysym if not conn: self.disp = Display() else: self.disp = conn self.xRoot = self.disp.screen().root self.xRoot.change_attributes(event_mask=X.KeyPressMask) thread.start_new_thread(self._xlib_wait,(),) else: # Using xcb and the xcffib python bindings Apache 2 http://stackoverflow.com/questions/40100/apache-license-vs-bsd-vs-mit self.modders = xcb_modifiers self.trivial_mods = xcb_trivial_mods self._the_grab = self._xcb_the_grab self.get_keycode = self._xcb_get_keycode self._get_keysym = self._xcb_get_keysym if not conn: self.conn = xcffib.connect() else: self.conn = conn self.root = self.conn.get_setup().roots[0].root thread.start_new_thread(self._xcb_wait,(),) if consumer == 'callback': if self.verbose: print('In Callback') def thread_me(): while 1: time.sleep(self.check_queue_interval) try: event = self.data_queue.get(block=False) except queue.Empty: pass else: event = mark_event_type(event) hotkey = self.parse_event(event) #~ for cb in self.get_callback(hotkey, event.event_type): #when i was using the keypress / keyrelease shit for cb in self.get_callback(hotkey): if event.event_type == 'keypress': if self.verbose: print('calling ', repr(cb)) cb(event) # TBD either throw these up in a thread, or pass in a queue to be put onto thread.start_new_thread(thread_me,(),) elif callable(consumer): def thread_me(): while 1: time.sleep(self.check_queue_interval) try: event = self.data_queue.get(block=False) except queue.Empty: pass else: hotkey = self.parse_event(mark_event_type(event)) if event.event_type == 'keypress': args = [cb for cb in self.get_callback(hotkey)] #~ callbacks = [cb for cb in self.get_callback(hotkey, event.event_type)] consumer(event, hotkey, args) thread.start_new_thread(thread_me,(),) else: print('You need to handle grabbing events yourself!') def _xlib_wait(self): # Pushes Event onto queue while 1: event = self.xRoot.display.next_event() self.data_queue.put(event) def _xcb_wait(self): # Pushes Event onto queue while 1: event = self.conn.wait_for_event() self.data_queue.put(event) def _nt_wait(self): # Pushes Event onto queue # I don't understand the windows msg system # I can only get hotkeys to work if they are registeed in the # Thread that is listening for them. # So any changes to the hotkeys have to be signaled to be done # By the thread. (including unregistering) # A new queue is checked and runs functions, either adding # or removing new hotkeys, then the windows msg queue is checked msg = ctypes.wintypes.MSG () while 1: try: remove_or_add = self.hk_action_queue.get(block=False) except queue.Empty: pass else: remove_or_add() # Checking the windows message Queue if user32.PeekMessageA(byref(msg), 0, 0, 0, PM_REMOVE): if msg.message == win32con.WM_HOTKEY: self.data_queue.put(msg) else: print('some other message') time.sleep(self.check_queue_interval) def _nt_get_keycode(self, key, disp=None): return vk_codes[key] def _nt_get_keysym(self, keycode): for key, value in vk_codes.items(): if value == keycode: return key def _nt_the_grab(self, keycode, masks, id, root=None): if not user32.RegisterHotKey(None, id, masks, keycode): raise RegisterError('The bind is probably already in use elsewhere on the system') #TBD RAISE RROR ON LINUX SYSTEMS def _xlib_get_keycode(self, key) : keysym = XK.string_to_keysym(key) if keysym == 0: keysym = XK.string_to_keysym(special_X_keysyms[key]) keycode = self.disp.keysym_to_keycode(keysym) return keycode def _xlib_get_keysym(self, keycode, i=0): keysym = self.disp.keycode_to_keysym(keycode, i) return keybind.keysym_strings.get(keysym, [None])[0] #https://lists.gnu.org/archive/html/stumpwm-devel/2006-04/msg00033.html def _xlib_the_grab(self, keycode, masks): #TBD error handlig http://tronche.com/gui/x/xlib/event-handling/protocol-errors/default-handlers.html #~ try: self.xRoot.grab_key(keycode, masks, 1, X.GrabModeAsync, X.GrabModeAsync) #~ except Xlib.error.BadAccess: #~ raise RegisterError('The bind is probably already in use elsewhere on the system') def _xcb_the_grab(self, keycode, masks): try: for triv_mod in self.trivial_mods: self.conn.core.GrabKeyChecked(True, self.root, triv_mod | masks, keycode, xproto.GrabMode.Async, xproto.GrabMode.Async).check() except xproto.AccessError: raise RegisterError('The bind is probably already in use elsewhere on the system') def _xcb_get_keycode(self, key): return keybind.lookup_string(key) def _xcb_get_keysym(self, keycode, i=0): keysym = keybind.get_keysym(keycode, i) return keybind.keysym_strings.get(keysym, [None])[0]
class EventManager(object): POINTER_MIN_MOVE = 2.0 # px ZOOM_THRESHOLD = 10 # mm ZOOM_FUNCTION_DURATION = .5 # seconds ZOOM_FUNCTION_RESET_TIMEOUT = 2 # seconds FUNCTIONS_DEFAULT_DURATION = .5 # seconds def __init__(self): self._display = Display() self._run_times = {} self._last_pointer_move = 0 self._last_zoom = 0 self._last_zoom_distance = -1 self.s = self._display.screen() self.root = self.s.root def scroll_up(self): self._press_and_release_key_combo(WORKSPACE_UP) def scroll_down(self): self._press_and_release_key_combo(WORKSPACE_DOWN) def _set_pointer(self, x, y): self.root.warp_pointer(x,y) self._display.sync() def click(self): fake_input(self._display, X.ButtonPress, 1) fake_input(self._display, X.ButtonRelease, 1) self._display.sync() def mouse_press(self): fake_input(self._display, X.ButtonPress, 1) self._display.sync() def mouse_release(self): fake_input(self._display, X.ButtonRelease, 1) self._display.sync() def toggle_activities(self): self._run_function(self._toggle_activities_real, self.FUNCTIONS_DEFAULT_DURATION) def _toggle_activities_real(self): self._press_and_release_key_combo(ACTIVITIES_KEY) def _run_function(self, function, timeout, *args): ''' Runs a function if it hasn't run for less than the specified timeout. ''' last_run = self._run_times.get(function, 0) current_time = time.time() if current_time - last_run > timeout: function(*args) self._run_times[function] = current_time def _move_desktop(self, dir_keysym): self._press_and_release_key_combo(MOVE_DESKTOP_BASE_KEY_COMBO + (dir_keysym,)) def move_next_desktop(self): self._run_function(self._move_desktop, self.FUNCTIONS_DEFAULT_DURATION, XK.XK_Down) def move_previous_desktop(self): self._run_function(self._move_desktop, self.FUNCTIONS_DEFAULT_DURATION, XK.XK_Up) def _press_and_release_key_combo(self, combo): for action in (X.KeyPress, X.KeyRelease): for keysym in combo: key = self._display.keysym_to_keycode(keysym) fake_input(self._display, action, key) self._display.sync() def _press_and_release_key(self, akey): for action in (X.KeyPress, X.KeyRelease): key = self._display.keysym_to_keycode(akey) fake_input(self._display, action, key) self._display.sync() def _press_key(self, akey): key = self._display.keysym_to_keycode(akey) fake_input(self._display, X.KeyPress, key) self._display.sync() def _release_key(self, akey): key = self._display.keysym_to_keycode(akey) fake_input(self._display, X.KeyRelease, key) self._display.sync() def _change_zoom(self, distance): if distance > self._last_zoom_distance: self._press_and_release_key_combo(INCREASE_ZOOM_COMBO) else: self._press_and_release_key_combo(DECREASE_ZOOM_COMBO) def zoom(self, distance): ''' Uses the distance between two points to check whether the zoom should be increased, decreased or not applied at all. ''' current_time = time.time() time_since_last_zoom = current_time - self._last_zoom if time_since_last_zoom < self.ZOOM_FUNCTION_DURATION: return if time_since_last_zoom > self.ZOOM_FUNCTION_RESET_TIMEOUT: self._last_zoom_distance = -1 if self._last_zoom_distance == -1: self._last_zoom_distance = distance elif abs(self._last_zoom_distance - distance) > self.ZOOM_THRESHOLD: self._change_zoom(distance) self._last_zoom_distance = distance self._last_zoom = current_time def zoom_scroll(self, distance): ''' Uses the distance between two points to check whether the zoom should be increased, decreased or not applied at all. ''' current_time = time.time() time_since_last_zoom = current_time - self._last_zoom if time_since_last_zoom < self.ZOOM_FUNCTION_DURATION: return if time_since_last_zoom > self.ZOOM_FUNCTION_RESET_TIMEOUT: self._last_zoom_distance = -1 if self._last_zoom_distance == -1: self._last_zoom_distance = distance elif abs(self._last_zoom_distance - distance) > self.ZOOM_THRESHOLD: if self._last_zoom_distance - distance > 0: self._press_and_release_key(LEFT) else: self._press_and_release_key(RIGHT) self._last_zoom = current_time
class PyKeyboard(PyKeyboardMeta): """ The PyKeyboard implementation for X11 systems (mostly linux). This allows one to simulate keyboard input. """ def __init__(self, display=None): PyKeyboardMeta.__init__(self) self.display = Display(display) self.display2 = Display(display) self.special_key_assignment() def _handle_key(self, character, event): """Handles either a key press or release, depending on ``event``. :param character: The key to handle. See :meth:`press_key` and :meth:`release_key` for information about this parameter. :param event: The *Xlib* event. This should be either :attr:`Xlib.X.KeyPress` or :attr:`Xlib.X.KeyRelease` """ try: # Detect uppercase or shifted character shifted = self.is_char_shifted(character) except AttributeError: # Handle the case of integer keycode argument with display_manager(self.display) as d: fake_input(d, event, character) else: with display_manager(self.display) as d: if shifted: fake_input(d, event, self.shift_key) keycode = self.lookup_character_keycode(character) fake_input(d, event, keycode) def press_key(self, character=''): """ Press a given character key. Also works with character keycodes as integers, but not keysyms. """ self._handle_key(character, X.KeyPress) def release_key(self, character=''): """ Release a given character key. Also works with character keycodes as integers, but not keysyms. """ self._handle_key(character, X.KeyRelease) def special_key_assignment(self): """ Determines the keycodes for common special keys on the keyboard. These are integer values and can be passed to the other key methods. Generally speaking, these are non-printable codes. """ #This set of keys compiled using the X11 keysymdef.h file as reference #They comprise a relatively universal set of keys, though there may be #exceptions which may come up for other OSes and vendors. Countless #special cases exist which are not handled here, but may be extended. #TTY Function Keys self.backspace_key = self.lookup_character_keycode('BackSpace') self.tab_key = self.lookup_character_keycode('Tab') self.linefeed_key = self.lookup_character_keycode('Linefeed') self.clear_key = self.lookup_character_keycode('Clear') self.return_key = self.lookup_character_keycode('Return') self.enter_key = self.return_key # Because many keyboards call it "Enter" self.pause_key = self.lookup_character_keycode('Pause') self.scroll_lock_key = self.lookup_character_keycode('Scroll_Lock') self.sys_req_key = self.lookup_character_keycode('Sys_Req') self.escape_key = self.lookup_character_keycode('Escape') self.delete_key = self.lookup_character_keycode('Delete') #Modifier Keys self.shift_l_key = self.lookup_character_keycode('Shift_L') self.shift_r_key = self.lookup_character_keycode('Shift_R') self.shift_key = self.shift_l_key # Default Shift is left Shift self.alt_l_key = self.lookup_character_keycode('Alt_L') self.alt_r_key = self.lookup_character_keycode('Alt_R') self.altgr_key = self.lookup_character_keycode('ISO_Level3_Shift') self.alt_key = self.alt_l_key # Default Alt is left Alt self.control_l_key = self.lookup_character_keycode('Control_L') self.control_r_key = self.lookup_character_keycode('Control_R') self.control_key = self.control_l_key # Default Ctrl is left Ctrl self.caps_lock_key = self.lookup_character_keycode('Caps_Lock') self.capital_key = self.caps_lock_key # Some may know it as Capital self.shift_lock_key = self.lookup_character_keycode('Shift_Lock') self.meta_l_key = self.lookup_character_keycode('Meta_L') self.meta_r_key = self.lookup_character_keycode('Meta_R') self.super_l_key = self.lookup_character_keycode('Super_L') self.windows_l_key = self.super_l_key # Cross-support; also it's printed there self.super_r_key = self.lookup_character_keycode('Super_R') self.windows_r_key = self.super_r_key # Cross-support; also it's printed there self.hyper_l_key = self.lookup_character_keycode('Hyper_L') self.hyper_r_key = self.lookup_character_keycode('Hyper_R') #Cursor Control and Motion self.home_key = self.lookup_character_keycode('Home') self.up_key = self.lookup_character_keycode('Up') self.down_key = self.lookup_character_keycode('Down') self.left_key = self.lookup_character_keycode('Left') self.right_key = self.lookup_character_keycode('Right') self.end_key = self.lookup_character_keycode('End') self.begin_key = self.lookup_character_keycode('Begin') self.page_up_key = self.lookup_character_keycode('Page_Up') self.page_down_key = self.lookup_character_keycode('Page_Down') self.prior_key = self.lookup_character_keycode('Prior') self.next_key = self.lookup_character_keycode('Next') #Misc Functions self.select_key = self.lookup_character_keycode('Select') self.print_key = self.lookup_character_keycode('Print') self.print_screen_key = self.print_key # Seems to be the same thing self.snapshot_key = self.print_key # Another name for printscreen self.execute_key = self.lookup_character_keycode('Execute') self.insert_key = self.lookup_character_keycode('Insert') self.undo_key = self.lookup_character_keycode('Undo') self.redo_key = self.lookup_character_keycode('Redo') self.menu_key = self.lookup_character_keycode('Menu') self.apps_key = self.menu_key # Windows... self.find_key = self.lookup_character_keycode('Find') self.cancel_key = self.lookup_character_keycode('Cancel') self.help_key = self.lookup_character_keycode('Help') self.break_key = self.lookup_character_keycode('Break') self.mode_switch_key = self.lookup_character_keycode('Mode_switch') self.script_switch_key = self.lookup_character_keycode('script_switch') self.num_lock_key = self.lookup_character_keycode('Num_Lock') #Keypad Keys: Dictionary structure keypad = [ 'Space', 'Tab', 'Enter', 'F1', 'F2', 'F3', 'F4', 'Home', 'Left', 'Up', 'Right', 'Down', 'Prior', 'Page_Up', 'Next', 'Page_Down', 'End', 'Begin', 'Insert', 'Delete', 'Equal', 'Multiply', 'Add', 'Separator', 'Subtract', 'Decimal', 'Divide', 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ] self.keypad_keys = dict( (k, self.lookup_character_keycode('KP_' + str(k))) for k in keypad) self.numpad_keys = self.keypad_keys #Function Keys/ Auxilliary Keys #FKeys self.function_keys = [None] + [ self.lookup_character_keycode('F' + str(i)) for i in range(1, 36) ] #LKeys self.l_keys = [None] + [ self.lookup_character_keycode('L' + str(i)) for i in range(1, 11) ] #RKeys self.r_keys = [None] + [ self.lookup_character_keycode('R' + str(i)) for i in range(1, 16) ] #Unsupported keys from windows self.kana_key = None self.hangeul_key = None # old name - should be here for compatibility self.hangul_key = None self.junjua_key = None self.final_key = None self.hanja_key = None self.kanji_key = None self.convert_key = None self.nonconvert_key = None self.accept_key = None self.modechange_key = None self.sleep_key = None def lookup_character_keycode(self, character): """ Looks up the keysym for the character then returns the keycode mapping for that keysym. """ keysym = Xlib.XK.string_to_keysym(character) if not keysym: try: keysym = getattr(Xlib.keysymdef.xkb, 'XK_' + character, 0) except: keysym = 0 if not keysym: keysym = Xlib.XK.string_to_keysym(KEYSYMS[character]) return self.display.keysym_to_keycode(keysym)
class PyKeyboard(PyKeyboardMeta): def __init__(self, display=None): PyKeyboardMeta.__init__(self) self.display = Display(display) self.display2 = Display(display) self.special_key_assignment() def press_key(self, character=''): try: # Detect uppercase or shifted character shifted = self.is_char_shifted(character) except AttributeError: # Handle the case of integer keycode argument fake_input(self.display, X.KeyPress, character) self.display.sync() else: if shifted: fake_input(self.display, X.KeyPress, self.shift_key) keycode = self.lookup_character_keycode(character) fake_input(self.display, X.KeyPress, keycode) self.display.sync() def release_key(self, character=''): """ Release a given character key. Also works with character keycodes as integers, but not keysyms. """ try: # Detect uppercase or shifted character shifted = self.is_char_shifted(character) except AttributeError: # Handle the case of integer keycode argument fake_input(self.display, X.KeyRelease, character) self.display.sync() else: if shifted: fake_input(self.display, X.KeyRelease, self.shift_key) keycode = self.lookup_character_keycode(character) fake_input(self.display, X.KeyRelease, keycode) self.display.sync() def special_key_assignment(self): self.backspace_key = self.lookup_character_keycode('BackSpace') self.tab_key = self.lookup_character_keycode('Tab') self.linefeed_key = self.lookup_character_keycode('Linefeed') self.clear_key = self.lookup_character_keycode('Clear') self.return_key = self.lookup_character_keycode('Return') self.enter_key = self.return_key # Because many keyboards call it "Enter" self.pause_key = self.lookup_character_keycode('Pause') self.scroll_lock_key = self.lookup_character_keycode('Scroll_Lock') self.sys_req_key = self.lookup_character_keycode('Sys_Req') self.escape_key = self.lookup_character_keycode('Escape') self.delete_key = self.lookup_character_keycode('Delete') #Modifier Keys self.shift_l_key = self.lookup_character_keycode('Shift_L') self.shift_r_key = self.lookup_character_keycode('Shift_R') self.shift_key = self.shift_l_key # Default Shift is left Shift self.alt_l_key = self.lookup_character_keycode('Alt_L') self.alt_r_key = self.lookup_character_keycode('Alt_R') self.alt_key = self.alt_l_key # Default Alt is left Alt self.control_l_key = self.lookup_character_keycode('Control_L') self.control_r_key = self.lookup_character_keycode('Control_R') self.control_key = self.control_l_key # Default Ctrl is left Ctrl self.caps_lock_key = self.lookup_character_keycode('Caps_Lock') self.capital_key = self.caps_lock_key # Some may know it as Capital self.shift_lock_key = self.lookup_character_keycode('Shift_Lock') self.meta_l_key = self.lookup_character_keycode('Meta_L') self.meta_r_key = self.lookup_character_keycode('Meta_R') self.super_l_key = self.lookup_character_keycode('Super_L') self.windows_l_key = self.super_l_key # Cross-support; also it's printed there self.super_r_key = self.lookup_character_keycode('Super_R') self.windows_r_key = self.super_r_key # Cross-support; also it's printed there self.hyper_l_key = self.lookup_character_keycode('Hyper_L') self.hyper_r_key = self.lookup_character_keycode('Hyper_R') #Cursor Control and Motion self.home_key = self.lookup_character_keycode('Home') self.up_key = self.lookup_character_keycode('Up') self.down_key = self.lookup_character_keycode('Down') self.left_key = self.lookup_character_keycode('Left') self.right_key = self.lookup_character_keycode('Right') self.end_key = self.lookup_character_keycode('End') self.begin_key = self.lookup_character_keycode('Begin') self.page_up_key = self.lookup_character_keycode('Page_Up') self.page_down_key = self.lookup_character_keycode('Page_Down') self.prior_key = self.lookup_character_keycode('Prior') self.next_key = self.lookup_character_keycode('Next') #Misc Functions self.select_key = self.lookup_character_keycode('Select') self.print_key = self.lookup_character_keycode('Print') self.print_screen_key = self.print_key # Seems to be the same thing self.snapshot_key = self.print_key # Another name for printscreen self.execute_key = self.lookup_character_keycode('Execute') self.insert_key = self.lookup_character_keycode('Insert') self.undo_key = self.lookup_character_keycode('Undo') self.redo_key = self.lookup_character_keycode('Redo') self.menu_key = self.lookup_character_keycode('Menu') self.apps_key = self.menu_key # Windows... self.find_key = self.lookup_character_keycode('Find') self.cancel_key = self.lookup_character_keycode('Cancel') self.help_key = self.lookup_character_keycode('Help') self.break_key = self.lookup_character_keycode('Break') self.mode_switch_key = self.lookup_character_keycode('Mode_switch') self.script_switch_key = self.lookup_character_keycode('script_switch') self.num_lock_key = self.lookup_character_keycode('Num_Lock') #Keypad Keys: Dictionary structure keypad = [ 'Space', 'Tab', 'Enter', 'F1', 'F2', 'F3', 'F4', 'Home', 'Left', 'Up', 'Right', 'Down', 'Prior', 'Page_Up', 'Next', 'Page_Down', 'End', 'Begin', 'Insert', 'Delete', 'Equal', 'Multiply', 'Add', 'Separator', 'Subtract', 'Decimal', 'Divide', 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ] self.keypad_keys = { k: self.lookup_character_keycode('KP_' + str(k)) for k in keypad } self.numpad_keys = self.keypad_keys #Function Keys/ Auxilliary Keys #FKeys self.function_keys = [None] + [ self.lookup_character_keycode('F' + str(i)) for i in range(1, 36) ] #LKeys self.l_keys = [None] + [ self.lookup_character_keycode('L' + str(i)) for i in range(1, 11) ] #RKeys self.r_keys = [None] + [ self.lookup_character_keycode('R' + str(i)) for i in range(1, 16) ] #Unsupported keys from windows self.kana_key = None self.hangeul_key = None # old name - should be here for compatibility self.hangul_key = None self.junjua_key = None self.final_key = None self.hanja_key = None self.kanji_key = None self.convert_key = None self.nonconvert_key = None self.accept_key = None self.modechange_key = None self.sleep_key = None def lookup_character_keycode(self, character): keysym = Xlib.XK.string_to_keysym(character) if keysym == 0: keysym = Xlib.XK.string_to_keysym(special_X_keysyms[character]) return self.display.keysym_to_keycode(keysym)