/** * Copyright 2021 Johannes Marbach * * This file is part of buffyboard, hereafter referred to as the program. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "uinput_device.h" #include #include #include #include #include /** * Static variables */ static int fd = -1; struct input_event event; /** * Static prototypes */ /** * Emit an event on the device. * @param type event type * @param code event code * @param value event value * @return true if emitting the event was succesful, false otherwise */ static bool uinput_device_emit(int type, int code, int value); /** * Emit a synchronisation event on the device * @return true if emitting the event was succesful, false otherwise */ static bool uinput_device_synchronise(); /** * Static functions */ static bool uinput_device_emit(int type, int code, int value) { event.type = type; event.code = code; event.value = value; event.time.tv_sec = 0; event.time.tv_usec = 0; if (write(fd, &event, sizeof(event)) != sizeof(event)) { perror("Could not emit event"); return false; } return true; } static bool uinput_device_synchronise() { return uinput_device_emit(EV_SYN, SYN_REPORT, 0); } /** * Public functions */ bool bb_uinput_device_init(int * const scancodes, int num_scancodes) { fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK); if (fd < 0) { perror("Could not open /dev/uinput"); return false; } if (ioctl(fd, UI_SET_EVBIT, EV_KEY) < 0) { perror("Could not set EVBIT for EV_KEY"); return false; } if (ioctl(fd, UI_SET_EVBIT, EV_SYN) < 0) { perror("Could not set EVBIT for EV_SYN"); return false; } for (int i = 0; i < num_scancodes; ++i) { if (ioctl(fd, UI_SET_KEYBIT, scancodes[i]) < 0) { perror("Could not set KEYBIT"); return false; } } struct uinput_user_dev device; memset(&device, 0, sizeof(device)); strcpy(device.name, "buffyboard"); device.id.bustype = BUS_USB; device.id.vendor = 1; device.id.product = 1; device.id.version = 1; if (ioctl(fd, UI_DEV_SETUP, &device) < 0) { perror("Could not set up uinput device"); return false; } if (ioctl(fd, UI_DEV_CREATE) < 0) { perror("Could not create uinput device"); return false; } memset(&event, 0, sizeof(event)); return true; } bool bb_uinput_device_emit_key_down(int scancode) { return uinput_device_emit(EV_KEY, scancode, 1) && uinput_device_synchronise(); } bool bb_uinput_device_emit_key_up(int scancode) { return uinput_device_emit(EV_KEY, scancode, 0) && uinput_device_synchronise(); }