예제 #1
0
def record_context(dpy, ev_range, dev_range):
    range_spec = xlib.XRecordAllocRange()
    range_spec.contents.delivered_events.first = ev_range[0]
    range_spec.contents.delivered_events.last = ev_range[1]
    range_spec.contents.device_events.first = dev_range[0]
    range_spec.contents.device_events.last = dev_range[1]
    rec_ctx = xlib.XRecordCreateContext(
        dpy, 0, xlib.byref(xlib.c_ulong(xlib.XRecordAllClients)), 1,
        xlib.byref(range_spec), 1)
    xlib.XFree(range_spec)
    return rec_ctx
예제 #2
0
def record_context(dpy, ev_range, dev_range):
    range_spec = xlib.XRecordAllocRange()
    range_spec.contents.delivered_events.first = ev_range[0]
    range_spec.contents.delivered_events.last = ev_range[1]
    range_spec.contents.device_events.first = dev_range[0]
    range_spec.contents.device_events.last = dev_range[1]
    rec_ctx = xlib.XRecordCreateContext(
        dpy, 0,
        xlib.byref(xlib.c_ulong(xlib.XRecordAllClients)), 1,
        xlib.byref(range_spec), 1)
    xlib.XFree(range_spec)
    return rec_ctx
예제 #3
0
def create_replay_window(dpy):
    win_attr = xlib.XSetWindowAttributes()
    win_attr.override_redirect = True
    win = xlib.XCreateWindow(dpy, xlib.XDefaultRootWindow(dpy), 0, 0, 1, 1, 0,
                             xlib.CopyFromParent, xlib.InputOnly, None,
                             xlib.CWOverrideRedirect, xlib.byref(win_attr))
    return win
예제 #4
0
def record_context(dpy, ev_ranges, dev_ranges):
    ev_ranges = coalesce_ranges(ev_ranges)
    dev_ranges = coalesce_ranges(dev_ranges)

    specs = max(len(ev_ranges), len(dev_ranges))
    range_specs = (xlib.POINTER(xlib.XRecordRange) * specs)()

    for i in range(specs):
        range_specs[i] = xlib.XRecordAllocRange()
        if len(ev_ranges) > i:
            range_specs[i].contents.delivered_events.first = ev_ranges[i][0]
            range_specs[i].contents.delivered_events.last = ev_ranges[i][1]
        if len(dev_ranges) > i:
            range_specs[i].contents.device_events.first = dev_ranges[i][0]
            range_specs[i].contents.device_events.last = dev_ranges[i][1]

    rec_ctx = xlib.XRecordCreateContext(
        dpy, 0,
        xlib.byref(xlib.c_ulong(xlib.XRecordAllClients)), 1,
        range_specs, specs)

    for i in range(specs):
        xlib.XFree(range_specs[i])

    return rec_ctx
예제 #5
0
def record_context(dpy, ev_ranges, dev_ranges):
    ev_ranges = coalesce_ranges(ev_ranges)
    dev_ranges = coalesce_ranges(dev_ranges)

    specs = max(len(ev_ranges), len(dev_ranges))
    range_specs = (xlib.POINTER(xlib.XRecordRange) * specs)()

    for i in range(specs):
        range_specs[i] = xlib.XRecordAllocRange()
        if len(ev_ranges) > i:
            range_specs[i].contents.delivered_events.first = ev_ranges[i][0]
            range_specs[i].contents.delivered_events.last = ev_ranges[i][1]
        if len(dev_ranges) > i:
            range_specs[i].contents.device_events.first = dev_ranges[i][0]
            range_specs[i].contents.device_events.last = dev_ranges[i][1]

    rec_ctx = xlib.XRecordCreateContext(
        dpy, 0,
        xlib.byref(xlib.c_ulong(xlib.XRecordAllClients)), 1,
        range_specs, specs)

    for i in range(specs):
        xlib.XFree(range_specs[i])

    return rec_ctx
