def main(argv): display = Display() if not display.has_extension('XFIXES'): if display.query_extension('XFIXES') is None: print('XFIXES extension not supported', file=sys.stderr) return 1 xfixes_version = display.xfixes_query_version() print('Found XFIXES version %s.%s' % ( xfixes_version.major_version, xfixes_version.minor_version, ), file=sys.stderr) screen = display.screen() print('Hiding cursor ...', file=sys.stderr) screen.root.xfixes_hide_cursor() display.sync() time.sleep(5) print('Showing cursor ...', file=sys.stderr) screen.root.xfixes_hide_cursor() display.sync()
def run_sensor(mouse): record_dpy = Display() # Check if the extension is present if not record_dpy.has_extension("RECORD"): print("RECORD extension not found") sys.exit(1) r = record_dpy.record_get_version(0, 0) print("RECORD extension version %d.%d" % (r.major_version, r.minor_version)) # Create a recording context; we only want key and mouse events ctx = record_dpy.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.ButtonPress, X.MotionNotify), 'errors': (0, 0), 'client_started': False, 'client_died': False, }]) # Enable the context; this only returns after a call to record_disable_context, # while calling the callback function in the meantime record_dpy.record_enable_context(ctx, record_callback(record_dpy, mouse)) # Finally free the context record_dpy.record_free_context(ctx)
def main(): parser = argparse.ArgumentParser() parser.add_argument("-t", "--timeout", help="specify a timeout interval between 1 and infinity", type=int, required=True) args = parser.parse_args() display = Display() if not display.has_extension('XFIXES'): if display.query_extension('XFIXES') is None: print('XFIXES extension not supported', file=sys.stderr) return 1 xfixes_version = display.xfixes_query_version() print('Found XFIXES version %s.%s' % ( xfixes_version.major_version, xfixes_version.minor_version, ), file=sys.stderr) screen = display.screen() mouse = Mouse(display, screen, args.timeout) mouse.start() run_sensor(mouse)
class Record: def __init__(self): self.record_thread = threading.Thread( target=self._record, name='x keyboard listener thread') self.recording_connection = Display() self.recording_connection.set_error_handler( self._record_display_error_handler) if not self.recording_connection.has_extension("RECORD"): raise Exception("RECORD extension not found") r = self.recording_connection.record_get_version(0, 0) print("RECORD extension version %d.%d" % (r.major_version, r.minor_version)) self.context = self.recording_connection.record_create_context( 0, [record.AllClients], CONTEXT_FILTER) def start(self): self.recording_connection.sync() self.record_thread.start() def stop(self): if self.record_thread.is_alive(): conn = Display() conn.record_disable_context(self.context) conn.close() print('display stopped recording') self.record_thread.join() print('recording thread ended') # # xlib plugs # def _record(self): self.recording_connection.record_enable_context( self.context, self.handler) self.recording_connection.record_free_context(self.context) self.recording_connection.close() def _record_display_error_handler(self, exception, *args): print('Error at record display: {}'.format(exception), file=sys.stderr) def handler(self, reply): data = reply.data while len(data): event, data = rq.EventField(None).parse_binary_value( data, self.recording_connection.display, None, None) if event.type == X.KeyPress: format_key_event(event)
def main(argv): if len(sys.argv) != 2: sys.exit( 'usage: {0} SELECTION\n\n' 'SELECTION is typically PRIMARY, SECONDARY or CLIPBOARD.\n'.format( sys.argv[0])) display = Display() sel_name = sys.argv[1] sel_atom = display.get_atom(sel_name) if not display.has_extension('XFIXES'): if display.query_extension('XFIXES') is None: print('XFIXES extension not supported', file=sys.stderr) return 1 xfixes_version = display.xfixes_query_version() print('Found XFIXES version %s.%s' % ( xfixes_version.major_version, xfixes_version.minor_version, ), file=sys.stderr) screen = display.screen() mask = xfixes.XFixesSetSelectionOwnerNotifyMask | \ xfixes.XFixesSelectionWindowDestroyNotifyMask | \ xfixes.XFixesSelectionClientCloseNotifyMask display.xfixes_select_selection_input(screen.root, sel_atom, mask) while True: e = display.next_event() print(e) if (e.type, e.sub_code) == display.extension_event.SetSelectionOwnerNotify: print('SetSelectionOwner: owner=0x{0:08x}'.format(e.owner.id)) elif (e.type, e.sub_code ) == display.extension_event.SelectionWindowDestroyNotify: print('SelectionWindowDestroy: owner=0x{0:08x}'.format(e.owner.id)) elif (e.type, e.sub_code ) == display.extension_event.SelectionClientCloseNotify: print('SelectionClientClose: owner=0x{0:08x}'.format(e.owner.id))
def main(argv): parser = OptionParser() parser.add_option('--generate', action='store_true', default=False) parser.add_option('--proto', default='MIT-MAGIC-COOKIE-1') parser.add_option('--trusted', action='store_true', default=False) parser.add_option('--untrusted', action='store_true', default=False) parser.add_option('--revoke', action='store_true', default=False) opts, args = parser.parse_args(argv[1:]) if opts.trusted and opts.untrusted: parser.error('--trusted and --untrusted cannot be combined') if not any((opts.generate, opts.revoke)): parser.error('specify --generate or --revoke') display = Display() if not display.has_extension('SECURITY'): if display.query_extension('SECURITY') is None: print('SECURITY extension not supported', file=sys.stderr) return 1 security_version = display.security_query_version() print('SECURITY version %s.%s' % ( security_version.major_version, security_version.minor_version, ), file=sys.stderr) if opts.generate: kwargs = {} if opts.trusted: kwargs['trust_level'] = security.SecurityClientTrusted elif opts.untrusted: kwargs['trust_level'] = security.SecurityClientUntrusted reply = display.security_generate_authorization(opts.proto, **kwargs) print(reply.authid) elif opts.revoke: for arg in args: authid = int(arg, 10) display.security_revoke_authorization(authid)
import sys import os # Change path so we find Xlib from pprint import pprint from Xlib.display import Display from Xlib.ext.nvcontrol import Gpu, Cooler sys.path.append(os.path.join(os.path.dirname(__file__), '..')) if __name__ == '__main__': display = Display() # Check for extension if not display.has_extension('NV-CONTROL'): sys.stderr.write('{}: server does not have the NV-CONTROL extension\n'.format(sys.argv[0])) ext = display.query_extension('NV-CONTROL') print(ext) sys.stderr.write("\n".join(display.list_extensions())) if ext is None: sys.exit(1) gpu = Gpu(0) fan = Cooler(0) perf_level = 3 dic = { 'get_gpu_count': display.nvcontrol_get_gpu_count(), 'get_vram': display.nvcontrol_get_vram(gpu),
class KeyListener(threading.Thread): ''' Usage: keylistener = KeyListener() Initially: keylistener.addKeyListener("L_CTRL+L_SHIFT+y", callable) Note that it is necessary to bind all possible combinations because an order of key presses can be different, for example, "L_CTRL+y+L_SHIFT" Now: keylistener.addKeyListener("Control_L+c+c", callable) ''' def __init__(self): threading.Thread.__init__(self) self.finished = threading.Event() self.contextEventMask = [X.KeyPress, X.MotionNotify] # Give these some initial values # Hook to our display. self.local_dpy = Display() self.record_dpy = Display() self.pressed = [] self.listeners = {} self.character = None ''' 0: Nothing caught; 1: Read buffer and call main module; 2: Call main module ''' self.status = 0 ''' need the following because XK.keysym_to_string() only does printable chars rather than being the correct inverse of XK.string_to_keysym() ''' def lookup_keysym(self, keysym): for name in dir(XK): if name.startswith("XK_") and getattr(XK, name) == keysym: return name.lstrip("XK_") return '[%d]' % keysym def processevents(self, reply): if reply.category != record.FromServer: return if reply.client_swapped: print_v('* received swapped protocol data, cowardly ignored') return # I added 'str', since we receive an error without it if not len(str(reply.data)) or ord(str(reply.data[0])) < 2: # not an event return data = reply.data while len(data): event, data = rq.EventField(None).parse_binary_value( data, self.record_dpy.display, None, None) keycode = event.detail keysym = self.local_dpy.keycode_to_keysym(event.detail, 0) self.character = self.lookup_keysym(keysym) if self.character: if event.type == X.KeyPress: self.press() elif event.type == X.KeyRelease: self.release() def run(self): # Check if the extension is present if not self.record_dpy.has_extension('RECORD'): print_v('RECORD extension not found') sys.exit(1) r = self.record_dpy.record_get_version(0, 0) mes = 'RECORD extension version {}.{}'.format(r.major_version, r.minor_version) print_v(mes) # Create a recording context; we only want key events self.ctx = self.record_dpy.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) # (X.KeyPress, X.ButtonPress) , 'device_events': tuple(self.contextEventMask), 'errors': (0, 0), 'client_started': False, 'client_died': False, }]) ''' Enable the context; this only returns after a call to record_disable_context, while calling the callback function in the meantime ''' self.record_dpy.record_enable_context(self.ctx, self.processevents) # Finally free the context self.record_dpy.record_free_context(self.ctx) def cancel(self): self.finished.set() self.local_dpy.record_disable_context(self.ctx) self.local_dpy.flush() def append(self): if len(self.pressed) > 0: if self.pressed[0] in ('Control_L', 'Control_R', 'Alt_L', 'Alt_R'): self.pressed.append(self.character) def press(self): if len(self.pressed) == 2: if self.pressed[1] == 'grave': self.pressed = [] elif len(self.pressed) == 3: self.pressed = [] if self.character in ('Control_L', 'Control_R', 'Alt_L', 'Alt_R'): self.pressed = [self.character] elif self.character in ('c', 'Insert', 'grave'): self.append() action = self.listeners.get(tuple(self.pressed), False) print_v('Current action:', str(tuple(self.pressed))) if action: action() def release(self): """must be called whenever a key release event has occurred.""" # A released Control key is not taken into account # A cyrillic 'с' symbol is recognized as Latin 'c' if not self.character in ('c', 'Insert', 'grave'): self.pressed = [] def addKeyListener(self, hotkeys, callable): keys = tuple(hotkeys.split('+')) print_v('Added new keylistener for :', str(keys)) self.listeners[keys] = callable def check(self): # Returns 0..2 if self.status: print_v('Hotkey has been caught!') status = self.status self.status = 0 return status def set_status(self, status=0): self.status = status print_v('Setting status to %d!' % self.status)
from Xlib.display import Display from Xlib import X, threaded from Xlib.ext import record from Xlib.protocol import rq import time import threading debug_key_event = False debug_key_press = False debug_new_listener = False local_dpy = Display() record_dpy = Display() # Check if the extension is present if not record_dpy.has_extension('RECORD'): print('KeyListener Error: RECORD extension not found') sys.exit(1) r = record_dpy.record_get_version(0, 0) print( f'KeyListener: RECORD extension version {r.major_version}.{r.minor_version}' ) keysym_map = { 32: 'SPACE', 39: '\'', 44: ',', 45: '-', 46: '.', 47: '/', 48: '0',
class KeyboardListener: def __init__(self, callback=None, on_error=None): self.on_error = on_error self.callback = callback # XLib errors are received asynchronously, thus the need for a running state flag self.stopped = False self.record_thread = threading.Thread( target=self._record, name='x keyboard listener thread') self.well_thread = threading.Thread(target=self._drop_key, daemon=True, name='hotkey well thread') self.recording_connection = Display() self.well_connection = Display() self.recording_connection.set_error_handler( self._record_display_error_handler) self.well_connection.set_error_handler( self._local_display_error_handler) if not self.recording_connection.has_extension("RECORD"): raise Exception("RECORD extension not found") r = self.recording_connection.record_get_version(0, 0) print("RECORD extension version %d.%d" % (r.major_version, r.minor_version)) self.context = self.recording_connection.record_create_context( 0, [record.AllClients], CONTEXT_FILTER) self.mod_keys_set = set() for mods in self.well_connection.get_modifier_mapping(): for mod in mods: self.mod_keys_set.add(mod) self.root = self.well_connection.screen().root self.root.change_attributes(event_mask=X.KeyPressMask | X.KeyReleaseMask) self.modifiers_count = self.modified_count = 0 self.code_map = {} self.composed_code_map = {} self.composed_mapping_first_code = None self.multiplier = '' # # API # def bind(self, key): if self.stopped: return if len(key.accelerators) == 1: self._bind_single_accelerator(key) elif len(key.accelerators) == 2: self._bind_composed_accelerator(key) self.well_connection.sync() if self.stopped: print('Unable to bind: {}'.format(', '.join(key.accelerators)), file=sys.stderr) def start(self): self.well_connection.sync() self.recording_connection.sync() if self.stopped: return self.well_thread.start() self.record_thread.start() def stop(self): self.stopped = True if self.record_thread.is_alive(): self.well_connection.record_disable_context(self.context) self.well_connection.close() print('display stopped recording') self.record_thread.join() print('recording thread ended') # # Thread targets # def _drop_key(self): while not self.stopped: self.well_connection.next_event() def _record(self): self.recording_connection.record_enable_context( self.context, self.handler) self.recording_connection.record_free_context(self.context) self.recording_connection.close() def _record_display_error_handler(self, exception, *args): print('Error at record display: {}'.format(exception), file=sys.stderr) if not self.stopped: self.stopped = True self.on_error() def _local_display_error_handler(self, exception, *args): print('Error at local display: {}'.format(exception), file=sys.stderr) if not self.stopped: self.stopped = True self.on_error() # # Internal API # def _grab_keys(self, code, mask): self.root.grab_key(code, mask, True, X.GrabModeAsync, X.GrabModeAsync) self.root.grab_key(code, mask | X.Mod2Mask, True, X.GrabModeAsync, X.GrabModeAsync) def _bind_single_accelerator(self, key): gdk_keyval, code, mask = parse_accelerator(key.accelerators[0]) self._grab_keys(code, mask) if code not in self.code_map: self.code_map[code] = {} self.code_map[code][mask] = key def _bind_composed_accelerator(self, key): gdk_keyval, code, mask = parse_accelerator(key.accelerators[0]) second_gdk_keyval, second_code, second_mask = parse_accelerator( key.accelerators[1]) self._grab_keys(code, mask) if code not in self.composed_code_map: self.composed_code_map[code] = {} if mask not in self.composed_code_map[code]: self.composed_code_map[code][mask] = {} if second_code not in self.composed_code_map[code][mask]: self.composed_code_map[code][mask][second_code] = {} if second_mask in self.composed_code_map[code][mask][second_code]: raise Exception('key ({}) already mapped'.format(', '.join( key.accelerators))) self.composed_code_map[code][mask][second_code][second_mask] = key # # Event handling # def handler(self, reply): data = reply.data while len(data): event, data = rq.EventField(None).parse_binary_value( data, self.recording_connection.display, None, None) if event.detail in self.mod_keys_set: self.modifiers_count += 1 if event.type == X.KeyPress else -1 self.modified_count = 0 continue if self.modifiers_count: self.modified_count += 1 if event.type == X.KeyPress else -1 if event.type == X.KeyPress: self.handle_keypress(event) def handle_keypress(self, event): _wasmapped, keyval, egroup, level, consumed = Gdk.Keymap.get_default( ).translate_keyboard_state(event.detail, Gdk.ModifierType(event.state), 0) code = event.detail event.keyval = keyval # TODO: explain mask = normalize_state(event.state) if self.composed_mapping_first_code and self.composed_mapping_first_code != ( code, mask): key_name = Gdk.keyval_name(event.keyval) if not mask and key_name and key_name.isdigit(): self.multiplier = self.multiplier + key_name return second_code_map = self.composed_code_map[ self.composed_mapping_first_code[0]][ self.composed_mapping_first_code[1]] if code in second_code_map and mask in second_code_map[code]: multiplier_int = int(self.multiplier) if self.multiplier else 1 self.callback(second_code_map[code][mask], event, multiplier=multiplier_int) self.composed_mapping_first_code = None elif self.modified_count == 1: if code in self.code_map and mask in self.code_map[code]: self.callback(self.code_map[code][mask], event) if code in self.composed_code_map and mask in self.composed_code_map[ code]: self.composed_mapping_first_code = (code, mask) self.multiplier = ''
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