#include #include #include #include #include #include #include #include #include #include "input.h" struct input_keymap_entry_v2 { #define KEYMAP_BY_INDEX (1 << 0) uint8_t flags; uint8_t len; uint16_t index; uint32_t keycode; uint8_t scancode[32]; }; #ifndef EVIOCGKEYCODE_V2 #define EVIOCGKEYCODE_V2 _IOR('E', 0x04, struct input_keymap_entry_v2) #endif struct kbd_entry { unsigned int scancode; unsigned int keycode; }; struct kbd_map { struct kbd_entry *map; int keys; int size; int alloc; }; /* ------------------------------------------------------------------ */ static struct kbd_map* kbd_map_read(int fd, unsigned int version) { struct kbd_entry entry; struct kbd_map *map; int rc; map = malloc(sizeof(*map)); memset(map,0,sizeof(*map)); for (map->size = 0; map->size < 65536; map->size++) { if (version < 0x10001) { entry.scancode = map->size; entry.keycode = KEY_RESERVED; rc = ioctl(fd, EVIOCGKEYCODE, &entry); if (rc < 0) { break; } } else { struct input_keymap_entry_v2 ke = { .index = map->size, .flags = KEYMAP_BY_INDEX, .len = sizeof(uint32_t), .keycode = KEY_RESERVED, }; rc = ioctl(fd, EVIOCGKEYCODE_V2, &ke); if (rc < 0) break; memcpy(&entry.scancode, ke.scancode, sizeof(entry.scancode)); entry.keycode = ke.keycode; } if (map->size >= map->alloc) { map->alloc += 64; map->map = realloc(map->map, map->alloc * sizeof(entry)); } map->map[map->size] = entry; if (KEY_RESERVED != entry.keycode) map->keys++; } if (map->keys) { fprintf(stderr,"map: %d keys, size: %d/%d\n", map->keys, map->size, map->alloc); return map; } else { free(map); return NULL; } } static int kbd_map_write(int fh, struct kbd_map *map) { int i,rc; for (i = 0; i < map->size; i++) { rc = ioctl(fh, EVIOCSKEYCODE, &map->map[i]); if (0 != rc) { fprintf(stderr,"ioctl EVIOCSKEYCODE(%d,%d): %s\n", map->map[i].scancode,map->map[i].keycode, strerror(errno)); return -1; } } return 0; } static void kbd_key_print(FILE *fp, int scancode, int keycode) { fprintf(fp, "0x%04x = %3d # %s\n", scancode, keycode, ev_type_name(EV_KEY, keycode)); } static void kbd_map_print(FILE *fp, struct kbd_map *map, int complete) { int i; for (i = 0; i < map->size; i++) { if (!complete && KEY_RESERVED == map->map[i].keycode) continue; kbd_key_print(fp,map->map[i].scancode,map->map[i].keycode); } } static int kbd_map_parse(FILE *fp, struct kbd_map *map) { struct kbd_entry entry; char line[80],scancode[80],keycode[80]; int i; int idx = 0; while ((NULL != fgets(line,sizeof(line),fp)) && (idx < map->keys)) { if (2 != sscanf(line," %80s = %80s", scancode, keycode)) { fprintf(stderr,"parse error: %s",line); return -1; } /* parse scancode */ if (0 == strncasecmp(scancode,"0x",2)) { entry.scancode = strtol(scancode, NULL, 16); } else { entry.scancode = strtol(scancode, NULL, 10); } if (entry.scancode < 0) { fprintf(stderr,"scancode %d invalid\n", entry.scancode); return -1; } /* parse keycode */ for (i = 0; i < KEY_MAX; i++) { if (!EV_TYPE_NAME[EV_KEY][i]) continue; if (0 == strcmp(keycode,EV_TYPE_NAME[EV_KEY][i])) break; } if (i == KEY_MAX) entry.keycode = atoi(keycode); else entry.keycode = i; fprintf(stderr,"set: "); kbd_key_print(stderr,entry.scancode,entry.keycode); map->map[idx++] = entry; } return 0; } /* ------------------------------------------------------------------ */ static void kbd_print_bits(int fd) { BITFIELD bits[KEY_CNT/sizeof(BITFIELD)]; int rc,bit; rc = ioctl(fd,EVIOCGBIT(EV_KEY,sizeof(bits)),bits); if (rc < 0) return; for (bit = 0; bit < rc*8 && bit < KEY_MAX; bit++) { if (!test_bit(bit,bits)) continue; if (EV_TYPE_NAME[EV_KEY][bit]) { fprintf(stderr,"bits: %s\n", EV_TYPE_NAME[EV_KEY][bit]); } else { fprintf(stderr,"bits: unknown [%d]\n", bit); } } } static void show_kbd(int nr, int fd, unsigned int protocol_version) { struct kbd_map *map; device_info(nr, fd, true); map = kbd_map_read(fd, protocol_version); if (map) kbd_map_print(stdout, map, 0); else kbd_print_bits(fd); } static int set_kbd(int fd, unsigned int protocol_version, char *mapfile) { struct kbd_map *map; FILE *fp; map = kbd_map_read(fd, protocol_version); if (NULL == map) { fprintf(stderr,"device has no map\n"); close(fd); return -1; } if (0 == strcmp(mapfile,"-")) fp = stdin; else { fp = fopen(mapfile,"r"); if (NULL == fp) { fprintf(stderr,"open %s: %s\n",mapfile,strerror(errno)); close(fd); return -1; } } if (0 != kbd_map_parse(fp,map) || 0 != kbd_map_write(fd,map)) { return -1; } return 0; } static int usage(char *prog, int error) { fprintf(error ? stderr : stdout, "usage: %s [ -f file ] devnr\n", prog); exit(error); } int main(int argc, char *argv[]) { int c, devnr, fd; char *mapfile = NULL; unsigned int protocol_version; int rc = EXIT_FAILURE; for (;;) { if (-1 == (c = getopt(argc, argv, "hf:"))) break; switch (c) { case 'f': mapfile = optarg; break; case 'h': usage(argv[0],0); default: usage(argv[0],1); } } if (optind == argc) usage(argv[0],1); devnr = atoi(argv[optind]); fd = device_open(devnr, 1); if (fd < 0) goto out; if (ioctl(fd, EVIOCGVERSION, &protocol_version) < 0) { fprintf(stderr, "Unable to query evdev protocol version: %s\n", strerror(errno)); goto out_close; } if (mapfile) set_kbd(fd, protocol_version, mapfile); else show_kbd(devnr, fd, protocol_version); rc = EXIT_SUCCESS; out_close: close(fd); out: return rc; } /* --------------------------------------------------------------------- * Local variables: * c-basic-offset: 8 * End: */