예제 #6
0
 def _event_keypress(self, kev, data):
     buf = xlib.create_string_buffer(16)
     keysym = xlib.KeySym()
     status = xlib.Status()
     ret = xlib.Xutf8LookupString(self._kbd_replay_xic, kev, buf, len(buf),
                                  xlib.byref(keysym), xlib.byref(status))
     if ret != xlib.NoSymbol:
         if 32 <= keysym.value <= 126:
             # avoid ctrl sequences, just take the character value
             data.string = chr(keysym.value)
         else:
             try:
                 data.string = buf.value.decode('utf-8')
             except UnicodeDecodeError:
                 pass
     data.keysym = keysym.value
     data.status = status.value
예제 #7
0
 def _event_keypress(self, kev, data):
     buf = xlib.create_string_buffer(16)
     keysym = xlib.KeySym()
     status = xlib.Status()
     ret = xlib.Xutf8LookupString(self.replay_xic, kev, buf, len(buf),
                                  xlib.byref(keysym), xlib.byref(status))
     if ret != xlib.NoSymbol:
         if 32 <= keysym.value <= 126:
             # avoid ctrl sequences, just take the character value
             data.string = chr(keysym.value)
         else:
             try:
                 data.string = buf.value.decode('utf-8')
             except UnicodeDecodeError:
                 pass
     data.keysym = keysym.value
     data.status = status.value
예제 #8
0
def phantom_release(dpy, kev):
    if not xlib.XPending(dpy):
        return False
    ev = xlib.XEvent()
    xlib.XPeekEvent(dpy, xlib.byref(ev))
    return (ev.type == xlib.KeyPress and \
            ev.xkey.state == kev.state and \
            ev.xkey.keycode == kev.keycode and \
            ev.xkey.time == kev.time)
예제 #9
0
def create_replay_window(dpy):
    win_attr = xlib.XSetWindowAttributes()
    win_attr.override_redirect = True
    win = xlib.XCreateWindow(dpy, xlib.XDefaultRootWindow(dpy),
                             0, 0, 1, 1, 0,
                             xlib.CopyFromParent, xlib.InputOnly, None,
                             xlib.CWOverrideRedirect,
                             xlib.byref(win_attr))
    return win
예제 #10
0
def phantom_release(dpy, kev):
    if not xlib.XPending(dpy):
        return False
    ev = xlib.XEvent()
    xlib.XPeekEvent(dpy, xlib.byref(ev))
    return (ev.type == xlib.KeyPress and \
            ev.xkey.state == kev.state and \
            ev.xkey.keycode == kev.keycode and \
            ev.xkey.time == kev.time)
예제 #11
0
    def run(self):
        # control connection
        self.control_dpy = xlib.XOpenDisplay(None)
        xlib.XSynchronize(self.control_dpy, True)

        # unmapped replay window
        self.replay_dpy = xlib.XOpenDisplay(None)
        self.custom_atom = xlib.XInternAtom(self.replay_dpy, b"SCREENKEY",
                                            False)
        replay_fd = xlib.XConnectionNumber(self.replay_dpy)
        self.replay_win = create_replay_window(self.replay_dpy)

        if self.input_types & InputType.keyboard:
            self._kbd_init()

        # initialize recording context
        ev_ranges = []
        dev_ranges = []
        if self.input_types & InputType.keyboard:
            ev_ranges.append([xlib.FocusIn, xlib.FocusOut])
            dev_ranges.append([xlib.KeyPress, xlib.KeyRelease])
        if self.input_types & InputType.button:
            dev_ranges.append([xlib.ButtonPress, xlib.ButtonRelease])
        if self.input_types & InputType.movement:
            dev_ranges.append([xlib.MotionNotify, xlib.MotionNotify])
        self.record_ctx = record_context(self.control_dpy, ev_ranges,
                                         dev_ranges)

        record_dpy = xlib.XOpenDisplay(None)
        record_fd = xlib.XConnectionNumber(record_dpy)
        # we need to keep the record_ref alive(!)
        record_ref = record_enable(record_dpy, self.record_ctx,
                                   self._event_received)

        # event loop
        self.lock.release()
        while True:
            with self.lock:
                if self.stopped:
                    break

            r_fd = []
            if xlib.XPending(record_dpy):
                r_fd.append(record_fd)
            if xlib.XPending(self.replay_dpy):
                r_fd.append(replay_fd)
            if not r_fd:
                r_fd, _, _ = select.select([record_fd, replay_fd], [], [])
            if not r_fd:
                break

            if record_fd in r_fd:
                xlib.XRecordProcessReplies(record_dpy)
                xlib.XFlush(self.replay_dpy)

            if replay_fd in r_fd:
                ev = xlib.XEvent()
                xlib.XNextEvent(self.replay_dpy, xlib.byref(ev))
                if self.input_types & InputType.keyboard:
                    self._kbd_process(ev)

        # finalize
        xlib.XRecordFreeContext(self.control_dpy, self.record_ctx)
        xlib.XCloseDisplay(self.control_dpy)
        xlib.XCloseDisplay(record_dpy)
        del record_ref

        if self.input_types & InputType.keyboard:
            self._kbd_del()

        xlib.XDestroyWindow(self.replay_dpy, self.replay_win)
        xlib.XCloseDisplay(self.replay_dpy)
