Как настроить устройства libinput из кода C?

На wayland нет конфигурационного файла для libinput. Обычно это не проблема, потому что среды рабочего стола (например, Gnome) часто предлагают способ настройки устройств. Однако нет возможности включить эмуляцию среднего щелчка для сенсорной панели. По умолчанию (используя области кнопок, чтобы я мог щелкнуть правой кнопкой мыши в нижней правой части сенсорной панели) также создается область средней кнопки. Это часто приводит к тому, что я нажимаю среднюю кнопку, когда вместо этого пытаюсь щелкнуть левой кнопкой мыши и щелкнуть средней кнопкой (что приводит к вставке чего-либо). Эта область среднего щелчка может быть отключена, если включена эмуляция среднего уровня, однако, поскольку Gnome не предоставляет способа настроить это, я решил попытаться создать свою собственную программу для этого.

Я просмотрел документы и примеры API libinput (к сожалению, я не могу найти примеры конфигурации устройства). Следующий код — это то, что я собрал (скомпилировал с помощью команды в комментарии).

/**
 * Simple program to setup libinput touchpad to use middle click emulation in wayland.
 *
 * To build install libinput-devel and libudev-devel
 * gcc -o middleemulation main.c `pkg-config --cflags --libs libinput libudev`
 * 
 * Copyright 2019 Marcus Behel
 *
 *Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <libudev.h>
#include <libinput.h>

static int open_restricted(const char *path, int flags, void *user_data){
  int fd = open(path, flags);
  return fd < 0 ? -errno : fd;
}

static void close_restricted(int fd, void *user_data){
  close(fd);
}

const static struct libinput_interface interface = {
        .open_restricted = open_restricted,
        .close_restricted = close_restricted,
};

int main(void){

  struct libinput *li;
  struct libinput_event *ev;
  struct udev *udev = udev_new();
  int dev_count = 0, tp_count = 0;

  li = libinput_udev_create_context(&interface, NULL, udev);
  libinput_udev_assign_seat(li, "seat0");
  libinput_dispatch(li);

  while ((ev = libinput_get_event(li))) {
    if (libinput_event_get_type(ev) == LIBINPUT_EVENT_DEVICE_ADDED){
      dev_count++;

      double w = 0, h = 0;
      struct libinput_device *dev = libinput_event_get_device(ev);
      const char *name = libinput_device_get_name(dev);
      if(libinput_device_has_capability(dev, LIBINPUT_DEVICE_CAP_POINTER) &&
     libinput_device_get_size(dev, &w, &h) == 0){
    // Pointer with a size is a touchpad
    tp_count++;

    // This is a touchpad. Enable middle click emulation
    printf("Found touchpad: '%s'.\n", name);

    printf("Is middle click enabled: %s.\n", libinput_device_config_middle_emulation_get_enabled(dev) ? "true" : "false");

    if(libinput_device_config_middle_emulation_is_available(dev)){
      printf("Enabling middle emulation for device...");
      enum libinput_config_status err = libinput_device_config_middle_emulation_set_enabled(dev, LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED);

      if(err == LIBINPUT_CONFIG_STATUS_SUCCESS){
        printf("Succeeded.\n");
      }else{
        printf("Failed.\n");
      }

      printf("Is middle click enabled: %s.\n\n", libinput_device_config_middle_emulation_get_enabled(dev) ? "true" : "false");

    }else{
      printf("Device does not support middle emulation.\n\n");
    }
      }
    }

    libinput_event_destroy(ev);
    libinput_dispatch(li);
  }

  libinput_unref(li);

  if(dev_count == 0){
    fprintf(stderr, "No libinput devices were found. Run this as root and make sure libinput driver is enabled.\n");
    return 1;
  }

  if(tp_count == 0){
    printf("No touchpads found on this system.");
  }

  return 0;
}

Я тестировал это на Ubuntu 18.04 (Dell Inspiron 5000) и на Fedora 30 (HP Pavilion 15). В обоих случаях программа указывает на успех, однако при запуске libinput list-devices она по-прежнему показывает, что промежуточная эмуляция отключена, и поведение не меняется.

Выход из программы (HP Pavilion)

Found touchpad: 'SynPS/2 Synaptics TouchPad'.
Is middle click enabled: false.
Enabling middle emulation for device...Succeeded.
Is middle click enabled: true.

Вывод из libinput list-devices после запуска программы

Device:           SynPS/2 Synaptics TouchPad
Kernel:           /dev/input/event4
Group:            9
Seat:             seat0, default
Size:             106x61mm
Capabilities:     pointer gesture
Tap-to-click:     disabled
Tap-and-drag:     enabled
Tap drag lock:    disabled
Left-handed:      disabled
Nat.scrolling:    disabled
Middle emulation: disabled
Calibration:      n/a
Scroll methods:   *two-finger edge 
Click methods:    *button-areas clickfinger 
Disable-w-typing: enabled
Accel profiles:   none
Rotation:         n/a


person Androprise    schedule 25.06.2019    source источник
comment
Может быть, изменения для каждого процесса?   -  person Bjorn A.    schedule 25.06.2019


Ответы (1)


Похоже, для работы по назначению потребуется библиотека предварительной загрузки. Решение здесь: https://github.com/gaul/libinput-force-middle-click-emulation.

person Androprise    schedule 25.06.2019
comment
К сожалению, это на самом деле не решает проблему, так как активация эмуляции среднего щелчка не отключает надоедливую виртуальную кнопку в нижней части сенсорной панели. @marJavaCode Удалось ли вам это исправить? - person Romain Bigz; 26.05.2020
comment
@Romain Bigz У меня это сработало на Fedora 30. У меня больше нет этой системы, поэтому я не могу проверить. Я помню, что установил hook.so в /usr/local/lib и соответственно изменил путь в команде экспорта. У меня не было / нет системы Wayland, использующей mutter 3.36.1+, поэтому я не знаю об использовании команды gsettings в README этого проекта. - person Androprise; 07.06.2020