class XlibInterface:
    def __init__(self):
        pass
        self.display = Display()
        self.root = self.display.screen().root

    def grab_keyboard(self):
        self.root.change_attributes(event_mask=KeyPressMask | KeyReleaseMask)
        self.root.grab_keyboard(False, GrabModeAsync, GrabModeAsync,
                                CurrentTime)

    @staticmethod
    def event_is_keypress(event) -> bool:
        if event.type is KeyPress:
            return True
        else:
            return False

    def events_pending(self) -> bool:
        return self.display.pending_events()

    def get_next_event(self):
        return self.display.next_event()

    def stop_listening(self):
        self.display.ungrab_keyboard(CurrentTime)
        self.display.flush()
Esempio n. 2
0
def mouse_move(x, y):
    from Xlib.display import Display
    from Xlib import X
    from Xlib.ext.xtest import fake_input
    d = Display()
    fake_input(d, X.MotionNotify, x=x, y=y)
    d.flush()
Esempio n. 3
0
class PointerMonitor(GObject.GObject, threading.Thread):
    __gsignals__ = {
        'activate': (GObject.SignalFlags.RUN_LAST, None, ()),
    }

    def __init__(self):
        GObject.GObject.__init__ (self)
        threading.Thread.__init__ (self)
        self.setDaemon (True)
        self.display = Display()
        self.root = self.display.screen().root
        self.windows = []

    # Receives GDK windows
    def addWindowToMonitor(self, window):
        gdk.gdk_x11_drawable_get_xid.argtypes = [c_void_p]
        xWindow = self.display.create_resource_object("window", gdk.gdk_x11_drawable_get_xid(hash(window)))
        self.windows.append(xWindow)

    def grabPointer(self):
        self.root.grab_button(X.AnyButton, X.AnyModifier, True, X.ButtonPressMask, X.GrabModeSync, X.GrabModeAsync, 0, 0)
        self.display.flush()

    def ungrabPointer(self):
        self.root.ungrab_button(X.AnyButton, X.AnyModifier)
        self.display.flush()

    def idle(self):
        self.emit("activate")
        return False

    def activate(self):
        GLib.idle_add(self.run)

    def run(self):
        self.running = True
        while self.running:
            event = self.display.next_event()
            try:
                if event.type == X.ButtonPress:
                    # Check if pointer is inside monitored windows
                    for w in self.windows:
                        p = w.query_pointer()
                        g = w.get_geometry()
                        if p.win_x >= 0 and p.win_y >= 0 and p.win_x <= g.width and p.win_y <= g.height:
                            break
                    else:
                        # Is outside, so activate
                        GLib.idle_add(self.idle)
                    self.display.allow_events(X.ReplayPointer, event.time)
                else:
                    self.display.allow_events(X.ReplayPointer, X.CurrentTime)
            except Exception as e:
                print "Unexpected error: " + str(e)

    def stop(self):
        self.running = False
        self.root.ungrab_button(X.AnyButton, X.AnyModifier)
        self.display.close()
Esempio n. 4
0
class PointerMonitor(GObject.GObject, threading.Thread):
    __gsignals__ = {
        'activate': (GObject.SignalFlags.RUN_LAST, None, ()),
    }
       
    def __init__(self):
        GObject.GObject.__init__ (self)
        threading.Thread.__init__ (self)
        self.setDaemon (True)
        self.display = Display()
        self.root = self.display.screen().root
        self.windows = []
        
    # Receives GDK windows
    def addWindowToMonitor(self, window):
        xWindow = self.display.create_resource_object("window", gdk.gdk_x11_drawable_get_xid(hash(window)))
        self.windows.append(xWindow)
            
    def grabPointer(self):
        self.root.grab_button(X.AnyButton, X.AnyModifier, True, X.ButtonPressMask, X.GrabModeSync, X.GrabModeAsync, 0, 0)
        self.display.flush()
        
    def ungrabPointer(self):
        self.root.ungrab_button(X.AnyButton, X.AnyModifier)
        self.display.flush()

    def idle(self):
        self.emit("activate")
        return False

    def activate(self):
        GLib.idle_add(self.run)
                    
    def run(self):
        self.running = True
        while self.running:
            event = self.display.next_event()
            try:
                if event.type == X.ButtonPress:
                    # Check if pointer is inside monitored windows
                    for w in self.windows:
                        p = w.query_pointer()
                        g = w.get_geometry()
                        if p.win_x >= 0 and p.win_y >= 0 and p.win_x <= g.width and p.win_y <= g.height:
                            break
                    else:
                        # Is outside, so activate
                        GLib.idle_add(self.idle)
                    self.display.allow_events(X.ReplayPointer, event.time)
                else:        
                    self.display.allow_events(X.ReplayPointer, X.CurrentTime)
            except Exception as e:
                print "Unexpected error: " + str(e)

    def stop(self):
        self.running = False
        self.root.ungrab_button(X.AnyButton, X.AnyModifier)
        self.display.close()
Esempio n. 5
0
class PyMouseEvent(PyMouseEventMeta):
    def __init__(self):
        PyMouseEventMeta.__init__(self)
        self.display = Display()
        self.display2 = 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.MotionNotify),
                    'errors': (0, 0),
                    'client_started': False,
                    'client_died': False,
                }])

    def run(self):
        if self.capture:
            self.display2.screen().root.grab_pointer(
                True, X.ButtonPressMask | X.ButtonReleaseMask, 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):
        self.display.record_disable_context(self.ctx)
        self.display.ungrab_pointer(X.CurrentTime)
        self.display.flush()
        self.display2.record_disable_context(self.ctx)
        self.display2.ungrab_pointer(X.CurrentTime)
        self.display2.flush()

    def handler(self, reply):
        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:
                keysym = self.display.keycode_to_keysym(event.detail, 0)
                self.keypress(keysym)
            if event.type == X.KeyRelease:
                keysym = self.display.keycode_to_keysym(event.detail, 0)
                self.keyrelease(keysym)
            if event.type == X.ButtonPress:
                self.click(event.root_x, event.root_y,
                           (None, 1, 3, 2, 3, 3, 3)[event.detail], True)
            elif event.type == X.ButtonRelease:
                self.click(event.root_x, event.root_y,
                           (None, 1, 3, 2, 3, 3, 3)[event.detail], False)
            else:
                self.move(event.root_x, event.root_y)
Esempio n. 6
0
class PyMouseEvent(PyMouseEventMeta):
    ## XXX Mario: hack for mouse wheel support!
    ##   - may incompatible with other platforms, but works for me.
    ##   - there seems to be good solution on github but waiting for acceptance (since 2 years..)
#    _BUTTONS = (None, 1, 3, 2, 3, 3, 3)  ## original
    _BUTTONS = (0, 1, 3, 2, 4, 5, 0)   ## with mouse wheel 



    def __init__(self, display=':0'):
        PyMouseEventMeta.__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.ButtonPressMask, X.ButtonReleaseMask),
                    'errors': (0, 0),
                    'client_started': False,
                    'client_died': False,
            }])

    def run(self):
        if self.capture:
            self.display2.screen().root.grab_pointer(True, X.ButtonPressMask | X.ButtonReleaseMask, 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):
        self.display.record_disable_context(self.ctx)
        self.display.ungrab_pointer(X.CurrentTime)
        self.display.flush()
        self.display2.record_disable_context(self.ctx)
        self.display2.ungrab_pointer(X.CurrentTime)
        self.display2.flush()

    def handler(self, reply):
        data = reply.data
        
        while len(data):
            event, data = rq.EventField(None).parse_binary_value(data, self.display.display, None, None)

            if event.type == X.ButtonPress:
                self.click(event.root_x, event.root_y, self._BUTTONS[event.detail], True)
            elif event.type == X.ButtonRelease:
                self.click(event.root_x, event.root_y, self._BUTTONS[event.detail], False)
            else:
                self.move(event.root_x, event.root_y)
Esempio n. 7
0
class PyMouseEvent(PyMouseEventMeta):
    def __init__(self):
        PyMouseEventMeta.__init__(self)
        self.display = Display()
        self.display2 = 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.MotionNotify),
                    'errors': (0, 0),
                    'client_started': False,
                    'client_died': False,
            }])


    def run(self):
        if self.capture:
            self.display2.screen().root.grab_pointer(True, X.ButtonPressMask | X.ButtonReleaseMask, 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):
        self.display.record_disable_context(self.ctx)
        self.display.ungrab_pointer(X.CurrentTime)
        self.display.flush()
        self.display2.record_disable_context(self.ctx)
        self.display2.ungrab_pointer(X.CurrentTime)
        self.display2.flush()

    def handler(self, reply):
        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:
                keysym = self.display.keycode_to_keysym(event.detail, 0)
                self.keypress(keysym)
            if event.type == X.KeyRelease:
                keysym = self.display.keycode_to_keysym(event.detail, 0)
                self.keyrelease(keysym)
            if event.type == X.ButtonPress:
                self.click(event.root_x, event.root_y, (None, 1, 3, 2, 3, 3, 3)[event.detail], True)
            elif event.type == X.ButtonRelease:
                self.click(event.root_x, event.root_y, (None, 1, 3, 2, 3, 3, 3)[event.detail], False)
            else:
                self.move(event.root_x, event.root_y)
Esempio n. 8
0
	def block_keyboard(self):
		self.lock_keyboard = True
		display = Display()
		root = display.screen().root
		# Grap the keyboard
		root.grab_keyboard(owner_events = False, pointer_mode = X.GrabModeAsync, keyboard_mode = X.GrabModeAsync, time = X.CurrentTime)
		# Consume keyboard events
		self.key_lock_condition.acquire()
		while self.lock_keyboard:
			self.key_lock_condition.wait()
		self.key_lock_condition.release()
		# Ungrap the keyboard
		display.ungrab_keyboard(X.CurrentTime)
		display.flush()
