more input wip
[libpicofe.git] / linux / in_evdev.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <sys/types.h>
4 #include <sys/stat.h>
5 #include <fcntl.h>
6 #include <sys/ioctl.h>
7 #include <unistd.h>
8 #include <linux/input.h>
9 #include <errno.h>
10
11 #include "../common/common.h"
12 #include "../common/input.h"
13 #include "in_evdev.h"
14
15 #define BIT(x) (keybits[(x)/sizeof(keybits[0])/8] & \
16         (1 << ((x) & (sizeof(keybits[0])*8-1))))
17
18 int in_evdev_probe(void)
19 {
20         int i;
21
22         for (i = 0;; i++)
23         {
24                 int u, ret, fd, keybits[KEY_MAX/sizeof(int)];
25                 int support = 0, count = 0;
26                 char name[64];
27
28                 snprintf(name, sizeof(name), "/dev/input/event%d", i);
29                 fd = open(name, O_RDONLY|O_NONBLOCK);
30                 if (fd == -1)
31                         break;
32
33                 /* check supported events */
34                 ret = ioctl(fd, EVIOCGBIT(0, sizeof(support)), &support);
35                 if (ret == -1) {
36                         printf("in_evdev: ioctl failed on %s\n", name);
37                         goto skip;
38                 }
39
40                 if (!(support & (1 << EV_KEY)))
41                         goto skip;
42
43                 ret = ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybits)), keybits);
44                 if (ret == -1) {
45                         printf("in_evdev: ioctl failed on %s\n", name);
46                         goto skip;
47                 }
48
49                 /* check for interesting keys */
50                 for (u = 0; u < KEY_MAX; u++) {
51                         if (BIT(u) && u != KEY_POWER && u != KEY_SLEEP)
52                                 count++;
53                 }
54
55                 if (count == 0)
56                         goto skip;
57
58                 strcpy(name, "evdev:");
59                 ioctl(fd, EVIOCGNAME(sizeof(name)-6), name+6);
60                 printf("in_evdev: found \"%s\" with %d events (type %08x)\n",
61                         name+6, count, support);
62                 in_register(name, IN_DRVID_EVDEV, (void *)fd);
63                 continue;
64
65 skip:
66                 close(fd);
67         }
68
69         return 0;
70 }
71
72 void in_evdev_free(void *drv_data)
73 {
74         close((int)drv_data);
75 }
76
77 int in_evdev_bind_count(void)
78 {
79         return 512;
80 }
81
82 int in_evdev_update(void *drv_data, int *binds)
83 {
84         struct input_event ev[16];
85         int keybits[KEY_MAX/sizeof(int)];
86         int fd = (int)drv_data;
87         int result = 0, changed = 0;
88         int rd, ret, u;
89
90         while (1) {
91                 rd = read(fd, ev, sizeof(ev));
92                 if (rd < (int)sizeof(ev[0])) {
93                         if (errno != EAGAIN)
94                                 perror("in_evdev: read failed");
95                         break;
96                 }
97
98                 changed = 1;
99         }
100
101 /*
102         if (!changed)
103                 return 0;
104 */
105         ret = ioctl(fd, EVIOCGKEY(sizeof(keybits)), keybits);
106         if (ret == -1) {
107                 perror("in_evdev: ioctl failed");
108                 return 0;
109         }
110
111         printf("#%d: ", fd);
112         for (u = 0; u < KEY_MAX; u++) {
113                 if (BIT(u)) {
114                         printf(" %d", u);
115                         result |= binds[u];
116                 }
117         }
118         printf("\n");
119
120         return result;
121 }
122
123 int in_evdev_update_menu(void **data, int count)
124 {
125         const int *fds = (const int *)data;
126         static int result = 0;
127         int i, ret, fdmax = -1;
128         int oldresult = result;
129         long flags;
130
131         /* switch to blocking mode */
132         for (i = 0; i < count; i++) {
133                 if (fds[i] > fdmax) fdmax = fds[i];
134
135                 flags = (long)fcntl(fds[i], F_GETFL);
136                 if ((int)flags == -1) {
137                         perror("in_evdev: F_GETFL fcntl failed");
138                         continue;
139                 }
140                 flags &= ~O_NONBLOCK;
141                 ret = fcntl(fds[i], F_SETFL, flags);
142                 if (ret == -1)
143                         perror("in_evdev: F_SETFL fcntl failed");
144         }
145
146         while (1)
147         {
148                 struct input_event ev[64];
149                 int fd, rd;
150                 fd_set fdset;
151
152                 FD_ZERO(&fdset);
153                 for (i = 0; i < count; i++)
154                         FD_SET(fds[i], &fdset);
155
156                 ret = select(fdmax + 1, &fdset, NULL, NULL, NULL);
157                 if (ret == -1)
158                 {
159                         perror("in_evdev: select failed");
160                         sleep(1);
161                         return 0;
162                 }
163
164                 for (i = 0; i < count; i++)
165                         if (FD_ISSET(fds[i], &fdset))
166                                 fd = fds[i];
167
168                 rd = read(fd, ev, sizeof(ev[0]) * 64);
169                 if (rd < (int) sizeof(ev[0])) {
170                         perror("in_evdev: error reading");
171                         sleep(1);
172                         return 0;
173                 }
174
175                 #define mapkey(o,k) \
176                         case o: \
177                                 if (ev[i].value) result |= k; \
178                                 else result &= ~k; \
179                                 break
180                 for (i = 0; i < rd / sizeof(ev[0]); i++)
181                 {
182                         if (ev[i].type != EV_KEY || ev[i].value < 0 || ev[i].value > 1)
183                                 continue;
184
185                         switch (ev[i].code) {
186                                 /* keyboards */
187                                 mapkey(KEY_UP,          PBTN_UP);
188                                 mapkey(KEY_DOWN,        PBTN_DOWN);
189                                 mapkey(KEY_LEFT,        PBTN_LEFT);
190                                 mapkey(KEY_RIGHT,       PBTN_RIGHT);
191                                 mapkey(KEY_ENTER,       PBTN_EAST);
192                                 mapkey(KEY_ESC,         PBTN_SOUTH);
193                         }
194                 }
195                 #undef mapkey
196
197                 if (oldresult != result) break;
198         }
199
200         /* switch back to non-blocking mode */
201         for (i = 0; i < count; i++) {
202                 if (fds[i] > fdmax) fdmax = fds[i];
203
204                 flags = (long)fcntl(fds[i], F_GETFL);
205                 if ((int)flags == -1) {
206                         perror("in_evdev: F_GETFL fcntl failed");
207                         continue;
208                 }
209                 flags |= O_NONBLOCK;
210                 ret = fcntl(fds[i], F_SETFL, flags);
211                 if (ret == -1)
212                         perror("in_evdev: F_SETFL fcntl failed");
213         }
214
215         return result;
216 }
217