289 lines
7.4 KiB
Diff
289 lines
7.4 KiB
Diff
Author: Michael Schmitz <schmitz@biophys.uni-duesseldorf.de>
|
|
Description: rescan event devices on disconnects
|
|
|
|
Note @q66: modified to use /run instead of /var/run
|
|
|
|
--- a/mouseemu.8
|
|
+++ b/mouseemu.8
|
|
@@ -52,13 +52,20 @@
|
|
.B -nofork
|
|
don't run in the background
|
|
.TP
|
|
+.B -autorescan
|
|
+Automatically scan every 5s for new devices. This is normally not need, as udev should
|
|
+inform mouseemu about new devices.
|
|
+.TP
|
|
.B -help
|
|
show usage message
|
|
.PP
|
|
The key codes for the buttons and modifiers are key scancodes. They can be found in
|
|
include/linux/input.h in the kernel headers or by using `showkey` in a console. The
|
|
keycodes must be given as decimal values (`showkey` displays hex values!).
|
|
-
|
|
+.PP
|
|
+Mouseemu does normally not automatically scan for new devices. An udev rule is used
|
|
+to trigger a rescan when new devices are connected. You can also trigger a rescan
|
|
+manually by sending a HUP signal to the mouseemu process.
|
|
.SH EXAMPLES
|
|
.PP
|
|
To have the same behaviour as in MacOS X (CTRL-click for right mouse button and no
|
|
@@ -69,7 +76,12 @@
|
|
.RE
|
|
.PP
|
|
The code for the (left) mouse button is 272 (0x110 in hex). The code for CTRL is 29.
|
|
-
|
|
+.PP
|
|
+Trigger a rescan for newly attached devices:
|
|
+.PP
|
|
+.RS 4
|
|
+.B kill -HUP `cat /run/mouseemu.pid`
|
|
+.RE
|
|
.SH AUTHOR
|
|
Mouseemu was written by Colin Leroy
|
|
.nh
|
|
--- a/mouseemu.c
|
|
+++ b/mouseemu.c
|
|
@@ -19,6 +19,7 @@
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
+#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <string.h>
|
|
#include <signal.h>
|
|
@@ -51,12 +52,14 @@
|
|
|
|
static int running = -1;
|
|
volatile sig_atomic_t answer = 1;
|
|
+volatile sig_atomic_t rescan = 0;
|
|
pid_t pid = -1;
|
|
-#define EVENT_DEVS 6
|
|
+#define EVENT_DEVS 32
|
|
static kdev eventdevs[EVENT_DEVS];
|
|
static input_handler ihandler[EVENT_DEVS];
|
|
|
|
-
|
|
+static int debug = 0;
|
|
+static int autorescan = 0;
|
|
|
|
static void send_event(int fd, int type, int code, int value)
|
|
{
|
|
@@ -224,12 +227,18 @@
|
|
ioctl(fd, EVIOCGBIT(0, EV_MAX), bit);
|
|
if (test_bit(EV_KEY, bit) && test_bit(EV_REP, bit)) {
|
|
ioctl(fd, EVIOCGID, id);
|
|
+ /* our own virtual keyboard (on rescans)*/
|
|
+ if (id[ID_PRODUCT] == 0x1F && id[ID_VENDOR] == 0x1F) {
|
|
+ close(fd);
|
|
+ continue;
|
|
+ }
|
|
if (id[ID_PRODUCT] != eventdevs[m].product ||
|
|
id[ID_VENDOR] != eventdevs[m].vendor) {
|
|
if (eventdevs[m].handle >= 0) {
|
|
unregister_inputhandler(eventdevs[m].handle);
|
|
close(eventdevs[m].handle);
|
|
}
|
|
+ if (debug) fprintf(stderr, "keyboard: fd %d event%d, vendor %4x product %4x\n", fd, n, id[ID_VENDOR], id[ID_PRODUCT]);
|
|
eventdevs[m].handle= fd;
|
|
eventdevs[m].product = id[ID_PRODUCT];
|
|
eventdevs[m].vendor = id[ID_VENDOR];
|
|
@@ -238,12 +247,18 @@
|
|
m++;
|
|
} else if (test_bit(EV_REL, bit)) {
|
|
ioctl(fd, EVIOCGID, id);
|
|
+ /* our own virtual mouse (on rescans)*/
|
|
+ if (id[ID_PRODUCT] == 0x1E && id[ID_VENDOR] == 0x1F) {
|
|
+ close(fd);
|
|
+ continue;
|
|
+ }
|
|
if (id[ID_PRODUCT] != eventdevs[m].product ||
|
|
id[ID_VENDOR] != eventdevs[m].vendor) {
|
|
if (eventdevs[m].handle >= 0) {
|
|
unregister_inputhandler(eventdevs[m].handle);
|
|
close(eventdevs[m].handle);
|
|
}
|
|
+ if (debug) fprintf(stderr, "mouse : fd %d event%d, vendor %4x product %4x\n", fd, n, id[ID_VENDOR], id[ID_PRODUCT]);
|
|
eventdevs[m].handle= fd;
|
|
eventdevs[m].product = id[ID_PRODUCT];
|
|
eventdevs[m].vendor = id[ID_VENDOR];
|
|
@@ -261,6 +276,27 @@
|
|
}
|
|
}
|
|
|
|
+void rescan_devs()
|
|
+{
|
|
+ int i, cfd;
|
|
+
|
|
+ for (i=0; i<EVENT_DEVS; i++) {
|
|
+ if (ihandler[i].fd != -1) {
|
|
+ cfd=ihandler[i].fd;
|
|
+ unregister_inputhandler(ihandler[i].fd);
|
|
+ close(cfd);
|
|
+ i--;
|
|
+ }
|
|
+ }
|
|
+ for (i=0; i<EVENT_DEVS; i++) {
|
|
+ eventdevs[i].product = 0;
|
|
+ eventdevs[i].vendor = 0;
|
|
+ eventdevs[i].handle = -1;
|
|
+ }
|
|
+ usleep(100);
|
|
+ scan_for_devs();
|
|
+}
|
|
+
|
|
int register_inputhandler (int fd, void (*func)(int fd), int grab)
|
|
{
|
|
int n;
|
|
@@ -300,7 +336,7 @@
|
|
|
|
FD_ZERO(watchset);
|
|
for (maxfd=n=0; n < EVENT_DEVS; n++) {
|
|
- if (ihandler[n].fd == -1) break;
|
|
+ if (ihandler[n].fd == -1) continue;
|
|
FD_SET(ihandler[n].fd, watchset);
|
|
if (ihandler[n].fd > maxfd)
|
|
maxfd = ihandler[n].fd;
|
|
@@ -313,7 +349,7 @@
|
|
int n;
|
|
|
|
for (n=0; n < EVENT_DEVS; n++) {
|
|
- if (ihandler[n].fd == -1) break;
|
|
+ if (ihandler[n].fd == -1) continue;
|
|
if (FD_ISSET(ihandler[n].fd, inset))
|
|
ihandler[n].handler (ihandler[n].fd);
|
|
}
|
|
@@ -461,7 +497,7 @@
|
|
|
|
void uinput_cleanup()
|
|
{
|
|
- int i;
|
|
+ int i, cfd;
|
|
|
|
printf("mouseemu: cleaning...\n");
|
|
|
|
@@ -470,8 +506,9 @@
|
|
|
|
for (i=0; i<EVENT_DEVS; i++) {
|
|
if (ihandler[i].fd != -1) {
|
|
+ cfd=ihandler[i].fd;
|
|
unregister_inputhandler(ihandler[i].fd);
|
|
- close(ihandler[i].fd);
|
|
+ close(cfd);
|
|
}
|
|
}
|
|
|
|
@@ -489,6 +526,11 @@
|
|
{
|
|
if (sig_num == SIGUSR1) {
|
|
answer = 1;
|
|
+ } else if (sig_num == SIGHUP) {
|
|
+ rescan = 1;
|
|
+ } else if (sig_num == SIGALRM) {
|
|
+ rescan = 1;
|
|
+ alarm(5);
|
|
} else {
|
|
//printf("mouseemu: aborting on sig %i \n",sig_num);
|
|
/*terminate the parent:*/
|
|
@@ -512,10 +554,13 @@
|
|
|
|
/*SIGUSR1 for process communication
|
|
*SIGTERM and SIGCHLD for quitting
|
|
+ *SIGHUP and SIGALRM for rescaning devices
|
|
*/
|
|
sigaction(SIGUSR1, &usr_action, NULL);
|
|
sigaction(SIGTERM, &usr_action, NULL);
|
|
+ sigaction(SIGHUP, &usr_action, NULL);
|
|
sigaction(SIGCHLD, &usr_action, NULL);
|
|
+ sigaction(SIGALRM, &usr_action, NULL);
|
|
|
|
sigprocmask(SIG_UNBLOCK, &mask, 0);
|
|
|
|
@@ -529,7 +574,8 @@
|
|
"\t[-scroll SCROLL_MOD]\n"
|
|
"\t[-typing-block DELAY]\n"
|
|
"\t[-device UINPUT_DEVICE]\n"
|
|
- "\t[-nofork]\n",
|
|
+ "\t[-nofork]\n"
|
|
+ "\t[-autorescan]\n",
|
|
argv[0]);
|
|
fprintf(stream, "All modifier and button key arguments are\n"
|
|
"key scancodes. They can be found in \n"
|
|
@@ -643,6 +689,11 @@
|
|
nofork=1;
|
|
i += 1;
|
|
continue;
|
|
+ }
|
|
+ else if (!strcmp(argv[i], "-autorescan")) {
|
|
+ autorescan=1;
|
|
+ i += 1;
|
|
+ continue;
|
|
} else {
|
|
usage(stderr, argv);
|
|
}
|
|
@@ -680,8 +731,15 @@
|
|
*
|
|
*/
|
|
|
|
+ struct sigaction sa;
|
|
sigset_t mask, oldmask;
|
|
|
|
+ /* SIGHUP and SIGALRM are only useful in the child */
|
|
+ memset(&sa, 0, sizeof(sa));
|
|
+ sa.sa_handler = SIG_IGN;
|
|
+ sigaction(SIGHUP, &sa, NULL);
|
|
+ sigaction(SIGALRM, &sa, NULL);
|
|
+
|
|
/*we start only after we received the first sigusr1 from child:*/
|
|
|
|
sigemptyset(&mask);
|
|
@@ -715,6 +773,9 @@
|
|
|
|
//strncpy(argv[0],"mouseemu",argv0size);
|
|
startops:
|
|
+ if (nofork)
|
|
+ debug = 1;
|
|
+
|
|
for (i=0; i<EVENT_DEVS; i++) {
|
|
eventdevs[i].handle = -1;
|
|
eventdevs[i].vendor = 0;
|
|
@@ -736,18 +797,35 @@
|
|
|
|
|
|
chdir("/");
|
|
-
|
|
+
|
|
+ if (autorescan)
|
|
+ alarm(5);
|
|
+
|
|
/*main loop*/
|
|
|
|
while(running > 0) {
|
|
|
|
tv.tv_sec = 1; tv.tv_usec = 0;
|
|
maxfd = create_fdset(&inset);
|
|
- if ((val = select (maxfd+1, &inset, NULL, NULL, &tv)) >= 0) {
|
|
+ val = select (maxfd+1, &inset, NULL, NULL, &tv);
|
|
+ /* signal received, so rescan for devices when idle*/
|
|
+ if (val == 0 && rescan) {
|
|
+ rescan = 0;
|
|
+ rescan_devs();
|
|
+ }
|
|
+ if (val >= 0) {
|
|
if (val == 0)
|
|
usleep(10);
|
|
- else
|
|
- call_inputhandler(&inset);
|
|
+ else {
|
|
+ if (errno == ENODEV) {
|
|
+ if (debug) fprintf(stderr, "select returned %d, errno %d, rescanning devices\n", val, errno);
|
|
+ errno = 0;
|
|
+ rescan_devs();
|
|
+ usleep(500);
|
|
+ } else {
|
|
+ call_inputhandler(&inset);
|
|
+ }
|
|
+ }
|
|
}
|
|
/* tell the parent we are running without problems */
|
|
/* What should we do if the parent is dead? */
|