Esempio n. 9
0
    def __init__(self, display=None):
        if display is None:
            display = Display()

        self.d = display
        self.screen = self.d.screen()
        bgsize = 20
        bgpm = self.screen.root.create_pixmap(bgsize, bgsize,
                                              self.screen.root_depth)
        bggc = self.screen.root.create_gc(foreground=self.screen.black_pixel,
                                          background=self.screen.black_pixel)
        bgpm.fill_rectangle(bggc, 0, 0, bgsize, bgsize)
        bggc.change(foreground=self.screen.white_pixel)
        bgpm.arc(bggc, -bgsize // 2, 0, bgsize, bgsize, 0, 360 * 64)
        bgpm.arc(bggc, bgsize // 2, 0, bgsize, bgsize, 0, 360 * 64)
        bgpm.arc(bggc, 0, -bgsize // 2, bgsize, bgsize, 0, 360 * 64)
        bgpm.arc(bggc, 0, bgsize // 2, bgsize, bgsize, 0, 360 * 64)

        self.window = self.screen.root.create_window(
            100,
            100,
            400,
            300,
            0,
            self.screen.root_depth,
            X.InputOutput,
            X.CopyFromParent,
            background_pixmap=bgpm,
            event_mask=(X.StructureNotifyMask
                        | X.ButtonReleaseMask),
            colormap=X.CopyFromParent)

        self.WM_DELETE_WINDOW = self.d.intern_atom('WM_DELETE_WINDOW')
        self.WM_PROTOCOLS = self.d.intern_atom('WM_PROTOCOLS')

        self.window.set_wm_name('i3 test window')
        self.window.set_wm_class('i3win', 'i3win')

        self.window.set_wm_protocols([self.WM_DELETE_WINDOW])
        self.window.set_wm_hints(flags=Xutil.StateHint,
                                 initial_state=Xutil.NormalState)

        self.window.set_wm_normal_hints(flags=(Xutil.PPosition | Xutil.PSize
                                               | Xutil.PMinSize),
                                        min_width=50,
                                        min_height=50)

        self.window.map()
        display.flush()
Esempio n. 10
0
	def block_keyboard(self):
		logging.info("Lock the keyboard")
		self.lock_keyboard = True
		display = Display()
		root = display.screen().root
		# Grap the keyboard
		root.grab_keyboard(owner_events = False, pointer_mode = X.GrabModeAsync, keyboard_mode = X.GrabModeAsync, time = X.CurrentTime)
		# Consume keyboard events
		self.key_lock_condition.acquire()
		while self.lock_keyboard:
			self.key_lock_condition.wait()
		self.key_lock_condition.release()
		
		# Ungrap the keyboard
		logging.info("Unlock the keyboard")
		display.ungrab_keyboard(X.CurrentTime)
		display.flush()
Esempio n. 11
0
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)
Esempio n. 12
0
class mwsd:
    def __init__(self, args):

        self.verbose = args.verbose
        self.ip = "localhost"
        self.port = args.port
        self.ignore = args.ignore

        self.disp = Display()
        self.screen = self.disp.screen()
        self.root = self.screen.root

        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.setup_socket()

        self.ids = []
        self.windows = []

        self.status = False
        self.running = True

        self.lock = threading.Lock()

# Communication to daemon

    def setup_socket(self):
        #        self.socket.setblocking(False)
        self.socket.bind((self.ip, self.port))
        self.socket.listen(1)

        # Running the server in a other thread
        self.running = True
        self.thread = threading.Thread(target=self.server_listen)
        self.thread.daemon = True
        self.thread.start()

    def server_listen(self):
        while self.running is True:

            connection, client_address = self.socket.accept()

            try:
                msg = ""
                while True:
                    data = connection.recv(16)

                    if data:
                        msg += data.decode()
                    else:
                        break

                if msg != "":
                    msg_list = msg.split()

                    if self.verbose is True:
                        print(msg)

                    if msg_list[0] == "add":
                        for id in msg_list[1:]:
                            self.add(int(id))
                        connection.sendall("done".encode())
                    elif msg_list[0] == "rm":
                        for id in msg_list[1:]:
                            self.rm(int(id))
                        connection.sendall("done".encode())
                    elif msg_list[0] == "clear":
                        self.clear()
                    elif msg_list[0] == "active":
                        self.active()
                    elif msg_list[0] == "deactive":
                        self.deactive()
                    elif msg_list[0] == "toggle":
                        if self.status is True:
                            self.active()
                        else:
                            self.deactive()
                    elif msg_list[0] == "stop":
                        self.terminate()
                    else:
                        print("Unknown command")
                        connection.sendall("UnknownCommand".encode())

            finally:
                connection.close()

# Actions

    def add(self, id: int):
        self.lock.acquire(blocking=True)
        self.ids.append(id)
        self.windows.append(self.disp.create_resource_object('window', id))
        self.grab(self.windows[-1])
        self.lock.release()

    def rm(self, id: int):
        self.lock.acquire(blocking=True)

        index = self.ids.index(id)
        self.ids.remove(id)
        self.windows.remove(self.windows[index])

        self.lock.release()

    def clear(self):
        self.lock.acquire(blocking=True)

        self.windows.clear()
        self.ids.clear()

        self.lock.release()

    def active(self):
        self.status = True

    def deactive(self):
        self.status = False

    def terminate(self):
        self.running = False

# Daemon main function

    def listen(self):
        while self.running:
            # X11
            if len(self.windows) != 0 and len(self.ids) != 0:
                evt = self.disp.next_event()
                if evt.type in [X.KeyPress]:
                    keycode = evt.detail
                    if self.verbose is True:
                        print("Keycode:", keycode)

                    self.disp.allow_events(X.ReplayKeyboard, X.CurrentTime)
                    if self.status is True:
                        for window in self.windows:
                            self.press(window, keycode, evt.state)
                    else:
                        index = self.ids.index(evt.window.id)
                        self.press(self.windows[index], keycode, evt.state)

                if evt.type == X.DestroyNotify:
                    try:
                        self.rm(evt.window.id)
                    except ValueError:
                        pass

# X11

    def event(self, name, window, detail, state):
        return name(time=X.CurrentTime,
                    root=self.root,
                    window=window,
                    same_screen=0,
                    child=Xlib.X.NONE,
                    root_x=0,
                    root_y=0,
                    event_x=0,
                    event_y=0,
                    state=state,
                    detail=detail)

    def press(self, window, keycode, mask=X.NONE):
        window.send_event(self.event(event.KeyPress, window, keycode, mask),
                          propagate=True)
        window.send_event(self.event(event.KeyRelease, window, keycode, mask),
                          propagate=True)
        self.disp.flush()
        self.disp.sync()

    def grab(self, window):
        window.grab_key(X.AnyKey, X.AnyModifier, True, X.GrabModeAsync,
                        X.GrabModeAsync)

        # Ungrab window manager shortcuts (Super + ...)
        for key in self.ignore:
            window.ungrab_key(key, X.AnyModifier, True)

        window.change_attributes(event_mask=X.KeyReleaseMask | X.KeyPressMask
                                 | X.StructureNotifyMask)

    def ungrab(self, window):
        window.ungrab_key(X.AnyKey, X.AnyModifier, True)


# Cleanup

    def cleanup(self):
        self.running = False
Esempio n. 13
0
class GlobalKeyBinding(GObject.GObject, threading.Thread):
    __gsignals__ = {
        'activate': (GObject.SignalFlags.RUN_LAST, None, ()),
    }

    def __init__(self):
        GObject.GObject.__init__ (self)
        threading.Thread.__init__ (self)
        self.setDaemon (True)

        self.keymap = Gdk.Keymap().get_default()
        self.display = Display()
        self.screen = self.display.screen()
        self.window = self.screen.root
        self.ignored_masks = self.get_mask_combinations(X.LockMask | X.Mod2Mask | X.Mod5Mask)
        self.map_modifiers()
        self.raw_keyval = None
        self.keytext = ""

    def map_modifiers(self):
        gdk_modifiers =(Gdk.ModifierType.CONTROL_MASK, Gdk.ModifierType.SHIFT_MASK, Gdk.ModifierType.MOD1_MASK,
                        Gdk.ModifierType.MOD2_MASK, Gdk.ModifierType.MOD3_MASK, Gdk.ModifierType.MOD4_MASK, Gdk.ModifierType.MOD5_MASK,
                        Gdk.ModifierType.SUPER_MASK, Gdk.ModifierType.HYPER_MASK)
        self.known_modifiers_mask = 0
        for modifier in gdk_modifiers:
            if "Mod" not in Gtk.accelerator_name(0, modifier) or "Mod4" in Gtk.accelerator_name(0, modifier):
                self.known_modifiers_mask |= modifier

    def grab(self, key):
        accelerator = key
        accelerator = accelerator.replace("<Super>", "<Mod4>")
        keyval, modifiers = Gtk.accelerator_parse(accelerator)
        if not accelerator or (not keyval and not modifiers):
            self.keycode = None
            self.modifiers = None
            return False

        self.keytext = key
        try:
            self.keycode = self.keymap.get_entries_for_keyval(keyval).keys[0].keycode
        except:
            # In Betsy, the get_entries_for_keyval() returns an unamed tuple...
            self.keycode = self.keymap.get_entries_for_keyval(keyval)[1][0].keycode
        self.modifiers = int(modifiers)

        catch = error.CatchError(error.BadAccess)
        for ignored_mask in self.ignored_masks:
            mod = modifiers | ignored_mask
            result = self.window.grab_key(self.keycode, mod, True, X.GrabModeAsync, X.GrabModeAsync, onerror=catch)
        self.display.flush()
        # sync has been blocking. Don't know why.
        #self.display.sync()
        if catch.get_error():
            return False
        return True

    def ungrab(self):
        if self.keycode:
            self.window.ungrab_key(self.keycode, X.AnyModifier, self.window)

    def rebind(self, key):
        self.ungrab()
        if key != "":
            self.grab(key)
        else:
            self.keytext = ""

    def set_focus_window(self, window = None):
        self.ungrab()
        if window is None:
            self.window = self.screen.root
        else:
            self.window = self.display.create_resource_object("window", window.get_xid())
        self.grab(self.keytext)

    def get_mask_combinations(self, mask):
        return [x for x in xrange(mask+1) if not (x & ~mask)]

    def idle(self):
        self.emit("activate")
        return False

    def activate(self):
        GLib.idle_add(self.run)

    def run(self):
        self.running = True
        wait_for_release = False
        while self.running:
            event = self.display.next_event()
            try:
                self.current_event_time = event.time
                if event.detail == self.keycode and event.type == X.KeyPress and not wait_for_release:
                    modifiers = event.state & self.known_modifiers_mask
                    if modifiers == self.modifiers:
                        wait_for_release = True
                        self.display.allow_events(X.AsyncKeyboard, event.time)
                    else:
                        self.display.allow_events(X.ReplayKeyboard, event.time)
                elif event.detail == self.keycode and wait_for_release:
                    if event.type == X.KeyRelease:
                        wait_for_release = False
                        GLib.idle_add(self.idle)
                    self.display.allow_events(X.AsyncKeyboard, event.time)
                else:
                    self.display.send_event(self.window, event, X.KeyPressMask | X.KeyReleaseMask, True)
                    self.display.allow_events(X.ReplayKeyboard, event.time)
                    wait_for_release = False
            except AttributeError:
                continue

    def stop(self):
        self.running = False
        self.ungrab()
        self.display.close()
Esempio n. 14
0
class PyMouseEvent(PyMouseEventMeta):
    def __init__(self, capture=False, capture_move=False, display=None):
        PyMouseEventMeta.__init__(self,
                                  capture=capture,
                                  capture_move=capture_move)
        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.ButtonPressMask, X.ButtonReleaseMask),
                    'errors': (0, 0),
                    'client_started': False,
                    'client_died': False,
                }])

    def run(self):
        try:
            if self.capture and self.capture_move:
                capturing = X.ButtonPressMask | X.ButtonReleaseMask | X.PointerMotionMask
            elif self.capture:
                capturing = X.ButtonPressMask | X.ButtonReleaseMask
            elif self.capture_move:
                capturing = X.PointerMotionMask
            else:
                capturing = False

            if capturing:
                self.display2.screen().root.grab_pointer(
                    True, capturing, X.GrabModeAsync, X.GrabModeAsync, 0, 0,
                    X.CurrentTime)
                self.display.screen().root.grab_pointer(
                    True, capturing, X.GrabModeAsync, X.GrabModeAsync, 0, 0,
                    X.CurrentTime)

            self.display2.record_enable_context(self.ctx, self.handler)
            self.display2.record_free_context(self.ctx)
        except KeyboardInterrupt:
            self.stop()

    def stop(self):
        self.display.flush()
        self.display.record_disable_context(self.ctx)
        self.display.ungrab_pointer(X.CurrentTime)
        self.display2.flush()
        self.display2.record_disable_context(self.ctx)
        self.display2.ungrab_pointer(X.CurrentTime)

    def handler(self, reply):
        data = reply.data
        while len(data):
            event, data = rq.EventField(None).parse_binary_value(
                data, self.display.display, None, None)

            #In X11, the button numbers are: leftclick=1, middleclick=2,
            #  rightclick=3, scrollup=4, scrolldown=5, scrollleft=6,
            #  scrollright=7
            #  For the purposes of the cross-platform interface of PyMouse, we
            #  invert the button number values of the right and middle buttons
            if event.type == X.ButtonPress:
                self.click(event.root_x, event.root_y,
                           (None, 1, 3, 2, 4, 5, 6, 7)[event.detail], True)
            elif event.type == X.ButtonRelease:
                self.click(event.root_x, event.root_y,
                           (None, 1, 3, 2, 4, 5, 6, 7)[event.detail], False)
            else:
                self.move(event.root_x, event.root_y)
for x in range(10):
    #print 'Wait count: ', x
    bus = dbus.SessionBus()
    fm = bus.get_object('org.freedesktop.FileManager1',
                        '/org/freedesktop/FileManager1')
    locs = fm.Get('org.freedesktop.FileManager1',
                  'XUbuntuOpenLocationsXids',
                  dbus_interface='org.freedesktop.DBus.Properties')

    if len(locs) == len(lines):
        break

    sleep(1)

# Wait for nautilus windows to get reparented
sleep(5)

# Position the windows
for windid, folders in locs.items():
    args = winds[folders[0]]
    wnd = getWin(windid)
    # Change the gravity to static so that we can set an absolute position
    hints = wnd.get_wm_normal_hints()
    hints['win_gravity'] = StaticGravity
    wnd.set_wm_normal_hints(hints)
    wnd.configure(x=int(args[0]),
                  y=int(args[1]),
                  width=int(args[2]),
                  height=int(args[3]))
    dpy.flush()
Esempio n. 16
0
class GlobalKeyBinding(GObject.GObject, threading.Thread):
    __gsignals__ = {
        'activate': (GObject.SignalFlags.RUN_LAST, None, ()),
    }

    def __init__(self):
        try:
            GObject.GObject.__init__(self)
            threading.Thread.__init__(self)
            self.setDaemon(True)

            self.keymap = Gdk.Keymap().get_default()
            self.display = Display()
            self.screen = self.display.screen()
            self.window = self.screen.root
            self.showscreen = Wnck.Screen.get_default()
            self.ignored_masks = self.get_mask_combinations(X.LockMask
                                                            | X.Mod2Mask
                                                            | X.Mod5Mask)
            self.map_modifiers()
            self.raw_keyval = None
            self.keytext = ""
        except Exception as cause:
            print(("init keybinding error: \n", str(cause)))
            self.display = None
            return None

    def is_hotkey(self, key, modifier):
        keymatch = False
        modmatch = False
        modifier = modifier & ~Gdk.ModifierType.SUPER_MASK
        modint = int(modifier)
        if self.get_keycode(key) == self.keycode or self.get_keycode(
                key) == 134:
            keymatch = True
        for ignored_mask in self.ignored_masks:
            if self.modifiers | ignored_mask == modint | ignored_mask:
                modmatch = True
                break
        return keymatch and modmatch

    def map_modifiers(self):
        gdk_modifiers = (Gdk.ModifierType.CONTROL_MASK,
                         Gdk.ModifierType.SHIFT_MASK,
                         Gdk.ModifierType.MOD1_MASK,
                         Gdk.ModifierType.MOD2_MASK,
                         Gdk.ModifierType.MOD3_MASK,
                         Gdk.ModifierType.MOD4_MASK,
                         Gdk.ModifierType.MOD5_MASK,
                         Gdk.ModifierType.SUPER_MASK,
                         Gdk.ModifierType.HYPER_MASK)
        self.known_modifiers_mask = 0
        for modifier in gdk_modifiers:
            if "Mod" not in Gtk.accelerator_name(
                    0, modifier) or "Mod4" in Gtk.accelerator_name(
                        0, modifier):
                self.known_modifiers_mask |= modifier

    def get_keycode(self, keyval):
        return self.keymap.get_entries_for_keyval(keyval).keys[0].keycode

    def grab(self, key):
        if self.display == None:
            return False
        accelerator = key
        accelerator = accelerator.replace("<Super>", "<Mod4>")
        keyval, modifiers = Gtk.accelerator_parse(accelerator)
        if not accelerator or (not keyval and not modifiers):
            self.keycode = None
            self.modifiers = None
            return False

        self.keytext = key
        self.keycode = self.get_keycode(keyval)
        self.modifiers = int(modifiers)

        catch = error.CatchError(error.BadAccess)
        for ignored_mask in self.ignored_masks:
            mod = modifiers | ignored_mask
            result = self.window.grab_key(self.keycode,
                                          mod,
                                          True,
                                          X.GrabModeAsync,
                                          X.GrabModeSync,
                                          onerror=catch)
            result = self.window.grab_key(134,
                                          mod,
                                          True,
                                          X.GrabModeAsync,
                                          X.GrabModeSync,
                                          onerror=catch)
        self.display.flush()
        # sync has been blocking. Don't know why.
        #self.display.sync()
        if catch.get_error():
            return False
        return True

    def ungrab(self):
        if self.display == None:
            return
        if self.keycode:
            self.window.ungrab_key(self.keycode, X.AnyModifier, self.window)
            self.window.ungrab_key(134, X.AnyModifier, self.window)

    def rebind(self, key):
        self.ungrab()
        if key != "":
            self.grab(key)
        else:
            self.keytext = ""

    def set_focus_window(self, window=None):
        if self.display == None:
            return
        self.ungrab()
        if window is None:
            self.window = self.screen.root
        else:
            self.window = self.display.create_resource_object(
                "window", window.get_xid())
        self.grab(self.keytext)

    def get_mask_combinations(self, mask):
        return [x for x in range(mask + 1) if not (x & ~mask)]

    def idle(self):
        self.emit("activate")
        return False

    def activate(self):
        GLib.idle_add(self.run)

    def run(self):
        if self.display == None:
            return
        self.running = True
        wait_for_release = False
        showdesktop = True
        while self.running:
            event = self.display.next_event()
            try:
                self.current_event_time = event.time
                if (event.detail == self.keycode and event.type == X.KeyPress
                        and not wait_for_release) or (
                            event.detail == 134 and event.type == X.KeyPress
                            and not wait_for_release):
                    modifiers = event.state & self.known_modifiers_mask
                    if modifiers == self.modifiers:
                        wait_for_release = True
                        self.display.allow_events(X.SyncKeyboard, event.time)
                    else:
                        self.display.allow_events(X.ReplayKeyboard, event.time)
                elif (event.detail == self.keycode
                      and wait_for_release) or (event.detail == 134
                                                and wait_for_release):
                    if event.type == X.KeyRelease:
                        wait_for_release = False
                        GLib.idle_add(self.idle)
                    self.display.allow_events(X.SyncKeyboard, event.time)
                elif event.detail == 40 and event.type == X.KeyPress:  #super+d
                    self.display.allow_events(X.SyncKeyboard, event.time)
                elif event.detail == 40 and event.type == X.KeyRelease:  #super+d
                    if showdesktop:
                        self.showscreen.toggle_showing_desktop(True)
                        showdesktop = False
                    else:
                        self.showscreen.toggle_showing_desktop(False)
                        showdesktop = True
                    self.display.allow_events(X.ReplayKeyboard, event.time)
                elif event.detail == 33 and event.type == X.KeyPress:  #super+p
                    self.display.allow_events(X.SyncKeyboard, event.time)
                elif event.detail == 33 and event.type == X.KeyRelease:  #super+p
                    self.display.allow_events(X.ReplayKeyboard, event.time)
                elif event.detail == 26 and event.type == X.KeyPress:  #super+e
                    self.display.allow_events(X.SyncKeyboard, event.time)
                elif event.detail == 26 and event.type == X.KeyRelease:  #super+e
                    os.system("peony &")
                    self.display.allow_events(X.ReplayKeyboard, event.time)
                else:
                    self.display.allow_events(X.ReplayKeyboard, event.time)
            except AttributeError:
                continue

    def stop(self):
        self.running = False
        self.ungrab()
        self.display.close()
Esempio n. 17
0
class PointerMonitor(GObject.GObject, threading.Thread):
    __gsignals__ = {
        'activate': (GObject.SignalFlags.RUN_LAST, None, ()),
    }

    def __init__(self):
        GObject.GObject.__init__ (self)
        threading.Thread.__init__ (self)
        self.setDaemon (True)
        self.display = Display()
        self.root = self.display.screen().root
        self.windows = []

    # Receives GDK windows
    def addWindowToMonitor(self, window):
        self.windows.append(window)

    def grabPointer(self):
        self.root.grab_button(X.AnyButton, X.AnyModifier, True, X.ButtonPressMask, X.GrabModeSync, X.GrabModeAsync, 0, 0)
        self.display.flush()

    def ungrabPointer(self):
        self.root.ungrab_button(X.AnyButton, X.AnyModifier)
        self.display.flush()

    def idle(self):
        self.emit("activate")
        return False

    def activate(self):
        GLib.idle_add(self.run)

    def run(self):
        self.running = True
        while self.running:
            event = self.display.next_event()
            try:
                if event.type == X.ButtonPress:
                    # Check if pointer is inside monitored windows
                    for w in self.windows:
                        if Gtk.check_version (3, 20, 0) is None:
                            pdevice = Gdk.Display.get_default().get_default_seat().get_pointer()
                        else:
                            pdevice = Gdk.Display.get_default().get_device_manager().get_client_pointer()
                        p = self.get_window().get_device_position(pdevice)
                        g = self.get_size()

                        if p.x >= 0 and p.y >= 0 and p.x <= g.width and p.y <= g.height:
                            break
                    else:
                        # Is outside, so activate
                        GLib.idle_add(self.idle)
                    self.display.allow_events(X.ReplayPointer, event.time)
                else:
                    self.display.allow_events(X.ReplayPointer, X.CurrentTime)
            except Exception as e:
                print "Unexpected error: " + str(e)

    def stop(self):
        self.running = False
        self.root.ungrab_button(X.AnyButton, X.AnyModifier)
        self.display.close()
