blob: 1a9bdeaf64bf63928630110be8cd6710548ade44 [file] [log] [blame]
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <stdio.h>
18#include <stdlib.h>
19#include <fcntl.h>
20#include <dirent.h>
21#include <sys/poll.h>
Christopher Laisac731c82010-11-24 18:49:52 -060022#include <limits.h>
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080023
24#include <linux/input.h>
25
Christopher Laisac731c82010-11-24 18:49:52 -060026#include "../common.h"
27
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080028#include "minui.h"
29
30#define MAX_DEVICES 16
31
Christopher Laisac731c82010-11-24 18:49:52 -060032enum {
33 DOWN_NOT,
34 DOWN_SENT,
35 DOWN_RELEASED,
36};
37
38struct virtualkey {
39 int scancode;
40 int centerx, centery;
41 int width, height;
42};
43
44struct position {
45 int x, y;
46 int synced;
47 struct input_absinfo xi, yi;
48};
49
50struct ev {
51 struct pollfd *fd;
52
53 struct virtualkey *vks;
54 int vk_count;
55
56 struct position p, mt_p;
57 int down;
58};
59
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080060static struct pollfd ev_fds[MAX_DEVICES];
Christopher Laisac731c82010-11-24 18:49:52 -060061static struct ev evs[MAX_DEVICES];
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080062static unsigned ev_count = 0;
63
Christopher Laisac731c82010-11-24 18:49:52 -060064static inline int ABS(int x) {
65 return x<0?-x:x;
66}
67
68/* Returns empty tokens */
69static char *vk_strtok_r(char *str, const char *delim, char **save_str)
70{
71 if(!str) {
72 if(!*save_str) return NULL;
73 str = (*save_str) + 1;
74 }
75 *save_str = strpbrk(str, delim);
76 if(*save_str) **save_str = '\0';
77 return str;
78}
79
80static int vk_init(struct ev *e)
81{
82 char vk_path[PATH_MAX] = "/sys/board_properties/virtualkeys.";
83 char vks[2048], *ts;
84 ssize_t len;
85 int vk_fd;
86 int i;
87
88 e->vk_count = 0;
89
90 len = strlen(vk_path);
91 len = ioctl(e->fd->fd, EVIOCGNAME(sizeof(vk_path) - len), vk_path + len);
92 if (len <= 0)
93 return -1;
94
95 vk_fd = open(vk_path, O_RDONLY);
96 if (vk_fd < 0)
97 return -1;
98
99 len = read(vk_fd, vks, sizeof(vks)-1);
100 close(vk_fd);
101 if (len <= 0)
102 return -1;
103
104 vks[len] = '\0';
105
106 /* Parse a line like:
107 keytype:keycode:centerx:centery:width:height:keytype2:keycode2:centerx2:...
108 */
109 for (ts = vks, e->vk_count = 1; *ts; ++ts) {
110 if (*ts == ':')
111 ++e->vk_count;
112 }
113
114 if (e->vk_count % 6) {
115 LOGW("minui: %s is %d %% 6\n", vk_path, e->vk_count % 6);
116 }
117 e->vk_count /= 6;
118 if (e->vk_count <= 0)
119 return -1;
120
121 e->down = DOWN_NOT;
122
123 ioctl(e->fd->fd, EVIOCGABS(ABS_X), &e->p.xi);
124 ioctl(e->fd->fd, EVIOCGABS(ABS_Y), &e->p.yi);
125 e->p.synced = 0;
126
127 ioctl(e->fd->fd, EVIOCGABS(ABS_MT_POSITION_X), &e->mt_p.xi);
128 ioctl(e->fd->fd, EVIOCGABS(ABS_MT_POSITION_Y), &e->mt_p.yi);
129 e->mt_p.synced = 0;
130
131 e->vks = malloc(sizeof(*e->vks) * e->vk_count);
132
133 for (i = 0; i < e->vk_count; ++i) {
134 char *token[6];
135 int j;
136
137 for (j = 0; j < 6; ++j) {
138 token[j] = vk_strtok_r((i||j)?NULL:vks, ":", &ts);
139 }
140
141 if (strcmp(token[0], "0x01") != 0) {
142 /* Java does string compare, so we do too. */
143 LOGW("minui: %s: ignoring unknown virtual key type %s\n", vk_path, token[0]);
144 continue;
145 }
146
147 e->vks[i].scancode = strtol(token[1], NULL, 0);
148 e->vks[i].centerx = strtol(token[2], NULL, 0);
149 e->vks[i].centery = strtol(token[3], NULL, 0);
150 e->vks[i].width = strtol(token[4], NULL, 0);
151 e->vks[i].height = strtol(token[5], NULL, 0);
152 }
153
154 return 0;
155}
156
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800157int ev_init(void)
158{
159 DIR *dir;
160 struct dirent *de;
161 int fd;
162
163 dir = opendir("/dev/input");
164 if(dir != 0) {
165 while((de = readdir(dir))) {
166// fprintf(stderr,"/dev/input/%s\n", de->d_name);
167 if(strncmp(de->d_name,"event",5)) continue;
168 fd = openat(dirfd(dir), de->d_name, O_RDONLY);
169 if(fd < 0) continue;
170
171 ev_fds[ev_count].fd = fd;
172 ev_fds[ev_count].events = POLLIN;
Christopher Laisac731c82010-11-24 18:49:52 -0600173 evs[ev_count].fd = &ev_fds[ev_count];
174
175 /* Load virtualkeys if there are any */
176 vk_init(&evs[ev_count]);
177
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800178 ev_count++;
179 if(ev_count == MAX_DEVICES) break;
180 }
181 }
182
183 return 0;
184}
185
186void ev_exit(void)
187{
Christopher Laisac731c82010-11-24 18:49:52 -0600188 while (ev_count-- > 0) {
189 if (evs[ev_count].vk_count) {
190 free(evs[ev_count].vks);
191 evs[ev_count].vk_count = 0;
192 }
193 close(ev_fds[ev_count].fd);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800194 }
195}
196
Christopher Laisac731c82010-11-24 18:49:52 -0600197static int vk_inside_display(__s32 value, struct input_absinfo *info, int screen_size)
198{
199 int screen_pos;
200
201 if (info->minimum == info->maximum)
202 return 0;
203
204 screen_pos = (value - info->minimum) * (screen_size - 1) / (info->maximum - info->minimum);
205 return (screen_pos >= 0 && screen_pos < screen_size);
206}
207
208static int vk_tp_to_screen(struct position *p, int *x, int *y)
209{
210 if (p->xi.minimum == p->xi.maximum || p->yi.minimum == p->yi.maximum)
211 return 0;
212
213 *x = (p->x - p->xi.minimum) * (gr_fb_width() - 1) / (p->xi.maximum - p->xi.minimum);
214 *y = (p->y - p->yi.minimum) * (gr_fb_height() - 1) / (p->yi.maximum - p->yi.minimum);
215
216 if (*x >= 0 && *x < gr_fb_width() &&
217 *y >= 0 && *y < gr_fb_height()) {
218 return 0;
219 }
220
221 return 1;
222}
223
224/* Translate a virtual key in to a real key event, if needed */
225/* Returns non-zero when the event should be consumed */
226static int vk_modify(struct ev *e, struct input_event *ev)
227{
228 int i;
229 int x, y;
230
231 if (ev->type == EV_KEY) {
232 if (ev->code == BTN_TOUCH && !ev->value)
233 e->down = DOWN_RELEASED;
234 return 0;
235 }
236
237 if (ev->type == EV_ABS) {
238 switch (ev->code) {
239 case ABS_X:
240 e->p.synced = 1;
241 e->p.x = ev->value;
242 return !vk_inside_display(e->p.x, &e->p.xi, gr_fb_width());
243 case ABS_Y:
244 e->p.synced = 1;
245 e->p.y = ev->value;
246 return !vk_inside_display(e->p.y, &e->p.yi, gr_fb_height());
247 case ABS_MT_POSITION_X:
248 if (e->mt_p.synced & 2) return 1;
249 e->mt_p.synced = 1;
250 e->mt_p.x = ev->value;
251 return !vk_inside_display(e->mt_p.x, &e->mt_p.xi, gr_fb_width());
252 case ABS_MT_POSITION_Y:
253 if (e->mt_p.synced & 2) return 1;
254 e->mt_p.synced = 1;
255 e->mt_p.y = ev->value;
256 return !vk_inside_display(e->mt_p.y, &e->mt_p.yi, gr_fb_height());
257 case ABS_MT_TOUCH_MAJOR:
258 if (e->mt_p.synced & 2) return 1;
259 if (!ev->value) e->down = DOWN_RELEASED;
260 return 0;
261 }
262
263 return 0;
264 }
265
266 if (ev->type != EV_SYN)
267 return 0;
268
269 if (ev->code == SYN_MT_REPORT) {
270 /* Ignore the rest of the points */
271 e->mt_p.synced |= 2;
272 return 0;
273 }
274 if (ev->code != SYN_REPORT)
275 return 0;
276
277 if (e->down == DOWN_RELEASED) {
278 e->down = DOWN_NOT;
279 /* TODO: Send emulated key release? */
280 return 1;
281 }
282
283 if (!(e->p.synced && vk_tp_to_screen(&e->p, &x, &y)) &&
284 !((e->mt_p.synced & 1) && vk_tp_to_screen(&e->mt_p, &x, &y))) {
285 return 0;
286 }
287
288 e->p.synced = e->mt_p.synced = 0;
289
290 if (e->down)
291 return 1;
292
293 for (i = 0; i < e->vk_count; ++i) {
294 int xd = ABS(e->vks[i].centerx - x);
295 int yd = ABS(e->vks[i].centery - y);
296 if (xd < e->vks[i].width/2 && yd < e->vks[i].height/2) {
297 /* Fake a key event */
298 e->down = DOWN_SENT;
299
300 ev->type = EV_KEY;
301 ev->code = e->vks[i].scancode;
302 ev->value = 1;
303 return 0;
304 }
305 }
306
307 return 1;
308}
309
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800310int ev_get(struct input_event *ev, unsigned dont_wait)
311{
312 int r;
313 unsigned n;
314
315 do {
316 r = poll(ev_fds, ev_count, dont_wait ? 0 : -1);
317
318 if(r > 0) {
319 for(n = 0; n < ev_count; n++) {
320 if(ev_fds[n].revents & POLLIN) {
321 r = read(ev_fds[n].fd, ev, sizeof(*ev));
Christopher Laisac731c82010-11-24 18:49:52 -0600322 if(r == sizeof(*ev)) {
323 if (!vk_modify(&evs[n], ev))
324 return 0;
325 }
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800326 }
327 }
328 }
329 } while(dont_wait == 0);
330
331 return -1;
332}