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

Andor Demarteau andor at nl.linux.org
Sat Dec 15 11:28:30 EST 2007


nice concept however for yoru special gkeys you could have used 
setkeycoeds and loadkey, at elast for the console.
on my dell inspiron system some keypresses give off unknown keycode 
messages.
It refers to setkeycodes to assign them
On Sat, 15 Dec 2007, Mario Lang wrote:

 > Hi.
 > 
 > Virtual console screen readers that wanted to use the
 > normal keyboard for review functionality always had the
 > problem on linux that some sort of a non-standardized kernel
 > patch was needed to get keysniffing to work.
 > 
 > I've been thinking about a method that allows to do this completely
 > from within userspace without any kernel patching.  Now that
 > I had actually found another use case for this for me personally,
 > I went ahead and implemented the idea to see if it actually works.
 > 
 > And yes, it does!
 > 
 > The plan is as follows:
 >  * We iterate the input event devices in /dev/input/event* to find
 >    one with criteria that we can use (we can test for bustype, usb product/vendor ID,
 >    or for the presence of individual keys).
 >  * We then create a "uinput device" to feed keypresses back to the kernel.
 >  * We "grab" the keyboard, i.e., keypresses are no longer sent to the
 >    system, but to us (in userspace) exclusively.
 >  * Whenever we read in a key from our keyboard, we check if
 >    we handle that key, if not, we pass it back to the uinput device,
 >    which in turn will pass it back to the system.
 > 
 > The example code below is written for a Sun type 6 USB
 > keyboard which I happen to own.  This keyboard has some extra keys which
 > I'd like to use.  Most of them are not bound in Linux itself,
 > but two (MUTE and VOLUMEDOWN) do in fact insert garbage if pressed.
 > So I had to write this tool to be able to use these keys for
 > my own purpuses while avoiding them to generate garbage input when used.
 > 
 > The same method could be used in brltty to achieve the following
 > things we've identified in the past as worthwhile to implement:
 >  * Support braille displays without navigation keys (I've heard
 >    some japanese models are built that way).
 >  * Provide screen review for speech only situations.
 >  * And last but not least, provide better bindings for displays
 >    that do have very few navigation keys (the vario or bookworm comes to mind).
 > 
 > Since keyboards can have many different keys these days (think
 > USB multimedia keyboards), I guess the best way
 > to impelement this in brltty is to couple it with
 > some configuration file parsing that would allow the user
 > to define which keyboard actions are bound to which brltty commands.
 > 
 > I am open to all input here.  As usual, I am not the best code designer,
 > 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;
 > }
 > 
 > 
 > 

-- 
Andor Demarteau                 E-mail: andor at nl.linux.org
student computer science        www: http://www.nl.linux.org/~andor
UU based & VU guest-student     jabber,icq,msn,voip: do ask ;)
-----------


More information about the BRLTTY mailing list