Esempio n. 18
0
class BreakScreen:
    """
    The fullscreen window which prevents users from using the computer.
    This class reads the break_screen.glade and build the user interface.
    """
    def __init__(self, context, on_skip, on_postpone, style_sheet_path):
        self.context = context
        self.count_labels = []
        self.display = Display()
        self.enable_postpone = False
        self.enable_shortcut = False
        self.is_pretified = False
        self.keycode_shortcut_postpone = 65
        self.keycode_shortcut_skip = 9
        self.on_postpone = on_postpone
        self.on_skip = on_skip
        self.shortcut_disable_time = 2
        self.strict_break = False
        self.windows = []

        # Initialize the theme
        css_provider = Gtk.CssProvider()
        css_provider.load_from_path(style_sheet_path)
        Gtk.StyleContext.add_provider_for_screen(
            Gdk.Screen.get_default(), css_provider,
            Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)

    def initialize(self, config):
        """
        Initialize the internal properties from configuration
        """
        logging.info("Initialize the break screen")
        self.enable_postpone = config.get('allow_postpone', False)
        self.keycode_shortcut_postpone = config.get('shortcut_postpone', 65)
        self.keycode_shortcut_skip = config.get('shortcut_skip', 9)
        self.shortcut_disable_time = config.get('shortcut_disable_time', 2)
        self.strict_break = config.get('strict_break', False)

    def skip_break(self):
        """
        Skip the break from the break screen
        """
        logging.info("User skipped the break")
        # Must call on_skip before close to lock screen before closing the break screen
        self.on_skip()
        self.close()

    def postpone_break(self):
        """
        Postpone the break from the break screen
        """
        logging.info("User postponed the break")
        self.on_postpone()
        self.close()

    def on_window_delete(self, *args):
        """
        Window close event handler.
        """
        logging.info("Closing the break screen")
        self.close()

    def on_skip_clicked(self, button):
        """
        Skip button press event handler.
        """
        self.skip_break()

    def on_postpone_clicked(self, button):
        """
        Postpone button press event handler.
        """
        self.postpone_break()

    def show_count_down(self, countdown, seconds):
        """
        Show/update the count down on all screens.
        """
        self.enable_shortcut = self.shortcut_disable_time <= seconds
        mins, secs = divmod(countdown, 60)
        timeformat = '{:02d}:{:02d}'.format(mins, secs)
        GLib.idle_add(lambda: self.__update_count_down(timeformat))

    def show_message(self, break_obj, widget, tray_actions=[]):
        """
        Show the break screen with the given message on all displays.
        """
        message = break_obj.name
        image_path = break_obj.image
        self.enable_shortcut = self.shortcut_disable_time <= 0
        GLib.idle_add(lambda: self.__show_break_screen(message, image_path,
                                                       widget, tray_actions))

    def close(self):
        """
        Hide the break screen from active window and destroy all other windows
        """
        logging.info("Close the break screen(s)")
        self.__release_keyboard()

        # Destroy other windows if exists
        GLib.idle_add(lambda: self.__destroy_all_screens())

    def __tray_action(self, button, tray_action):
        """
        Tray action handler.
        Hides all toolbar buttons for this action and call the action provided by the plugin.
        """
        tray_action.reset()
        tray_action.action()

    def __show_break_screen(self, message, image_path, widget, tray_actions):
        """
        Show an empty break screen on all screens.
        """
        # Lock the keyboard
        utility.start_thread(self.__lock_keyboard)

        screen = Gtk.Window().get_screen()
        no_of_monitors = screen.get_n_monitors()
        logging.info("Show break screens in %d display(s)", no_of_monitors)

        for monitor in range(no_of_monitors):
            monitor_gemoetry = screen.get_monitor_geometry(monitor)
            x = monitor_gemoetry.x
            y = monitor_gemoetry.y

            builder = Gtk.Builder()
            builder.add_from_file(BREAK_SCREEN_GLADE)
            builder.connect_signals(self)

            window = builder.get_object("window_main")
            lbl_message = builder.get_object("lbl_message")
            lbl_count = builder.get_object("lbl_count")
            lbl_widget = builder.get_object("lbl_widget")
            img_break = builder.get_object("img_break")
            box_buttons = builder.get_object("box_buttons")
            toolbar = builder.get_object("toolbar")

            for tray_action in tray_actions:
                toolbar_button = None
                if tray_action.system_icon:
                    toolbar_button = Gtk.ToolButton.new_from_stock(
                        tray_action.get_icon())
                else:
                    toolbar_button = Gtk.ToolButton.new(
                        tray_action.get_icon(), tray_action.name)
                tray_action.add_toolbar_button(toolbar_button)
                toolbar_button.connect(
                    "clicked",
                    lambda button, action: self.__tray_action(button, action),
                    tray_action)
                toolbar_button.set_tooltip_text(_(tray_action.name))
                toolbar.add(toolbar_button)
                toolbar_button.show()

            # Add the buttons
            if self.enable_postpone:
                # Add postpone button
                btn_postpone = Gtk.Button(_('Postpone'))
                btn_postpone.get_style_context().add_class('btn_postpone')
                btn_postpone.connect('clicked', self.on_postpone_clicked)
                btn_postpone.set_visible(True)
                box_buttons.pack_start(btn_postpone, True, True, 0)

            if not self.strict_break:
                # Add the skip button
                btn_skip = Gtk.Button(_('Skip'))
                btn_skip.get_style_context().add_class('btn_skip')
                btn_skip.connect('clicked', self.on_skip_clicked)
                btn_skip.set_visible(True)
                box_buttons.pack_start(btn_skip, True, True, 0)

            # Set values
            if image_path:
                img_break.set_from_file(image_path)
            lbl_message.set_label(message)
            lbl_widget.set_markup(widget)

            self.windows.append(window)
            self.count_labels.append(lbl_count)

            # Set visual to apply css theme. It should be called before show method.
            window.set_visual(window.get_screen().get_rgba_visual())
            if self.context['desktop'] == 'kde':
                # Fix flickering screen in KDE by setting opacity to 1
                window.set_opacity(0.9)

            # In Unity, move the window before present
            window.move(x, y)
            window.resize(monitor_gemoetry.width, monitor_gemoetry.height)
            window.stick()
            window.set_keep_above(True)
            window.present()
            # In other desktop environments, move the window after present
            window.move(x, y)
            window.resize(monitor_gemoetry.width, monitor_gemoetry.height)
            logging.info("Moved break screen to Display[%d, %d]", x, y)
            window.fullscreen()

    def __update_count_down(self, count):
        """
        Update the countdown on all break screens.
        """
        for label in self.count_labels:
            label.set_text(count)

    def __lock_keyboard(self):
        """
        Lock the keyboard to prevent the user from using keyboard shortcuts
        """
        logging.info("Lock the keyboard")
        self.lock_keyboard = True

        # Grab the keyboard
        root = self.display.screen().root
        root.change_attributes(event_mask=X.KeyPressMask | X.KeyReleaseMask)
        root.grab_keyboard(True, X.GrabModeAsync, X.GrabModeAsync,
                           X.CurrentTime)

        # Consume keyboard events
        while self.lock_keyboard:
            if self.display.pending_events() > 0:
                # Avoid waiting for next event by checking pending events
                event = self.display.next_event()
                if self.enable_shortcut and event.type == X.KeyPress:
                    if event.detail == self.keycode_shortcut_skip and not self.strict_break:
                        self.skip_break()
                        break
                    elif self.enable_postpone and event.detail == self.keycode_shortcut_postpone:
                        self.postpone_break()
                        break
            else:
                # Reduce the CPU usage by sleeping for a second
                time.sleep(1)

    def __release_keyboard(self):
        """
        Release the locked keyboard.
        """
        logging.info("Unlock the keyboard")
        self.lock_keyboard = False
        self.display.ungrab_keyboard(X.CurrentTime)
        self.display.flush()

    def __destroy_all_screens(self):
        """
        Close all the break screens.
        """
        for win in self.windows:
            win.destroy()
        del self.windows[:]
        del self.count_labels[:]
Esempio n. 19
0
class GlobalKeyBinding(GObject.GObject, threading.Thread):
    __gsignals__ = {
        'activate': (GObject.SignalFlags.RUN_LAST, None, ()),
    }

    def __init__(self):
        GObject.GObject.__init__(self)
        threading.Thread.__init__(self)
        self.setDaemon(True)

        self.keymap = capi.get_widget(gdk.gdk_keymap_get_default())
        self.display = Display()
        self.screen = self.display.screen()
        self.window = self.screen.root
        self.ignored_masks = self.get_mask_combinations(X.LockMask | X.Mod2Mask
                                                        | X.Mod5Mask)
        self.map_modifiers()
        self.raw_keyval = None
        self.keytext = ""

    def is_hotkey(self, key, modifier):
        keymatch = False
        modmatch = False
        modifier = modifier & ~Gdk.ModifierType.SUPER_MASK
        modint = int(modifier)
        if self.get_keycode(key) == self.keycode:
            keymatch = True
        for ignored_mask in self.ignored_masks:
            if self.modifiers | ignored_mask == modint | ignored_mask:
                modmatch = True
                break
        return keymatch and modmatch

    def map_modifiers(self):
        gdk_modifiers = (Gdk.ModifierType.CONTROL_MASK,
                         Gdk.ModifierType.SHIFT_MASK,
                         Gdk.ModifierType.MOD1_MASK,
                         Gdk.ModifierType.MOD2_MASK,
                         Gdk.ModifierType.MOD3_MASK,
                         Gdk.ModifierType.MOD4_MASK,
                         Gdk.ModifierType.MOD5_MASK,
                         Gdk.ModifierType.SUPER_MASK,
                         Gdk.ModifierType.HYPER_MASK)
        self.known_modifiers_mask = 0
        for modifier in gdk_modifiers:
            if "Mod" not in Gtk.accelerator_name(
                    0, modifier) or "Mod4" in Gtk.accelerator_name(
                        0, modifier):
                self.known_modifiers_mask |= modifier

    def get_keycode(self, keyval):
        count = c_int()
        array = (KeymapKey * 10)()
        keys = cast(array, POINTER(KeymapKey))
        gdk.gdk_keymap_get_entries_for_keyval(hash(self.keymap), keyval,
                                              byref(keys), byref(count))
        return keys[0].keycode

    def grab(self, key):
        accelerator = key
        accelerator = accelerator.replace("<Super>", "<Mod4>")
        keyval, modifiers = Gtk.accelerator_parse(accelerator)
        if not accelerator or (not keyval and not modifiers):
            self.keycode = None
            self.modifiers = None
            return False

        self.keytext = key
        self.keycode = self.get_keycode(keyval)
        self.modifiers = int(modifiers)

        catch = error.CatchError(error.BadAccess)
        for ignored_mask in self.ignored_masks:
            mod = modifiers | ignored_mask
            result = self.window.grab_key(self.keycode,
                                          mod,
                                          True,
                                          X.GrabModeAsync,
                                          X.GrabModeSync,
                                          onerror=catch)
        self.display.flush()
        # sync has been blocking. Don't know why.
        #self.display.sync()
        if catch.get_error():
            return False
        return True

    def ungrab(self):
        if self.keycode:
            self.window.ungrab_key(self.keycode, X.AnyModifier, self.window)

    def rebind(self, key):
        self.ungrab()
        if key != "":
            self.grab(key)
        else:
            self.keytext = ""

    def set_focus_window(self, window=None):
        self.ungrab()
        if window is None:
            self.window = self.screen.root
        else:
            self.window = self.display.create_resource_object(
                "window", gdk.gdk_x11_drawable_get_xid(hash(window)))
        self.grab(self.keytext)

    def get_mask_combinations(self, mask):
        return [x for x in xrange(mask + 1) if not (x & ~mask)]

    def idle(self):
        self.emit("activate")
        return False

    def activate(self):
        GLib.idle_add(self.run)

    def run(self):
        self.running = True
        wait_for_release = False
        while self.running:
            event = self.display.next_event()
            try:
                self.current_event_time = event.time
                if event.detail == self.keycode and event.type == X.KeyPress and not wait_for_release:
                    modifiers = event.state & self.known_modifiers_mask
                    if modifiers == self.modifiers:
                        wait_for_release = True
                        self.display.allow_events(X.AsyncKeyboard, event.time)
                    else:
                        self.display.allow_events(X.ReplayKeyboard, event.time)
                elif event.detail == self.keycode and wait_for_release:
                    if event.type == X.KeyRelease:
                        wait_for_release = False
                        GLib.idle_add(self.idle)
                    self.display.allow_events(X.AsyncKeyboard, event.time)
                else:
                    self.display.allow_events(X.ReplayKeyboard, event.time)
            except AttributeError:
                continue

    def stop(self):
        self.running = False
        self.ungrab()
        self.display.close()
Esempio n. 20
0
class GridMouseVooDoo(Thread):

    def __init__(self, wm, button=10):
        Thread.__init__(self)

        self.button = button

        self.display = Display()
        self.ctx = self.display.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.ButtonPressMask, X.ButtonReleaseMask),
                    'errors': (0, 0),
                    'client_started': False,
                    'client_died': False,
            }])

        self.wm = wm
        self.area = None

    def run(self):
        logger.info("Starting Thread")
        self.display.record_enable_context(self.ctx, self.handler)
        self.display.record_free_context(self.ctx)

    def handler(self, reply):
        logger.debug("Handler called")
        data = reply.data
        while len(data):
            event, data = rq.EventField(None).parse_binary_value(data,
                                self.display.display, None, None)
            if event.type == X.ButtonPress:
                if event.detail == self.button:
                    self.press(event.root_x, event.root_y)
            elif event.type == X.ButtonRelease:
                if event.detail == self.button:
                    self.release(event.root_x, event.root_y)
            else:
                self.move(event.root_x, event.root_y)

    def stop(self):
        logger.info("Stopping Thread")
        self.display.record_disable_context(self.ctx)
        self.display.ungrab_pointer(X.CurrentTime)
        self.display.flush()
        logger.debug("Thread stopped")

    def press(self, x, y):
        self.area = Area(x, y)
        logger.info("Mouse button pressed")
        self.move(x, y)

    def release(self, x, y):
        self.move(x, y)
        logger.info("%s" % self.area)
        self.wm.move_window_to_area(self.area)
        self.area = None
        logger.info("Mouse button released")

    def move(self, x, y):
        if not self.area:
            logger.debug("Mouse moved to %d, %d but no button pressed" %
                         (x, y))
            return
        self.area.add_point(x, y)
        logger.debug("Mouse moved to %d, %d" % (x, y))
