Подтвердить что ты не робот

Как вставить синтетические события мыши в очередь ввода X11

У меня есть встроенное устройство под управлением Linux/X11, которое подключается к устройству, которое передает события касания через USB-соединение. Это устройство не распознается ни в какой форме стандартного ввода указателя/мыши. То, что я пытаюсь сделать, это найти способ "вставлять" события мыши в X11, когда внешнее устройство сообщает об этом событии.

Это позволит удалить необходимость моего приложения (написанного на C с использованием Gtk +) для подделки нажатий мыши с вызовами Gtk +.

Если это может быть сделано, моему приложению Gtk + не нужно знать или заботиться об устройстве, генерирующем события касания. Он просто появится в приложении в качестве стандартных событий мыши.

Кто-нибудь знает, как вставить синтетические события мыши в X11?

Сейчас я делаю следующее, которое работает, но не оптимально.

GtkWidget *btnSpin;     /* sample button */

gboolean buttonPress_cb( void *btn );
gboolean buttonDePress_cb( void *btn );


/*  make this call after the device library calls the TouchEvent_cb() callback
    and the application has determined which, if any, button was touched

    In this example we are assuming btnSpin was touched.

    This function will, in 5ms, begin the process of causing the button to do it 
    normal animation ( button in, button out effects ) and then send the actual
    button_clicked event to the button.
*/
g_timeout_add(5, (GSourceFunc) buttonPress_cb, (void *)btnSpin);


/*  this callback is fired 5ms after the g_timeout_add() function above.
    It first sets the button state to ACTIVE to begin the animation cycle (pressed look)
    And then 250ms later calls buttonDePress_cb which will make the button look un-pressed
    and then send the button_clicked event.
*/    
gboolean buttonPress_cb( void *btn )
{

    gtk_widget_set_state((GtkWidget *)btn, GTK_STATE_ACTIVE);
    g_timeout_add(250, (GSourceFunc) buttonDePress_cb, btn);


    return( FALSE );
}

/*  Sets button state back to NORMAL ( not pressed look )
    and sends the button_clicked event so that the registered signal handler for the
    button can be activated
*/
gboolean buttonDePress_cb( void *btn )
{

    gtk_widget_set_state( btn, GTK_STATE_NORMAL);
    gtk_button_clicked( GTK_BUTTON( btn ));

    return( FALSE );
}
4b9b3361

Ответ 1

В системе ввода Linux есть средство для использования в пользовательском пространстве устройств ввода, называемых uinput. Вы можете написать фоновую программу, которая использует вашу библиотеку обратного вызова устройства для отправки входных событий в ядро. Сервер X (при условии, что он использует модуль ввода evdev) будет обрабатывать их так же, как и любое другое событие мыши.

Там есть библиотека под названием libsuinput, что делает ее довольно простой. Он даже включает пример программы ввода мыши, которую вы, вероятно, можете использовать в качестве модели. Однако, поскольку ваше устройство является сенсорным устройством, оно, вероятно, будет использовать абсолютные оси (ABS_X, ABS_Y) вместо относительного (REL_X, REL_Y).

Ответ 2

Существует несколько методов.

  • Используйте XSendEvent. Предостережение: некоторые рамки приложения игнорируют события, отправленные с помощью XSendEvent. Я думаю, что Gtk + нет, но я не проверял.
  • Используйте XTestFakeMotionEvent и XTestFakeButtonEvent. Вам нужно расширение XTest на вашем X-сервере.
  • Напишите драйвер ядра для вашего устройства, чтобы он отображался как мышь/тачпад.

Ответ 3

Самое интересное - реализовать драйвер устройства внутри ядра, который создает файл /dev/input/eventX, который говорит об evdev-протоколе. Я рекомендую вам прочитать книгу под названием Linux Device Drivers, если вы хотите это сделать. Книга свободно доступна в Интернете.

Если вы хотите сделать это в пользовательском пространстве, я предлагаю вам использовать Xlib (или XCB). На простом Xlib (язык C) вы можете использовать X Test Extension или XSendEvent().

Также существует бинарный файл xte из пакета xautomation (на Debian, sudo apt-get install xautomation и затем man xte). xte очень прост в использовании, и вы также можете посмотреть его исходный код, чтобы узнать, как использовать X Test Extension.

Указатели

Ответ 4

Похоже, что после небольшого исследования Gtk + использует библиотеку GDK, которая может делать то, что я хочу, без необходимости глубоко вникать в кодирование X11 или писать драйвер ядра. Хотя, если бы у меня было время, я бы предпочел написать драйвер мыши для ядра Linux.

Используя Справочное руководство GDK 2 Я обнаружил, что могу сделать следующее:

Используйте gtk_event_put() для добавления GdkEvent типа GdkEventButton

Структура a GdkEventButton такова:

struct GdkEventButton {
  GdkEventType type;
  GdkWindow *window;
  gint8 send_event;
  guint32 time;
  gdouble x;
  gdouble y;
  gdouble *axes;
  guint state;
  guint button;
  GdkDevice *device;
  gdouble x_root, y_root;
};

Большинство этих полей будут заполнены тривиально, за исключением:

gdouble x;
    the x coordinate of the pointer relative to the window.

gdouble y;
    the y coordinate of the pointer relative to the window.

GdkDevice *device;
    the device where the event originated.

gdouble x_root;
    the x coordinate of the pointer relative to the root of the screen.

gdouble y_root;
    the y coordinate of the pointer relative to the root of the screen.

Мне нужно будет исследовать, как преобразовать координаты корня экрана в относительные координаты окна.

*device - Я не уверен, что мне нужно использовать это поле (значение NULL), потому что это для расширенного устройства ввода. Однако, если мне нужно иметь действительное устройство здесь, я должен иметь возможность использовать gdk_devices_list()