blob: efdca9556504b31dd6313db3072eb2cad53bdd93 [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
Koushik Duttadf1e4062010-12-18 17:42:31 -080037#define ABS_MT_POSITION_X 0x35
38#define ABS_MT_POSITION_Y 0x36
39#define ABS_MT_TOUCH_MAJOR 0x30
40#define SYN_MT_REPORT 2
41
Christopher Laisac731c82010-11-24 18:49:52 -060042struct virtualkey {
43 int scancode;
44 int centerx, centery;
45 int width, height;
46};
47
48struct position {
49 int x, y;
Christopher Lais229a5432010-11-27 22:37:50 -060050 int pressed;
Christopher Laisac731c82010-11-24 18:49:52 -060051 struct input_absinfo xi, yi;
52};
53
54struct ev {
55 struct pollfd *fd;
56
57 struct virtualkey *vks;
58 int vk_count;
59
60 struct position p, mt_p;
Christopher Lais229a5432010-11-27 22:37:50 -060061 int sent, mt_idx;
Christopher Laisac731c82010-11-24 18:49:52 -060062};
63
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080064static struct pollfd ev_fds[MAX_DEVICES];
Christopher Laisac731c82010-11-24 18:49:52 -060065static struct ev evs[MAX_DEVICES];
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080066static unsigned ev_count = 0;
67
Christopher Laisac731c82010-11-24 18:49:52 -060068static inline int ABS(int x) {
69 return x<0?-x:x;
70}
71
Christopher Lais44bd4942010-11-27 13:36:23 -060072int vibrate(int timeout_ms)
73{
74 char str[20];
75 int fd;
76 int ret;
77
78 fd = open(VIBRATOR_TIMEOUT_FILE, O_WRONLY);
79 if (fd < 0)
80 return -1;
81
82 ret = snprintf(str, sizeof(str), "%d", timeout_ms);
83 ret = write(fd, str, ret);
84 close(fd);
85
86 if (ret < 0)
87 return -1;
88
89 return 0;
90}
91
Christopher Laisac731c82010-11-24 18:49:52 -060092/* Returns empty tokens */
93static char *vk_strtok_r(char *str, const char *delim, char **save_str)
94{
95 if(!str) {
96 if(!*save_str) return NULL;
97 str = (*save_str) + 1;
98 }
99 *save_str = strpbrk(str, delim);
100 if(*save_str) **save_str = '\0';
101 return str;
102}
103
104static int vk_init(struct ev *e)
105{
106 char vk_path[PATH_MAX] = "/sys/board_properties/virtualkeys.";
107 char vks[2048], *ts;
108 ssize_t len;
109 int vk_fd;
110 int i;
111
112 e->vk_count = 0;
113
114 len = strlen(vk_path);
115 len = ioctl(e->fd->fd, EVIOCGNAME(sizeof(vk_path) - len), vk_path + len);
116 if (len <= 0)
117 return -1;
118
119 vk_fd = open(vk_path, O_RDONLY);
120 if (vk_fd < 0)
121 return -1;
122
123 len = read(vk_fd, vks, sizeof(vks)-1);
124 close(vk_fd);
125 if (len <= 0)
126 return -1;
127
128 vks[len] = '\0';
129
130 /* Parse a line like:
131 keytype:keycode:centerx:centery:width:height:keytype2:keycode2:centerx2:...
132 */
133 for (ts = vks, e->vk_count = 1; *ts; ++ts) {
134 if (*ts == ':')
135 ++e->vk_count;
136 }
137
138 if (e->vk_count % 6) {
139 LOGW("minui: %s is %d %% 6\n", vk_path, e->vk_count % 6);
140 }
141 e->vk_count /= 6;
142 if (e->vk_count <= 0)
143 return -1;
144
Christopher Lais229a5432010-11-27 22:37:50 -0600145 e->sent = 0;
146 e->mt_idx = 0;
Christopher Laisac731c82010-11-24 18:49:52 -0600147
148 ioctl(e->fd->fd, EVIOCGABS(ABS_X), &e->p.xi);
149 ioctl(e->fd->fd, EVIOCGABS(ABS_Y), &e->p.yi);
Christopher Lais229a5432010-11-27 22:37:50 -0600150 e->p.pressed = 0;
Christopher Laisac731c82010-11-24 18:49:52 -0600151
152 ioctl(e->fd->fd, EVIOCGABS(ABS_MT_POSITION_X), &e->mt_p.xi);
153 ioctl(e->fd->fd, EVIOCGABS(ABS_MT_POSITION_Y), &e->mt_p.yi);
Christopher Lais229a5432010-11-27 22:37:50 -0600154 e->mt_p.pressed = 0;
Christopher Laisac731c82010-11-24 18:49:52 -0600155
156 e->vks = malloc(sizeof(*e->vks) * e->vk_count);
157
158 for (i = 0; i < e->vk_count; ++i) {
159 char *token[6];
160 int j;
161
162 for (j = 0; j < 6; ++j) {
163 token[j] = vk_strtok_r((i||j)?NULL:vks, ":", &ts);
164 }
165
166 if (strcmp(token[0], "0x01") != 0) {
167 /* Java does string compare, so we do too. */
168 LOGW("minui: %s: ignoring unknown virtual key type %s\n", vk_path, token[0]);
169 continue;
170 }
171
172 e->vks[i].scancode = strtol(token[1], NULL, 0);
173 e->vks[i].centerx = strtol(token[2], NULL, 0);
174 e->vks[i].centery = strtol(token[3], NULL, 0);
175 e->vks[i].width = strtol(token[4], NULL, 0);
176 e->vks[i].height = strtol(token[5], NULL, 0);
177 }
178
179 return 0;
180}
181
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800182int ev_init(void)
183{
184 DIR *dir;
185 struct dirent *de;
186 int fd;
187
188 dir = opendir("/dev/input");
189 if(dir != 0) {
190 while((de = readdir(dir))) {
191// fprintf(stderr,"/dev/input/%s\n", de->d_name);
192 if(strncmp(de->d_name,"event",5)) continue;
193 fd = openat(dirfd(dir), de->d_name, O_RDONLY);
194 if(fd < 0) continue;
195
196 ev_fds[ev_count].fd = fd;
197 ev_fds[ev_count].events = POLLIN;
Christopher Laisac731c82010-11-24 18:49:52 -0600198 evs[ev_count].fd = &ev_fds[ev_count];
199
200 /* Load virtualkeys if there are any */
201 vk_init(&evs[ev_count]);
202
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800203 ev_count++;
204 if(ev_count == MAX_DEVICES) break;
205 }
206 }
207
208 return 0;
209}
210
211void ev_exit(void)
212{
Christopher Laisac731c82010-11-24 18:49:52 -0600213 while (ev_count-- > 0) {
214 if (evs[ev_count].vk_count) {
215 free(evs[ev_count].vks);
216 evs[ev_count].vk_count = 0;
217 }
218 close(ev_fds[ev_count].fd);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800219 }
220}
221
Christopher Laisac731c82010-11-24 18:49:52 -0600222static int vk_inside_display(__s32 value, struct input_absinfo *info, int screen_size)
223{
224 int screen_pos;
225
226 if (info->minimum == info->maximum)
227 return 0;
228
229 screen_pos = (value - info->minimum) * (screen_size - 1) / (info->maximum - info->minimum);
230 return (screen_pos >= 0 && screen_pos < screen_size);
231}
232
233static int vk_tp_to_screen(struct position *p, int *x, int *y)
234{
235 if (p->xi.minimum == p->xi.maximum || p->yi.minimum == p->yi.maximum)
236 return 0;
237
238 *x = (p->x - p->xi.minimum) * (gr_fb_width() - 1) / (p->xi.maximum - p->xi.minimum);
239 *y = (p->y - p->yi.minimum) * (gr_fb_height() - 1) / (p->yi.maximum - p->yi.minimum);
240
241 if (*x >= 0 && *x < gr_fb_width() &&
242 *y >= 0 && *y < gr_fb_height()) {
243 return 0;
244 }
245
246 return 1;
247}
248
249/* Translate a virtual key in to a real key event, if needed */
250/* Returns non-zero when the event should be consumed */
251static int vk_modify(struct ev *e, struct input_event *ev)
252{
253 int i;
254 int x, y;
255
256 if (ev->type == EV_KEY) {
Christopher Lais229a5432010-11-27 22:37:50 -0600257 if (ev->code == BTN_TOUCH)
258 e->p.pressed = ev->value;
Christopher Laisac731c82010-11-24 18:49:52 -0600259 return 0;
260 }
261
262 if (ev->type == EV_ABS) {
263 switch (ev->code) {
264 case ABS_X:
Christopher Laisac731c82010-11-24 18:49:52 -0600265 e->p.x = ev->value;
266 return !vk_inside_display(e->p.x, &e->p.xi, gr_fb_width());
267 case ABS_Y:
Christopher Laisac731c82010-11-24 18:49:52 -0600268 e->p.y = ev->value;
269 return !vk_inside_display(e->p.y, &e->p.yi, gr_fb_height());
270 case ABS_MT_POSITION_X:
Christopher Lais229a5432010-11-27 22:37:50 -0600271 if (e->mt_idx) return 1;
Christopher Laisac731c82010-11-24 18:49:52 -0600272 e->mt_p.x = ev->value;
273 return !vk_inside_display(e->mt_p.x, &e->mt_p.xi, gr_fb_width());
274 case ABS_MT_POSITION_Y:
Christopher Lais229a5432010-11-27 22:37:50 -0600275 if (e->mt_idx) return 1;
Christopher Laisac731c82010-11-24 18:49:52 -0600276 e->mt_p.y = ev->value;
277 return !vk_inside_display(e->mt_p.y, &e->mt_p.yi, gr_fb_height());
278 case ABS_MT_TOUCH_MAJOR:
Christopher Lais229a5432010-11-27 22:37:50 -0600279 if (e->mt_idx) return 1;
280 if (e->sent)
281 e->mt_p.pressed = (ev->value > 0);
282 else
283 e->mt_p.pressed = (ev->value > PRESS_THRESHHOLD);
Christopher Laisac731c82010-11-24 18:49:52 -0600284 return 0;
285 }
286
287 return 0;
288 }
289
290 if (ev->type != EV_SYN)
291 return 0;
292
293 if (ev->code == SYN_MT_REPORT) {
294 /* Ignore the rest of the points */
Christopher Lais229a5432010-11-27 22:37:50 -0600295 ++e->mt_idx;
296 return 1;
Christopher Laisac731c82010-11-24 18:49:52 -0600297 }
298 if (ev->code != SYN_REPORT)
299 return 0;
300
Christopher Lais229a5432010-11-27 22:37:50 -0600301 /* Report complete */
Christopher Laisac731c82010-11-24 18:49:52 -0600302
Christopher Lais229a5432010-11-27 22:37:50 -0600303 e->mt_idx = 0;
304
305 if (!e->p.pressed && !e->mt_p.pressed) {
306 /* No touch */
307 e->sent = 0;
Christopher Laisac731c82010-11-24 18:49:52 -0600308 return 0;
309 }
310
Christopher Lais229a5432010-11-27 22:37:50 -0600311 if (!(e->p.pressed && vk_tp_to_screen(&e->p, &x, &y)) &&
312 !(e->mt_p.pressed && vk_tp_to_screen(&e->mt_p, &x, &y))) {
313 /* No touch inside vk area */
314 return 0;
315 }
Christopher Laisac731c82010-11-24 18:49:52 -0600316
Christopher Lais229a5432010-11-27 22:37:50 -0600317 if (e->sent) {
318 /* We've already sent a fake key for this touch */
Christopher Laisac731c82010-11-24 18:49:52 -0600319 return 1;
Christopher Lais229a5432010-11-27 22:37:50 -0600320 }
321
322 /* The screen is being touched on the vk area */
323 e->sent = 1;
Christopher Laisac731c82010-11-24 18:49:52 -0600324
325 for (i = 0; i < e->vk_count; ++i) {
326 int xd = ABS(e->vks[i].centerx - x);
327 int yd = ABS(e->vks[i].centery - y);
328 if (xd < e->vks[i].width/2 && yd < e->vks[i].height/2) {
329 /* Fake a key event */
Christopher Laisac731c82010-11-24 18:49:52 -0600330 ev->type = EV_KEY;
331 ev->code = e->vks[i].scancode;
332 ev->value = 1;
Christopher Lais44bd4942010-11-27 13:36:23 -0600333
334 vibrate(VIBRATOR_TIME_MS);
Christopher Laisac731c82010-11-24 18:49:52 -0600335 return 0;
336 }
337 }
338
339 return 1;
340}
341
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800342int ev_get(struct input_event *ev, unsigned dont_wait)
343{
344 int r;
345 unsigned n;
346
347 do {
348 r = poll(ev_fds, ev_count, dont_wait ? 0 : -1);
349
350 if(r > 0) {
351 for(n = 0; n < ev_count; n++) {
352 if(ev_fds[n].revents & POLLIN) {
353 r = read(ev_fds[n].fd, ev, sizeof(*ev));
Christopher Laisac731c82010-11-24 18:49:52 -0600354 if(r == sizeof(*ev)) {
355 if (!vk_modify(&evs[n], ev))
356 return 0;
357 }
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800358 }
359 }
360 }
361 } while(dont_wait == 0);
362
363 return -1;
364}