Как отправить нажатие клавиши после захвата другого ключевого события в X11 - PullRequest
0 голосов
/ 14 марта 2020

Я пытаюсь реализовать скрипт Python в Linux для захвата клавиши, нажмите a, отправьте клавишу, снова нажмите a (чтобы она дважды отправляла a).

Через некоторый код в https://github.com/PeterHo/Linalfred/blob/master/src/globalhotkey.py я пришел к следующему.

Ключ получен в порядке, но отправка события нажатия клавиши ничего не делает. Что мне здесь не хватает?

Я также посмотрел на вопрос глобально перехватывать, игнорировать и отправлять ключевые события с помощью python xlib, распознавать ложные данные . Опубликованное решение, похоже, даже не получает события (после переноса с print на Python 3).

import time

from Xlib import X, protocol
from Xlib.display import Display
from Xlib.ext import record

display = None
root = None

def handler(reply):
    data = reply.data
    while len(data):
        event, data = protocol.rq.EventField(None).parse_binary_value(data, display.display, None, None)
        if event.type == X.KeyPress:
            keycode = event.detail
            print(keycode)
            if keycode == 38:
                window = Display().get_input_focus().focus
                event = protocol.event.KeyPress(
                    time=int(time.time()),
                    root=root,
                    window=window,
                    same_screen=0, child=X.NONE,
                    root_x=0, root_y=0, event_x=0, event_y=0,
                    state=0,
                    detail=keycode
                )
                window.send_event(event, propagate=True)
                event = protocol.event.KeyRelease(
                    time=int(time.time()),
                    root=root,
                    window=window,
                    same_screen=0, child=X.NONE,
                    root_x=0, root_y=0, event_x=0, event_y=0,
                    state=0,
                    detail=keycode
                )
                window.send_event(event, propagate=True)


def main():
    global display, root
    display = Display()
    root = display.screen().root

    ctx = 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.KeyReleaseMask, X.ButtonReleaseMask),
            'errors': (0, 0),
            'client_started': False,
            'client_died': False,
        }]
    )
    display.record_enable_context(ctx, handler)
    display.record_free_context(ctx)

    while True:
        # Infinite wait, doesn't do anything as no events are grabbed.
        event = root.display.next_event()


if __name__ == '__main__':
    main()

1 Ответ

0 голосов
/ 15 марта 2020

Я сегодня погуглил немного больше, и наткнулся на Отправка нажатий клавиш на Speci c windows в X , который работал для меня.

Ключевая идея состоит в том, чтобы используйте display вместо window для отправки событий и sync на дисплее. Без синхронизации дисплея нажатие клавиши вообще не будет зарегистрировано.

disp.send_event(window, event, propagate=True)
disp.sync()

Применительно к нашему сценарию, приведенному выше, у нас есть следующая рабочая версия:

import time

from Xlib import X, protocol
from Xlib.display import Display
from Xlib.ext import record

display = None
root = None

def handler(reply):
    data = reply.data
    while len(data):
        event, data = protocol.rq.EventField(None).parse_binary_value(data, display.display, None, None)
        if event.type == X.KeyPress:
            keycode = event.detail
            print(keycode)
            if keycode == 38:
                disp = Display()
                window = disp.get_input_focus().focus
                root = disp.screen().root
                event = protocol.event.KeyPress(
                    time=0,
                    root=root, window=window, same_screen=0, child=X.NONE,
                    root_x=0, root_y=0, event_x=0, event_y=0,
                    state=0, detail=keycode
                )
                disp.send_event(window, event, propagate=True)
                disp.sync()
                event = protocol.event.KeyRelease(
                    time=0,
                    root=root, window=window, same_screen=0, child=X.NONE,
                    root_x=0, root_y=0, event_x=0, event_y=0,
                    state=0, detail=keycode
                )
                disp.send_event(window, event, propagate=True)
                disp.sync()


def main():
    global display, root
    display = Display()
    root = display.screen().root

    ctx = 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.KeyReleaseMask, X.ButtonReleaseMask),
            'errors': (0, 0),
            'client_started': False,
            'client_died': False,
        }]
    )
    display.record_enable_context(ctx, handler)
    display.record_free_context(ctx)

    while True:
        # Infinite wait, doesn't do anything as no events are grabbed.
        event = root.display.next_event()


if __name__ == '__main__':
    main()
...