Witam,
sprawa może i głupia, bo zainspirowana filmikiem: , ale pytania będą raczej do ekspertów.
Rozważmy następujący blokujący (i działający) kod:
#include <sys/types.h>
#include <sys/mouse.h>
#include <err.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
struct mouse_event {
uint8_t buttons;
int8_t hdx;
int8_t hdy;
int8_t ldx;
int8_t ldy;
int8_t hdz;
int8_t ldz;
int8_t ext_buttons;
};
int
main(int argc, char **argv)
{
int error, fd;
short dx, dy, dz;
struct mouse_event ev;
fd = open("/dev/sysmouse", O_RDONLY);
if (fd < 0)
err(1, "open(2) failed");
for (;;) {
if (read(fd, &ev, sizeof(ev)) != sizeof(ev))
err(1, "read(2) failed");
dx = ev.hdx + ev.ldx;
dy = ev.hdy + ev.ldy;
dz = ev.hdz + ev.ldz;
printf("%c %c %c x=%d y=%d z=%d\n",
ev.buttons & 0x4 ? ' ' : 'L',
ev.buttons & 0x2 ? ' ' : 'M',
ev.buttons & 0x1 ? ' ' : 'R',
dx, dy, dz);
}
return (0);
}
Z różnych względów chciałbym go sobie przerobić na wersję nieblokującą:
#include <sys/types.h>
#include <sys/event.h>
#include <sys/mouse.h>
#include <assert.h>
#include <err.h>
#include <fcntl.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
/*
* W razie wątpliwości patrz: man 4 mouse
*/
struct mouse_event {
uint8_t buttons;
int8_t hdx;
int8_t hdy;
int8_t ldx;
int8_t ldy;
int8_t hdz;
int8_t ldz;
int8_t ext_buttons;
};
/*
* Wyciągnięcie tylko po to, żeby nie zaciemnić kodu main().
*/
static void
handle_mouse(int fd)
{
short dx, dy, dz;
struct mouse_event ev;
if (read(fd, &ev, sizeof(ev)) != sizeof(ev))
err(1, "read(2) failed");
dx = ev.hdx + ev.ldx;
dy = ev.hdy + ev.ldy;
dz = ev.hdz + ev.ldz;
printf("%c %c %c x=%d y=%d z=%d\n", ev.buttons & 0x4 ? ' ' : 'L',
ev.buttons & 0x2 ? ' ' : 'M', ev.buttons & 0x1 ? ' ' : 'R',
dx, dy, dz);
}
int
main(int argc, char **argv)
{
int error, fd, kq;
struct kevent kev;
fd = open("/dev/sysmouse", O_RDONLY | O_NONBLOCK);
if (fd < 0)
err(1, "open(2) failed");
kq = kqueue();
if (kq < 0)
err(1, "kevent(2) failed");
/*
* Rejestracja eventów.
*/
EV_SET(&kev, fd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0);
error = kevent(kq, &kev, 1, NULL, 0, NULL);
if (error < 0)
err(1, "kevent(2) failed");
EV_SET(&kev, SIGTERM, EVFILT_SIGNAL, EV_ADD | EV_ENABLE, 0, 0, 0);
error = kevent(kq, &kev, 1, NULL, 0, NULL);
if (error < 0)
err(1, "kevent(2) failed");
for (;;) {
error = kevent(kq, NULL, 0, &kev, 1, NULL);
if (error < 0)
err(1, "kevent(2) failed");
/*
* Timeout jest niedopuszczalny, więc możemy dostać co najwyżej
* jeden event.
* */
assert(error == 1);
if (kev.filter == EVFILT_READ && kev.ident == fd) {
handle_mouse(fd);
} else if (kev.filter == EVFILT_SIGNAL &&
kev.ident == SIGTERM) {
break;
} else {
fprintf(stderr, "WTF!?: %d %lu\n", kev.filter,
kev.ident);
}
}
close(fd);
return (0);
}
Która to z kolei kończy się takim oto nieciekawym komunikatem:
mouse-nblk: kevent(2) failed: Operation not supported by device
Teraz pytania:
- Czy wszystkie urządzenia w katalogu /dev/ nie wspierają kevent(2)?
- Czy jest to tylko kwestia mojego sterownika do myszy (/sys/dev/vt/vt_sysmouse.c)?
Jeśli na pytanie (2) odpowiedź jest twierdząca:
Czy wystarczyłoby przeczytać kqueue(9), aby doimplementować brakującą obsługę zdarzeń w sterowniku myszy? Sensem pytania jest: czy to tylko kwestia wsparcia w sterowniku, czy trzeba modyfikować coś więcej?
Ukłony.