예제 #12
0
    def run(self):
        self.control_dpy = xlib.XOpenDisplay(None)
        xlib.XSynchronize(self.control_dpy, True)
        self.record_ctx = record_context(self.control_dpy,
                                         [xlib.FocusIn, xlib.FocusOut],
                                         [xlib.KeyPress, xlib.KeyRelease])
        record_dpy = xlib.XOpenDisplay(None)
        record_fd = xlib.XConnectionNumber(record_dpy)

        # note that we never ever map the window
        self.replay_dpy = xlib.XOpenDisplay(None)
        self.custom_atom = xlib.XInternAtom(self.replay_dpy, "SCREENKEY",
                                            False)
        replay_fd = xlib.XConnectionNumber(self.replay_dpy)
        self.replay_win = create_replay_window(self.replay_dpy)

        if self.compose:
            style = xlib.XIMPreeditNothing | xlib.XIMStatusNothing
        else:
            style = xlib.XIMPreeditNone | xlib.XIMStatusNone

        # TODO: implement preedit callbacks for on-the-spot composition
        #       (this would fix focus-stealing for the global IM state)
        replay_xim = xlib.XOpenIM(self.replay_dpy, None, None, None)
        if not replay_xim:
            raise Exception("Cannot initialize input method")

        self.replay_xic = xlib.XCreateIC(replay_xim, xlib.XNClientWindow,
                                         self.replay_win, xlib.XNInputStyle,
                                         style, None)
        xlib.XSetICFocus(self.replay_xic)

        # we need to keep the proc_ref alive
        proc_ref = record_enable(record_dpy, self.record_ctx,
                                 self._event_received)
        last_ev = xlib.XEvent()

        self.lock.release()
        while True:
            with self.lock:
                if self.stopped:
                    break

            r_fd = []
            if xlib.XPending(record_dpy):
                r_fd.append(record_fd)
            if xlib.XPending(self.replay_dpy):
                r_fd.append(replay_fd)
            if not r_fd:
                r_fd, _, _ = select.select([record_fd, replay_fd], [], [])
            if not r_fd:
                break

            if record_fd in r_fd:
                xlib.XRecordProcessReplies(record_dpy)
                xlib.XFlush(self.replay_dpy)

            if replay_fd in r_fd:
                ev = xlib.XEvent()
                xlib.XNextEvent(self.replay_dpy, xlib.byref(ev))
                if ev.type == xlib.ClientMessage and \
                   ev.xclient.message_type == self.custom_atom:
                    if ev.xclient.data[0] in [xlib.FocusIn, xlib.FocusOut]:
                        # We do not keep track of multiple XICs, just reset
                        xic = xlib.Xutf8ResetIC(self.replay_xic)
                        if xic is not None: xlib.XFree(xic)
                    continue
                elif ev.type in [xlib.KeyPress, xlib.KeyRelease]:
                    ev.xkey.send_event = False
                    ev.xkey.window = self.replay_win

                filtered = bool(xlib.XFilterEvent(ev, 0))
                if ev.type not in [xlib.KeyPress, xlib.KeyRelease]:
                    continue
                if ev.type == xlib.KeyRelease and \
                   phantom_release(self.replay_dpy, ev.xkey):
                    continue

                data = KeyData()
                data.filtered = filtered
                data.pressed = (ev.type == xlib.KeyPress)
                data.repeated = (ev.type == last_ev.type and \
                                 ev.xkey.state == last_ev.xkey.state and \
                                 ev.xkey.keycode == last_ev.xkey.keycode)
                data.mods_mask = ev.xkey.state
                self._event_modifiers(ev.xkey, data)
                if not data.filtered and data.pressed and self.translate:
                    self._event_keypress(ev.xkey, data)
                else:
                    self._event_lookup(ev.xkey, data)
                self._event_processed(data)
                last_ev = ev

        xlib.XRecordFreeContext(self.control_dpy, self.record_ctx)
        xlib.XCloseDisplay(self.control_dpy)
        xlib.XCloseDisplay(record_dpy)
        del proc_ref

        xlib.XDestroyIC(self.replay_xic)
        xlib.XCloseIM(replay_xim)
        xlib.XDestroyWindow(self.replay_dpy, self.replay_win)
        xlib.XCloseDisplay(self.replay_dpy)
