blob: f2f4426b6217ef44ee8ab6be972d4b8bbf3bb73e [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 Lais44bd4942010-11-27 13:36:23 -060032#define VIBRATOR_TIMEOUT_FILE "/sys/class/timed_output/vibrator/enable"
33#define VIBRATOR_TIME_MS 50
34
Christopher Lais229a5432010-11-27 22:37:50 -060035#define PRESS_THRESHHOLD 10
36
Christopher Laisac731c82010-11-24 18:49:52 -060037enum {
38 DOWN_NOT,
39 DOWN_SENT,
40 DOWN_RELEASED,
41};
42
43struct virtualkey {
44 int scancode;
45 int centerx, centery;
46 int width, height;
47};
48
49struct position {
50 int x, y;
Christopher Lais229a5432010-11-27 22:37:50 -060051 int pressed;
Christopher Laisac731c82010-11-24 18:49:52 -060052 struct input_absinfo xi, yi;
53};
54
55struct ev {
56 struct pollfd *fd;
57
58 struct virtualkey *vks;
59 int vk_count;
60
61 struct position p, mt_p;
Christopher Lais229a5432010-11-27 22:37:50 -060062 int sent, mt_idx;
Christopher Laisac731c82010-11-24 18:49:52 -060063};
64
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080065static struct pollfd ev_fds[MAX_DEVICES];
Christopher Laisac731c82010-11-24 18:49:52 -060066static struct ev evs[MAX_DEVICES];
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080067static unsigned ev_count = 0;
68
Christopher Laisac731c82010-11-24 18:49:52 -060069static inline int ABS(int x) {
70 return x<0?-x:x;
71}
72
Christopher Lais44bd4942010-11-27 13:36:23 -060073int vibrate(int timeout_ms)
74{
75 char str[20];
76 int fd;
77 int ret;
78
79 fd = open(VIBRATOR_TIMEOUT_FILE, O_WRONLY);
80 if (fd < 0)
81 return -1;
82
83 ret = snprintf(str, sizeof(str), "%d", timeout_ms);
84 ret = write(fd, str, ret);
85 close(fd);
86
87 if (ret < 0)
88 return -1;
89
90 return 0;
91}
92
Christopher Laisac731c82010-11-24 18:49:52 -060093/* Returns empty tokens */
94static char *vk_strtok_r(char *str, const char *delim, char **save_str)
95{
96 if(!str) {
97 if(!*save_str) return NULL;
98 str = (*save_str) + 1;
99 }
100 *save_str = strpbrk(str, delim);
101 if(*save_str) **save_str = '\0';
102 return str;
103}
104
105static int vk_init(struct ev *e)
106{
107 char vk_path[PATH_MAX] = "/sys/board_properties/virtualkeys.";
108 char vks[2048], *ts;
109 ssize_t len;
110 int vk_fd;
111 int i;
112
113 e->vk_count = 0;
114
115 len = strlen(vk_path);
116 len = ioctl(e->fd->fd, EVIOCGNAME(sizeof(vk_path) - len), vk_path + len);
117 if (len <= 0)
118 return -1;
119
120 vk_fd = open(vk_path, O_RDONLY);
121 if (vk_fd < 0)
122 return -1;
123
124 len = read(vk_fd, vks, sizeof(vks)-1);
125 close(vk_fd);
126 if (len <= 0)
127 return -1;
128
129 vks[len] = '\0';
130
131 /* Parse a line like:
132 keytype:keycode:centerx:centery:width:height:keytype2:keycode2:centerx2:...
133 */
134 for (ts = vks, e->vk_count = 1; *ts; ++ts) {
135 if (*ts == ':')
136 ++e->vk_count;
137 }
138
139 if (e->vk_count % 6) {
140 LOGW("minui: %s is %d %% 6\n", vk_path, e->vk_count % 6);
141 }
142 e->vk_count /= 6;
143 if (e->vk_count <= 0)
144 return -1;
145
Christopher Lais229a5432010-11-27 22:37:50 -0600146 e->sent = 0;
147 e->mt_idx = 0;
Christopher Laisac731c82010-11-24 18:49:52 -0600148
149 ioctl(e->fd->fd, EVIOCGABS(ABS_X), &e->p.xi);
150 ioctl(e->fd->fd, EVIOCGABS(ABS_Y), &e->p.yi);
Christopher Lais229a5432010-11-27 22:37:50 -0600151 e->p.pressed = 0;
Christopher Laisac731c82010-11-24 18:49:52 -0600152
153 ioctl(e->fd->fd, EVIOCGABS(ABS_MT_POSITION_X), &e->mt_p.xi);
154 ioctl(e->fd->fd, EVIOCGABS(ABS_MT_POSITION_Y), &e->mt_p.yi);
Christopher Lais229a5432010-11-27 22:37:50 -0600155 e->mt_p.pressed = 0;
Christopher Laisac731c82010-11-24 18:49:52 -0600156
157 e->vks = malloc(sizeof(*e->vks) * e->vk_count);
158
159 for (i = 0; i < e->vk_count; ++i) {
160 char *token[6];
161 int j;
162
163 for (j = 0; j < 6; ++j) {
164 token[j] = vk_strtok_r((i||j)?NULL:vks, ":", &ts);
165 }
166
167 if (strcmp(token[0], "0x01") != 0) {
168 /* Java does string compare, so we do too. */
169 LOGW("minui: %s: ignoring unknown virtual key type %s\n", vk_path, token[0]);
170 continue;
171 }
172
173 e->vks[i].scancode = strtol(token[1], NULL, 0);
174 e->vks[i].centerx = strtol(token[2], NULL, 0);
175 e->vks[i].centery = strtol(token[3], NULL, 0);
176 e->vks[i].width = strtol(token[4], NULL, 0);
177 e->vks[i].height = strtol(token[5], NULL, 0);
178 }
179
180 return 0;
181}
182
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800183int ev_init(void)
184{
185 DIR *dir;
186 struct dirent *de;
187 int fd;
188
189 dir = opendir("/dev/input");
190 if(dir != 0) {
191 while((de = readdir(dir))) {
192// fprintf(stderr,"/dev/input/%s\n", de->d_name);
193 if(strncmp(de->d_name,"event",5)) continue;
194 fd = openat(dirfd(dir), de->d_name, O_RDONLY);
195 if(fd < 0) continue;
196
197 ev_fds[ev_count].fd = fd;
198 ev_fds[ev_count].events = POLLIN;
Christopher Laisac731c82010-11-24 18:49:52 -0600199 evs[ev_count].fd = &ev_fds[ev_count];
200
201 /* Load virtualkeys if there are any */
202 vk_init(&evs[ev_count]);
203
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800204 ev_count++;
205 if(ev_count == MAX_DEVICES) break;
206 }
207 }
208
209 return 0;
210}
211
212void ev_exit(void)
213{
Christopher Laisac731c82010-11-24 18:49:52 -0600214 while (ev_count-- > 0) {
215 if (evs[ev_count].vk_count) {
216 free(evs[ev_count].vks);
217 evs[ev_count].vk_count = 0;
218 }
219 close(ev_fds[ev_count].fd);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800220 }
221}
222
Christopher Laisac731c82010-11-24 18:49:52 -0600223static int vk_inside_display(__s32 value, struct input_absinfo *info, int screen_size)
224{
225 int screen_pos;
226
227 if (info->minimum == info->maximum)
228 return 0;
229
230 screen_pos = (value - info->minimum) * (screen_size - 1) / (info->maximum - info->minimum);
231 return (screen_pos >= 0 && screen_pos < screen_size);
232}
233
234static int vk_tp_to_screen(struct position *p, int *x, int *y)
235{
236 if (p->xi.minimum == p->xi.maximum || p->yi.minimum == p->yi.maximum)
237 return 0;
238
239 *x = (p->x - p->xi.minimum) * (gr_fb_width() - 1) / (p->xi.maximum - p->xi.minimum);
240 *y = (p->y - p->yi.minimum) * (gr_fb_height() - 1) / (p->yi.maximum - p->yi.minimum);
241
242 if (*x >= 0 && *x < gr_fb_width() &&
243 *y >= 0 && *y < gr_fb_height()) {
244 return 0;
245 }
246
247 return 1;
248}
249
250/* Translate a virtual key in to a real key event, if needed */
251/* Returns non-zero when the event should be consumed */
252static int vk_modify(struct ev *e, struct input_event *ev)
253{
254 int i;
255 int x, y;
256
257 if (ev->type == EV_KEY) {
Christopher Lais229a5432010-11-27 22:37:50 -0600258 if (ev->code == BTN_TOUCH)
259 e->p.pressed = ev->value;
Christopher Laisac731c82010-11-24 18:49:52 -0600260 return 0;
261 }
262
263 if (ev->type == EV_ABS) {
264 switch (ev->code) {
265 case ABS_X:
Christopher Laisac731c82010-11-24 18:49:52 -0600266 e->p.x = ev->value;
267 return !vk_inside_display(e->p.x, &e->p.xi, gr_fb_width());
268 case ABS_Y:
Christopher Laisac731c82010-11-24 18:49:52 -0600269 e->p.y = ev->value;
270 return !vk_inside_display(e->p.y, &e->p.yi, gr_fb_height());
271 case ABS_MT_POSITION_X:
Christopher Lais229a5432010-11-27 22:37:50 -0600272 if (e->mt_idx) return 1;
Christopher Laisac731c82010-11-24 18:49:52 -0600273 e->mt_p.x = ev->value;
274 return !vk_inside_display(e->mt_p.x, &e->mt_p.xi, gr_fb_width());
275 case ABS_MT_POSITION_Y:
Christopher Lais229a5432010-11-27 22:37:50 -0600276 if (e->mt_idx) return 1;
Christopher Laisac731c82010-11-24 18:49:52 -0600277 e->mt_p.y = ev->value;
278 return !vk_inside_display(e->mt_p.y, &e->mt_p.yi, gr_fb_height());
279 case ABS_MT_TOUCH_MAJOR:
Christopher Lais229a5432010-11-27 22:37:50 -0600280 if (e->mt_idx) return 1;
281 if (e->sent)
282 e->mt_p.pressed = (ev->value > 0);
283 else
284 e->mt_p.pressed = (ev->value > PRESS_THRESHHOLD);
Christopher Laisac731c82010-11-24 18:49:52 -0600285 return 0;
286 }
287
288 return 0;
289 }
290
291 if (ev->type != EV_SYN)
292 return 0;
293
294 if (ev->code == SYN_MT_REPORT) {
295 /* Ignore the rest of the points */
Christopher Lais229a5432010-11-27 22:37:50 -0600296 ++e->mt_idx;
297 return 1;
Christopher Laisac731c82010-11-24 18:49:52 -0600298 }
299 if (ev->code != SYN_REPORT)
300 return 0;
301
Christopher Lais229a5432010-11-27 22:37:50 -0600302 /* Report complete */
Christopher Laisac731c82010-11-24 18:49:52 -0600303
Christopher Lais229a5432010-11-27 22:37:50 -0600304 e->mt_idx = 0;
305
306 if (!e->p.pressed && !e->mt_p.pressed) {
307 /* No touch */
308 e->sent = 0;
Christopher Laisac731c82010-11-24 18:49:52 -0600309 return 0;
310 }
311
Christopher Lais229a5432010-11-27 22:37:50 -0600312 if (!(e->p.pressed && vk_tp_to_screen(&e->p, &x, &y)) &&
313 !(e->mt_p.pressed && vk_tp_to_screen(&e->mt_p, &x, &y))) {
314 /* No touch inside vk area */
315 return 0;
316 }
Christopher Laisac731c82010-11-24 18:49:52 -0600317
Christopher Lais229a5432010-11-27 22:37:50 -0600318 if (e->sent) {
319 /* We've already sent a fake key for this touch */
Christopher Laisac731c82010-11-24 18:49:52 -0600320 return 1;
Christopher Lais229a5432010-11-27 22:37:50 -0600321 }
322
323 /* The screen is being touched on the vk area */
324 e->sent = 1;
Christopher Laisac731c82010-11-24 18:49:52 -0600325
326 for (i = 0; i < e->vk_count; ++i) {
327 int xd = ABS(e->vks[i].centerx - x);
328 int yd = ABS(e->vks[i].centery - y);
329 if (xd < e->vks[i].width/2 && yd < e->vks[i].height/2) {
330 /* Fake a key event */
Christopher Laisac731c82010-11-24 18:49:52 -0600331 ev->type = EV_KEY;
332 ev->code = e->vks[i].scancode;
333 ev->value = 1;
Christopher Lais44bd4942010-11-27 13:36:23 -0600334
335 vibrate(VIBRATOR_TIME_MS);
Christopher Laisac731c82010-11-24 18:49:52 -0600336 return 0;
337 }
338 }
339
340 return 1;
341}
342
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800343int ev_get(struct input_event *ev, unsigned dont_wait)
344{
345 int r;
346 unsigned n;
347
348 do {
349 r = poll(ev_fds, ev_count, dont_wait ? 0 : -1);
350
351 if(r > 0) {
352 for(n = 0; n < ev_count; n++) {
353 if(ev_fds[n].revents & POLLIN) {
354 r = read(ev_fds[n].fd, ev, sizeof(*ev));
Christopher Laisac731c82010-11-24 18:49:52 -0600355 if(r == sizeof(*ev)) {
356 if (!vk_modify(&evs[n], ev))
357 return 0;
358 }
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800359 }
360 }
361 }
362 } while(dont_wait == 0);
363
364 return -1;
365}