ELECOM EX-G extra Button Workaround
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