[BRLTTY] Proof of concept code: Filter keyboard keypresses on Linux

Samuel Thibault samuel.thibault at ens-lyon.org
Sat Dec 15 11:24:37 EST 2007


Mario Lang, le Sat 15 Dec 2007 17:17:47 +0100, a écrit :
> As usual, I am not the best code designer,

Nobody is :)
> so some starting help for getting this into brltty core would
> be very appreciated?  Dave?
> 
> P.S.: The following code checks for a specific keyboard.
> We will of course want to do something much more generic here,
> like test for a keyboard that actually has the keys we'd like to watch out for.
> The function has_event() can be used to do this, a call like
> has_event(filedescriptor, EV_KEY, KEY_ESC) will return 1 if the keyboard
> associated with filedescriptor does have an ESC key...
> 
> #include <dirent.h>
> #include <fcntl.h>
> #include <linux/input.h>
> #include <linux/uinput.h>
> #include <stdio.h>
> #include <string.h>
> #include <sys/stat.h>
> #include <sys/types.h>
> #include <unistd.h>
> 
> static int
> has_event(int fd, unsigned short type, unsigned short code)
> {
> #define MAX(a,b) a>b?a:b
>   const unsigned int len = sizeof(unsigned long)*8;
>   const unsigned int max = MAX(EV_MAX,
> 			       MAX(KEY_MAX,
> 				   MAX(REL_MAX,
> 				       MAX(ABS_MAX,
> 					   MAX(LED_MAX,
> 					       MAX(SND_MAX, FF_MAX))))));
>   unsigned long bits[(max+len-1)/len];
>   if (ioctl(fd, EVIOCGBIT(type, max), bits)) {
>     return (bits[code/len] >> (code%len)) & 1;
>   }
>   return 0;
> #undef MAX
> }
> 
> static int
> constructKeyboard (char *name, struct input_id *id, unsigned long *keymask)
> {
>   int fd;
>   if ((fd = open("/dev/input/uinput", O_WRONLY)) > 0) {
>     struct uinput_user_dev description;
> 
>     memset(&description, 0, sizeof(description));
>     strncpy(description.name, name, UINPUT_MAX_NAME_SIZE);
>     memcpy(&description.id, id, sizeof(description.id));
>     if (write(fd, &description, sizeof(description)) == sizeof(description)) {
>       int key;
> 
>       ioctl(fd, UI_SET_EVBIT, EV_KEY);
>       ioctl(fd, UI_SET_EVBIT, EV_REP);
> 
>       for (key=KEY_RESERVED; key<=KEY_MAX; key++) {
>         if ((keymask[key/(sizeof(unsigned long)*8)] >> (key%(sizeof(unsigned long)*8)))&1) {
> 	  ioctl(fd, UI_SET_KEYBIT, key);
> 	}
>       }
>       if (ioctl(fd, UI_DEV_CREATE) != -1) {
> 	return fd;
>       } else {
> 	perror("ioctl UI_DEV_CREATE");
>       }
>     } else {
>       perror("write (struct uinput_user_dev)");
>     }
>   } else {
>     perror("open /dev/input/uinput");
>   }
>   return -1;
> }
> 
> int
> main(int argc, char *argv[])
> {
>   char root[] = "/dev/input";
>   int rootLength = strlen(root);
>   int foundKeyboard = 0;
>   DIR *directory;
> 
>   if ((directory = opendir(root))) {
>     struct dirent *entry;
> 
>     while ((entry = readdir(directory))) {
>       size_t nameLength = strlen(entry->d_name);
>       struct stat status;
>       char path[rootLength + 1 + nameLength + 1];
> 
>       snprintf(path, sizeof(path), "%s/%s", root, entry->d_name);
>       if (stat(path, &status) == -1) continue;
>       if (S_ISCHR(status.st_mode)) {
>         int fd;
> 
>         if ((fd = open(path, O_RDONLY)) > 0) {
>           struct input_id id;
> 	  
>           if (ioctl(fd, EVIOCGID, &id) != -1) {
>             if (id.bustype == 3 &&
>                 id.vendor == 0X0430 && id.product == 0X0005 &&
> 		has_event(fd, EV_KEY, KEY_HELP)) {
> 	      unsigned long keymask[(KEY_MAX+(sizeof(unsigned long)*8)-1)/(sizeof(unsigned long)*8)];
>               struct input_event event;
> 
>               foundKeyboard = 1;
> 
> 	      if (ioctl(fd, EVIOCGBIT(EV_KEY, KEY_MAX), keymask)) {
> 		int uinput = constructKeyboard("test", &id, keymask);
> 	      
> 		if (uinput != -1) {
> 		  ioctl(fd, EVIOCGRAB, 1);
> 		  while (read(fd, &event, sizeof(event)) == sizeof(event)) {
> 		    if (event.type == EV_KEY) {
> 		      switch (event.code) {
> 		      case KEY_MUTE:
> 			printf("MUTE %s\n", event.value ? "press":"release");
> 			break;
> 		      case KEY_VOLUMEDOWN:
> 			printf("VOLUMEDOWN %s\n", event.value ? "press":"release");
> 			break;
> 		      case KEY_VOLUMEUP:
> 			printf("VOLUMEUP %s\n", event.value ? "press":"release");
> 			break;
> 		      case KEY_POWER:
> 			printf("POWER %s\n", event.value ? "press":"release");
> 			break;
> 		      case KEY_STOP:
> 			printf("STOP %s\n", event.value ? "press":"release");
> 			break;
> 		      case KEY_AGAIN:
> 			printf("AGAIN %s\n", event.value ? "press":"release");
> 			break;
> 		      case KEY_PROPS:
> 			printf("PROPS %s\n", event.value ? "press":"release");
> 			break;;
> 		      case KEY_UNDO:
> 			printf("UNDO %s\n", event.value ? "press":"release");
> 			break;;
> 		      default:
> 			write(uinput, &event, sizeof(event));
> 			printf("%d = %d\n", event.code, event.value);
> 		      }
> 		    }
> 		  }
> 
> 		  ioctl(fd, EVIOCGRAB, 0);
> 		  close(uinput);
> 		}
> 	      }
> 	    }
>           }
>           close(fd);
>         }
>       }
>     }
>     closedir(directory);
> 
>     if (!foundKeyboard) {
>       printf("No supported USB keyboard found.\n");
>     }
>   } else {
>     fprintf(stderr, "Unable to open %s\n", root);
>   }
>   return 0;
> }
> 
> 
> -- 
> CYa,
>   Mario | Debian Developer <URL:http://debian.org/>
>   .''`. | Get my public key via finger mlang at db.debian.org
>  : :' : | 1024D/7FC1A0854909BCCDBE6C102DDFFC022A6B113E44
>  `. `'
>    `-      <URL:http://delysid.org/>  <URL:http://www.staff.tugraz.at/mlang/>
> _______________________________________________
> This message was sent via the BRLTTY mailing list.
> To post a message, send an e-mail to: BRLTTY at mielke.cc
> For general information, go to: http://mielke.cc/mailman/listinfo/brltty
> 

-- 
Samuel
"c'est pas nous qui sommes à la rue, c'est la rue qui est à nous"


More information about the BRLTTY mailing list