def _kbd_init(self): self._kbd_last_ev = xlib.XEvent() if self.kbd_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) self._kbd_replay_xim = xlib.XOpenIM(self.replay_dpy, None, None, None) if not self._kbd_replay_xim: raise Exception("Cannot initialize input method") self._kbd_replay_xic = xlib.XCreateIC(self._kbd_replay_xim, xlib.XNClientWindow, self.replay_win, xlib.XNInputStyle, style, None) xlib.XSetICFocus(self._kbd_replay_xic)
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)