michael@0: /* michael@0: * Copyright (C) 2005 The Android Open Source Project michael@0: * michael@0: * Licensed under the Apache License, Version 2.0 (the "License"); michael@0: * you may not use this file except in compliance with the License. michael@0: * You may obtain a copy of the License at michael@0: * michael@0: * http://www.apache.org/licenses/LICENSE-2.0 michael@0: * michael@0: * Unless required by applicable law or agreed to in writing, software michael@0: * distributed under the License is distributed on an "AS IS" BASIS, michael@0: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. michael@0: * See the License for the specific language governing permissions and michael@0: * limitations under the License. michael@0: */ michael@0: michael@0: // michael@0: #ifndef _RUNTIME_EVENT_HUB_H michael@0: #define _RUNTIME_EVENT_HUB_H michael@0: michael@0: #include "Input.h" michael@0: #include "InputDevice.h" michael@0: #include "Keyboard.h" michael@0: #include "KeyLayoutMap.h" michael@0: #include "KeyCharacterMap.h" michael@0: #include "VirtualKeyMap.h" michael@0: #include michael@0: #include michael@0: #include "cutils_log.h" michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #include "linux_input.h" michael@0: #include michael@0: michael@0: /* Convenience constants. */ michael@0: michael@0: #define BTN_FIRST 0x100 // first button code michael@0: #define BTN_LAST 0x15f // last button code michael@0: michael@0: /* michael@0: * These constants are used privately in Android to pass raw timestamps michael@0: * through evdev from uinput device drivers because there is currently no michael@0: * other way to transfer this information. The evdev driver automatically michael@0: * timestamps all input events with the time they were posted and clobbers michael@0: * whatever information was passed in. michael@0: * michael@0: * For the purposes of this hack, the timestamp is specified in the michael@0: * CLOCK_MONOTONIC timebase and is split into two EV_MSC events specifying michael@0: * seconds and microseconds. michael@0: */ michael@0: #define MSC_ANDROID_TIME_SEC 0x6 michael@0: #define MSC_ANDROID_TIME_USEC 0x7 michael@0: michael@0: namespace android { michael@0: michael@0: enum { michael@0: // Device id of a special "virtual" keyboard that is always present. michael@0: VIRTUAL_KEYBOARD_ID = -1, michael@0: // Device id of the "built-in" keyboard if there is one. michael@0: BUILT_IN_KEYBOARD_ID = 0, michael@0: }; michael@0: michael@0: /* michael@0: * A raw event as retrieved from the EventHub. michael@0: */ michael@0: struct RawEvent { michael@0: nsecs_t when; michael@0: int32_t deviceId; michael@0: int32_t type; michael@0: int32_t code; michael@0: int32_t value; michael@0: }; michael@0: michael@0: /* Describes an absolute axis. */ michael@0: struct RawAbsoluteAxisInfo { michael@0: bool valid; // true if the information is valid, false otherwise michael@0: michael@0: int32_t minValue; // minimum value michael@0: int32_t maxValue; // maximum value michael@0: int32_t flat; // center flat position, eg. flat == 8 means center is between -8 and 8 michael@0: int32_t fuzz; // error tolerance, eg. fuzz == 4 means value is +/- 4 due to noise michael@0: int32_t resolution; // resolution in units per mm or radians per mm michael@0: michael@0: inline void clear() { michael@0: valid = false; michael@0: minValue = 0; michael@0: maxValue = 0; michael@0: flat = 0; michael@0: fuzz = 0; michael@0: resolution = 0; michael@0: } michael@0: }; michael@0: michael@0: /* michael@0: * Input device classes. michael@0: */ michael@0: enum { michael@0: /* The input device is a keyboard or has buttons. */ michael@0: INPUT_DEVICE_CLASS_KEYBOARD = 0x00000001, michael@0: michael@0: /* The input device is an alpha-numeric keyboard (not just a dial pad). */ michael@0: INPUT_DEVICE_CLASS_ALPHAKEY = 0x00000002, michael@0: michael@0: /* The input device is a touchscreen or a touchpad (either single-touch or multi-touch). */ michael@0: INPUT_DEVICE_CLASS_TOUCH = 0x00000004, michael@0: michael@0: /* The input device is a cursor device such as a trackball or mouse. */ michael@0: INPUT_DEVICE_CLASS_CURSOR = 0x00000008, michael@0: michael@0: /* The input device is a multi-touch touchscreen. */ michael@0: INPUT_DEVICE_CLASS_TOUCH_MT = 0x00000010, michael@0: michael@0: /* The input device is a directional pad (implies keyboard, has DPAD keys). */ michael@0: INPUT_DEVICE_CLASS_DPAD = 0x00000020, michael@0: michael@0: /* The input device is a gamepad (implies keyboard, has BUTTON keys). */ michael@0: INPUT_DEVICE_CLASS_GAMEPAD = 0x00000040, michael@0: michael@0: /* The input device has switches. */ michael@0: INPUT_DEVICE_CLASS_SWITCH = 0x00000080, michael@0: michael@0: /* The input device is a joystick (implies gamepad, has joystick absolute axes). */ michael@0: INPUT_DEVICE_CLASS_JOYSTICK = 0x00000100, michael@0: michael@0: /* The input device has a vibrator (supports FF_RUMBLE). */ michael@0: INPUT_DEVICE_CLASS_VIBRATOR = 0x00000200, michael@0: michael@0: /* The input device is virtual (not a real device, not part of UI configuration). */ michael@0: INPUT_DEVICE_CLASS_VIRTUAL = 0x40000000, michael@0: michael@0: /* The input device is external (not built-in). */ michael@0: INPUT_DEVICE_CLASS_EXTERNAL = 0x80000000, michael@0: }; michael@0: michael@0: /* michael@0: * Gets the class that owns an axis, in cases where multiple classes might claim michael@0: * the same axis for different purposes. michael@0: */ michael@0: extern uint32_t getAbsAxisUsage(int32_t axis, uint32_t deviceClasses); michael@0: michael@0: /* michael@0: * Grand Central Station for events. michael@0: * michael@0: * The event hub aggregates input events received across all known input michael@0: * devices on the system, including devices that may be emulated by the simulator michael@0: * environment. In addition, the event hub generates fake input events to indicate michael@0: * when devices are added or removed. michael@0: * michael@0: * The event hub provides a stream of input events (via the getEvent function). michael@0: * It also supports querying the current actual state of input devices such as identifying michael@0: * which keys are currently down. Finally, the event hub keeps track of the capabilities of michael@0: * individual input devices, such as their class and the set of key codes that they support. michael@0: */ michael@0: class EventHubInterface : public virtual RefBase { michael@0: protected: michael@0: EventHubInterface() { } michael@0: virtual ~EventHubInterface() { } michael@0: michael@0: public: michael@0: // Synthetic raw event type codes produced when devices are added or removed. michael@0: enum { michael@0: // Sent when a device is added. michael@0: DEVICE_ADDED = 0x10000000, michael@0: // Sent when a device is removed. michael@0: DEVICE_REMOVED = 0x20000000, michael@0: // Sent when all added/removed devices from the most recent scan have been reported. michael@0: // This event is always sent at least once. michael@0: FINISHED_DEVICE_SCAN = 0x30000000, michael@0: michael@0: FIRST_SYNTHETIC_EVENT = DEVICE_ADDED, michael@0: }; michael@0: michael@0: virtual uint32_t getDeviceClasses(int32_t deviceId) const = 0; michael@0: michael@0: virtual InputDeviceIdentifier getDeviceIdentifier(int32_t deviceId) const = 0; michael@0: michael@0: virtual void getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const = 0; michael@0: michael@0: virtual status_t getAbsoluteAxisInfo(int32_t deviceId, int axis, michael@0: RawAbsoluteAxisInfo* outAxisInfo) const = 0; michael@0: michael@0: virtual bool hasRelativeAxis(int32_t deviceId, int axis) const = 0; michael@0: michael@0: virtual bool hasInputProperty(int32_t deviceId, int property) const = 0; michael@0: michael@0: virtual status_t mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, michael@0: int32_t* outKeycode, uint32_t* outFlags) const = 0; michael@0: michael@0: virtual status_t mapAxis(int32_t deviceId, int32_t scanCode, michael@0: AxisInfo* outAxisInfo) const = 0; michael@0: michael@0: // Sets devices that are excluded from opening. michael@0: // This can be used to ignore input devices for sensors. michael@0: virtual void setExcludedDevices(const Vector& devices) = 0; michael@0: michael@0: /* michael@0: * Wait for events to become available and returns them. michael@0: * After returning, the EventHub holds onto a wake lock until the next call to getEvent. michael@0: * This ensures that the device will not go to sleep while the event is being processed. michael@0: * If the device needs to remain awake longer than that, then the caller is responsible michael@0: * for taking care of it (say, by poking the power manager user activity timer). michael@0: * michael@0: * The timeout is advisory only. If the device is asleep, it will not wake just to michael@0: * service the timeout. michael@0: * michael@0: * Returns the number of events obtained, or 0 if the timeout expired. michael@0: */ michael@0: virtual size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) = 0; michael@0: michael@0: /* michael@0: * Query current input state. michael@0: */ michael@0: virtual int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const = 0; michael@0: virtual int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const = 0; michael@0: virtual int32_t getSwitchState(int32_t deviceId, int32_t sw) const = 0; michael@0: virtual status_t getAbsoluteAxisValue(int32_t deviceId, int32_t axis, michael@0: int32_t* outValue) const = 0; michael@0: michael@0: /* michael@0: * Examine key input devices for specific framework keycode support michael@0: */ michael@0: virtual bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes, michael@0: uint8_t* outFlags) const = 0; michael@0: michael@0: virtual bool hasScanCode(int32_t deviceId, int32_t scanCode) const = 0; michael@0: virtual bool hasLed(int32_t deviceId, int32_t led) const = 0; michael@0: virtual void setLedState(int32_t deviceId, int32_t led, bool on) = 0; michael@0: michael@0: virtual void getVirtualKeyDefinitions(int32_t deviceId, michael@0: Vector& outVirtualKeys) const = 0; michael@0: michael@0: virtual sp getKeyCharacterMap(int32_t deviceId) const = 0; michael@0: virtual bool setKeyboardLayoutOverlay(int32_t deviceId, const sp& map) = 0; michael@0: michael@0: /* Control the vibrator. */ michael@0: virtual void vibrate(int32_t deviceId, nsecs_t duration) = 0; michael@0: virtual void cancelVibrate(int32_t deviceId) = 0; michael@0: michael@0: /* Requests the EventHub to reopen all input devices on the next call to getEvents(). */ michael@0: virtual void requestReopenDevices() = 0; michael@0: michael@0: /* Wakes up getEvents() if it is blocked on a read. */ michael@0: virtual void wake() = 0; michael@0: michael@0: /* Dump EventHub state to a string. */ michael@0: virtual void dump(String8& dump) = 0; michael@0: michael@0: /* Called by the heatbeat to ensures that the reader has not deadlocked. */ michael@0: virtual void monitor() = 0; michael@0: }; michael@0: michael@0: class EventHub : public EventHubInterface michael@0: { michael@0: public: michael@0: EventHub(); michael@0: michael@0: virtual uint32_t getDeviceClasses(int32_t deviceId) const; michael@0: michael@0: virtual InputDeviceIdentifier getDeviceIdentifier(int32_t deviceId) const; michael@0: michael@0: virtual void getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const; michael@0: michael@0: virtual status_t getAbsoluteAxisInfo(int32_t deviceId, int axis, michael@0: RawAbsoluteAxisInfo* outAxisInfo) const; michael@0: michael@0: virtual bool hasRelativeAxis(int32_t deviceId, int axis) const; michael@0: michael@0: virtual bool hasInputProperty(int32_t deviceId, int property) const; michael@0: michael@0: virtual status_t mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, michael@0: int32_t* outKeycode, uint32_t* outFlags) const; michael@0: michael@0: virtual status_t mapAxis(int32_t deviceId, int32_t scanCode, michael@0: AxisInfo* outAxisInfo) const; michael@0: michael@0: virtual void setExcludedDevices(const Vector& devices); michael@0: michael@0: virtual int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const; michael@0: virtual int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const; michael@0: virtual int32_t getSwitchState(int32_t deviceId, int32_t sw) const; michael@0: virtual status_t getAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t* outValue) const; michael@0: michael@0: virtual bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes, michael@0: const int32_t* keyCodes, uint8_t* outFlags) const; michael@0: michael@0: virtual size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize); michael@0: michael@0: virtual bool hasScanCode(int32_t deviceId, int32_t scanCode) const; michael@0: virtual bool hasLed(int32_t deviceId, int32_t led) const; michael@0: virtual void setLedState(int32_t deviceId, int32_t led, bool on); michael@0: michael@0: virtual void getVirtualKeyDefinitions(int32_t deviceId, michael@0: Vector& outVirtualKeys) const; michael@0: michael@0: virtual sp getKeyCharacterMap(int32_t deviceId) const; michael@0: virtual bool setKeyboardLayoutOverlay(int32_t deviceId, const sp& map); michael@0: michael@0: virtual void vibrate(int32_t deviceId, nsecs_t duration); michael@0: virtual void cancelVibrate(int32_t deviceId); michael@0: michael@0: virtual void requestReopenDevices(); michael@0: michael@0: virtual void wake(); michael@0: michael@0: virtual void dump(String8& dump); michael@0: virtual void monitor(); michael@0: michael@0: protected: michael@0: virtual ~EventHub(); michael@0: michael@0: private: michael@0: struct Device { michael@0: Device* next; michael@0: michael@0: int fd; // may be -1 if device is virtual michael@0: const int32_t id; michael@0: const String8 path; michael@0: const InputDeviceIdentifier identifier; michael@0: michael@0: uint32_t classes; michael@0: michael@0: uint8_t keyBitmask[(KEY_MAX + 1) / 8]; michael@0: uint8_t absBitmask[(ABS_MAX + 1) / 8]; michael@0: uint8_t relBitmask[(REL_MAX + 1) / 8]; michael@0: uint8_t swBitmask[(SW_MAX + 1) / 8]; michael@0: uint8_t ledBitmask[(LED_MAX + 1) / 8]; michael@0: uint8_t ffBitmask[(FF_MAX + 1) / 8]; michael@0: uint8_t propBitmask[(INPUT_PROP_MAX + 1) / 8]; michael@0: michael@0: String8 configurationFile; michael@0: PropertyMap* configuration; michael@0: VirtualKeyMap* virtualKeyMap; michael@0: KeyMap keyMap; michael@0: michael@0: sp overlayKeyMap; michael@0: sp combinedKeyMap; michael@0: michael@0: bool ffEffectPlaying; michael@0: int16_t ffEffectId; // initially -1 michael@0: michael@0: int32_t timestampOverrideSec; michael@0: int32_t timestampOverrideUsec; michael@0: michael@0: Device(int fd, int32_t id, const String8& path, const InputDeviceIdentifier& identifier); michael@0: ~Device(); michael@0: michael@0: void close(); michael@0: michael@0: inline bool isVirtual() const { return fd < 0; } michael@0: michael@0: const sp& getKeyCharacterMap() const { michael@0: if (combinedKeyMap != NULL) { michael@0: return combinedKeyMap; michael@0: } michael@0: return keyMap.keyCharacterMap; michael@0: } michael@0: }; michael@0: michael@0: status_t openDeviceLocked(const char *devicePath); michael@0: void createVirtualKeyboardLocked(); michael@0: void addDeviceLocked(Device* device); michael@0: michael@0: status_t closeDeviceByPathLocked(const char *devicePath); michael@0: void closeDeviceLocked(Device* device); michael@0: void closeAllDevicesLocked(); michael@0: michael@0: status_t scanDirLocked(const char *dirname); michael@0: void scanDevicesLocked(); michael@0: status_t readNotifyLocked(); michael@0: michael@0: Device* getDeviceLocked(int32_t deviceId) const; michael@0: Device* getDeviceByPathLocked(const char* devicePath) const; michael@0: michael@0: bool hasKeycodeLocked(Device* device, int keycode) const; michael@0: michael@0: void loadConfigurationLocked(Device* device); michael@0: status_t loadVirtualKeyMapLocked(Device* device); michael@0: status_t loadKeyMapLocked(Device* device); michael@0: michael@0: bool isExternalDeviceLocked(Device* device); michael@0: michael@0: // Protect all internal state. michael@0: mutable Mutex mLock; michael@0: michael@0: // The actual id of the built-in keyboard, or NO_BUILT_IN_KEYBOARD if none. michael@0: // EventHub remaps the built-in keyboard to id 0 externally as required by the API. michael@0: enum { michael@0: // Must not conflict with any other assigned device ids, including michael@0: // the virtual keyboard id (-1). michael@0: NO_BUILT_IN_KEYBOARD = -2, michael@0: }; michael@0: int32_t mBuiltInKeyboardId; michael@0: michael@0: int32_t mNextDeviceId; michael@0: michael@0: KeyedVector mDevices; michael@0: michael@0: Device *mOpeningDevices; michael@0: Device *mClosingDevices; michael@0: michael@0: bool mNeedToSendFinishedDeviceScan; michael@0: bool mNeedToReopenDevices; michael@0: bool mNeedToScanDevices; michael@0: Vector mExcludedDevices; michael@0: michael@0: int mEpollFd; michael@0: int mINotifyFd; michael@0: int mWakeReadPipeFd; michael@0: int mWakeWritePipeFd; michael@0: michael@0: // Ids used for epoll notifications not associated with devices. michael@0: static const uint32_t EPOLL_ID_INOTIFY = 0x80000001; michael@0: static const uint32_t EPOLL_ID_WAKE = 0x80000002; michael@0: michael@0: // Epoll FD list size hint. michael@0: static const int EPOLL_SIZE_HINT = 8; michael@0: michael@0: // Maximum number of signalled FDs to handle at a time. michael@0: static const int EPOLL_MAX_EVENTS = 16; michael@0: michael@0: // The array of pending epoll events and the index of the next event to be handled. michael@0: struct epoll_event mPendingEventItems[EPOLL_MAX_EVENTS]; michael@0: size_t mPendingEventCount; michael@0: size_t mPendingEventIndex; michael@0: bool mPendingINotify; michael@0: }; michael@0: michael@0: }; // namespace android michael@0: michael@0: #endif // _RUNTIME_EVENT_HUB_H