16f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin/* 26f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin * Copyright © 2012 Ran Benita <ran234@gmail.com> 36f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin * 46f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin * Permission is hereby granted, free of charge, to any person obtaining a 56f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin * copy of this software and associated documentation files (the "Software"), 66f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin * to deal in the Software without restriction, including without limitation 76f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin * the rights to use, copy, modify, merge, publish, distribute, sublicense, 86f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin * and/or sell copies of the Software, and to permit persons to whom the 96f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin * Software is furnished to do so, subject to the following conditions: 106f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin * 116f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin * The above copyright notice and this permission notice (including the next 126f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin * paragraph) shall be included in all copies or substantial portions of the 136f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin * Software. 146f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin * 156f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 166f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 176f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 186f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 196f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 206f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 216f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin * DEALINGS IN THE SOFTWARE. 226f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin */ 236f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 246f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin#include <dirent.h> 256f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin#include <errno.h> 266f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin#include <fcntl.h> 276f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin#include <fnmatch.h> 286f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin#include <limits.h> 296f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin#include <locale.h> 306f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin#include <signal.h> 316f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin#include <string.h> 326f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin#include <unistd.h> 336f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 346f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin#include <sys/epoll.h> 356f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin#include <linux/input.h> 366f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 376f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin#include "test.h" 386f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 396f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinstruct keyboard { 406f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin char *path; 416f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin int fd; 426f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin struct xkb_state *state; 436f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin struct xkb_compose_state *compose_state; 446f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin struct keyboard *next; 456f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin}; 466f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 476f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinstatic bool terminate; 486f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinstatic int evdev_offset = 8; 496f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinstatic bool report_state_changes; 506f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinstatic bool with_compose; 516f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 526f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin#define NLONGS(n) (((n) + LONG_BIT - 1) / LONG_BIT) 536f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 546f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinstatic bool 556f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinevdev_bit_is_set(const unsigned long *array, int bit) 566f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin{ 576f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin return array[bit / LONG_BIT] & (1LL << (bit % LONG_BIT)); 586f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin} 596f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 606f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin/* Some heuristics to see if the device is a keyboard. */ 616f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinstatic bool 626f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinis_keyboard(int fd) 636f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin{ 646f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin int i; 656f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin unsigned long evbits[NLONGS(EV_CNT)] = { 0 }; 666f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin unsigned long keybits[NLONGS(KEY_CNT)] = { 0 }; 676f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 686f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin errno = 0; 696f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin ioctl(fd, EVIOCGBIT(0, sizeof(evbits)), evbits); 706f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin if (errno) 716f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin return false; 726f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 736f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin if (!evdev_bit_is_set(evbits, EV_KEY)) 746f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin return false; 756f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 766f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin errno = 0; 776f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybits)), keybits); 786f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin if (errno) 796f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin return false; 806f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 816f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin for (i = KEY_RESERVED; i <= KEY_MIN_INTERESTING; i++) 826f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin if (evdev_bit_is_set(keybits, i)) 836f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin return true; 846f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 856f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin return false; 866f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin} 876f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 886f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinstatic int 896f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinkeyboard_new(struct dirent *ent, struct xkb_keymap *keymap, 906f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin struct xkb_compose_table *compose_table, struct keyboard **out) 916f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin{ 926f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin int ret; 936f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin char *path; 946f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin int fd; 956f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin struct xkb_state *state; 966f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin struct xkb_compose_state *compose_state = NULL; 976f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin struct keyboard *kbd; 986f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 996f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin ret = asprintf(&path, "/dev/input/%s", ent->d_name); 1006f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin if (ret < 0) 1016f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin return -ENOMEM; 1026f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 1036f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin fd = open(path, O_NONBLOCK | O_CLOEXEC | O_RDONLY); 1046f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin if (fd < 0) { 1056f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin ret = -errno; 1066f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin goto err_path; 1076f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin } 1086f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 1096f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin if (!is_keyboard(fd)) { 1106f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin /* Dummy "skip this device" value. */ 1116f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin ret = -ENOTSUP; 1126f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin goto err_fd; 1136f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin } 1146f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 1156f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin state = xkb_state_new(keymap); 1166f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin if (!state) { 1176f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin fprintf(stderr, "Couldn't create xkb state for %s\n", path); 1186f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin ret = -EFAULT; 1196f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin goto err_fd; 1206f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin } 1216f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 1226f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin if (with_compose) { 1236f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin compose_state = xkb_compose_state_new(compose_table, 1246f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin XKB_COMPOSE_STATE_NO_FLAGS); 1256f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin if (!compose_state) { 1266f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin fprintf(stderr, "Couldn't create compose state for %s\n", path); 1276f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin ret = -EFAULT; 1286f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin goto err_state; 1296f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin } 1306f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin } 1316f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 1326f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin kbd = calloc(1, sizeof(*kbd)); 1336f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin if (!kbd) { 1346f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin ret = -ENOMEM; 1356f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin goto err_compose_state; 1366f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin } 1376f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 1386f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin kbd->path = path; 1396f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin kbd->fd = fd; 1406f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin kbd->state = state; 1416f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin kbd->compose_state = compose_state; 1426f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin *out = kbd; 1436f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin return 0; 1446f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 1456f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinerr_compose_state: 1466f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin xkb_compose_state_unref(compose_state); 1476f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinerr_state: 1486f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin xkb_state_unref(state); 1496f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinerr_fd: 1506f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin close(fd); 1516f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinerr_path: 1526f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin free(path); 1536f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin return ret; 1546f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin} 1556f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 1566f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinstatic void 1576f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinkeyboard_free(struct keyboard *kbd) 1586f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin{ 1596f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin if (!kbd) 1606f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin return; 1616f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin if (kbd->fd >= 0) 1626f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin close(kbd->fd); 1636f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin free(kbd->path); 1646f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin xkb_state_unref(kbd->state); 1656f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin xkb_compose_state_unref(kbd->compose_state); 1666f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin free(kbd); 1676f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin} 1686f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 1696f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinstatic int 1706f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinfilter_device_name(const struct dirent *ent) 1716f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin{ 1726f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin return !fnmatch("event*", ent->d_name, 0); 1736f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin} 1746f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 1756f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinstatic struct keyboard * 1766f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinget_keyboards(struct xkb_keymap *keymap, 1776f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin struct xkb_compose_table *compose_table) 1786f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin{ 1796f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin int ret, i, nents; 1806f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin struct dirent **ents; 1816f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin struct keyboard *kbds = NULL, *kbd = NULL; 1826f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 1836f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin nents = scandir("/dev/input", &ents, filter_device_name, alphasort); 1846f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin if (nents < 0) { 1856f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin fprintf(stderr, "Couldn't scan /dev/input: %s\n", strerror(errno)); 1866f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin return NULL; 1876f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin } 1886f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 1896f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin for (i = 0; i < nents; i++) { 1906f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin ret = keyboard_new(ents[i], keymap, compose_table, &kbd); 1916f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin if (ret) { 1926f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin if (ret == -EACCES) { 1936f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin fprintf(stderr, "Couldn't open /dev/input/%s: %s. " 1946f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin "You probably need root to run this.\n", 1956f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin ents[i]->d_name, strerror(-ret)); 1966f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin break; 1976f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin } 1986f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin if (ret != -ENOTSUP) { 1996f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin fprintf(stderr, "Couldn't open /dev/input/%s: %s. Skipping.\n", 2006f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin ents[i]->d_name, strerror(-ret)); 2016f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin } 2026f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin continue; 2036f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin } 2046f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 2056f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin kbd->next = kbds; 2066f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin kbds = kbd; 2076f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin } 2086f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 2096f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin if (!kbds) { 2106f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin fprintf(stderr, "Couldn't find any keyboards I can use! Quitting.\n"); 2116f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin goto err; 2126f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin } 2136f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 2146f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinerr: 2156f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin for (i = 0; i < nents; i++) 2166f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin free(ents[i]); 2176f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin free(ents); 2186f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin return kbds; 2196f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin} 2206f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 2216f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinstatic void 2226f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinfree_keyboards(struct keyboard *kbds) 2236f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin{ 2246f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin struct keyboard *next; 2256f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 2266f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin while (kbds) { 2276f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin next = kbds->next; 2286f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin keyboard_free(kbds); 2296f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin kbds = next; 2306f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin } 2316f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin} 2326f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 2336f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin/* The meaning of the input_event 'value' field. */ 2346f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinenum { 2356f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin KEY_STATE_RELEASE = 0, 2366f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin KEY_STATE_PRESS = 1, 2376f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin KEY_STATE_REPEAT = 2, 2386f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin}; 2396f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 2406f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinstatic void 2416f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinprocess_event(struct keyboard *kbd, uint16_t type, uint16_t code, int32_t value) 2426f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin{ 2436f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin xkb_keycode_t keycode; 2446f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin struct xkb_keymap *keymap; 2456f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin enum xkb_state_component changed; 2466f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin enum xkb_compose_status status; 2476f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 2486f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin if (type != EV_KEY) 2496f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin return; 2506f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 2516f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin keycode = evdev_offset + code; 2526f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin keymap = xkb_state_get_keymap(kbd->state); 2536f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 2546f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin if (value == KEY_STATE_REPEAT && !xkb_keymap_key_repeats(keymap, keycode)) 2556f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin return; 2566f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 2576f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin if (with_compose && value != KEY_STATE_RELEASE) { 2586f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin xkb_keysym_t keysym = xkb_state_key_get_one_sym(kbd->state, keycode); 2596f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin xkb_compose_state_feed(kbd->compose_state, keysym); 2606f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin } 2616f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 2626f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin if (value != KEY_STATE_RELEASE) 2636f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin test_print_keycode_state(kbd->state, kbd->compose_state, keycode); 2646f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 2656f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin if (with_compose) { 2666f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin status = xkb_compose_state_get_status(kbd->compose_state); 2676f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin if (status == XKB_COMPOSE_CANCELLED || status == XKB_COMPOSE_COMPOSED) 2686f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin xkb_compose_state_reset(kbd->compose_state); 2696f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin } 2706f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 2716f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin if (value == KEY_STATE_RELEASE) 2726f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin changed = xkb_state_update_key(kbd->state, keycode, XKB_KEY_UP); 2736f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin else 2746f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin changed = xkb_state_update_key(kbd->state, keycode, XKB_KEY_DOWN); 2756f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 2766f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin if (report_state_changes) 2776f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin test_print_state_changes(changed); 2786f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin} 2796f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 2806f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinstatic int 2816f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinread_keyboard(struct keyboard *kbd) 2826f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin{ 2836f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin ssize_t len; 2846f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin struct input_event evs[16]; 2856f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 2866f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin /* No fancy error checking here. */ 2876f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin while ((len = read(kbd->fd, &evs, sizeof(evs))) > 0) { 2886f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin const size_t nevs = len / sizeof(struct input_event); 2896f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin for (size_t i = 0; i < nevs; i++) 2906f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin process_event(kbd, evs[i].type, evs[i].code, evs[i].value); 2916f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin } 2926f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 2936f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin if (len < 0 && errno != EWOULDBLOCK) { 2946f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin fprintf(stderr, "Couldn't read %s: %s\n", kbd->path, strerror(errno)); 2956f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin return -errno; 2966f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin } 2976f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 2986f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin return 0; 2996f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin} 3006f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 3016f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinstatic int 3026f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinloop(struct keyboard *kbds) 3036f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin{ 3046f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin int i, ret; 3056f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin int epfd; 3066f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin struct keyboard *kbd; 3076f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin struct epoll_event ev; 3086f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin struct epoll_event evs[16]; 3096f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 3106f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin epfd = epoll_create1(0); 3116f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin if (epfd < 0) { 3126f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin fprintf(stderr, "Couldn't create epoll instance: %s\n", 3136f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin strerror(errno)); 3146f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin return -errno; 3156f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin } 3166f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 3176f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin for (kbd = kbds; kbd; kbd = kbd->next) { 3186f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin memset(&ev, 0, sizeof(ev)); 3196f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin ev.events = EPOLLIN; 3206f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin ev.data.ptr = kbd; 3216f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin ret = epoll_ctl(epfd, EPOLL_CTL_ADD, kbd->fd, &ev); 3226f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin if (ret) { 3236f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin ret = -errno; 3246f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin fprintf(stderr, "Couldn't add %s to epoll: %s\n", 3256f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin kbd->path, strerror(errno)); 3266f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin goto err_epoll; 3276f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin } 3286f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin } 3296f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 3306f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin while (!terminate) { 3316f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin ret = epoll_wait(epfd, evs, 16, -1); 3326f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin if (ret < 0) { 3336f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin if (errno == EINTR) 3346f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin continue; 3356f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin ret = -errno; 3366f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin fprintf(stderr, "Couldn't poll for events: %s\n", 3376f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin strerror(errno)); 3386f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin goto err_epoll; 3396f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin } 3406f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 3416f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin for (i = 0; i < ret; i++) { 3426f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin kbd = evs[i].data.ptr; 3436f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin ret = read_keyboard(kbd); 3446f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin if (ret) { 3456f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin goto err_epoll; 3466f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin } 3476f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin } 3486f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin } 3496f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 3506f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin close(epfd); 3516f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin return 0; 3526f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 3536f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinerr_epoll: 3546f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin close(epfd); 3556f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin return ret; 3566f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin} 3576f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 3586f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinstatic void 3596f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinsigintr_handler(int signum) 3606f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin{ 3616f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin terminate = true; 3626f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin} 3636f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 3646f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinint 3656f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinmain(int argc, char *argv[]) 3666f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin{ 3676f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin int ret; 3686f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin int opt; 3696f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin struct keyboard *kbds; 3706f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin struct xkb_context *ctx; 3716f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin struct xkb_keymap *keymap; 3726f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin struct xkb_compose_table *compose_table = NULL; 3736f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin const char *rules = NULL; 3746f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin const char *model = NULL; 3756f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin const char *layout = NULL; 3766f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin const char *variant = NULL; 3776f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin const char *options = NULL; 3786f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin const char *keymap_path = NULL; 3796f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin const char *locale; 3806f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin struct sigaction act; 3816f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 3826f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin setlocale(LC_ALL, ""); 3836f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 3846f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin while ((opt = getopt(argc, argv, "r:m:l:v:o:k:n:cd")) != -1) { 3856f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin switch (opt) { 3866f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin case 'r': 3876f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin rules = optarg; 3886f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin break; 3896f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin case 'm': 3906f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin model = optarg; 3916f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin break; 3926f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin case 'l': 3936f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin layout = optarg; 3946f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin break; 3956f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin case 'v': 3966f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin variant = optarg; 3976f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin break; 3986f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin case 'o': 3996f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin options = optarg; 4006f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin break; 4016f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin case 'k': 4026f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin keymap_path = optarg; 4036f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin break; 4046f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin case 'n': 4056f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin errno = 0; 4066f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin evdev_offset = strtol(optarg, NULL, 10); 4076f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin if (errno) { 4086f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin fprintf(stderr, "error: -n option expects a number\n"); 4096f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin exit(EXIT_FAILURE); 4106f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin } 4116f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin break; 4126f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin case 'c': 4136f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin report_state_changes = true; 4146f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin break; 4156f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin case 'd': 4166f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin with_compose = true; 4176f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin break; 4186f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin case '?': 4196f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin fprintf(stderr, " Usage: %s [-r <rules>] [-m <model>] " 4206f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin "[-l <layout>] [-v <variant>] [-o <options>]\n", 4216f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin argv[0]); 4226f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin fprintf(stderr, " or: %s -k <path to keymap file>\n", 4236f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin argv[0]); 4246f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin fprintf(stderr, "For both: -n <evdev keycode offset>\n" 4256f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin " -c (to report changes to the state)\n" 4266f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin " -d (to enable compose)\n"); 4276f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin exit(2); 4286f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin } 4296f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin } 4306f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 4316f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin ctx = test_get_context(0); 4326f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin if (!ctx) { 4336f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin ret = -1; 4346f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin fprintf(stderr, "Couldn't create xkb context\n"); 4356f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin goto err_out; 4366f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin } 4376f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 4386f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin if (keymap_path) { 4396f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin FILE *file = fopen(keymap_path, "r"); 4406f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin if (!file) { 4416f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin ret = EXIT_FAILURE; 4426f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin fprintf(stderr, "Couldn't open '%s': %s\n", 4436f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin keymap_path, strerror(errno)); 4446f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin goto err_ctx; 4456f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin } 4466f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin keymap = xkb_keymap_new_from_file(ctx, file, 4476f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin XKB_KEYMAP_FORMAT_TEXT_V1, 0); 4486f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin fclose(file); 4496f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin } 4506f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin else { 4516f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin keymap = test_compile_rules(ctx, rules, model, layout, variant, 4526f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin options); 4536f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin } 4546f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 4556f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin if (!keymap) { 4566f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin ret = -1; 4576f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin fprintf(stderr, "Couldn't create xkb keymap\n"); 4586f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin goto err_ctx; 4596f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin } 4606f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 4616f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin if (with_compose) { 4626f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin locale = setlocale(LC_CTYPE, NULL); 4636f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin compose_table = 4646f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin xkb_compose_table_new_from_locale(ctx, locale, 4656f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin XKB_COMPOSE_COMPILE_NO_FLAGS); 4666f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin if (!compose_table) { 4676f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin ret = -1; 4686f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin fprintf(stderr, "Couldn't create compose from locale\n"); 4696f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin goto err_xkb; 4706f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin } 4716f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin } 4726f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 4736f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin kbds = get_keyboards(keymap, compose_table); 4746f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin if (!kbds) { 4756f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin ret = -1; 4766f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin goto err_compose; 4776f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin } 4786f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 4796f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin act.sa_handler = sigintr_handler; 4806f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin sigemptyset(&act.sa_mask); 4816f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin act.sa_flags = 0; 4826f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin sigaction(SIGINT, &act, NULL); 4836f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin sigaction(SIGTERM, &act, NULL); 4846f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 4856f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin /* Instead of fiddling with termios.. */ 4866f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin system("stty -echo"); 4876f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 4886f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin ret = loop(kbds); 4896f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin if (ret) 4906f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin goto err_stty; 4916f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin 4926f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinerr_stty: 4936f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin system("stty echo"); 4946f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin free_keyboards(kbds); 4956f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinerr_compose: 4966f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin xkb_compose_table_unref(compose_table); 4976f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinerr_xkb: 4986f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin xkb_keymap_unref(keymap); 4996f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinerr_ctx: 5006f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin xkb_context_unref(ctx); 5016f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinerr_out: 5026f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin exit(ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE); 5036f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin} 504