Esempio n. 21
0
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
Esempio n. 22
0
class GlobalKeyBinding(GObject.GObject, threading.Thread):
    __gsignals__ = {
        'activate': (GObject.SignalFlags.RUN_LAST, None, ()),
    }

    def __init__(self):
        GObject.GObject.__init__(self)
        threading.Thread.__init__(self)
        self.setDaemon(True)

        self.keymap = Gdk.Keymap().get_default()
        self.display = Display()
        self.screen = self.display.screen()
        self.window = self.screen.root
        self.ignored_masks = self.get_mask_combinations(X.LockMask | X.Mod2Mask
                                                        | X.Mod5Mask)
        self.map_modifiers()
        self.raw_keyval = None
        self.keytext = ""

    def map_modifiers(self):
        gdk_modifiers = (Gdk.ModifierType.CONTROL_MASK,
                         Gdk.ModifierType.SHIFT_MASK,
                         Gdk.ModifierType.MOD1_MASK,
                         Gdk.ModifierType.MOD2_MASK,
                         Gdk.ModifierType.MOD3_MASK,
                         Gdk.ModifierType.MOD4_MASK,
                         Gdk.ModifierType.MOD5_MASK,
                         Gdk.ModifierType.SUPER_MASK,
                         Gdk.ModifierType.HYPER_MASK)
        self.known_modifiers_mask = 0
        for modifier in gdk_modifiers:
            if "Mod" not in Gtk.accelerator_name(
                    0, modifier) or "Mod4" in Gtk.accelerator_name(
                        0, modifier):
                self.known_modifiers_mask |= modifier

    def grab(self, key):
        accelerator = key
        accelerator = accelerator.replace("<Super>", "<Mod4>")
        keyval, modifiers = Gtk.accelerator_parse(accelerator)
        if not accelerator or (not keyval and not modifiers):
            self.keycode = None
            self.modifiers = None
            return False

        self.keytext = key
        try:
            self.keycode = self.keymap.get_entries_for_keyval(
                keyval).keys[0].keycode
        except AttributeError:
            # In older Gtk3 the get_entries_for_keyval() returns an unnamed tuple...
            self.keycode = self.keymap.get_entries_for_keyval(
                keyval)[1][0].keycode
        self.modifiers = int(modifiers)

        # Request to receive key press/release reports from other windows that may not be using modifiers
        catch = error.CatchError(error.BadWindow)
        if self.modifiers:
            self.window.change_attributes(onerror=catch,
                                          event_mask=X.KeyPressMask
                                          | X.KeyReleaseMask)
        else:
            self.window.change_attributes(onerror=catch,
                                          event_mask=X.NoEventMask)
        if catch.get_error():
            return False

        catch = error.CatchError(error.BadAccess)
        for ignored_mask in self.ignored_masks:
            mod = modifiers | ignored_mask
            result = self.window.grab_key(self.keycode,
                                          mod,
                                          True,
                                          X.GrabModeAsync,
                                          X.GrabModeAsync,
                                          onerror=catch)
        self.display.flush()
        # sync has been blocking. Don't know why.
        #self.display.sync()
        if catch.get_error():
            return False
        return True

    def ungrab(self):
        if self.keycode:
            self.window.ungrab_key(self.keycode, X.AnyModifier, self.window)

    def rebind(self, key):
        self.ungrab()
        if key != "":
            self.grab(key)
        else:
            self.keytext = ""

    def set_focus_window(self, window=None):
        self.ungrab()
        if window is None:
            self.window = self.screen.root
        else:
            self.window = self.display.create_resource_object(
                "window", window.get_xid())
        self.grab(self.keytext)

    def get_mask_combinations(self, mask):
        return [x for x in xrange(mask + 1) if not (x & ~mask)]

    def idle(self):
        self.emit("activate")
        return False

    def activate(self):
        GLib.idle_add(self.run)

    def run(self):
        self.running = True
        wait_for_release = False
        while self.running:
            event = self.display.next_event()

            if self.modifiers:
                # Use simpler logic when using traditional combined keybindings
                modifiers = event.state & self.known_modifiers_mask
                if event.type == X.KeyPress and event.detail == self.keycode and modifiers == self.modifiers:
                    GLib.idle_add(self.idle)

            else:
                try:
                    if event.type == X.KeyPress and event.detail == self.keycode and not wait_for_release:
                        modifiers = event.state & self.known_modifiers_mask
                        if modifiers == self.modifiers:
                            wait_for_release = True
                    elif event.type == X.KeyRelease and event.detail == self.keycode and wait_for_release:
                        GLib.idle_add(self.idle)
                        wait_for_release = False
                    else:
                        self.display.ungrab_keyboard(X.CurrentTime)
                        # Send the event up in case another window is listening to it
                        self.display.send_event(
                            event.window, event,
                            X.KeyPressMask | X.KeyReleaseMask, True)
                        wait_for_release = False
                except AttributeError:
                    continue

    def stop(self):
        self.running = False
        self.ungrab()
        self.display.close()
Esempio n. 23
0
class Prenestr(object):

    def __init__(self):
        self.ratio = 0.5
        self.wborder = 10
        self.hborder = 30
        self.disp = Display()
        self.root = self.disp.screen().root

        # we tell the X server we want to catch keyPress event
        self.root.change_attributes(event_mask=X.KeyPressMask)

        self.grab_key(K_L)
        self.grab_key(K_H)
        self.grab_key(K_L, X.Mod4Mask | X.ShiftMask)
        self.grab_key(K_H, X.Mod4Mask | X.ShiftMask)
        self.grab_key(K_T)
        self.grab_key(K_ENTER)
        while True:
            event = self.root.display.next_event()
            if event.type == X.KeyPress:
                self.keypress(event)

    def get_active(self):
        id = self.root.get_full_property(
            self.disp.intern_atom("_NET_ACTIVE_WINDOW"), 0).value[0]
        obj = self.disp.create_resource_object('window', id)
        return (id, obj)

    def _send_event(self, win, ctype, data, mask=None):
        data = (data + ([0] * (5 - len(data))))[:5]
        ev = protocol.event.ClientMessage(window=win,
                                          client_type=ctype, data=(32, (data)))
        self.root.send_event(ev, event_mask=X.SubstructureRedirectMask)

    def workarea(self):
        v = self.root.get_full_property(
            self.disp.intern_atom("_NET_WORKAREA"), 0).value
        return v[0], v[1], v[2], v[3]

    def move(self, win, to='left', y_pos=0, y_nbwin=1):
        id, obj = win
        rx, ry, rw, rh = self.workarea()

        if to == 'left':
            x = rx
            y = ry
            w = rw * self.ratio - self.wborder
            h = rh
        elif to == 'right':
            x = rx + rw * self.ratio + self.wborder
            y = ry + y_pos * (rh / y_nbwin)
            w = rw * (1 - self.ratio) - self.wborder
            h = rh / y_nbwin
            if y_nbwin > 1:
                h = h - self.hborder

        # Reset state
        self._send_event(id,
                self.disp.intern_atom("_NET_WM_STATE"),
                [0, self.disp.intern_atom("_NET_WM_STATE_MAXIMIZED_VERT"),
                    self.disp.intern_atom("_NET_WM_STATE_MAXIMIZED_HORZ")])
        obj.configure(x=x, y=y, width=w, height=h, stack_mode=X.Above)
        self._send_event(id,
                self.disp.intern_atom("_NET_ACTIVE_WINDOW"), [])
        self.disp.flush()

    def grab_key(self, key, mask=X.Mod4Mask, ungrab=False):
        self.root.grab_key(key, mask, 1, X.GrabModeAsync, X.GrabModeAsync)
        if ungrab:
            self.ungrab_list.append(key)

    def ungrab_key(self, key, mask=X.Mod4Mask):
        self.root.ungrab_key(key, mask, 1)

    def tile(self, master='position'):
        current_window = self.get_active()
        win_list = self.root.get_full_property(
            self.disp.intern_atom("_NET_CLIENT_LIST"),
            Xatom.WINDOW).value
        current_desktop = self.root.get_full_property(
            self.disp.intern_atom("_NET_CURRENT_DESKTOP"), 0).value[0]
        desk_list = []
        for win_id in win_list:
            obj = self.disp.create_resource_object('window', win_id)
            windesk = obj.get_full_property(
                self.disp.intern_atom("_NET_WM_DESKTOP"), 0).value[0]
            if windesk == current_desktop:
                # This window is on the current desktop

                # Skip if transient
                transient = obj.get_wm_transient_for()
                if transient and transient != self.root:
                    continue

                # Skip if hidden
                state = obj.get_full_property(
                    self.disp.intern_atom("_NET_WM_STATE"), Xatom.ATOM)
                dock = obj.get_full_property(
                    self.disp.intern_atom("_NET_WM_WINDOW_TYPE"), Xatom.ATOM)

                if (state and self.disp.intern_atom("_NET_WM_STATE_HIDDEN") in state.value
                    or self.disp.intern_atom("_NET_WM_STATE_SKIP_TASKBAR") in state.value
                    or self.disp.intern_atom("_NET_WM_STATE_SKIP_PAGER") in state.value):
                    # hidden
                    continue
                if (dock and self.disp.intern_atom("_NET_WM_WINDOW_TYPE_DOCK") in dock.value
                    and self.disp.intern_atom("_NET_WM_WINDOW_TYPE_TOOLBAR") in dock.value
                    and self.disp.intern_atom("_NET_WM_WINDOW_TYPE_MENU") in dock.value
                    and self.disp.intern_atom("_NET_ACTIVE_WINDOW_TYPE_SPLASH") in dock.value
                    and self.disp.intern_atom("_NET_ACTIVE_WINDOW_TYPE_DIALOG") in dock.value):
                    # hidden
                    continue

                desk_list.append((win_id, obj))

        if not desk_list:
            return

        def get_geom(window):
            wg = window.get_geometry()
            tl = window.translate_coords(self.root, wg.x, wg.y)
            return (-tl.x, -tl.y, wg.width, wg.height)

        geom = [(w, get_geom(w[1])) for w in desk_list]

        if master == 'position':
            left = min(geom, key=lambda l: l[1][0])[0]
        else:
            left = current_window

        self.move(left, to="left")
        others = [w for w in geom if w[0][0] != left[0]]
        others.sort(key=lambda l: l[1][1])

        for pos, win in enumerate(others):
            self.move(win[0], to="right", y_pos=pos, y_nbwin=len(others))


        # Reactivate window
        self._send_event(current_window[0],
                         self.disp.intern_atom("_NET_ACTIVE_WINDOW"), [])

        return

    def keypress(self, event):

        if event.detail == K_H:
            if event.state & X.ShiftMask:
                self.ratio -= 0.1
                if self.ratio < 0:
                    self.ratio = 0
                self.tile()
            else:
                self.move(self.get_active())
        elif event.detail == K_L:
            if event.state & X.ShiftMask:
                self.ratio += 0.1
                if self.ratio > 1:
                    self.ratio = 1
                self.tile()
            else:
                self.move(self.get_active(), to='right')
        elif event.detail == K_T:
            self.tile()
        elif event.detail == K_ENTER:
            self.tile(master='active')
Esempio n. 24
0
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
Esempio n. 25
0
File: scan.py Progetto: pho/anc
    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)
  if len(actual) != 9:
    continue #Bad

  for i in range(0, 8):
    if list(actual)[i] == '0':
      xtest.fake_input(d, X.KeyPress, but[i])  
      d.sync()
      d.flush()
    else:
      xtest.fake_input(d, X.KeyRelease, but[i])  
      d.sync() 
      d.flush()
      
  sleep(delay)
