Skip Navigation

ELECOM EX-G extra Button Workaround

ELECOM Trackball EX-G Modelle haben ein neues Chipset, das (mal wieder) die Anzahl Buttons falsch meldet. Für einige Chipsets gibt es dafür schon Workaround-Code im Linux Kernel. Wenn dein extra Button nicht geht, kannst Du seine Clicks mit diesem Beispiel C-Programm (kompilieren mit gcc) detektieren und vllt. irgendwas machen:

 
    
#define _GNU_SOURCE
#include <fcntl.h>
#include <unistd.h>
#include <linux/hiddev.h>
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <spawn.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <errno.h>
#include <string.h>

void sigio_handler(int signo) {
    // Dummy handler to "nudge" the process
    //write(STDERR_FILENO, "SIGIO received\n", 15);
}

int main(int argc, char *argv[] /*, char *envp[]*/) {
    if (argc != 2 ) {
        printf("Usage: %s /dev/usb/hiddev?\nWhere \"?\" is a number.\n", argv[0]);
        return 1;
    }
    int fd = open(argv[1], O_RDONLY);
    if (fd < 0) { perror("open"); return 1; }
    char *xdotoolargs[] = { "pxdotool", "key", "p", NULL };
    extern char **environ;
    struct hiddev_event ev;
    int buttonNr=0;
    bool pressed=false;
    int status=-1;
    pid_t pid;

    // Set up dummy SIGIO handler
    struct sigaction sa;
    sa.sa_handler = sigio_handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    if (sigaction(SIGIO, &sa, NULL) < 0) {
        perror("sigaction");
        close(fd);
        return 1;
    }

    // Set ownership and signal
    if (fcntl(fd, F_SETOWN, getpid()) < 0) {
        perror("fcntl F_SETOWN");
        close(fd);
        return 1;
    }

    if (fcntl(fd, F_SETSIG, SIGIO) < 0) {
        perror("fcntl F_SETSIG");
        close(fd);
        return 1;
    }

    // Enable asynchronous I/O
    int flags = fcntl(fd, F_GETFL);
    if (fcntl(fd, F_SETFL, flags | O_ASYNC) < 0) {
        perror("fcntl F_SETFL O_ASYNC");
        close(fd);
        return 1;
    }

    int ev_size = sizeof(ev);
    while (1) {
        ssize_t n = read(fd, &ev, ev_size);
        if (n < 0 || n < ev_size) {
            if (errno == EINTR) continue; // Interrupted by signal
            perror("read");
            break;
        }
        if ( ev.hid == 589829) {
            if ( buttonNr == 1) {
                if ( ev.value == 1 ) {
                    if (!pressed) {
                        // extra button mouse down
                        printf(">>> HID event: button=%d, type=%d, value=%d\n",
                                            buttonNr,  ev.hid, ev.value);
                        fflush(stdout);
                        if(status==0){
                                waitpid(pid, &status, 0);
                        }
                        status = posix_spawn(&pid, "/usr/bin/xdotool", NULL, NULL, xdotoolargs, environ);
                        pressed=true;
                    }
                } else if(pressed) {
                    // extra button mouse up
                    //printf("<<< HID event: button=%d, type=%d, value=%d\n",
                    //                        buttonNr,  ev.hid, ev.value);
                    //fflush(stdout);
                    pressed=false;
                }
            //} else {
            //   // some other button with same event ID the kernel/X/wayland can handle (up or down)
            //   printf("--- HID event: button=%d, type=%d, value=%d\n",
            //                           buttonNr,  ev.hid, ev.value);
            //   fflush(stdout);
            }
            buttonNr++;
        } else {
            // more buttons or mouse events, but with different IDs
            //printf("    HID event: button=%d, type=%d, value=%d\n",
            //                        buttonNr,  ev.hid, ev.value);
            //fflush(stdout);
            buttonNr=0;
        }
    }
    if(status==0){
        waitpid(pid, &status, 0);
    }
    printf("Read all. Closing.");
    close(fd);
    return 0;
}

  

//edit: fixed read stalling after a while; launching xdotool as an example directly

0 comments

No comments