/* * Copyright 2007 The Android Open Source Project * * Input event device. */ #include "Common.h" #include #include #include #include #include /* * Input event device state. */ typedef struct EventState { struct input_id ident; char* name; char* location; char* idstr; int protoVersion; } EventState; /* * Key bit mask, for EVIOCGBIT(EV_KEY). * * (For now, just pretend to be a "goldfish" like the emulator.) */ static const unsigned char gKeyBitMask[64] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, }; /* * Set some stuff up. */ static void configureInitialState(const char* pathName, EventState* eventState) { /* * Swim like a goldfish. */ eventState->ident.bustype = 0; eventState->ident.vendor = 0; eventState->ident.product = 0; eventState->ident.version = 0; eventState->name = strdup(gWrapSim.keyMap); eventState->location = strdup(""); eventState->idstr = strdup(""); eventState->protoVersion = 0x010000; } /* * Free up the state structure. */ static void freeState(EventState* eventState) { if (eventState != NULL) { free(eventState->name); free(eventState->location); free(eventState->idstr); free(eventState); } } /* * Handle one of the EVIOCGABS requests. * * Currently not doing much here. */ static void handleAbsGet(int reqIdx, void* argp) { struct input_absinfo info; switch (reqIdx) { case ABS_X: wsLog(" req for abs X\n"); break; case ABS_Y: wsLog(" req for abs Y\n"); break; case ABS_PRESSURE: wsLog(" req for abs PRESSURE\n"); break; case ABS_TOOL_WIDTH: wsLog(" req for abs TOOL_WIDTH\n"); break; default: wsLog(" req for unexpected event abs 0x%02x\n", reqIdx); break; } memset(&info, 0, sizeof(info)); memcpy(argp, &info, sizeof(struct input_absinfo)); } /* * Return the next available input event. * * We just pass this through to the real "read", since "fd" is real. */ static ssize_t readEvent(FakeDev* dev, int fd, void* buf, size_t count) { return _ws_read(fd, buf, count); } /* * Somebody is trying to write to the event pipe. This can be used to set * the state of LED. */ static ssize_t writeEvent(FakeDev* dev, int fd, const void* buf, size_t count) { const struct input_event* piev; if (count == sizeof(*piev)) { piev = (const struct input_event*) buf; if (piev->type == EV_LED) { wsLog("%s: set LED code=%d value=%d\n", dev->debugName, piev->code, piev->value); } else { wsLog("%s: writeEvent got %d bytes, type=%d\n", dev->debugName, count, piev->type); } } else { wsLog("%s: warning: writeEvent got %d bytes, not sure why\n", dev->debugName, count); } return count; } /* * Handle event ioctls. */ static int ioctlEvent(FakeDev* dev, int fd, int request, void* argp) { EventState* state = (EventState*) dev->state; unsigned int urequest = (unsigned int) request; wsLog("%s: ioctl(0x%x, %p)\n", dev->debugName, urequest, argp); if (_IOC_TYPE(urequest) != _IOC_TYPE(EVIOCGVERSION)) { wsLog("%s: inappropriate ioctl 0x%08x\n", dev->debugName, urequest); return -1; } if (urequest == EVIOCGVERSION) { *(int*)argp = state->protoVersion; } else if (urequest == EVIOCGID) { memcpy(argp, &state->ident, sizeof(struct input_id)); } else if (_IOC_NR(urequest) == _IOC_NR(EVIOCGNAME(0))) { int maxLen = _IOC_SIZE(urequest); int strLen = (int) strlen(state->name); if (strLen >= maxLen) { errno = EINVAL; return -1; } memcpy(argp, state->name, strLen+1); return strLen; } else if (_IOC_NR(urequest) == _IOC_NR(EVIOCGPHYS(0))) { int maxLen = _IOC_SIZE(urequest); int strLen = (int) strlen(state->location); if (strLen >= maxLen) { errno = EINVAL; return -1; } memcpy(argp, state->location, strLen+1); return strLen; } else if (_IOC_NR(urequest) == _IOC_NR(EVIOCGUNIQ(0))) { /* device doesn't seem to support this, neither will we */ return -1; } else if (_IOC_NR(urequest) == _IOC_NR(EVIOCGBIT(EV_KEY,0))) { /* keys */ int maxLen = _IOC_SIZE(urequest); if (maxLen > (int) sizeof(gKeyBitMask)) maxLen = sizeof(gKeyBitMask); memcpy(argp, gKeyBitMask, maxLen); } else if (_IOC_NR(urequest) == _IOC_NR(EVIOCGBIT(EV_REL,0))) { /* relative controllers (trackball) */ int maxLen = _IOC_SIZE(urequest); memset(argp, 0xff, maxLen); } else if (!getenv("NOTOUCH") && _IOC_NR(urequest) == _IOC_NR(EVIOCGBIT(EV_ABS,0))) { // absolute controllers (touch screen) int maxLen = _IOC_SIZE(urequest); memset(argp, 0xff, maxLen); } else if (_IOC_NR(urequest) >= _IOC_NR(EVIOCGABS(ABS_X)) && _IOC_NR(urequest) <= _IOC_NR(EVIOCGABS(ABS_MAX))) { /* get abs value / limits */ int reqIdx = _IOC_NR(urequest) - _IOC_NR(EVIOCGABS(ABS_X)); handleAbsGet(reqIdx, argp); } else { wsLog("GLITCH: UNKNOWN ioctl request 0x%x on %s\n", urequest, dev->debugName); return -1; } return 0; } /* * Free up our state before closing down the fake descriptor. */ static int closeEvent(FakeDev* dev, int fd) { freeState((EventState*)dev->state); dev->state = NULL; if (gWrapSim.keyInputDevice == dev) { gWrapSim.keyInputDevice = NULL; wsLog("Sim input device closed\n"); } return 0; } /* * Open an input event device. */ FakeDev* wsOpenDevEvent(const char* pathName, int flags) { FakeDev* newDev = wsCreateRealFakeDev(pathName); if (newDev != NULL) { newDev->read = readEvent; newDev->write = writeEvent; newDev->ioctl = ioctlEvent; newDev->close = closeEvent; EventState* eventState = calloc(1, sizeof(EventState)); configureInitialState(pathName, eventState); newDev->state = eventState; /* * First one opened becomes the place where we queue up input * events from the simulator. This approach will fail if the * app opens the device, then opens it a second time for input, * then closes the first. The app doesn't currently do this (though * it does do quick opens to fiddle with LEDs). */ if (gWrapSim.keyInputDevice == NULL) { gWrapSim.keyInputDevice = newDev; wsLog("Device %p / %d will receive sim input events\n", newDev, newDev->fd); } } return newDev; } /* * Write a key event. */ static int sendKeyEvent(FakeDev* dev, int code, int isDown) { struct input_event iev; ssize_t actual; gettimeofday(&iev.time, NULL); iev.type = EV_KEY; iev.code = code; iev.value = (isDown != 0) ? 1 : 0; actual = _ws_write(dev->otherFd, &iev, sizeof(iev)); if (actual != (ssize_t) sizeof(iev)) { wsLog("WARNING: send key event partial write (%d of %d)\n", actual, sizeof(iev)); return -1; } return 0; } /* * Write an absolute (touch screen) event. */ static int sendAbsButton(FakeDev* dev, int x, int y, int isDown) { struct input_event iev; ssize_t actual; wsLog("absButton x=%d y=%d down=%d\n", x, y, isDown); gettimeofday(&iev.time, NULL); iev.type = EV_KEY; iev.code = BTN_TOUCH; iev.value = (isDown != 0) ? 1 : 0; actual = _ws_write(dev->otherFd, &iev, sizeof(iev)); if (actual != (ssize_t) sizeof(iev)) { wsLog("WARNING: send touch event partial write (%d of %d)\n", actual, sizeof(iev)); return -1; } return 0; } /* * Write an absolute (touch screen) event. */ static int sendAbsMovement(FakeDev* dev, int x, int y) { struct input_event iev; ssize_t actual; wsLog("absMove x=%d y=%d\n", x, y); gettimeofday(&iev.time, NULL); iev.type = EV_ABS; iev.code = ABS_X; iev.value = x; actual = _ws_write(dev->otherFd, &iev, sizeof(iev)); if (actual != (ssize_t) sizeof(iev)) { wsLog("WARNING: send abs movement event partial X write (%d of %d)\n", actual, sizeof(iev)); return -1; } iev.code = ABS_Y; iev.value = y; actual = _ws_write(dev->otherFd, &iev, sizeof(iev)); if (actual != (ssize_t) sizeof(iev)) { wsLog("WARNING: send abs movement event partial Y write (%d of %d)\n", actual, sizeof(iev)); return -1; } return 0; } /* * Not quite sure what this is for, but the emulator does it. */ static int sendAbsSyn(FakeDev* dev) { struct input_event iev; ssize_t actual; gettimeofday(&iev.time, NULL); iev.type = EV_SYN; iev.code = 0; iev.value = 0; actual = _ws_write(dev->otherFd, &iev, sizeof(iev)); if (actual != (ssize_t) sizeof(iev)) { wsLog("WARNING: send abs movement syn (%d of %d)\n", actual, sizeof(iev)); return -1; } return 0; } /* * Send a key event to the fake key event device. * * We have to translate the simulator key event into one or more device * key events. */ void wsSendSimKeyEvent(int key, int isDown) { FakeDev* dev; EventState* state; dev = gWrapSim.keyInputDevice; if (dev == NULL) return; sendKeyEvent(dev, key, isDown); } /* * Send a touch-screen event to the fake key event device. * * We have to translate the simulator key event into one or more device * key events. */ void wsSendSimTouchEvent(int action, int x, int y) { FakeDev* dev; EventState* state; dev = gWrapSim.keyInputDevice; if (dev == NULL) return; if (action == kTouchDown) { sendAbsMovement(dev, x, y); sendAbsButton(dev, x, y, 1); sendAbsSyn(dev); } else if (action == kTouchUp) { sendAbsButton(dev, x, y, 0); sendAbsSyn(dev); } else if (action == kTouchDrag) { sendAbsMovement(dev, x, y); sendAbsSyn(dev); } else { wsLog("WARNING: unexpected sim touch action %d\n", action); } }