Esempio n. 26
0
class GlobalKeyBinding(GObject.GObject, threading.Thread):
    __gsignals__ = {
        'activate': (GObject.SignalFlags.RUN_LAST, None, ()),
    }

    def __init__(self):
        GObject.GObject.__init__ (self)
        threading.Thread.__init__ (self)
        self.setDaemon (True)

        gdk.gdk_keymap_get_default.restype = c_void_p
        self.keymap = capi.get_widget (gdk.gdk_keymap_get_default())
        self.display = Display()
        self.screen = self.display.screen()
        self.window = self.screen.root
        self.ignored_masks = self.get_mask_combinations(X.LockMask | X.Mod2Mask | X.Mod5Mask)
        self.map_modifiers()
        self.raw_keyval = None
        self.keytext = ""

    def is_hotkey(self, key, modifier):
        keymatch = False
        modmatch = False
        modifier = modifier & ~Gdk.ModifierType.SUPER_MASK
        modint = int(modifier)
        if self.get_keycode(key) == self.keycode:
            keymatch = True
        for ignored_mask in self.ignored_masks:
            if self.modifiers | ignored_mask == modint | ignored_mask:
                modmatch = True
                break
        return keymatch and modmatch

    def map_modifiers(self):
        gdk_modifiers =(Gdk.ModifierType.CONTROL_MASK, Gdk.ModifierType.SHIFT_MASK, Gdk.ModifierType.MOD1_MASK,
                         Gdk.ModifierType.MOD2_MASK, Gdk.ModifierType.MOD3_MASK, Gdk.ModifierType.MOD4_MASK, Gdk.ModifierType.MOD5_MASK,
                         Gdk.ModifierType.SUPER_MASK, Gdk.ModifierType.HYPER_MASK)
        self.known_modifiers_mask = 0
        for modifier in gdk_modifiers:
            if "Mod" not in Gtk.accelerator_name(0, modifier) or "Mod4" in Gtk.accelerator_name(0, modifier):
                self.known_modifiers_mask |= modifier

    def get_keycode(self, keyval):
        count = c_int()
        array = (KeymapKey * 10)()
        keys = cast(array, POINTER(KeymapKey))
        gdk.gdk_keymap_get_entries_for_keyval.argtypes = [c_void_p, c_uint, c_void_p, c_void_p]
        gdk.gdk_keymap_get_entries_for_keyval(hash(self.keymap), keyval, byref(keys), byref(count))
        return keys[0].keycode

    def grab(self, key):
        accelerator = key
        accelerator = accelerator.replace("<Super>", "<Mod4>")
        keyval, modifiers = Gtk.accelerator_parse(accelerator)
        if not accelerator or (not keyval and not modifiers):
            self.keycode = None
            self.modifiers = None
            return False

        self.keytext = key
        self.keycode = self.get_keycode(keyval)
        self.modifiers = int(modifiers)

        catch = error.CatchError(error.BadAccess)
        for ignored_mask in self.ignored_masks:
            mod = modifiers | ignored_mask
            result = self.window.grab_key(self.keycode, mod, True, X.GrabModeAsync, X.GrabModeSync, onerror=catch)
        self.display.flush()
        # sync has been blocking. Don't know why.
        #self.display.sync()
        if catch.get_error():
            return False
        return True

    def ungrab(self):
        if self.keycode:
            self.window.ungrab_key(self.keycode, X.AnyModifier, self.window)
            
    def rebind(self, key):
        self.ungrab()
        if key != "":
            self.grab(key)
        else:
            self.keytext = ""
    
    def set_focus_window(self, window = None):
        self.ungrab()
        if window is None:
            self.window = self.screen.root
        else:
            gdk.gdk_x11_drawable_get_xid.argtypes = [c_void_p]
            self.window = self.display.create_resource_object("window", gdk.gdk_x11_drawable_get_xid(hash(window)))
        self.grab(self.keytext)

    def get_mask_combinations(self, mask):
        return [x for x in xrange(mask+1) if not (x & ~mask)]

    def idle(self):
        self.emit("activate")
        return False

    def activate(self):
        GLib.idle_add(self.run)

    def run(self):
        self.running = True
        wait_for_release = False
        while self.running:
            event = self.display.next_event()
            try:
                self.current_event_time = event.time
                if event.detail == self.keycode and event.type == X.KeyPress and not wait_for_release:
                    modifiers = event.state & self.known_modifiers_mask
                    if modifiers == self.modifiers:
                        wait_for_release = True
                        self.display.allow_events(X.AsyncKeyboard, event.time)
                    else:
                        self.display.allow_events(X.ReplayKeyboard, event.time)
                elif event.detail == self.keycode and wait_for_release:
                    if event.type == X.KeyRelease:
                        wait_for_release = False
                        GLib.idle_add(self.idle)
                    self.display.allow_events(X.AsyncKeyboard, event.time)
                else:
                    self.display.allow_events(X.ReplayKeyboard, event.time)
            except AttributeError:
                continue

    def stop(self):
        self.running = False
        self.ungrab()
        self.display.close()
Esempio n. 27
0
class Detect_Double_Ctrl(object):
    def show_app(self):
        DoubleCtrlSignal.instance().show_signal.emit()

    def handler(self, reply):
        """ This function is called when a xlib event is fired """
        data = reply.data
        while len(data):
            event, data = rq.EventField(None).parse_binary_value(
                data, self.disp.display, None, None)
            keysym = self.loc_disp.keycode_to_keysym(event.detail, 0)
            character = lookup_keysym(keysym)

            if event.type == X.KeyPress:
                self.keylistener.press(character)
            if event.type == X.KeyRelease:
                self.keylistener.release(character)

            # if event.detail == 1 and event.type == 5:
            #     delta = 2
            #     if self.first_click == 0.0:
            #         self.first_click = time.time()
            #         print 'a', delta
            #     else:
            #         self.second_click = time.time()
            #         delta = self.second_click - self.first_click
            #         self.first_click, self.second_click = 0.0, 0.0
            #         print delta
            #     if delta < 1:
            #         with os.popen('xsel') as xsel:
            #             word = xsel.read()
            #             emit = True if re.search(r'[a-zA-z]', word) else False
            #             if emit:#double click emit signal only when there exists words selected
            #                 x = event._data['root_x']
            #                 y = event._data['root_y']
            #                 # DoubleCtrlSignal.instance().doublle_ctrl_signal.emit(word, x, y)

            if character == 'Caps_Lock' and event.type == X.KeyPress:
                delta = 2
                if self.first_click == 0.0:
                    self.first_click = time.time()
                    logging.debug('#a %s %s %s', self.first_click,
                                  self.second_click, delta)
                else:
                    self.second_click = time.time()
                    delta = self.second_click - self.first_click
                    self.first_click, self.second_click = 0.0, 0.0
                    logging.debug('#b %s %s %s', self.first_click,
                                  self.second_click, delta)
                if delta < 1:
                    with os.popen('xsel') as xsel:
                        word = xsel.read()
                        emit = True if re.search(r'[a-zA-z]', word) else False
                        if emit:
                            logging.debug(word)

                        x = event._data['root_x']
                        y = event._data['root_y']
                        DoubleCtrlSignal.instance().doublle_ctrl_signal.emit(
                            word, x, y)

            # if event.detail == 66:
            #     if event.type == X.KeyPress:
            #         self.flag +=1
            #     elif event.type == X.KeyRelease:
            #         pass
            #     if event.type == X.KeyPress and self.flag % 2 == 0:
            #         temp = os.popen('xsel')
            #         word = temp.read()
            #         temp.close()
            #         # double capslock emit signal even though there no words selected to show the window
            #         x = event._data['root_x']
            #         y = event._data['root_y']
            #         DoubleCtrlSignal.instance().doublle_ctrl_signal.emit(word, x, y)

            if character == 'Escape':
                DoubleCtrlSignal.instance().esc_signal.emit()

    def detect_double_ctrl(self):

        root = self.disp.screen().root

        # Monitor keypress and button press
        self.ctx = self.disp.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.KeyReleaseMask, X.ButtonReleaseMask),
                    'errors': (0, 0),
                    'client_started': False,
                    'client_died': False,
                }])
        self.disp.record_enable_context(self.ctx, self.handler)

        self.disp.record_free_context(self.ctx)

    def __init__(self):
        self.disp = Display()
        self.loc_disp = Display()
        self.ctx = None
        self.flag = 0
        self.first_click = 0.0
        self.second_click = 0.0
        self.keylistener = KeyListener()
        self.keylistener.addKeyListener('Alt_L+l', self.show_app)
        self.keylistener.addKeyListener('l+Alt_L', self.show_app)
        self.mythread = threading.Thread(target=self.detect_double_ctrl)
        self.mythread.daemon = True
        self.mythread.start()

    def terminate(self):
        self.loc_disp.record_disable_context(self.ctx)
        self.loc_disp.flush()
        self.mythread.join()
Esempio n. 28
0
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
Esempio n. 29
0
class KeyPointer:
  def __init__(self):
    self.display = Display ()
    self.screen = self.display.screen()
    self.overlay = None
    self.root = self.screen.root
    self.keymap = gtk.gdk.keymap_get_default()

    self.click_keyval = gtk.keysyms.space
    self.click_keycode = self.keymap.get_entries_for_keyval(self.click_keyval)[0][0]
    self.finish_keyval = gtk.keysyms.Return
    self.finish_keycode = self.keymap.get_entries_for_keyval(self.finish_keyval)[0][0]

    self.setup_movementkeys(DEFAULT_MVMT)
    self.setup_keymapping(DEFAULT_MAP)

    self.init_gconf(GCONF_DIR)
    self.launch_cb()

  def init_gconf(self, app_dir):
    self.gconf = gconf.client_get_default ()
    self.gconf.add_dir (app_dir, gconf.CLIENT_PRELOAD_NONE)
    self.gconf.notify_add (LAYOUT_KEY, self.gconf_cb)
    self.gconf.notify_add (MOVEMENT_KEY, self.gconf_cb)

    self.read_gconf(app_dir)

  def read_gconf(self, app_dir):
    gconf_keymappings = self.gconf.get_list(LAYOUT_KEY, gconf.VALUE_STRING)
    gconf_font_size = self.gconf.get_int(FONT_SIZE_KEY)
    gconf_font_name = self.gconf.get_string(FONT_NAME_KEY)
    gconf_block_hint = self.gconf.get_bool(BLOCK_HINT_KEY)


    keymappings = []
    for line in gconf_keymappings:
      keymappings.append(line.strip())

    self.setup_keymapping(keymappings)
    self.overlay.setup_fonts(gconf_font_name, gconf_font_size)
    self.overlay.set_block_hint(gconf_block_hint)

  def setup_movementkeys(self, mapping_dict):
    self.movement_dict = mapping_dict
    self.movement_keycodes = {}
    print mapping_dict
    for key in mapping_dict:
      keyval = gtk.gdk.unicode_to_keyval(ord(key))
      keyval_entries = self.keymap.get_entries_for_keyval(keyval)
      for keyval_tuple in keyval_entries:
        self.movement_keycodes[keyval_tuple] = mapping_dict[key]

  def setup_keymapping(self, mapping_array):
    # Map the keys to an x,y pair of where the key falls on the keyboard
    self.keyboard_keyvals = {}
    self.keymapping_array = mapping_array
    self.max_height = len(mapping_array)
    self.max_width = max([ len(x) for x in mapping_array ])
    for y in xrange(len(mapping_array)):
      for x in xrange(len(mapping_array[y])):
        keyval = gtk.gdk.unicode_to_keyval(ord(mapping_array[y][x]))
        self.keyboard_keyvals[keyval] = (x, y)

    if self.overlay:
      self.overlay.destroy()
    self.overlay = Overlay(mapping_array)

  def gconf_cb(self, *args):
    # One of our settings changed, probably should re-read gconf data
    self.read_gconf(GCONF_DIR)

  def launch_cb(self, keybinding=None):
    t = threading.Thread(target=self.handle_screen)
    t.start()

  def handle_screen(self):
    w = self.screen.width_in_pixels
    h = self.screen.height_in_pixels
    gobject.idle_add(self.overlay.show, w, h)
    print 'Grabbing Keyboard Focus'
    self.root.grab_keyboard(True, X.GrabModeAsync, X.GrabModeAsync, X.CurrentTime)
    print 'Placing pointer'
    try:
      self.handle_keypresses()
      self.display.ungrab_keyboard(X.CurrentTime)
      self.display.flush()
      print 'Finished placing pointer'
    except:
      print "Couldn't handle keypresses"
      gtk.main_quit()
    gobject.idle_add(self.overlay.hide)


  def handle_keypress(self, e):
    # Find the coordinates of the key pressed
    # Check if this is a keypress event (not a release or button, etc)
    if e.__class__ is not Xlib.protocol.event.KeyPress:
      print "Not a KeyPress event"
      return

    # Check if this a movement or absolute mapping.
    gtk.gdk.threads_enter()
    keyval_tuple = self.keymap.translate_keyboard_state(e.detail, e.state, e.type)
    gtk.gdk.threads_leave()

    keyval, group, level, modifiers = keyval_tuple
    keycode = e.detail
    state = e.state

    if e.detail == self.click_keycode:
      # button= 1 left, 2 middle, 3 right
      def mouse_click(button):
        self.overlay.hide()
        time.sleep(0.10)
        Xlib.ext.xtest.fake_input(self.display,Xlib.X.ButtonPress, button)
        self.display.sync()
        Xlib.ext.xtest.fake_input(self.display,Xlib.X.ButtonRelease, button)
        self.display.sync()
        self.overlay.show(self.overlay.old_w, self.overlay.old_h)

      mouse_click(1)


    if keyval not in self.keyboard_keyvals and \
       keycode not in self.movement_keycodes:
      print "Keycode and keyval not in dictionary"
      return e.detail == self.finish_keycode

    w = self.screen.width_in_pixels
    h = self.screen.height_in_pixels
    print "012"
    # Find out if there are any modifiers being pressed
    # If ctrl + movement key is being pressed, move over by some amount
    if state & X.ControlMask and (keycode, group, level)  in self.movement_keycodes:
      print "Control Hold Movement Keys"
      movement = self.movement_keycodes[(keycode, group, level)]
      # move the cursor a little
      # Not sure how to calculate the amount to move by?
      # Maybe take the smallest h_block, w_block we have and divide into thirds?
      h_block = float(h) / self.max_height / 3
      w_block = float(w) / self.max_width / 3

      cursor_position = self.root.query_pointer()
      x = cursor_position.root_x
      y = cursor_position.root_y
      to_x, to_y = x, y
      if movement == 'left':
        to_x = x - w_block
      if movement == 'down':
        to_y = y + h_block
      if movement == 'up':
        to_y = y - w_block
      if movement == 'right':
        to_x = x + w_block
    else:
      print 'Moving Pointer'
      x, y = self.keyboard_keyvals[keyval]
      h_block = float(h) / len(self.keymapping_array)
      w_block = float(w) / len(self.keymapping_array[y])
    # divide the width by the number of rows we have and multiply by x to
    # figure out where the cursor goes

      to_x = w_block * x + (w_block / 2)
      to_y = h_block * y + (h_block / 2)

    print to_x, to_y
    self.root.warp_pointer(to_x, to_y)
    return e.detail == self.finish_keycode

  def handle_keypresses(self):
    self.root.change_attributes(event_mask = X.KeyPressMask)
    self.screen = self.display.screen()

    while True:
      print "Handling Keyboard Event"
      event = self.root.display.next_event()
      print event
      try:
        if self.handle_keypress(event):
          break
      except Exception, e:
        traceback.print_exc()
        break
    self.root.change_attributes(event_mask = X.NoEventMask)
    self.display.allow_events(X.AsyncKeyboard, X.CurrentTime)
