Como definir a posição absoluta do cursor do mouse em Wayland sem usar o mouse?

1

A questão é bem direta.

O que eu teria usado sob X [xdotool] obviamente não funciona avançando, e nenhuma nova solução óbvia surgiu devido à relativa nova adoção da via terrestre.

Soluções que exigem programação são aceitáveis.

    
por Akiva 08.02.2018 / 02:49

2 respostas

4

Você pode usar uinput ( linux/uinput.h ). Funciona tanto em X quanto em Wayland.

A página de documentação acima tem um exemplo que inclui a criação de um dispositivo virtual que se comporta como um mouse:

#include <linux/uinput.h>

void emit(int fd, int type, int code, int val)
{
   struct input_event ie;

   ie.type = type;
   ie.code = code;
   ie.value = val;
   /* timestamp values below are ignored */
   ie.time.tv_sec = 0;
   ie.time.tv_usec = 0;

   write(fd, &ie, sizeof(ie));
}

int main(void)
{
   struct uinput_setup usetup;
   int i = 50;

   int fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);

   /* enable mouse button left and relative events */
   ioctl(fd, UI_SET_EVBIT, EV_KEY);
   ioctl(fd, UI_SET_KEYBIT, BTN_LEFT);

   ioctl(fd, UI_SET_EVBIT, EV_REL);
   ioctl(fd, UI_SET_RELBIT, REL_X);
   ioctl(fd, UI_SET_RELBIT, REL_Y);

   memset(&usetup, 0, sizeof(usetup));
   usetup.id.bustype = BUS_USB;
   usetup.id.vendor = 0x1234; /* sample vendor */
   usetup.id.product = 0x5678; /* sample product */
   strcpy(usetup.name, "Example device");

   ioctl(fd, UI_DEV_SETUP, &usetup);
   ioctl(fd, UI_DEV_CREATE);

   /*
    * On UI_DEV_CREATE the kernel will create the device node for this
    * device. We are inserting a pause here so that userspace has time
    * to detect, initialize the new device, and can start listening to
    * the event, otherwise it will not notice the event we are about
    * to send. This pause is only needed in our example code!
    */
   sleep(1);

   /* Move the mouse diagonally, 5 units per axis */
   while (i--) {
      emit(fd, EV_REL, REL_X, 5);
      emit(fd, EV_REL, REL_Y, 5);
      emit(fd, EV_SYN, SYN_REPORT, 0);
      usleep(15000);
   }

   /*
    * Give userspace some time to read the events before we destroy the
    * device with UI_DEV_DESTOY.
    */
   sleep(1);

   ioctl(fd, UI_DEV_DESTROY);
   close(fd);

   return 0;
}
    
por 08.02.2018 / 04:04
1

Se você não quer escrever o código C para uinput , existem pacotes python e até mesmo alguns depuradores e utilitários de teste que funcionam no mesmo nível evdev , evemu-describe , evemu-device , evemu-play , evemu-record e evemu-event do pacote evemu. Você precisa ser root para usá-los. Aqui está um exemplo que encontra o dispositivo do mouse e os eventos que ele gera, então gera artificialmente um evento para ele.

Primeiro, listamos os dispositivos evdev:

$ sudo evemu-describe 
Available devices:
...
/dev/input/event5:     Logitech USB Optical Mouse
...

Este é um comando interativo, que depois de listar os dispositivos físicos nos pede para escolher um para mais detalhes sobre ele. Nós escolhemos 5, o mouse:

Select the device event number [0-9]: 5
...
# Input device name: "Logitech USB Optical Mouse"
...
# Supported events:
#   Event type 0 (EV_SYN)
#     Event code 0 (SYN_REPORT)
...
#   Event type 1 (EV_KEY)
#     Event code 272 (BTN_LEFT)
#     Event code 273 (BTN_RIGHT)
#     Event code 274 (BTN_MIDDLE)
#   Event type 2 (EV_REL)
#     Event code 0 (REL_X)
#     Event code 1 (REL_Y)
#     Event code 8 (REL_WHEEL)
...

Outro dos comandos do teste evemu nos mostrará os eventos que estão sendo gerados quando movemos o mouse:

$ sudo evemu-record /dev/input/event5
E: 4.223 0002 0000 0004 # EV_REL / REL_X                4
E: 4.223 0000 0000 0000 # ------------ SYN_REPORT (0) ------ +8ms
E: 4.231 0002 0000 0007 # EV_REL / REL_X                7
E: 4.231 0002 0001 0001 # EV_REL / REL_Y                1
E: 4.231 0000 0000 0000 # ------------ SYN_REPORT (0) ------ +8ms

Normalmente, para um movimento do mouse, há o tipo de evento EV_REL, o código de evento REL_X e ou REL_Y para o eixo de movimento relativo e a distância do valor do evento movida (4, 7, 1 acima). Os eventos são seguidos por um evento de sincronização do tipo EV_SYN com o código SYN_REPORT para sinalizar o final do evento.

Podemos injetar nosso próprio evento (por exemplo, um movimento de 20,10) com outro dos comandos de teste:

sudo evemu-event /dev/input/event5 --type EV_REL --code REL_X --value 20
sudo evemu-event /dev/input/event5 --type EV_REL --code REL_Y --value 10 --sync

A opção --sync adiciona o evento SYN_REPORT ao final (o equivalente a --type EV_SYN --code SYN_REPORT ).

Finalmente, outro comando de teste, evemu-device nos permite criar um novo dispositivo de entrada, fornecendo uma descrição como as que já vimos para o mouse. Ele usa /dev/uinput e cria um novo dispositivo /dev/input/event* , que podemos usar para enviar eventos.

Assim, mesmo que você não tenha um mouse, você pode adicionar um dinamicamente e controlá-lo como desejar. Eu não tenho um dispositivo com eventos de posição absoluta para fornecer um exemplo, mas você pode adicionar um dispositivo semelhante a um tablet e enviar eventos de movimentos absolutos através dele.

    
por 08.02.2018 / 16:57