blob: 955ce4dc32717c201ff06904bf96621e359f3a77 [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 -060037struct virtualkey {
38 int scancode;
39 int centerx, centery;
40 int width, height;
41};
42
43struct position {
44 int x, y;
Christopher Lais229a5432010-11-27 22:37:50 -060045 int pressed;
Christopher Laisac731c82010-11-24 18:49:52 -060046 struct input_absinfo xi, yi;
47};
48
49struct ev {
50 struct pollfd *fd;
51
52 struct virtualkey *vks;
53 int vk_count;
54
55 struct position p, mt_p;
Christopher Lais229a5432010-11-27 22:37:50 -060056 int sent, mt_idx;
Christopher Laisac731c82010-11-24 18:49:52 -060057};
58
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080059static struct pollfd ev_fds[MAX_DEVICES];
Christopher Laisac731c82010-11-24 18:49:52 -060060static struct ev evs[MAX_DEVICES];
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080061static unsigned ev_count = 0;
62
Christopher Laisac731c82010-11-24 18:49:52 -060063static inline int ABS(int x) {
64 return x<0?-x:x;
65}
66
Christopher Lais44bd4942010-11-27 13:36:23 -060067int vibrate(int timeout_ms)
68{
69 char str[20];
70 int fd;
71 int ret;
72
73 fd = open(VIBRATOR_TIMEOUT_FILE, O_WRONLY);
74 if (fd < 0)
75 return -1;
76
77 ret = snprintf(str, sizeof(str), "%d", timeout_ms);
78 ret = write(fd, str, ret);
79 close(fd);
80
81 if (ret < 0)
82 return -1;
83
84 return 0;
85}
86
Christopher Laisac731c82010-11-24 18:49:52 -060087/* Returns empty tokens */
88static char *vk_strtok_r(char *str, const char *delim, char **save_str)
89{
90 if(!str) {
91 if(!*save_str) return NULL;
92 str = (*save_str) + 1;
93 }
94 *save_str = strpbrk(str, delim);
95 if(*save_str) **save_str = '\0';
96 return str;
97}
98
99static int vk_init(struct ev *e)
100{
101 char vk_path[PATH_MAX] = "/sys/board_properties/virtualkeys.";
102 char vks[2048], *ts;
103 ssize_t len;
104 int vk_fd;
105 int i;
106
107 e->vk_count = 0;
108
109 len = strlen(vk_path);
110 len = ioctl(e->fd->fd, EVIOCGNAME(sizeof(vk_path) - len), vk_path + len);
111 if (len <= 0)
112 return -1;
113
114 vk_fd = open(vk_path, O_RDONLY);
115 if (vk_fd < 0)
116 return -1;
117
118 len = read(vk_fd, vks, sizeof(vks)-1);
119 close(vk_fd);
120 if (len <= 0)
121 return -1;
122
123 vks[len] = '\0';
124
125 /* Parse a line like:
126 keytype:keycode:centerx:centery:width:height:keytype2:keycode2:centerx2:...
127 */
128 for (ts = vks, e->vk_count = 1; *ts; ++ts) {
129 if (*ts == ':')
130 ++e->vk_count;
131 }
132
133 if (e->vk_count % 6) {
134 LOGW("minui: %s is %d %% 6\n", vk_path, e->vk_count % 6);
135 }
136 e->vk_count /= 6;
137 if (e->vk_count <= 0)
138 return -1;
139
Christopher Lais229a5432010-11-27 22:37:50 -0600140 e->sent = 0;
141 e->mt_idx = 0;
Christopher Laisac731c82010-11-24 18:49:52 -0600142
143 ioctl(e->fd->fd, EVIOCGABS(ABS_X), &e->p.xi);
144 ioctl(e->fd->fd, EVIOCGABS(ABS_Y), &e->p.yi);
Christopher Lais229a5432010-11-27 22:37:50 -0600145 e->p.pressed = 0;
Christopher Laisac731c82010-11-24 18:49:52 -0600146
147 ioctl(e->fd->fd, EVIOCGABS(ABS_MT_POSITION_X), &e->mt_p.xi);
148 ioctl(e->fd->fd, EVIOCGABS(ABS_MT_POSITION_Y), &e->mt_p.yi);
Christopher Lais229a5432010-11-27 22:37:50 -0600149 e->mt_p.pressed = 0;
Christopher Laisac731c82010-11-24 18:49:52 -0600150
151 e->vks = malloc(sizeof(*e->vks) * e->vk_count);
152
153 for (i = 0; i < e->vk_count; ++i) {
154 char *token[6];
155 int j;
156
157 for (j = 0; j < 6; ++j) {
158 token[j] = vk_strtok_r((i||j)?NULL:vks, ":", &ts);
159 }
160
161 if (strcmp(token[0], "0x01") != 0) {
162 /* Java does string compare, so we do too. */
163 LOGW("minui: %s: ignoring unknown virtual key type %s\n", vk_path, token[0]);
164 continue;
165 }
166
167 e->vks[i].scancode = strtol(token[1], NULL, 0);
168 e->vks[i].centerx = strtol(token[2], NULL, 0);
169 e->vks[i].centery = strtol(token[3], NULL, 0);
170 e->vks[i].width = strtol(token[4], NULL, 0);
171 e->vks[i].height = strtol(token[5], NULL, 0);
172 }
173
174 return 0;
175}
176
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800177int ev_init(void)
178{
179 DIR *dir;
180 struct dirent *de;
181 int fd;
182
183 dir = opendir("/dev/input");
184 if(dir != 0) {
185 while((de = readdir(dir))) {
186// fprintf(stderr,"/dev/input/%s\n", de->d_name);
187 if(strncmp(de->d_name,"event",5)) continue;
188 fd = openat(dirfd(dir), de->d_name, O_RDONLY);
189 if(fd < 0) continue;
190
191 ev_fds[ev_count].fd = fd;
192 ev_fds[ev_count].events = POLLIN;
Christopher Laisac731c82010-11-24 18:49:52 -0600193 evs[ev_count].fd = &ev_fds[ev_count];
194
195 /* Load virtualkeys if there are any */
196 vk_init(&evs[ev_count]);
197
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800198 ev_count++;
199 if(ev_count == MAX_DEVICES) break;
200 }
201 }
202
203 return 0;
204}
205
206void ev_exit(void)
207{
Christopher Laisac731c82010-11-24 18:49:52 -0600208 while (ev_count-- > 0) {
209 if (evs[ev_count].vk_count) {
210 free(evs[ev_count].vks);
211 evs[ev_count].vk_count = 0;
212 }
213 close(ev_fds[ev_count].fd);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800214 }
215}
216
Christopher Laisac731c82010-11-24 18:49:52 -0600217static int vk_inside_display(__s32 value, struct input_absinfo *info, int screen_size)
218{
219 int screen_pos;
220
221 if (info->minimum == info->maximum)
222 return 0;
223
224 screen_pos = (value - info->minimum) * (screen_size - 1) / (info->maximum - info->minimum);
225 return (screen_pos >= 0 && screen_pos < screen_size);
226}
227
228static int vk_tp_to_screen(struct position *p, int *x, int *y)
229{
230 if (p->xi.minimum == p->xi.maximum || p->yi.minimum == p->yi.maximum)
231 return 0;
232
233 *x = (p->x - p->xi.minimum) * (gr_fb_width() - 1) / (p->xi.maximum - p->xi.minimum);
234 *y = (p->y - p->yi.minimum) * (gr_fb_height() - 1) / (p->yi.maximum - p->yi.minimum);
235
236 if (*x >= 0 && *x < gr_fb_width() &&
237 *y >= 0 && *y < gr_fb_height()) {
238 return 0;
239 }
240
241 return 1;
242}
243
244/* Translate a virtual key in to a real key event, if needed */
245/* Returns non-zero when the event should be consumed */
246static int vk_modify(struct ev *e, struct input_event *ev)
247{
248 int i;
249 int x, y;
250
251 if (ev->type == EV_KEY) {
Christopher Lais229a5432010-11-27 22:37:50 -0600252 if (ev->code == BTN_TOUCH)
253 e->p.pressed = ev->value;
Christopher Laisac731c82010-11-24 18:49:52 -0600254 return 0;
255 }
256
257 if (ev->type == EV_ABS) {
258 switch (ev->code) {
259 case ABS_X:
Christopher Laisac731c82010-11-24 18:49:52 -0600260 e->p.x = ev->value;
261 return !vk_inside_display(e->p.x, &e->p.xi, gr_fb_width());
262 case ABS_Y:
Christopher Laisac731c82010-11-24 18:49:52 -0600263 e->p.y = ev->value;
264 return !vk_inside_display(e->p.y, &e->p.yi, gr_fb_height());
265 case ABS_MT_POSITION_X:
Christopher Lais229a5432010-11-27 22:37:50 -0600266 if (e->mt_idx) return 1;
Christopher Laisac731c82010-11-24 18:49:52 -0600267 e->mt_p.x = ev->value;
268 return !vk_inside_display(e->mt_p.x, &e->mt_p.xi, gr_fb_width());
269 case ABS_MT_POSITION_Y:
Christopher Lais229a5432010-11-27 22:37:50 -0600270 if (e->mt_idx) return 1;
Christopher Laisac731c82010-11-24 18:49:52 -0600271 e->mt_p.y = ev->value;
272 return !vk_inside_display(e->mt_p.y, &e->mt_p.yi, gr_fb_height());
273 case ABS_MT_TOUCH_MAJOR:
Christopher Lais229a5432010-11-27 22:37:50 -0600274 if (e->mt_idx) return 1;
275 if (e->sent)
276 e->mt_p.pressed = (ev->value > 0);
277 else
278 e->mt_p.pressed = (ev->value > PRESS_THRESHHOLD);
Christopher Laisac731c82010-11-24 18:49:52 -0600279 return 0;
280 }
281
282 return 0;
283 }
284
285 if (ev->type != EV_SYN)
286 return 0;
287
288 if (ev->code == SYN_MT_REPORT) {
289 /* Ignore the rest of the points */
Christopher Lais229a5432010-11-27 22:37:50 -0600290 ++e->mt_idx;
291 return 1;
Christopher Laisac731c82010-11-24 18:49:52 -0600292 }
293 if (ev->code != SYN_REPORT)
294 return 0;
295
Christopher Lais229a5432010-11-27 22:37:50 -0600296 /* Report complete */
Christopher Laisac731c82010-11-24 18:49:52 -0600297
Christopher Lais229a5432010-11-27 22:37:50 -0600298 e->mt_idx = 0;
299
300 if (!e->p.pressed && !e->mt_p.pressed) {
301 /* No touch */
302 e->sent = 0;
Christopher Laisac731c82010-11-24 18:49:52 -0600303 return 0;
304 }
305
Christopher Lais229a5432010-11-27 22:37:50 -0600306 if (!(e->p.pressed && vk_tp_to_screen(&e->p, &x, &y)) &&
307 !(e->mt_p.pressed && vk_tp_to_screen(&e->mt_p, &x, &y))) {
308 /* No touch inside vk area */
309 return 0;
310 }
Christopher Laisac731c82010-11-24 18:49:52 -0600311
Christopher Lais229a5432010-11-27 22:37:50 -0600312 if (e->sent) {
313 /* We've already sent a fake key for this touch */
Christopher Laisac731c82010-11-24 18:49:52 -0600314 return 1;
Christopher Lais229a5432010-11-27 22:37:50 -0600315 }
316
317 /* The screen is being touched on the vk area */
318 e->sent = 1;
Christopher Laisac731c82010-11-24 18:49:52 -0600319
320 for (i = 0; i < e->vk_count; ++i) {
321 int xd = ABS(e->vks[i].centerx - x);
322 int yd = ABS(e->vks[i].centery - y);
323 if (xd < e->vks[i].width/2 && yd < e->vks[i].height/2) {
324 /* Fake a key event */
Christopher Laisac731c82010-11-24 18:49:52 -0600325 ev->type = EV_KEY;
326 ev->code = e->vks[i].scancode;
327 ev->value = 1;
Christopher Lais44bd4942010-11-27 13:36:23 -0600328
329 vibrate(VIBRATOR_TIME_MS);
Christopher Laisac731c82010-11-24 18:49:52 -0600330 return 0;
331 }
332 }
333
334 return 1;
335}
336
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800337int ev_get(struct input_event *ev, unsigned dont_wait)
338{
339 int r;
340 unsigned n;
341
342 do {
343 r = poll(ev_fds, ev_count, dont_wait ? 0 : -1);
344
345 if(r > 0) {
346 for(n = 0; n < ev_count; n++) {
347 if(ev_fds[n].revents & POLLIN) {
348 r = read(ev_fds[n].fd, ev, sizeof(*ev));
Christopher Laisac731c82010-11-24 18:49:52 -0600349 if(r == sizeof(*ev)) {
350 if (!vk_modify(&evs[n], ev))
351 return 0;
352 }
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800353 }
354 }
355 }
356 } while(dont_wait == 0);
357
358 return -1;
359}