Esempio n. 30
0
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
Esempio n. 31
0
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
Esempio n. 32
0
class PointerMonitor(GObject.GObject, threading.Thread):
    __gsignals__ = {
        'activate': (GObject.SignalFlags.RUN_LAST, None, ()),
    }

    def __init__(self):
        GObject.GObject.__init__(self)
        threading.Thread.__init__(self)
        self.setDaemon(True)
        self.display = Display()
        self.root = self.display.screen().root
        self.windows = []

    # Receives GDK windows
    def addWindowToMonitor(self, window):
        self.windows.append(window)

    def grabPointer(self):
        self.root.grab_button(X.AnyButton, X.AnyModifier, True,
                              X.ButtonPressMask, X.GrabModeSync,
                              X.GrabModeAsync, 0, 0)
        self.display.flush()

    def ungrabPointer(self):
        self.root.ungrab_button(X.AnyButton, X.AnyModifier)
        self.display.flush()

    def idle(self):
        self.emit("activate")
        return False

    def activate(self):
        GLib.idle_add(self.run)

    def run(self):
        self.running = True
        while self.running:
            event = self.display.next_event()
            try:
                if event.type == X.ButtonPress:
                    # Check if pointer is inside monitored windows
                    for w in self.windows:
                        if (Gtk.MAJOR_VERSION, Gtk.MINOR_VERSION) >= (3, 20):
                            pdevice = Gdk.Display.get_default(
                            ).get_default_seat().get_pointer()
                        else:
                            pdevice = Gdk.Display.get_default(
                            ).get_device_manager().get_client_pointer()
                        p = self.get_window().get_device_position(pdevice)
                        g = self.get_size()
                        if p.x >= 0 and p.y >= 0 and p.x <= g.width and p.y <= g.height:
                            break
                    else:
                        # Is outside, so activate
                        GLib.idle_add(self.idle)
                    self.display.allow_events(X.ReplayPointer, event.time)
                else:
                    self.display.allow_events(X.ReplayPointer, X.CurrentTime)
            except Exception as e:
                print "Unexpected error: " + str(e)

    def stop(self):
        self.running = False
        self.root.ungrab_button(X.AnyButton, X.AnyModifier)
        self.display.close()
Esempio n. 33
0
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
Esempio n. 34
0
class PyMouseEvent(PyMouseEventMeta):
    def __init__(self, capture=False, capture_move=False, display=None):
        PyMouseEventMeta.__init__(self, capture=capture, capture_move=capture_move)
        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.ButtonPressMask, X.ButtonReleaseMask),
                    'errors': (0, 0),
                    'client_started': False,
                    'client_died': False,
            }])

    def run(self):
        try:
            if self.capture and self.capture_move:
                capturing = X.ButtonPressMask | X.ButtonReleaseMask | X.PointerMotionMask
            elif self.capture:
                capturing = X.ButtonPressMask | X.ButtonReleaseMask
            elif self.capture_move:
                capturing = X.PointerMotionMask
            else:
                capturing = False

            if capturing:
                self.display2.screen().root.grab_pointer(True,
                                                         capturing,
                                                         X.GrabModeAsync,
                                                         X.GrabModeAsync,
                                                         0, 0, X.CurrentTime)
                self.display.screen().root.grab_pointer(True,
                                                         capturing,
                                                         X.GrabModeAsync,
                                                         X.GrabModeAsync,
                                                         0, 0, X.CurrentTime)
    
            self.display2.record_enable_context(self.ctx, self.handler)
            self.display2.record_free_context(self.ctx)
        except KeyboardInterrupt:
            self.stop()

    def stop(self):
        self.display.flush()
        self.display.record_disable_context(self.ctx)
        self.display.ungrab_pointer(X.CurrentTime)
        self.display2.flush()
        self.display2.record_disable_context(self.ctx)
        self.display2.ungrab_pointer(X.CurrentTime)

    def handler(self, reply):
        data = reply.data
        while len(data):
            event, data = rq.EventField(None).parse_binary_value(data, self.display.display, None, None)

            #In X11, the button numbers are: leftclick=1, middleclick=2,
            #  rightclick=3, scrollup=4, scrolldown=5
            #  For the purposes of the cross-platform interface of PyMouse, we
            #  invert the button number values of the right and middle buttons
            if event.type == X.ButtonPress:
                self.click(event.root_x, event.root_y, (None, 1, 3, 2, 4, 5, 3)[event.detail], True)
            elif event.type == X.ButtonRelease:
                self.click(event.root_x, event.root_y, (None, 1, 3, 2, 4, 5, 3)[event.detail], False)
            else:
                self.move(event.root_x, event.root_y)
Esempio n. 35
0
class KeyPointer:
    def __init__(self):
        self.display = Display()
        self.screen = self.display.screen()
        self.root = self.screen.root
        self.keymap = gtk.gdk.keymap_get_default()
        self.finish_keyval = gtk.keysyms.Return
        self.finish_keycode = self.keymap.get_entries_for_keyval(self.finish_keyval)[0][0]

        self.setup_movementkeys(DEFAULT_MVMT)
        self.setup_keymapping(DEFAULT_MAP)
        self.init_gconf(GCONF_DIR)

    def init_gconf(self, app_dir):
        self.gconf = gconf.client_get_default()
        self.gconf.add_dir(app_dir, gconf.CLIENT_PRELOAD_NONE)
        self.gconf.notify_add(LAYOUT_KEY, self.gconf_cb)
        self.gconf.notify_add(MOVEMENT_KEY, self.gconf_cb)

        self.read_gconf(app_dir)

    def read_gconf(self, app_dir):
        gconf_keymappings = self.gconf.get_list(LAYOUT_KEY, gconf.VALUE_STRING)

        keymappings = []
        for line in gconf_keymappings:
            keymappings.append(line.strip())

        self.setup_keymapping(keymappings)

    def gconf_cb(self, *args):
        # One of our settings changed, probably should re-read gconf data
        self.read_gconf(GCONF_DIR)

    def launch_cb(self, keybinding):
        print "Grabbing Keyboard Focus"
        self.root.grab_keyboard(True, X.GrabModeAsync, X.GrabModeAsync, X.CurrentTime)
        print "Placing pointer"
        self.screen_handler()
        try:
            self.display.ungrab_keyboard(X.CurrentTime)
            self.display.flush()
            print "Finished placing pointer"
        except:
            gtk.main_quit()

    def setup_movementkeys(self, mapping_dict):
        self.movement_dict = mapping_dict
        self.movement_keycodes = {}
        for key in mapping_dict:
            keyval = gtk.gdk.unicode_to_keyval(ord(key))
            keycode = self.keymap.get_entries_for_keyval(keyval)[0][0]
            self.movement_keycodes[keycode] = mapping_dict[key]

    def setup_keymapping(self, mapping_array):
        # Map the keys to an x,y pair of where the key falls on the keyboard
        self.keyboard_keyvals = {}
        self.keymapping_array = mapping_array
        self.max_height = len(mapping_array)
        self.max_width = max([len(x) for x in mapping_array])
        for y in xrange(len(mapping_array)):
            for x in xrange(len(mapping_array[y])):
                keyval = gtk.gdk.unicode_to_keyval(ord(mapping_array[y][x]))
                self.keyboard_keyvals[keyval] = (x, y)

    def keypress_cb(self, e):
        # Find the coordinates of the key pressed

        try:
            # Check if this is a keypress event (not a release or button, etc)
            if e.__class__ is not Xlib.protocol.event.KeyPress:
                return
            keycode = e.detail
            state = e.state

            w = self.screen.width_in_pixels
            h = self.screen.height_in_pixels
            # Find out if there are any modifiers being pressed
            # If ctrl + movement key is being pressed, move over by some amount
            if state & X.ControlMask and keycode in self.movement_keycodes:
                print "Control Hold Movement Keys"
                movement = self.movement_keycodes[keycode]
                # move the cursor a little
                # Not sure how to calculate the amount to move by?
                # Maybe take the smallest h_block, w_block we have and divide into thirds?
                h_block = float(h) / self.max_height / 3
                w_block = float(w) / self.max_width / 3

                cursor_position = self.root.query_pointer()
                x = cursor_position.root_x
                y = cursor_position.root_y
                to_x, to_y = x, y
                if movement == "left":
                    to_x = x - w_block
                if movement == "down":
                    to_y = y + h_block
                if movement == "up":
                    to_y = y - w_block
                if movement == "right":
                    to_x = x + w_block

            else:
                keyval_tuple = self.keymap.translate_keyboard_state(e.detail, e.state, e.type)
                keyval, group, level, modifiers = keyval_tuple
                x, y = self.keyboard_keyvals[keyval]
                h_block = float(h) / len(self.keymapping_array)
                w_block = float(w) / len(self.keymapping_array[y])
                # divide the width by the number of rows we have and multiply by x to
                # figure out where the cursor goes

                to_x = w_block * x + (w_block / 2)
                to_y = h_block * y + (h_block / 2)

            print to_x, to_y
            self.root.warp_pointer(to_x, to_y)
        except KeyError, v:
            pass
        return e.detail == self.finish_keycode
