Cleanup dbindex.c a bit.
[playerz] / input-monitor.c
1 /* input-monitor.c: Monitors keyboard input.
2
3    Copyright (C) 2019 Michael Zucchi
4
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.
9
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.
14
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/>.
18 */
19 /**
20    This monitors the keyboard.
21
22    Or in this case a mele air mouse.
23
24    Could run this in-memory but as a separate process it can handle
25    some other crap like usb hotplug easier.
26
27  */
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <fcntl.h>
31 #include <poll.h>
32 #include <unistd.h>
33
34 #include <linux/input.h>
35
36 #include <stdlib.h>
37 #include <stdio.h>
38 #include <stdint.h>
39 #include <string.h>
40
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"
43
44 #include "dbindex.h"
45 #include "notify.h"
46
47 struct monitor {
48         int keyfd;
49         int mousefd;
50
51         notify_t player;
52
53         struct input_event repeat;
54 };
55
56 /*
57
58 stop x from reading the airmouse
59
60 $ xinput --list
61  .. find the airmouse devices (keyboard and mouse)
62 $ xinput set-int-prop XXX "Device Enabled" 8 0
63
64 */
65
66 /*
67
68
69  /dev/input/by-id/usb-2.4G_Wireless_Receiver-event-kbd
70
71 enter: 28 KEY_ENTER
72 home: 102 KEY_HOME
73
74 up: 103    KEY_UP
75 left: 105  KEY_LEFT
76 right: 106 KEY_RIGHT
77 down: 108  KEY_DOWN
78
79
80 square: 59   KEY_F1
81 cross: 60    KEY_F2
82 circle: 61   KEY_F3
83 triangle: 62 KEY_F4
84
85 keyboard: same
86
87 /dev/input/by-id/usb-2.4G_Wireless_Receiver-if01-event-mouse
88
89 mute: 113         KEY_MUTE
90 "-": 114          KEY_VOLUMEDOWN
91 "+": 115          KEY_VOLUMEUP
92
93 subtitles: 240    KEY_UNKNOWN
94 lips: 240         KEY_UNKNOWN
95
96 // mouse buttons
97 centre: 272       BTN_LEFT
98 back: 273         BTN_RIGHT
99 menu: 274         BTN_MIDDLE
100
101 display out: 377  KEY_TV
102 */
103
104 struct keymap {
105         enum notify_action action;
106         short code;
107         unsigned char flags;
108         unsigned char mode;
109 };
110
111 // flags
112 #define GEN_REPEAT 1
113
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 },
120
121         { NOTIFY_VOLUME_MUTE, KEY_MUTE },
122         { NOTIFY_VOLUME_DOWN, KEY_VOLUMEDOWN, GEN_REPEAT }, // - button
123         { NOTIFY_VOLUME_UP, KEY_VOLUMEUP, GEN_REPEAT },   // + button
124
125         { NOTIFY_PLAY_PAUSE, BTN_LEFT },
126 };
127
128 static int cmp_key(const void *ap, const void *bp) {
129         int needle = *((uint16_t *)ap);
130         const struct keymap *hay = bp;
131
132         return needle - hay->code;
133 }
134
135 static struct monitor *monitor_new(void) {
136         struct monitor *m = malloc(sizeof(*m));
137
138         m->keyfd = open(INPUT_KB, O_RDONLY);
139         if (m->keyfd == -1)
140                 goto fail;
141         m->mousefd = open(INPUT_MOUSE, O_RDONLY);
142         if (m->mousefd == -1)
143                 goto fail1;
144
145         m->player = notify_writer_new(NOTIFY_PLAYER);
146
147         return m;
148  fail1:
149         close(m->keyfd);
150  fail:
151         free(m);
152
153         return NULL;
154 }
155
156 static void monitor_free(struct monitor *m) {
157         notify_close(m->player);
158         close(m->mousefd);
159         close(m->keyfd);
160         free(m);
161 }
162
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);
166
167                 if (key) {
168                         // Special keys
169                         printf(" key %d action %d flags %d mode %d\n", key->code, key->action, key->flags, key->mode);
170                         if (ev->value) {
171                                 if (key->action == NOTIFY_PLAY_SEEK) {
172                                         struct notify_play_seek msg;
173
174                                         switch (key->mode) {
175                                         case 0:
176                                                 msg.mode = 0;
177                                                 msg.stamp = 0;
178                                                 break;
179                                         case 1:
180                                                 msg.mode = 1;
181                                                 msg.stamp = -15;
182                                                 break;
183                                         case 2:
184                                                 msg.mode = 1;
185                                                 msg.stamp = +15;
186                                                 break;
187                                         }
188                                         notify_msg_send(m->player, key->action, 0, &msg);
189                                 } else {
190                                         notify_msg_send(m->player, key->action, 0, NULL);
191                                 }
192
193                                 if (key->flags & GEN_REPEAT) {
194                                         printf("start repeat\n");
195                                         m->repeat = *ev;
196                                 }
197                         } else {
198                                 if (key->flags & GEN_REPEAT) {
199                                         printf("stop repeat\n");
200                                         memset(&m->repeat, 0, sizeof(m->repeat));
201                                 }
202                         }
203                 } else if (ev->value) {
204                         // All others, sort of
205                         if (ev->code == BTN_MIDDLE)
206                                 ev->code = KEY_MENU;
207                         else if (ev->code == KEY_UNKNOWN)
208                                 ev->code = KEY_HELP;
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);
212                 }
213         } else {
214                 //printf("?ev %d %04x %08x\n", ev->type, ev->code, ev->value);
215         }
216 }
217
218 /*
219                 switch (ev.code) {
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
225
226                 case KEY_HOME:  // house button
227
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
232
233                 case KEY_MUTE:       // mute
234                 case KEY_VOLUMEDOWN: // - button
235                 case KEY_VOLUMEUP:   // + button
236
237                 case KEY_UNKNOWN: // both the lips and the subtitle button
238
239                 case BTN_LEFT:  // face panel centre
240                 case BTN_RIGHT: // back button
241                 case BTN_MIDDLE: // menu /sandwich button
242
243                 case KEY_TV:    // 'output' button
244                         break;
245
246                 }
247 */
248
249 static void monitor(struct monitor *m) {
250         struct pollfd polla[2];
251         struct input_event ev;
252
253         // NB: if the player isn't running this will block
254
255         polla[0].fd = m->keyfd;
256         polla[0].events = POLLIN;
257         polla[1].fd = m->mousefd;
258         polla[1].events = POLLIN;
259
260         while (1) {
261                 //printf("poll, timeout = %d\n", m->repeat.value != 0 ? 50 : -1);
262
263                 int res = poll(polla, 2, m->repeat.value != 0 ? 50 : -1);
264                 if (res > 0) {
265                         for (int i=0;i<2;i++) {
266                                 if (polla[i].revents & POLLERR)
267                                         return;
268
269                                 if (polla[i].revents & POLLIN ){
270                                         read(polla[i].fd, &ev, sizeof(ev));
271                                         monitor_event(m, &ev);
272                                 }
273                         }
274                 } else if (res == 0) {
275                         printf(" repeat\n");
276                         monitor_event(m, &m->repeat);
277                 }
278         }
279 }
280
281 int main(int argc, char **argv) {
282         struct monitor *m = monitor_new();
283
284         if (m) {
285                 monitor(m);
286                 monitor_free(m);
287         }
288
289         return 0;
290 }