blob: 60060f49652a467e4233440b4c3c01fd38c9ef80 [file] [log] [blame]
The Android Open Source Project52d4c302009-03-03 19:29:09 -08001/*
2 * Copyright 2007 The Android Open Source Project
3 *
4 * Input event device.
5 */
6#include "Common.h"
7
8#include <stdlib.h>
9#include <string.h>
10
11#include <fcntl.h>
12#include <sys/ioctl.h>
13#include <linux/input.h>
14
15
16/*
17 * Input event device state.
18 */
19typedef struct EventState {
20 struct input_id ident;
21
22 char* name;
23 char* location;
24 char* idstr;
25 int protoVersion;
26} EventState;
27
28/*
29 * Key bit mask, for EVIOCGBIT(EV_KEY).
30 *
31 * (For now, just pretend to be a "goldfish" like the emulator.)
32 */
33static const unsigned char gKeyBitMask[64] = {
Marco Nelissen500248f2009-08-13 07:53:33 -070034 // These bits indicate which keys the device has
The Android Open Source Project52d4c302009-03-03 19:29:09 -080035 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
36 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
37 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
38 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
Marco Nelissen500248f2009-08-13 07:53:33 -070039 // These bits indicate other capabilities, such
40 // as whether it's a trackball or a touchscreen
41 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
42 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // touchscreen
43 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
44 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
45};
46
47/*
48 * Abs bit mask, for EVIOCGBIT(EV_ABS).
49 *
50 * Pretend to be a normal single touch panel
51 */
52static const unsigned char gAbsBitMask[64] = {
53 // these bits indicate the capabilities of the touch screen
54 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ABS_X, ABS_Y
55 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
56 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
57 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
58 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
59 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
60 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
61 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
The Android Open Source Project52d4c302009-03-03 19:29:09 -080062};
63
64/*
65 * Set some stuff up.
66 */
67static void configureInitialState(const char* pathName, EventState* eventState)
68{
69 /*
70 * Swim like a goldfish.
71 */
72 eventState->ident.bustype = 0;
73 eventState->ident.vendor = 0;
74 eventState->ident.product = 0;
75 eventState->ident.version = 0;
76
77 eventState->name = strdup(gWrapSim.keyMap);
78 eventState->location = strdup("");
79 eventState->idstr = strdup("");
80 eventState->protoVersion = 0x010000;
81}
82
83/*
84 * Free up the state structure.
85 */
86static void freeState(EventState* eventState)
87{
88 if (eventState != NULL) {
89 free(eventState->name);
90 free(eventState->location);
91 free(eventState->idstr);
92 free(eventState);
93 }
94}
95
96/*
97 * Handle one of the EVIOCGABS requests.
98 *
99 * Currently not doing much here.
100 */
101static void handleAbsGet(int reqIdx, void* argp)
102{
103 struct input_absinfo info;
104
105 switch (reqIdx) {
106 case ABS_X:
107 wsLog(" req for abs X\n");
108 break;
109 case ABS_Y:
110 wsLog(" req for abs Y\n");
111 break;
112 case ABS_PRESSURE:
113 wsLog(" req for abs PRESSURE\n");
114 break;
115 case ABS_TOOL_WIDTH:
116 wsLog(" req for abs TOOL_WIDTH\n");
117 break;
118 default:
119 wsLog(" req for unexpected event abs 0x%02x\n", reqIdx);
120 break;
121 }
122
123 memset(&info, 0, sizeof(info));
124 memcpy(argp, &info, sizeof(struct input_absinfo));
125}
126
127/*
128 * Return the next available input event.
129 *
130 * We just pass this through to the real "read", since "fd" is real.
131 */
132static ssize_t readEvent(FakeDev* dev, int fd, void* buf, size_t count)
133{
134 return _ws_read(fd, buf, count);
135}
136
137/*
138 * Somebody is trying to write to the event pipe. This can be used to set
139 * the state of LED.
140 */
141static ssize_t writeEvent(FakeDev* dev, int fd, const void* buf, size_t count)
142{
143 const struct input_event* piev;
144
145 if (count == sizeof(*piev)) {
146 piev = (const struct input_event*) buf;
147
148 if (piev->type == EV_LED) {
149 wsLog("%s: set LED code=%d value=%d\n",
150 dev->debugName, piev->code, piev->value);
151 } else {
152 wsLog("%s: writeEvent got %d bytes, type=%d\n",
153 dev->debugName, count, piev->type);
154 }
155 } else {
156 wsLog("%s: warning: writeEvent got %d bytes, not sure why\n",
157 dev->debugName, count);
158 }
159
160 return count;
161}
162
163/*
164 * Handle event ioctls.
165 */
166static int ioctlEvent(FakeDev* dev, int fd, int request, void* argp)
167{
168 EventState* state = (EventState*) dev->state;
169 unsigned int urequest = (unsigned int) request;
170
171 wsLog("%s: ioctl(0x%x, %p)\n", dev->debugName, urequest, argp);
172
173 if (_IOC_TYPE(urequest) != _IOC_TYPE(EVIOCGVERSION)) {
174 wsLog("%s: inappropriate ioctl 0x%08x\n", dev->debugName, urequest);
175 return -1;
176 }
177
178 if (urequest == EVIOCGVERSION) {
179 *(int*)argp = state->protoVersion;
180 } else if (urequest == EVIOCGID) {
181 memcpy(argp, &state->ident, sizeof(struct input_id));
182 } else if (_IOC_NR(urequest) == _IOC_NR(EVIOCGNAME(0))) {
183 int maxLen = _IOC_SIZE(urequest);
184 int strLen = (int) strlen(state->name);
185 if (strLen >= maxLen) {
186 errno = EINVAL;
187 return -1;
188 }
189 memcpy(argp, state->name, strLen+1);
190 return strLen;
191 } else if (_IOC_NR(urequest) == _IOC_NR(EVIOCGPHYS(0))) {
192 int maxLen = _IOC_SIZE(urequest);
193 int strLen = (int) strlen(state->location);
194 if (strLen >= maxLen) {
195 errno = EINVAL;
196 return -1;
197 }
198 memcpy(argp, state->location, strLen+1);
199 return strLen;
200 } else if (_IOC_NR(urequest) == _IOC_NR(EVIOCGUNIQ(0))) {
201 /* device doesn't seem to support this, neither will we */
202 return -1;
203 } else if (_IOC_NR(urequest) == _IOC_NR(EVIOCGBIT(EV_KEY,0))) {
204 /* keys */
205 int maxLen = _IOC_SIZE(urequest);
206 if (maxLen > (int) sizeof(gKeyBitMask))
207 maxLen = sizeof(gKeyBitMask);
208 memcpy(argp, gKeyBitMask, maxLen);
209 } else if (_IOC_NR(urequest) == _IOC_NR(EVIOCGBIT(EV_REL,0))) {
210 /* relative controllers (trackball) */
211 int maxLen = _IOC_SIZE(urequest);
212 memset(argp, 0xff, maxLen);
213 } else if (!getenv("NOTOUCH") && _IOC_NR(urequest) == _IOC_NR(EVIOCGBIT(EV_ABS,0))) {
214 // absolute controllers (touch screen)
215 int maxLen = _IOC_SIZE(urequest);
Marco Nelissen500248f2009-08-13 07:53:33 -0700216 if (maxLen > (int) sizeof(gAbsBitMask))
217 maxLen = sizeof(gAbsBitMask);
218 memcpy(argp, gAbsBitMask, maxLen);
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800219
220 } else if (_IOC_NR(urequest) >= _IOC_NR(EVIOCGABS(ABS_X)) &&
221 _IOC_NR(urequest) <= _IOC_NR(EVIOCGABS(ABS_MAX)))
222 {
223 /* get abs value / limits */
224 int reqIdx = _IOC_NR(urequest) - _IOC_NR(EVIOCGABS(ABS_X));
225 handleAbsGet(reqIdx, argp);
226 } else {
227 wsLog("GLITCH: UNKNOWN ioctl request 0x%x on %s\n",
228 urequest, dev->debugName);
229 return -1;
230 }
231
232 return 0;
233}
234
235/*
236 * Free up our state before closing down the fake descriptor.
237 */
238static int closeEvent(FakeDev* dev, int fd)
239{
240 freeState((EventState*)dev->state);
241 dev->state = NULL;
242 if (gWrapSim.keyInputDevice == dev) {
243 gWrapSim.keyInputDevice = NULL;
244 wsLog("Sim input device closed\n");
245 }
246 return 0;
247}
248
249/*
250 * Open an input event device.
251 */
252FakeDev* wsOpenDevEvent(const char* pathName, int flags)
253{
254 FakeDev* newDev = wsCreateRealFakeDev(pathName);
255 if (newDev != NULL) {
256 newDev->read = readEvent;
257 newDev->write = writeEvent;
258 newDev->ioctl = ioctlEvent;
259 newDev->close = closeEvent;
260
261 EventState* eventState = calloc(1, sizeof(EventState));
262
263 configureInitialState(pathName, eventState);
264 newDev->state = eventState;
265
266 /*
267 * First one opened becomes the place where we queue up input
268 * events from the simulator. This approach will fail if the
269 * app opens the device, then opens it a second time for input,
270 * then closes the first. The app doesn't currently do this (though
271 * it does do quick opens to fiddle with LEDs).
272 */
273 if (gWrapSim.keyInputDevice == NULL) {
274 gWrapSim.keyInputDevice = newDev;
275 wsLog("Device %p / %d will receive sim input events\n",
276 newDev, newDev->fd);
277 }
278 }
279
280 return newDev;
281}
282
283/*
284 * Write a key event.
285 */
286static int sendKeyEvent(FakeDev* dev, int code, int isDown)
287{
288 struct input_event iev;
289 ssize_t actual;
290
291 gettimeofday(&iev.time, NULL);
292 iev.type = EV_KEY;
293 iev.code = code;
294 iev.value = (isDown != 0) ? 1 : 0;
295
296 actual = _ws_write(dev->otherFd, &iev, sizeof(iev));
297 if (actual != (ssize_t) sizeof(iev)) {
298 wsLog("WARNING: send key event partial write (%d of %d)\n",
299 actual, sizeof(iev));
300 return -1;
301 }
302
303 return 0;
304}
305
306/*
307 * Write an absolute (touch screen) event.
308 */
309static int sendAbsButton(FakeDev* dev, int x, int y, int isDown)
310{
311 struct input_event iev;
312 ssize_t actual;
313
314 wsLog("absButton x=%d y=%d down=%d\n", x, y, isDown);
315
316 gettimeofday(&iev.time, NULL);
317 iev.type = EV_KEY;
318 iev.code = BTN_TOUCH;
319 iev.value = (isDown != 0) ? 1 : 0;
320
321 actual = _ws_write(dev->otherFd, &iev, sizeof(iev));
322 if (actual != (ssize_t) sizeof(iev)) {
323 wsLog("WARNING: send touch event partial write (%d of %d)\n",
324 actual, sizeof(iev));
325 return -1;
326 }
327
328 return 0;
329}
330
331/*
332 * Write an absolute (touch screen) event.
333 */
334static int sendAbsMovement(FakeDev* dev, int x, int y)
335{
336 struct input_event iev;
337 ssize_t actual;
338
339 wsLog("absMove x=%d y=%d\n", x, y);
340
341 gettimeofday(&iev.time, NULL);
342 iev.type = EV_ABS;
343 iev.code = ABS_X;
344 iev.value = x;
345
346 actual = _ws_write(dev->otherFd, &iev, sizeof(iev));
347 if (actual != (ssize_t) sizeof(iev)) {
348 wsLog("WARNING: send abs movement event partial X write (%d of %d)\n",
349 actual, sizeof(iev));
350 return -1;
351 }
352
353 iev.code = ABS_Y;
354 iev.value = y;
355
356 actual = _ws_write(dev->otherFd, &iev, sizeof(iev));
357 if (actual != (ssize_t) sizeof(iev)) {
358 wsLog("WARNING: send abs movement event partial Y write (%d of %d)\n",
359 actual, sizeof(iev));
360 return -1;
361 }
362
363 return 0;
364}
365
366/*
367 * Not quite sure what this is for, but the emulator does it.
368 */
369static int sendAbsSyn(FakeDev* dev)
370{
371 struct input_event iev;
372 ssize_t actual;
373
374 gettimeofday(&iev.time, NULL);
375 iev.type = EV_SYN;
376 iev.code = 0;
377 iev.value = 0;
378
379 actual = _ws_write(dev->otherFd, &iev, sizeof(iev));
380 if (actual != (ssize_t) sizeof(iev)) {
381 wsLog("WARNING: send abs movement syn (%d of %d)\n",
382 actual, sizeof(iev));
383 return -1;
384 }
385
386 return 0;
387}
388
389/*
390 * Send a key event to the fake key event device.
391 *
392 * We have to translate the simulator key event into one or more device
393 * key events.
394 */
395void wsSendSimKeyEvent(int key, int isDown)
396{
397 FakeDev* dev;
398 EventState* state;
399
400 dev = gWrapSim.keyInputDevice;
401 if (dev == NULL)
402 return;
403
404 sendKeyEvent(dev, key, isDown);
405}
406
407/*
408 * Send a touch-screen event to the fake key event device.
409 *
410 * We have to translate the simulator key event into one or more device
411 * key events.
412 */
413void wsSendSimTouchEvent(int action, int x, int y)
414{
415 FakeDev* dev;
416 EventState* state;
417
418 dev = gWrapSim.keyInputDevice;
419 if (dev == NULL)
420 return;
421
422 if (action == kTouchDown) {
423 sendAbsMovement(dev, x, y);
424 sendAbsButton(dev, x, y, 1);
425 sendAbsSyn(dev);
426 } else if (action == kTouchUp) {
427 sendAbsButton(dev, x, y, 0);
428 sendAbsSyn(dev);
429 } else if (action == kTouchDrag) {
430 sendAbsMovement(dev, x, y);
431 sendAbsSyn(dev);
432 } else {
433 wsLog("WARNING: unexpected sim touch action %d\n", action);
434 }
435}
436