Esempio n. 36
0
class BreakScreen:
    """
	The fullscreen window which prevents users from using the computer.
	This class reads the break_screen.glade and build the user interface.
	"""
    def __init__(self, context, on_skip, on_postpone, glade_file,
                 style_sheet_path):
        self.context = context
        self.on_skip = on_skip
        self.on_postpone = on_postpone
        self.is_pretified = False
        self.windows = []
        self.count_labels = []
        self.glade_file = glade_file
        self.enable_shortcut = False
        self.display = Display()

        # Initialize the theme
        css_provider = Gtk.CssProvider()
        css_provider.load_from_path(style_sheet_path)
        Gtk.StyleContext.add_provider_for_screen(
            Gdk.Screen.get_default(), css_provider,
            Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)

    def initialize(self, config, language):
        """
		Initialize the internal properties from configuration
		"""
        logging.info("Initialize the break screen")
        self.skip_button_text = language['ui_controls']['skip']
        self.postpone_button_text = language['ui_controls']['postpone']
        self.strict_break = config.get('strict_break', False)
        self.enable_postpone = config.get('allow_postpone', False)
        self.keycode_shortcut_skip = config.get('shortcut_skip', 9)
        self.keycode_shortcut_postpone = config.get('shortcut_postpone', 65)
        self.shortcut_disable_time = config.get('shortcut_disable_time', 2)

    def skip_break(self):
        """
		Skip the break from the break screen
		"""
        logging.info("User skipped the break")
        # Must call on_skip before close to lock screen before closing the break screen
        self.on_skip()
        self.close()

    def postpone_break(self):
        """
		Postpone the break from the break screen
		"""
        logging.info("User postponed the break")
        self.on_postpone()
        self.close()

    def on_window_delete(self, *args):
        """
		Window close event handler.
		"""
        logging.info("Closing the break screen")
        self.__release_keyboard()
        self.close()

    def on_skip_clicked(self, button):
        """
		Skip button press event handler.
		"""
        self.skip_break()

    def on_postpone_clicked(self, button):
        """
		Postpone button press event handler.
		"""
        self.postpone_break()

    def show_count_down(self, count_down, seconds):
        """
		Show/update the count down on all screens.
		"""
        self.enable_shortcut = not self.strict_break and self.shortcut_disable_time <= count_down
        mins, secs = divmod(seconds, 60)
        timeformat = '{:02d}:{:02d}'.format(mins, secs)
        GLib.idle_add(lambda: self.__update_count_down(timeformat))

    def show_message(self, message, image_path, plugins_data):
        """
		Show the break screen with the given message on all displays.
		"""
        self.enable_shortcut = not self.strict_break and self.shortcut_disable_time <= 0
        GLib.idle_add(lambda: self.__show_break_screen(message, image_path,
                                                       plugins_data))

    def close(self):
        """
		Hide the break screen from active window and destroy all other windows
		"""
        logging.info("Close the break screen(s)")
        self.__release_keyboard()

        # Destroy other windows if exists
        GLib.idle_add(lambda: self.__destroy_all_screens())

    def __show_break_screen(self, message, image_path, plugins_data):
        """
		Show an empty break screen on all screens.
		"""
        # Lock the keyboard
        thread = threading.Thread(target=self.__lock_keyboard)
        thread.start()

        logging.info("Show break screens in all displays")
        screen = Gtk.Window().get_screen()
        no_of_monitors = screen.get_n_monitors()

        for monitor in range(no_of_monitors):
            monitor_gemoetry = screen.get_monitor_geometry(monitor)
            x = monitor_gemoetry.x
            y = monitor_gemoetry.y

            builder = Gtk.Builder()
            builder.add_from_file(self.glade_file)
            builder.connect_signals(self)

            window = builder.get_object("window_main")
            lbl_message = builder.get_object("lbl_message")
            lbl_count = builder.get_object("lbl_count")
            lbl_left = builder.get_object("lbl_left")
            lbl_right = builder.get_object("lbl_right")
            img_break = builder.get_object("img_break")
            box_buttons = builder.get_object("box_buttons")

            # Add the buttons
            if not self.strict_break:
                # Add postpone button
                if self.enable_postpone:
                    btn_postpone = Gtk.Button(self.postpone_button_text)
                    btn_postpone.get_style_context().add_class('btn_postpone')
                    btn_postpone.connect('clicked', self.on_postpone_clicked)
                    btn_postpone.set_visible(True)
                    box_buttons.pack_start(btn_postpone, True, True, 0)

                # Add the skip button
                btn_skip = Gtk.Button(self.skip_button_text)
                btn_skip.get_style_context().add_class('btn_skip')
                btn_skip.connect('clicked', self.on_skip_clicked)
                btn_skip.set_visible(True)
                box_buttons.pack_start(btn_skip, True, True, 0)

            # Set values
            if image_path:
                img_break.set_from_file(image_path)
            lbl_message.set_label(message)
            lbl_left.set_markup(plugins_data['left'])
            lbl_right.set_markup(plugins_data['right'])

            self.windows.append(window)
            self.count_labels.append(lbl_count)

            # Set visual to apply css theme. It should be called before show method.
            window.set_visual(window.get_screen().get_rgba_visual())
            if self.context['desktop'] == 'kde':
                # Fix flickering screen in KDE by setting opacity to 1
                window.set_opacity(0.9)

            window.move(x, y)
            window.stick()
            window.set_keep_above(True)
            window.present()
            window.fullscreen()

    def __update_count_down(self, count):
        """
		Update the countdown on all break screens.
		"""
        for label in self.count_labels:
            label.set_text(count)

    def __lock_keyboard(self):
        """
		Lock the keyboard to prevent the user from using keyboard shortcuts
		"""
        logging.info("Lock the keyboard")
        self.lock_keyboard = True

        # Grab the keyboard
        root = self.display.screen().root
        root.change_attributes(event_mask=X.KeyPressMask | X.KeyReleaseMask)
        root.grab_keyboard(True, X.GrabModeAsync, X.GrabModeAsync,
                           X.CurrentTime)

        # Consume keyboard events
        while self.lock_keyboard:
            if self.display.pending_events() > 0:
                # Avoid waiting for next event by checking pending events
                event = self.display.next_event()
                if self.enable_shortcut and event.type == X.KeyPress:
                    if event.detail == self.keycode_shortcut_skip:
                        self.skip_break()
                        break
                    elif self.enable_postpone and event.detail == self.keycode_shortcut_postpone:
                        self.postpone_break()
                        break
            else:
                # Reduce the CPU usage by sleeping for a second
                time.sleep(1)

    def __release_keyboard(self):
        """
		Release the locked keyboard.
		"""
        logging.info("Unlock the keyboard")
        self.lock_keyboard = False
        self.display.ungrab_keyboard(X.CurrentTime)
        self.display.flush()

    def __destroy_all_screens(self):
        """
		Close all the break screens.
		"""
        for win in self.windows:
            win.destroy()
        del self.windows[:]
        del self.count_labels[:]
Esempio n. 37
0
class GlobalKeyBinding(GObject.GObject, threading.Thread):
    __gsignals__ = {
        'activate': (GObject.SignalFlags.RUN_LAST, None, ()),
    }

    def __init__(self):
        GObject.GObject.__init__(self)
        threading.Thread.__init__(self)
        self.setDaemon(True)

        self.keymap = Gdk.Keymap().get_default()
        self.display = Display()
        self.screen = self.display.screen()
        self.window = self.screen.root
        self.ignored_masks = self.get_mask_combinations(X.LockMask | X.Mod2Mask
                                                        | X.Mod5Mask)
        self.map_modifiers()
        self.raw_keyval = None
        self.keytext = ""

    def map_modifiers(self):
        gdk_modifiers = (Gdk.ModifierType.CONTROL_MASK,
                         Gdk.ModifierType.SHIFT_MASK,
                         Gdk.ModifierType.MOD1_MASK,
                         Gdk.ModifierType.MOD2_MASK,
                         Gdk.ModifierType.MOD3_MASK,
                         Gdk.ModifierType.MOD4_MASK,
                         Gdk.ModifierType.MOD5_MASK,
                         Gdk.ModifierType.SUPER_MASK,
                         Gdk.ModifierType.HYPER_MASK)
        self.known_modifiers_mask = 0
        for modifier in gdk_modifiers:
            if "Mod" not in Gtk.accelerator_name(
                    0, modifier) or "Mod4" in Gtk.accelerator_name(
                        0, modifier):
                self.known_modifiers_mask |= modifier

    def grab(self, key):
        accelerator = key
        accelerator = accelerator.replace("<Super>", "<Mod4>")
        keyval, modifiers = Gtk.accelerator_parse(accelerator)
        if not accelerator or (not keyval and not modifiers):
            self.keycode = None
            self.modifiers = None
            return False

        self.keytext = key
        try:
            self.keycode = self.keymap.get_entries_for_keyval(
                keyval).keys[0].keycode
        except AttributeError:
            # In older Gtk3 the get_entries_for_keyval() returns an unnamed tuple...
            self.keycode = self.keymap.get_entries_for_keyval(
                keyval)[1][0].keycode
        self.modifiers = int(modifiers)

        # Request to receive key press/release reports from other windows that may not be using modifiers
        catch = error.CatchError(error.BadWindow)
        if self.modifiers:
            self.window.change_attributes(onerror=catch,
                                          event_mask=X.KeyPressMask
                                          | X.KeyReleaseMask)
        else:
            self.window.change_attributes(onerror=catch,
                                          event_mask=X.NoEventMask)
        if catch.get_error():
            return False

        catch = error.CatchError(error.BadAccess)
        for ignored_mask in self.ignored_masks:
            mod = modifiers | ignored_mask
            result = self.window.grab_key(self.keycode,
                                          mod,
                                          True,
                                          X.GrabModeAsync,
                                          X.GrabModeAsync,
                                          onerror=catch)
        self.display.flush()
        if catch.get_error():
            return False

        catch = error.CatchError(error.BadCursor)
        if not self.modifiers:
            # We grab Super+click so that we can forward it to the window manager and allow Super+click bindings (window move, resize, etc.)
            self.window.grab_button(X.AnyButton, X.Mod4Mask, True,
                                    X.ButtonPressMask, X.GrabModeSync,
                                    X.GrabModeAsync, X.NONE, X.NONE)
        self.display.flush()
        if catch.get_error():
            return False

        return True

    def ungrab(self):
        if self.keycode:
            self.window.ungrab_key(self.keycode, X.AnyModifier, self.window)

    def rebind(self, key):
        self.ungrab()
        if key != "":
            self.grab(key)
        else:
            self.keytext = ""

    def set_focus_window(self, window=None):
        self.ungrab()
        if window is None:
            self.window = self.screen.root
        else:
            self.window = self.display.create_resource_object(
                "window", window.get_xid())
        self.grab(self.keytext)

    def get_mask_combinations(self, mask):
        return [x for x in range(mask + 1) if not (x & ~mask)]

    def idle(self):
        self.emit("activate")
        return False

    def activate(self):
        GLib.idle_add(self.run)

    # Get which window manager we're currently using (Marco, Compiz, Metacity, etc...)
    def get_wm(self):
        name = ''
        wm_check = self.display.get_atom('_NET_SUPPORTING_WM_CHECK')
        win_id = self.window.get_full_property(wm_check, X.AnyPropertyType)
        if win_id:
            w = self.display.create_resource_object("window", win_id.value[0])
            wm_name = self.display.get_atom('_NET_WM_NAME')
            prop = w.get_full_property(wm_name, X.AnyPropertyType)
            if prop:
                name = prop.value
        return name.lower()

    def run(self):
        self.running = True
        wait_for_release = False
        while self.running:
            event = self.display.next_event()

            if self.modifiers:
                # Use simpler logic when using traditional combined keybindings
                modifiers = event.state & self.known_modifiers_mask
                if event.type == X.KeyPress and event.detail == self.keycode and modifiers == self.modifiers:
                    GLib.idle_add(self.idle)

            else:
                try:
                    # KeyPress
                    if event.type == X.KeyPress and event.detail == self.keycode and not wait_for_release:
                        modifiers = event.state & self.known_modifiers_mask
                        if modifiers == self.modifiers:
                            wait_for_release = True

                    # KeyRelease
                    elif event.type == X.KeyRelease and event.detail == self.keycode and wait_for_release:
                        GLib.idle_add(self.idle)
                        wait_for_release = False

                    # Modifiers are often used with mouse events - don't let the system swallow those
                    elif event.type == X.ButtonPress:
                        self.display.allow_events(X.ReplayPointer,
                                                  X.CurrentTime)
                        # Compiz would rather not have the event sent to it and just read it from the replayed queue
                        wm = self.get_wm()
                        if wm != "compiz":
                            self.display.ungrab_keyboard(X.CurrentTime)
                            self.display.ungrab_pointer(X.CurrentTime)
                            query_pointer = self.window.query_pointer()
                            self.display.send_event(query_pointer.child, event,
                                                    X.ButtonPressMask, True)
                        wait_for_release = False

                    # If the user presses another key in between the KeyPress and the KeyRelease, they
                    # meant to use a different shortcut
                    else:
                        self.display.ungrab_keyboard(X.CurrentTime)
                        # Send the event up in case another window is listening to it
                        self.display.send_event(
                            event.window, event,
                            X.KeyPressMask | X.KeyReleaseMask, True)
                        wait_for_release = False
                except AttributeError:
                    continue

    def stop(self):
        self.running = False
        self.ungrab()
        self.display.close()