예제 #13
0
    def run(self):
        self.control_dpy = xlib.XOpenDisplay(None)
        xlib.XSynchronize(self.control_dpy, True)
        self.record_ctx = record_context(self.control_dpy,
                                         [xlib.FocusIn, xlib.FocusOut],
                                         [xlib.KeyPress, xlib.KeyRelease])
        record_dpy = xlib.XOpenDisplay(None)
        record_fd = xlib.XConnectionNumber(record_dpy)

        # note that we never ever map the window
        self.replay_dpy = xlib.XOpenDisplay(None)
        replay_fd = xlib.XConnectionNumber(self.replay_dpy)
        self.replay_win = create_replay_window(self.replay_dpy)

        if self.compose:
            style = xlib.XIMPreeditNothing | xlib.XIMStatusNothing
        else:
            style = xlib.XIMPreeditNone | xlib.XIMStatusNone

        # TODO: implement preedit callbacks for on-the-spot composition
        #       (this would fix focus-stealing for the global IM state)
        replay_xim = xlib.XOpenIM(self.replay_dpy, None, None, None)
        self.replay_xic = xlib.XCreateIC(replay_xim,
                                         xlib.XNClientWindow, self.replay_win,
                                         xlib.XNInputStyle, style,
                                         None)
        xlib.XSetICFocus(self.replay_xic)

        # we need to keep the proc_ref alive
        proc_ref = record_enable(record_dpy, self.record_ctx, self._event_received)
        last_ev = xlib.XEvent()

        self.lock.release()
        while True:
            with self.lock:
                if self.stopped:
                    break

            r_fd = []
            if xlib.XPending(record_dpy):
                r_fd.append(record_fd)
            if xlib.XPending(self.replay_dpy):
                r_fd.append(replay_fd)
            if not r_fd:
                r_fd, _, _ = select.select([record_fd, replay_fd], [], [])
            if not r_fd:
                break

            if record_fd in r_fd:
                xlib.XRecordProcessReplies(record_dpy)
                xlib.XFlush(self.replay_dpy)

            if replay_fd in r_fd:
                ev = xlib.XEvent()
                xlib.XNextEvent(self.replay_dpy, xlib.byref(ev))
                if ev.type in [xlib.KeyPress, xlib.KeyRelease]:
                    ev.xkey.send_event = False
                    ev.xkey.window = self.replay_win
                filtered = bool(xlib.XFilterEvent(ev, 0))
                if ev.type not in [xlib.KeyPress, xlib.KeyRelease]:
                    continue
                if ev.type == xlib.KeyRelease and \
                   phantom_release(self.replay_dpy, ev.xkey):
                    continue

                data = KeyData()
                data.filtered = filtered
                data.pressed = (ev.type == xlib.KeyPress)
                data.repeated = (ev.type == last_ev.type and \
                                 ev.xkey.state == last_ev.xkey.state and \
                                 ev.xkey.keycode == last_ev.xkey.keycode)
                data.mods_mask = ev.xkey.state
                self._event_modifiers(ev.xkey, data)
                if not data.filtered and data.pressed and self.translate:
                    self._event_keypress(ev.xkey, data)
                else:
                    self._event_lookup(ev.xkey, data)
                self._event_processed(data)
                last_ev = ev

        xlib.XRecordFreeContext(self.control_dpy, self.record_ctx)
        xlib.XCloseDisplay(self.control_dpy)
        xlib.XCloseDisplay(record_dpy)
        del proc_ref

        xlib.XDestroyIC(self.replay_xic)
        xlib.XCloseIM(replay_xim)
        xlib.XDestroyWindow(self.replay_dpy, self.replay_win)
        xlib.XCloseDisplay(self.replay_dpy)
