Skip to content

Instantly share code, notes, and snippets.

@saivert
Last active October 24, 2020 19:55
Show Gist options
  • Save saivert/28bb5bade6e4d936d4b49173b346ef44 to your computer and use it in GitHub Desktop.
Save saivert/28bb5bade6e4d936d4b49173b346ef44 to your computer and use it in GitHub Desktop.
// SPDX-License-Identifier: GPL-2.0
// Coding style: Linux kernel
#include <fcntl.h>
#include <unistd.h>
#include <poll.h>
#include <stdlib.h>
#include <ctype.h>
#include <signal.h>
#include <string.h>
#include <stdbool.h>
#include <linux/input.h>
#include <xkbcommon/xkbcommon.h>
#include <termios.h>
static int position_x, position_y;
static volatile sig_atomic_t doquit;
static void quit(int sig)
{
(void)sig;
doquit = 1;
}
int main(int argc, char *argv[])
{
int timeout_ms = 5000;
char *input_dev;
if (argc != 2) {
printf("Usage: evdev /dev/input/eventX\n");
return 1;
}
input_dev = argv[1];
int ret;
int previous_type;
struct pollfd fds[1];
signal(SIGINT, quit);
fds[0].fd = open(input_dev, O_RDONLY|O_NONBLOCK);
if (fds[0].fd < 0) {
printf("Error: unable open for reading '%s'\n", input_dev);
return 1;
}
// Disable local echo
struct termios old, new;
tcgetattr(STDIN_FILENO, &old); // get current settings
new = old; // create a backup
new.c_lflag &= ~(ICANON | ECHO); // disable line buffering and feedback
tcsetattr(STDIN_FILENO, TCSANOW, &new); // set our new config
struct xkb_state *xkb_state;
struct xkb_context *xkb_context;
struct xkb_keymap *xkb_keymap;
struct xkb_rule_names names = {
.rules = NULL,
.model = "pc105",
.layout = "no",
.variant = NULL,
.options = ""
};
const int input_size = sizeof(struct input_event);
unsigned char input_data[sizeof(struct input_event)];
memset(input_data, 0, input_size);
fds[0].events = POLLIN;
xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
xkb_keymap = xkb_keymap_new_from_names(xkb_context, &names,
XKB_KEYMAP_COMPILE_NO_FLAGS);
xkb_state = xkb_state_new(xkb_keymap);
printf("Evdev tester, press ^C to quit!\n\n");
while (!doquit) {
ret = poll(fds, 1, timeout_ms);
if (ret > 0) {
if (fds[0].revents) {
ssize_t r = read(fds[0].fd, input_data, input_size);
if (r < 0) {
printf("Error %d\n", (int)r);
break;
}
struct input_event *event = (struct input_event *)(input_data);
//printf("type = %hu, code = %hu value= %u\n", event->type, event->code, event->value);
xkb_keycode_t keycode;
xkb_keysym_t keysym;
if (event->type == EV_KEY && (event->value == 1 || event->value == 0)) {
xkb_state_update_key(xkb_state, event->code+8, event->value ? XKB_KEY_DOWN : XKB_KEY_UP);
if (event->code == BTN_LEFT)
printf("\33[2K\rKey pressed: Left mouse button %s\n", (event->value ? "pressed" : "released"));
else if (event->code == BTN_RIGHT)
printf("\33[2K\rKey pressed: Right mouse button %s\n", (event->value ? "pressed" : "released"));
}
if (event->type == EV_KEY && event->value == 1) {
keycode = event->code+8; // offset to convert from evdev scan code to xbk keycode
keysym = xkb_state_key_get_one_sym(xkb_state, keycode);
char keysym_name[64];
xkb_keysym_get_name(keysym, keysym_name, sizeof(keysym_name));
//printf("XKB Keysym = %s\n", keysym_name);
char *buffer;
int size;
// First find the needed size; return value is the same as snprintf(3).
size = xkb_state_key_get_utf8(xkb_state, keycode, NULL, 0) + 1;
if (size >= 1) {
buffer = calloc(1, size);
xkb_state_key_get_utf8(xkb_state, keycode, buffer, size);
// Don't print control characters
if (iscntrl(buffer[0]))
buffer[0] = '\0';
printf("\33[2K\rKey pressed: %s%s[%s]", buffer, buffer[0] ? " " : "", keysym_name);
fflush(stdout);
free(buffer);
}
} else if (event->type == EV_ABS) {
if (event->code == ABS_X)
position_x = event->value;
if (event->code == ABS_Y)
position_y = event->value;
previous_type = EV_ABS;
} else if (event->type == EV_SYN && event->code == SYN_REPORT && previous_type == EV_ABS) {
printf("\33[2K\rX = %d, Y = %d absolute", position_x, position_y);
fflush(stdout);
} else if (event->type == EV_REL) {
if (event->code == REL_X)
position_x += event->value;
if (event->code == REL_Y)
position_y += event->value;
previous_type = EV_REL;
} else if (event->type == EV_SYN && event->code == SYN_REPORT && previous_type == EV_REL) {
printf("\33[2K\rX = %d, Y = %d relative", position_x, position_y);
fflush(stdout);
}
memset(input_data, 0, input_size);
} else {
printf("Error!\n");
}
} else {
printf("\33[2K\rtimeout");
fflush(stdout);
}
}
tcsetattr(STDIN_FILENO, TCSANOW, &old);
xkb_keymap_unref(xkb_keymap);
xkb_state_unref(xkb_state);
xkb_context_unref(xkb_context);
close(fds[0].fd);
printf("\33[2K\rBye!\n");
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment