un paio di settimane fa ho comprato un mouse bluetooth della logitech (mx900)
il mouse in se per se va pero’ ci sono tanti bottoni che non vengono gestiti correttamente
dopo 5 giorni spesi nel cercare di capire come patchare hid del kernel per gestire tali bottoni in una maniera semiseria ho gettato la spugna e scritto questo driver
il risultato e’ ottimo pero’ il modo utilizzato per raggiungerlo abbastanza patetico.
il risultato e’ stato 200 righe di codice con i bottoni hardcoded.
qui il codice
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/input.h>
#include <linux/uinput.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/socket.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/l2cap.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>
#define GETBIT(v,n) ((v>>(n))&0×01)
#define SETBIT(v,n) (v |= (0×01<<(n)))
/* Globals */
static int uinp_fd = -1;
struct uinput_user_dev uinp; // uInput device structure
struct input_event event; // Input event structure
/* Setup the uinput device */
int setup_uinput_device () {
// Temporary variable
int i = 0;
// Open the input device
uinp_fd = open (”/dev/input/uinput”, O_WRONLY | O_NDELAY);
if (uinp_fd <= 0)
{
printf (”Unable to open uinput device. Are you root? \n”);
return -1;
}
memset (&uinp, 0, sizeof (uinp)); // Intialize the uInput device to NULL
strncpy (uinp.name, “Logitech Mx 900″, UINPUT_MAX_NAME_SIZE);
uinp.id.version = 4;
uinp.id.bustype = BUS_USB;
// Setup the uinput device
ioctl (uinp_fd, UI_SET_EVBIT, EV_KEY);
ioctl (uinp_fd, UI_SET_EVBIT, EV_REL);
ioctl (uinp_fd, UI_SET_RELBIT, REL_X);
ioctl (uinp_fd, UI_SET_RELBIT, REL_Y);
ioctl (uinp_fd, UI_SET_RELBIT, REL_WHEEL);
for (i = 0; i < 256; i++)
ioctl (uinp_fd, UI_SET_KEYBIT, i);
ioctl (uinp_fd, UI_SET_KEYBIT, BTN_MOUSE);
ioctl (uinp_fd, UI_SET_KEYBIT, BTN_LEFT);
ioctl (uinp_fd, UI_SET_KEYBIT, BTN_MIDDLE);
ioctl (uinp_fd, UI_SET_KEYBIT, BTN_RIGHT);
/* Create input device into input sub-system */
write (uinp_fd, &uinp, sizeof (uinp));
if (ioctl (uinp_fd, UI_DEV_CREATE))
{
printf (”Unable to create UINPUT device.”);
return -1;
}
return 1;
}
void move_mouse (int x, int y) {
memset (&event, 0, sizeof (event));
gettimeofday (&event.time, NULL);
event.type = EV_REL;
event.code = REL_X;
event.value = x;
write (uinp_fd, &event, sizeof (event));
event.type = EV_REL;
event.code = REL_Y;
event.value = y;
write (uinp_fd, &event, sizeof (event));
event.type = EV_SYN;
event.code = SYN_REPORT;
event.value = 0;
write (uinp_fd, &event, sizeof (event));
}
void report_button_and_wheel (char button_byte, char wheel) {
memset (&event, 0, sizeof (event));
gettimeofday (&event.time, NULL);
event.type = EV_KEY;
event.code = BTN_LEFT;
event.value = GETBIT(button_byte,0);
write(uinp_fd, &event, sizeof (event));
event.type = EV_KEY;
event.code = BTN_RIGHT;
event.value = GETBIT(button_byte,1);
write(uinp_fd, &event, sizeof (event));
event.type = EV_KEY;
event.code = BTN_MIDDLE;
event.value = GETBIT(button_byte,2);
write(uinp_fd, &event, sizeof (event));
event.type = EV_KEY;
event.code = KEY_ESC;
event.value = GETBIT(button_byte,3);
write(uinp_fd, &event, sizeof (event));
event.type = EV_KEY;
event.code = KEY_LEFTALT;
event.value = GETBIT(button_byte,4);
write(uinp_fd, &event, sizeof (event));
event.type = EV_KEY;
event.code = KEY_F12;
event.value = GETBIT(button_byte,5);
write(uinp_fd, &event, sizeof (event));
event.type = EV_KEY;
event.code = KEY_K;
event.value = GETBIT(button_byte,6);
write(uinp_fd, &event, sizeof (event));
event.type = EV_KEY;
event.code = KEY_J;
event.value = GETBIT(button_byte,7);
write(uinp_fd, &event, sizeof (event));
if (GETBIT(button_byte,6)==0 && GETBIT(button_byte,7)==0){
event.type = EV_REL;
event.code = REL_WHEEL;
event.value = wheel;
write(uinp_fd, &event, sizeof (event));
}
event.type = EV_SYN;
event.code = SYN_REPORT;
event.value = 0;
write (uinp_fd, &event, sizeof (event));
}
int main () {
struct sockaddr_l2 s_addr = { 0 };
struct sockaddr_l2 t_addr = { 0 };
int s, t, s_status, t_status, bytes_read;
char dest[18] = “00:07:61:09:59:46″;
start:
s = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
t = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
s_addr.l2_family = AF_BLUETOOTH;
s_addr.l2_psm = htobs(0×0013);
str2ba( dest, &s_addr.l2_bdaddr );
t_addr.l2_family = AF_BLUETOOTH;
t_addr.l2_psm = htobs(0×0011);
str2ba( dest, &t_addr.l2_bdaddr );
s_status = connect(s, (struct sockaddr *)&s_addr, sizeof(s_addr));
if ( s_status != 0){
fprintf(stderr,”unable to find the bluetooth device, retring …\n”);
goto start;
}
t_status = connect(t, (struct sockaddr *)&t_addr, sizeof(t_addr));
fprintf(stderr,”Connected, start reading…\n”);
if (setup_uinput_device () = 0){
short int rel_x, rel_y, temp_x, temp_y;
temp_x = buf[4];
temp_x = temp_x <>4;
temp_y = temp_y&0×000f;
rel_y = buf[5];
rel_y = rel_y << 4;
rel_y = rel_y & 0×0ff0;
rel_y = rel_y + temp_y;
if (GETBIT(rel_x,11)==1)
rel_x = rel_x | 0xf000;
if (GETBIT(rel_y,11)==1)
rel_y = rel_y | 0xf000;
move_mouse (rel_x,rel_y);
report_button_and_wheel(buf[2],buf[6]);
}
else {
printf(”somethings wrong, or everything is ok\n”);
goto start;
}
}
close(s);
close(t);
return 0;
}
modificare il mac address del mouse
compilare con
gcc -Wall -o mx900driver mx900driver.c -lbluetooth
sudo mx900driver
freccia laterale avanti = Alt
freccia laterale indietro = Esc
Tasto centrale con 2 quadrati disegnati dentro = F12
Freccia su (sopra alla rotella) = k
Freccia giu (sotto alla rotella) = j
gli ultimi 2 servono per scorrere gli item su google reader (o su altri siti se usate jackassify)
il resto dei tasti hanno una funzione normale
per modificare il comportamento modificate la funzione report_button_and_wheel cambiano l’event.code
il tutto e’ molto grezzo , se a qualcuno interessa miglioro le cose e faccio qualcosa di un po’ + usabile
p.s. per ora non ho idea se questa roba funzioni su installazioni a 64bit