1 /* input-monitor.c: Monitors keyboard input.
3 Copyright (C) 2019 Michael Zucchi
5 This program is free software: you can redistribute it and/or
6 modify it under the terms of the GNU General Public License as
7 published by the Free Software Foundation, either version 3 of the
8 License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see
17 <http://www.gnu.org/licenses/>.
20 This monitors the keyboard.
22 Or in this case a mele air mouse.
24 Could run this in-memory but as a separate process it can handle
25 some other crap like usb hotplug easier.
28 #include <sys/types.h>
34 #include <linux/input.h>
41 #define INPUT_KB "/dev/input/by-id/usb-2.4G_Wireless_Receiver-event-kbd"
42 #define INPUT_MOUSE "/dev/input/by-id/usb-2.4G_Wireless_Receiver-if01-event-mouse"
53 struct input_event repeat;
58 stop x from reading the airmouse
61 .. find the airmouse devices (keyboard and mouse)
62 $ xinput set-int-prop XXX "Device Enabled" 8 0
69 /dev/input/by-id/usb-2.4G_Wireless_Receiver-event-kbd
87 /dev/input/by-id/usb-2.4G_Wireless_Receiver-if01-event-mouse
90 "-": 114 KEY_VOLUMEDOWN
93 subtitles: 240 KEY_UNKNOWN
101 display out: 377 KEY_TV
105 enum notify_action action;
114 static const struct keymap map[] = {
115 { NOTIFY_PLAY_SEEK, KEY_HOME, 0, 0 }, // house button
116 { NOTIFY_PLAY_PREV, KEY_UP },
117 { NOTIFY_PLAY_SEEK, KEY_LEFT, 0, 1},
118 { NOTIFY_PLAY_SEEK, KEY_RIGHT, 0, 2 },
119 { NOTIFY_PLAY_NEXT, KEY_DOWN },
121 { NOTIFY_VOLUME_MUTE, KEY_MUTE },
122 { NOTIFY_VOLUME_DOWN, KEY_VOLUMEDOWN, GEN_REPEAT }, // - button
123 { NOTIFY_VOLUME_UP, KEY_VOLUMEUP, GEN_REPEAT }, // + button
125 { NOTIFY_PLAY_PAUSE, BTN_LEFT },
128 static int cmp_key(const void *ap, const void *bp) {
129 int needle = *((uint16_t *)ap);
130 const struct keymap *hay = bp;
132 return needle - hay->code;
135 static struct monitor *monitor_new(void) {
136 struct monitor *m = malloc(sizeof(*m));
138 m->keyfd = open(INPUT_KB, O_RDONLY);
141 m->mousefd = open(INPUT_MOUSE, O_RDONLY);
142 if (m->mousefd == -1)
145 m->player = notify_writer_new(NOTIFY_PLAYER);
156 static void monitor_free(struct monitor *m) {
157 notify_close(m->player);
163 static void monitor_event(struct monitor *m, struct input_event *ev) {
164 if (ev->type == EV_KEY) {
165 struct keymap *key = bsearch(&ev->code, map, sizeof(map)/sizeof(map[0]), sizeof(map[0]), cmp_key);
169 printf(" key %d action %d flags %d mode %d\n", key->code, key->action, key->flags, key->mode);
171 if (key->action == NOTIFY_PLAY_SEEK) {
172 struct notify_play_seek msg;
188 notify_msg_send(m->player, key->action, 0, &msg);
190 notify_msg_send(m->player, key->action, 0, NULL);
193 if (key->flags & GEN_REPEAT) {
194 printf("start repeat\n");
198 if (key->flags & GEN_REPEAT) {
199 printf("stop repeat\n");
200 memset(&m->repeat, 0, sizeof(m->repeat));
203 } else if (ev->value) {
204 // All others, sort of
205 if (ev->code == BTN_MIDDLE)
207 else if (ev->code == KEY_UNKNOWN)
209 printf(" ev %d %04x %08x\n", ev->type, ev->code, ev->value);
210 struct notify_key msg = {.code = ev->code };
211 notify_msg_send(m->player, NOTIFY_KEY, 0, &msg);
214 //printf("?ev %d %04x %08x\n", ev->type, ev->code, ev->value);
220 case KEY_ENTER: // enter button
221 case KEY_F1: // square
222 case KEY_F2: // cross
223 case KEY_F3: // circle
224 case KEY_F4: // triangle
226 case KEY_HOME: // house button
228 case KEY_UP: // face panel up
229 case KEY_DOWN: // face panel down
230 case KEY_LEFT: // face panel left
231 case KEY_RIGHT: // face panel right
233 case KEY_MUTE: // mute
234 case KEY_VOLUMEDOWN: // - button
235 case KEY_VOLUMEUP: // + button
237 case KEY_UNKNOWN: // both the lips and the subtitle button
239 case BTN_LEFT: // face panel centre
240 case BTN_RIGHT: // back button
241 case BTN_MIDDLE: // menu /sandwich button
243 case KEY_TV: // 'output' button
249 static void monitor(struct monitor *m) {
250 struct pollfd polla[2];
251 struct input_event ev;
253 // NB: if the player isn't running this will block
255 polla[0].fd = m->keyfd;
256 polla[0].events = POLLIN;
257 polla[1].fd = m->mousefd;
258 polla[1].events = POLLIN;
261 //printf("poll, timeout = %d\n", m->repeat.value != 0 ? 50 : -1);
263 int res = poll(polla, 2, m->repeat.value != 0 ? 50 : -1);
265 for (int i=0;i<2;i++) {
266 if (polla[i].revents & POLLERR)
269 if (polla[i].revents & POLLIN ){
270 read(polla[i].fd, &ev, sizeof(ev));
271 monitor_event(m, &ev);
274 } else if (res == 0) {
276 monitor_event(m, &m->repeat);
281 int main(int argc, char **argv) {
282 struct monitor *m = monitor_new();