예제 #14
0
    def run(self):
        # control connection
        self.control_dpy = xlib.XOpenDisplay(None)
        xlib.XSynchronize(self.control_dpy, True)

        # unmapped replay window
        self.replay_dpy = xlib.XOpenDisplay(None)
        self.custom_atom = xlib.XInternAtom(self.replay_dpy, b"SCREENKEY", False)
        replay_fd = xlib.XConnectionNumber(self.replay_dpy)
        self.replay_win = create_replay_window(self.replay_dpy)

        # bail during initialization errors
        try:
            if self.input_types & InputType.keyboard:
                self._kbd_init()
        except Exception as e:
            self.error = e
            xlib.XCloseDisplay(self.control_dpy)
            xlib.XDestroyWindow(self.replay_dpy, self.replay_win)
            xlib.XCloseDisplay(self.replay_dpy)

            # cheap wakeup() equivalent for compatibility
            glib.idle_add(self._event_callback, None)

            self._stop = True
            self.lock.release()
            return

        # initialize recording context
        ev_ranges = []
        dev_ranges = []
        if self.input_types & InputType.keyboard:
            ev_ranges.append([xlib.FocusIn, xlib.FocusOut])
            dev_ranges.append([xlib.KeyPress, xlib.KeyRelease])
        if self.input_types & InputType.button:
            dev_ranges.append([xlib.ButtonPress, xlib.ButtonRelease])
        if self.input_types & InputType.movement:
            dev_ranges.append([xlib.MotionNotify, xlib.MotionNotify])
        self.record_ctx = record_context(self.control_dpy, ev_ranges, dev_ranges);

        record_dpy = xlib.XOpenDisplay(None)
        record_fd = xlib.XConnectionNumber(record_dpy)
        # we need to keep the record_ref alive(!)
        record_ref = record_enable(record_dpy, self.record_ctx, self._event_received)

        # event loop
        self.lock.release()
        while True:
            with self.lock:
                if self._stop:
                    break

            r_fd = []
            if xlib.XPending(record_dpy):
                r_fd.append(record_fd)
            if xlib.XPending(self.replay_dpy):
                r_fd.append(replay_fd)
            if not r_fd:
                r_fd, _, _ = select.select([record_fd, replay_fd], [], [])
            if not r_fd:
                break

            if record_fd in r_fd:
                xlib.XRecordProcessReplies(record_dpy)
                xlib.XFlush(self.replay_dpy)

            if replay_fd in r_fd:
                ev = xlib.XEvent()
                xlib.XNextEvent(self.replay_dpy, xlib.byref(ev))
                if self.input_types & InputType.keyboard:
                    self._kbd_process(ev)

        # finalize
        self.lock.acquire()

        xlib.XRecordFreeContext(self.control_dpy, self.record_ctx)
        xlib.XCloseDisplay(self.control_dpy)
        xlib.XCloseDisplay(record_dpy)
        del record_ref

        if self.input_types & InputType.keyboard:
            self._kbd_del()

        xlib.XDestroyWindow(self.replay_dpy, self.replay_win)
        xlib.XCloseDisplay(self.replay_dpy)

        self._stop = True
        self.lock.release()