130|shell@cv6a638_base:/ # dumpsys input INPUT MANAGER (dumpsys input) Event Hub State: BuiltInKeyboardId: -2 Devices: -1: Virtual Classes: 0x40000023 Path: <virtual> Descriptor: a718a782d34bc767f4689c232d64d527998ea7fd Location: ControllerNumber: 0 UniqueId: <virtual> Identifier: bus=0x0000, vendor=0x0000, product=0x0000, version=0x0000 KeyLayoutFile: /system/usr/keylayout/Generic.kl KeyCharacterMapFile: /system/usr/keychars/Virtual.kcm ConfigurationFile: HaveKeyboardLayoutOverlay: false 1: MStar Smart TV Keypad Classes: 0x00000001 Path: /dev/input/event2 Descriptor: 8f43d929a9472e8dc54d48a6c41e2435e8eaff35 Location: ControllerNumber: 0 UniqueId: Identifier: bus=0x0006, vendor=0x3697, product=0x0002, version=0x0000 KeyLayoutFile: /system/usr/keylayout/Vendor_3697_Product_0002.kl KeyCharacterMapFile: /system/usr/keychars/Generic.kcm ConfigurationFile: HaveKeyboardLayoutOverlay: false 2: MCE IR Keyboard/Mouse (ir) Classes: 0x0000000b Path: /dev/input/event1 Descriptor: 2b764a30c0f74e1362d8ef86c5e4f12150af666f Location: /input0 ControllerNumber: 0 UniqueId: Identifier: bus=0x0000, vendor=0x0000, product=0x0000, version=0x0000 KeyLayoutFile: /system/usr/keylayout/Generic.kl KeyCharacterMapFile: /system/usr/keychars/Generic.kcm ConfigurationFile: HaveKeyboardLayoutOverlay: false 3: MStar Smart TV IR Receiver Classes: 0x00000001 Path: /dev/input/event0 Descriptor: 0e50bdc18d3ae0b6f247100cbd99062d93c208eb Location: /dev/ir ControllerNumber: 0 UniqueId: Identifier: bus=0x0018, vendor=0x3697, product=0x0001, version=0x0001 KeyLayoutFile: /system/usr/keylayout/Vendor_3697_Product_0001.kl KeyCharacterMapFile: /system/usr/keychars/Generic.kcm ConfigurationFile: HaveKeyboardLayoutOverlay: false 4: AVRCP Classes: 0x80000001 Path: /dev/input/event3 Descriptor: 89065b1db3afd7f700b4049a883d405d76233a40 Location: ControllerNumber: 0 UniqueId: Identifier: bus=0x0005, vendor=0x0000, product=0x0000, version=0x0000 KeyLayoutFile: /system/usr/keylayout/AVRCP.kl KeyCharacterMapFile: /system/usr/keychars/Generic.kcm ConfigurationFile: HaveKeyboardLayoutOverlay: false Input Reader State: Device -1: Virtual Generation: 2 IsExternal: false Sources: 0x00000301 KeyboardType: 2 Keyboard Input Mapper: Parameters: HasAssociatedDisplay: false OrientationAware: false KeyboardType: 2 Orientation: 0 KeyDowns: 0 keys currently down MetaState: 0x0 DownTime: 0 Device 1: MStar Smart TV Keypad Generation: 9 IsExternal: false Sources: 0x00000101 KeyboardType: 1 Keyboard Input Mapper: Parameters: HasAssociatedDisplay: false OrientationAware: false KeyboardType: 1 Orientation: 0 KeyDowns: 0 keys currently down MetaState: 0x0 DownTime: 0 Device 2: MCE IR Keyboard/Mouse (ir) Generation: 11 IsExternal: false Sources: 0x00002103 KeyboardType: 2 Motion Ranges: X: source=0x00002002, min=0.000, max=1919.000, flat=0.000, fuzz=0.000, resolution=0.000 Y: source=0x00002002, min=0.000, max=1079.000, flat=0.000, fuzz=0.000, resolution=0.000 PRESSURE: source=0x00002002, min=0.000, max=1.000, flat=0.000, fuzz=0.000, resolution=0.000 Keyboard Input Mapper: Parameters: HasAssociatedDisplay: false OrientationAware: false KeyboardType: 2 Orientation: 0 KeyDowns: 0 keys currently down MetaState: 0x0 DownTime: 0 Cursor Input Mapper: Parameters: HasAssociatedDisplay: true Mode: pointer OrientationAware: false XScale: 1.000 YScale: 1.000 XPrecision: 1.000 YPrecision: 1.000 HaveVWheel: false HaveHWheel: false VWheelScale: 1.000 HWheelScale: 1.000 Orientation: 0 ButtonState: 0x00000000 Down: false DownTime: 0 Device 3: MStar Smart TV IR Receiver Generation: 4 IsExternal: false Sources: 0x00000101 KeyboardType: 1 Keyboard Input Mapper: Parameters: HasAssociatedDisplay: false OrientationAware: false KeyboardType: 1 Orientation: 0 KeyDowns: 0 keys currently down MetaState: 0x0 DownTime: 0 Device 4: AVRCP Generation: 12 IsExternal: true Sources: 0x00000101 KeyboardType: 1 Keyboard Input Mapper: Parameters: HasAssociatedDisplay: false OrientationAware: false KeyboardType: 1 Orientation: 0 KeyDowns: 0 keys currently down MetaState: 0x0 DownTime: 0 Configuration: ExcludedDeviceNames: [] VirtualKeyQuietTime: 0.0ms PointerVelocityControlParameters: scale=1.000, lowThreshold=500.000, highThreshold=3000.000, acceleration=3.000 WheelVelocityControlParameters: scale=1.000, lowThreshold=15.000, highThreshold=50.000, acceleration=4.000 PointerGesture: Enabled: true QuietInterval: 100.0ms DragMinSwitchSpeed: 50.0px/s TapInterval: 150.0ms TapDragInterval: 300.0ms TapSlop: 20.0px MultitouchSettleInterval: 100.0ms MultitouchMinDistance: 15.0px SwipeTransitionAngleCosine: 0.3 SwipeMaxWidthRatio: 0.2 MovementSpeedRatio: 0.8 ZoomSpeedRatio: 0.3 Input Dispatcher State: DispatchEnabled: 1 DispatchFrozen: 0 FocusedApplication: name='AppWindowToken{42534628 token=Token{42532cb8 ActivityRecord{4255e728 u0 com.assem.launcher/.MainActivity t1}}}', dispatchingTimeout=5000.000ms FocusedWindow: name='Window{425a9768 u0 com.assem.launcher/com.assem.launcher.MainActivity}' TouchDown: false TouchSplit: false TouchDeviceId: -1 TouchSource: 0x00000000 TouchDisplayId: -1 TouchedWindows: <none> Windows: 0: name='Window{424d0270 u0 NotificationPanel}', displayId=0, paused=false, hasFocus=false, hasWallpaper=false, visible=false, canReceiveKeys=false, flags=0x01820300, type=0x000007e8, layer=211000, frame=[1152,-75][1920,1080], scale=1.000000, touchableRegion=[1152,-75][1920,1080], inputFeatures=0x00000000, ownerPid=2137, ownerUid=10003, dispatchingTimeout=5000.000ms 1: name='Window{42514f48 u0 KeyguardScrim}', displayId=0, paused=false, hasFocus=false, hasWallpaper=false, visible=false, canReceiveKeys=false, flags=0x00110900, type=0x000007ed, layer=121000, frame=[0,0][1920,1080], scale=1.000000, touchableRegion=[0,0][1920,1080], inputFeatures=0x00000000, ownerPid=2067, ownerUid=1000, dispatchingTimeout=5000.000ms 2: name='Window{425a9768 u0 com.assem.launcher/com.assem.launcher.MainActivity}', displayId=0, paused=false, hasFocus=true, hasWallpaper=false, visible=true, canReceiveKeys=true, flags=0x01810520, type=0x00000001, layer=21005, frame=[0,0][1920,1080], scale=1.000000, touchableRegion=[0,0][1920,1080], inputFeatures=0x00000000, ownerPid=2301, ownerUid=1000, dispatchingTimeout=5000.000ms 3: name='Window{424c7c38 u0 com.android.systemui.ImageWallpaper}', displayId=0, paused=false, hasFocus=false, hasWallpaper=false, visible=true, canReceiveKeys=false, flags=0x00000318, type=0x000007dd, layer=21000, frame=[0,0][1920,1280], scale=1.000000, touchableRegion=[0,0][1920,1280], inputFeatures=0x00000000, ownerPid=2137, ownerUid=10003, dispatchingTimeout=5000.000ms MonitoringChannels: 0: 'WindowManager (server)' RecentQueue: length=5 DeviceResetEvent(deviceId=-1), policyFlags=0x00000000, age=2045547.2ms DeviceResetEvent(deviceId=3), policyFlags=0x00000000, age=2045547.2ms DeviceResetEvent(deviceId=2), policyFlags=0x00000000, age=2045547.2ms DeviceResetEvent(deviceId=1), policyFlags=0x00000000, age=2045547.2ms DeviceResetEvent(deviceId=4), policyFlags=0x00000000, age=2033442.2ms PendingEvent: <none> InboundQueue: <empty> Connections: 0: channelName='425a9768 com.assem.launcher/com.assem.launcher.MainActivity (server)', windowName='Window{425a9768 u0 com.assem.launcher/com.assem.launcher.MainActivity}', status=NORMAL, monitor=false, inputPublisherBlocked=false OutboundQueue: <empty> WaitQueue: <empty> 1: channelName='WindowManager (server)', windowName='monitor', status=NORMAL, monitor=true, inputPublisherBlocked=false OutboundQueue: <empty> WaitQueue: <empty> 2: channelName='42514f48 KeyguardScrim (server)', windowName='Window{42514f48 u0 KeyguardScrim}', status=NORMAL, monitor=false, inputPublisherBlocked=false OutboundQueue: <empty> WaitQueue: <empty> 3: channelName='424d0270 NotificationPanel (server)', windowName='Window{424d0270 u0 NotificationPanel}', status=NORMAL, monitor=false, inputPublisherBlocked=false OutboundQueue: <empty> WaitQueue: <empty> 4: channelName='424c7c38 com.android.systemui.ImageWallpaper (server)', windowName='Window{424c7c38 u0 com.android.systemui.ImageWallpaper}', status=NORMAL, monitor=false, inputPublisherBlocked=false OutboundQueue: <empty> WaitQueue: <empty> AppSwitch: not pending Configuration: KeyRepeatDelay: 50.0ms KeyRepeatTimeout: 500.0ms shell@cv6a638_base:/ #我们可以看到在KeyLayoutFile条目中看到加载的按键映射文件,都是根据厂商ID和产品ID匹配对应文件的,例如
status_t EventHub::scanDirLocked(const char *dirname) { char devname[PATH_MAX]; char *filename; DIR *dir; struct dirent *de; dir = opendir(dirname); if(dir == NULL) return -1; strcpy(devname, dirname); filename = devname + strlen(devname); *filename++ = '/'; while((de = readdir(dir))) { if(de->d_name[0] == '.' && (de->d_name[1] == '\0' || (de->d_name[1] == '.' && de->d_name[2] == '\0'))) continue; strcpy(filename, de->d_name); openDeviceLocked(devname); } closedir(dir); return 0; }
shell@cv6a638_base:/ # ls /dev/input/ -al crw-rw---- root input 13, 64 1970-01-01 08:00 event0 crw-rw---- root input 13, 65 1970-01-01 08:00 event1 crw-rw---- root input 13, 66 1970-01-01 08:00 event2 crw-rw---- root input 13, 67 1970-01-02 08:01 event3 crw-rw---- root input 13, 0 1970-01-01 08:00 js0 crw-rw---- root input 13, 63 1970-01-01 08:00 mice crw-rw---- root input 13, 32 1970-01-01 08:00 mouse0这些设备中有鼠标,键盘,遥控器,滚动球等等,详细映射如下:
Event Hub State: BuiltInKeyboardId: -2 Devices: -1: Virtual Classes: 0x40000023 Path: <virtual> Descriptor: a718a782d34bc767f4689c232d64d527998ea7fd Location: ControllerNumber: 0 UniqueId: <virtual> Identifier: bus=0x0000, vendor=0x0000, product=0x0000, version=0x0000 KeyLayoutFile: /system/usr/keylayout/Generic.kl KeyCharacterMapFile: /system/usr/keychars/Virtual.kcm ConfigurationFile: HaveKeyboardLayoutOverlay: false 1: MStar Smart TV Keypad Classes: 0x00000001 Path: /dev/input/event2 Descriptor: 8f43d929a9472e8dc54d48a6c41e2435e8eaff35 Location: ControllerNumber: 0 UniqueId: Identifier: bus=0x0006, vendor=0x3697, product=0x0002, version=0x0000 KeyLayoutFile: /system/usr/keylayout/Vendor_3697_Product_0002.kl KeyCharacterMapFile: /system/usr/keychars/Generic.kcm ConfigurationFile: HaveKeyboardLayoutOverlay: false 2: MCE IR Keyboard/Mouse (ir) Classes: 0x0000000b Path: /dev/input/event1 Descriptor: 2b764a30c0f74e1362d8ef86c5e4f12150af666f Location: /input0 ControllerNumber: 0 UniqueId: Identifier: bus=0x0000, vendor=0x0000, product=0x0000, version=0x0000 KeyLayoutFile: /system/usr/keylayout/Generic.kl KeyCharacterMapFile: /system/usr/keychars/Generic.kcm ConfigurationFile: HaveKeyboardLayoutOverlay: false 3: MStar Smart TV IR Receiver Classes: 0x00000001 Path: /dev/input/event0 Descriptor: 0e50bdc18d3ae0b6f247100cbd99062d93c208eb Location: /dev/ir ControllerNumber: 0 UniqueId: Identifier: bus=0x0018, vendor=0x3697, product=0x0001, version=0x0001 KeyLayoutFile: /system/usr/keylayout/Vendor_3697_Product_0001.kl KeyCharacterMapFile: /system/usr/keychars/Generic.kcm ConfigurationFile: HaveKeyboardLayoutOverlay: false 4: AVRCP Classes: 0x80000001 Path: /dev/input/event3 Descriptor: 89065b1db3afd7f700b4049a883d405d76233a40 Location: ControllerNumber: 0 UniqueId: Identifier: bus=0x0005, vendor=0x0000, product=0x0000, version=0x0000 KeyLayoutFile: /system/usr/keylayout/AVRCP.kl KeyCharacterMapFile: /system/usr/keychars/Generic.kcm ConfigurationFile: HaveKeyboardLayoutOverlay: falseopenDeviceLocked完成单个设备信息的读取,并组装成Device添加至mDevices(KeyedVector<int32_t, Device*>)中
status_t EventHub::openDeviceLocked(const char *devicePath) { char buffer[80]; ALOGV("Opening device: %s", devicePath); int fd = open(devicePath, O_RDWR | O_CLOEXEC); if(fd < 0) { ALOGE("could not open %s, %s\n", devicePath, strerror(errno)); return -1; } InputDeviceIdentifier identifier; // Get device name. if(ioctl(fd, EVIOCGNAME(sizeof(buffer) - 1), &buffer) < 1) { //fprintf(stderr, "could not get device name for %s, %s\n", devicePath, strerror(errno)); } else { buffer[sizeof(buffer) - 1] = '\0'; identifier.name.setTo(buffer); } // Check to see if the device is on our excluded list for (size_t i = 0; i < mExcludedDevices.size(); i++) { const String8& item = mExcludedDevices.itemAt(i); if (identifier.name == item) { ALOGI("ignoring event id %s driver %s\n", devicePath, item.string()); close(fd); return -1; } } // Get device driver version. int driverVersion; if(ioctl(fd, EVIOCGVERSION, &driverVersion)) { ALOGE("could not get driver version for %s, %s\n", devicePath, strerror(errno)); close(fd); return -1; } // Get device identifier. struct input_id inputId; if(ioctl(fd, EVIOCGID, &inputId)) { ALOGE("could not get device input id for %s, %s\n", devicePath, strerror(errno)); close(fd); return -1; } identifier.bus = inputId.bustype; identifier.product = inputId.product; identifier.vendor = inputId.vendor; identifier.version = inputId.version; // Get device physical location. if(ioctl(fd, EVIOCGPHYS(sizeof(buffer) - 1), &buffer) < 1) { //fprintf(stderr, "could not get location for %s, %s\n", devicePath, strerror(errno)); } else { buffer[sizeof(buffer) - 1] = '\0'; identifier.location.setTo(buffer); } // Get device unique id. if(ioctl(fd, EVIOCGUNIQ(sizeof(buffer) - 1), &buffer) < 1) { //fprintf(stderr, "could not get idstring for %s, %s\n", devicePath, strerror(errno)); } else { buffer[sizeof(buffer) - 1] = '\0'; identifier.uniqueId.setTo(buffer); } // Fill in the descriptor. setDescriptor(identifier); // Make file descriptor non-blocking for use with poll(). if (fcntl(fd, F_SETFL, O_NONBLOCK)) { ALOGE("Error %d making device file descriptor non-blocking.", errno); close(fd); return -1; } // Allocate device. (The device object takes ownership of the fd at this point.) int32_t deviceId = mNextDeviceId++; Device* device = new Device(fd, deviceId, String8(devicePath), identifier); ALOGV("add device %d: %s\n", deviceId, devicePath); ALOGV(" bus: %04x\n" " vendor %04x\n" " product %04x\n" " version %04x\n", identifier.bus, identifier.vendor, identifier.product, identifier.version); ALOGV(" name: \"%s\"\n", identifier.name.string()); ALOGV(" location: \"%s\"\n", identifier.location.string()); ALOGV(" unique id: \"%s\"\n", identifier.uniqueId.string()); ALOGV(" descriptor: \"%s\"\n", identifier.descriptor.string()); ALOGV(" driver: v%d.%d.%d\n", driverVersion >> 16, (driverVersion >> 8) & 0xff, driverVersion & 0xff); // Load the configuration file for the device. loadConfigurationLocked(device); // Figure out the kinds of events the device reports. ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(device->keyBitmask)), device->keyBitmask); ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(device->absBitmask)), device->absBitmask); ioctl(fd, EVIOCGBIT(EV_REL, sizeof(device->relBitmask)), device->relBitmask); ioctl(fd, EVIOCGBIT(EV_SW, sizeof(device->swBitmask)), device->swBitmask); ioctl(fd, EVIOCGBIT(EV_LED, sizeof(device->ledBitmask)), device->ledBitmask); ioctl(fd, EVIOCGBIT(EV_FF, sizeof(device->ffBitmask)), device->ffBitmask); ioctl(fd, EVIOCGPROP(sizeof(device->propBitmask)), device->propBitmask); // See if this is a keyboard. Ignore everything in the button range except for // joystick and gamepad buttons which are handled like keyboards for the most part. bool haveKeyboardKeys = containsNonZeroByte(device->keyBitmask, 0, sizeof_bit_array(BTN_MISC)) || containsNonZeroByte(device->keyBitmask, sizeof_bit_array(KEY_OK), sizeof_bit_array(KEY_MAX + 1)); bool haveGamepadButtons = containsNonZeroByte(device->keyBitmask, sizeof_bit_array(BTN_MISC), sizeof_bit_array(BTN_MOUSE)) || containsNonZeroByte(device->keyBitmask, sizeof_bit_array(BTN_JOYSTICK), sizeof_bit_array(BTN_DIGI)); if (haveKeyboardKeys || haveGamepadButtons) { device->classes |= INPUT_DEVICE_CLASS_KEYBOARD; } // See if this is a cursor device such as a trackball or mouse. if (test_bit(BTN_MOUSE, device->keyBitmask) && test_bit(REL_X, device->relBitmask) && test_bit(REL_Y, device->relBitmask)) { device->classes |= INPUT_DEVICE_CLASS_CURSOR; } // MStar Android Patch Begin // See if this is a cursor device of cywee company if (test_bit(BTN_MOUSE, device->keyBitmask) && test_bit(REL_X, device->relBitmask) && test_bit(REL_Y, device->relBitmask) && test_bit(REL_RX, device->relBitmask) && test_bit(REL_RY, device->relBitmask)) { device->classes |= INPUT_DEVICE_CLASS_CYWEE_CURSOR; } // MStar Android Patch End // See if this is a touch pad. // Is this a new modern multi-touch driver? if (test_bit(ABS_MT_POSITION_X, device->absBitmask) && test_bit(ABS_MT_POSITION_Y, device->absBitmask)) { // Some joysticks such as the PS3 controller report axes that conflict // with the ABS_MT range. Try to confirm that the device really is // a touch screen. if (test_bit(BTN_TOUCH, device->keyBitmask) || !haveGamepadButtons) { device->classes |= INPUT_DEVICE_CLASS_TOUCH | INPUT_DEVICE_CLASS_TOUCH_MT; } // Is this an old style single-touch driver? } else if (test_bit(BTN_TOUCH, device->keyBitmask) && test_bit(ABS_X, device->absBitmask) && test_bit(ABS_Y, device->absBitmask)) { device->classes |= INPUT_DEVICE_CLASS_TOUCH; } // See if this device is a joystick. // Assumes that joysticks always have gamepad buttons in order to distinguish them // from other devices such as accelerometers that also have absolute axes. if (haveGamepadButtons) { uint32_t assumedClasses = device->classes | INPUT_DEVICE_CLASS_JOYSTICK; for (int i = 0; i <= ABS_MAX; i++) { if (test_bit(i, device->absBitmask) && (getAbsAxisUsage(i, assumedClasses) & INPUT_DEVICE_CLASS_JOYSTICK)) { device->classes = assumedClasses; break; } } } // Check whether this device has switches. for (int i = 0; i <= SW_MAX; i++) { if (test_bit(i, device->swBitmask)) { device->classes |= INPUT_DEVICE_CLASS_SWITCH; break; } } // Check whether this device supports the vibrator. if (test_bit(FF_RUMBLE, device->ffBitmask)) { device->classes |= INPUT_DEVICE_CLASS_VIBRATOR; } // Configure virtual keys. if ((device->classes & INPUT_DEVICE_CLASS_TOUCH)) { // Load the virtual keys for the touch screen, if any. // We do this now so that we can make sure to load the keymap if necessary. status_t status = loadVirtualKeyMapLocked(device); if (!status) { device->classes |= INPUT_DEVICE_CLASS_KEYBOARD; } } // Load the key map. // We need to do this for joysticks too because the key layout may specify axes. status_t keyMapStatus = NAME_NOT_FOUND; if (device->classes & (INPUT_DEVICE_CLASS_KEYBOARD | INPUT_DEVICE_CLASS_JOYSTICK)) { // Load the keymap for the device. keyMapStatus = loadKeyMapLocked(device); } // Configure the keyboard, gamepad or virtual keyboard. if (device->classes & INPUT_DEVICE_CLASS_KEYBOARD) { // Register the keyboard as a built-in keyboard if it is eligible. if (!keyMapStatus && mBuiltInKeyboardId == NO_BUILT_IN_KEYBOARD && isEligibleBuiltInKeyboard(device->identifier, device->configuration, &device->keyMap)) { mBuiltInKeyboardId = device->id; } // 'Q' key support = cheap test of whether this is an alpha-capable kbd if (hasKeycodeLocked(device, AKEYCODE_Q)) { device->classes |= INPUT_DEVICE_CLASS_ALPHAKEY; } // See if this device has a DPAD. if (hasKeycodeLocked(device, AKEYCODE_DPAD_UP) && hasKeycodeLocked(device, AKEYCODE_DPAD_DOWN) && hasKeycodeLocked(device, AKEYCODE_DPAD_LEFT) && hasKeycodeLocked(device, AKEYCODE_DPAD_RIGHT) && hasKeycodeLocked(device, AKEYCODE_DPAD_CENTER)) { device->classes |= INPUT_DEVICE_CLASS_DPAD; } // See if this device has a gamepad. for (size_t i = 0; i < sizeof(GAMEPAD_KEYCODES)/sizeof(GAMEPAD_KEYCODES[0]); i++) { if (hasKeycodeLocked(device, GAMEPAD_KEYCODES[i])) { device->classes |= INPUT_DEVICE_CLASS_GAMEPAD; break; } } // Disable kernel key repeat since we handle it ourselves unsigned int repeatRate[] = {0,0}; if (ioctl(fd, EVIOCSREP, repeatRate)) { ALOGW("Unable to disable kernel key repeat for %s: %s", devicePath, strerror(errno)); } } // If the device isn't recognized as something we handle, don't monitor it. if (device->classes == 0) { ALOGV("Dropping device: id=%d, path='%s', name='%s'", deviceId, devicePath, device->identifier.name.string()); delete device; return -1; } // Determine whether the device is external or internal. if (isExternalDeviceLocked(device)) { device->classes |= INPUT_DEVICE_CLASS_EXTERNAL; } if (device->classes & (INPUT_DEVICE_CLASS_JOYSTICK | INPUT_DEVICE_CLASS_GAMEPAD)) { device->controllerNumber = getNextControllerNumberLocked(device); } // Register with epoll. struct epoll_event eventItem; memset(&eventItem, 0, sizeof(eventItem)); eventItem.events = EPOLLIN; eventItem.data.u32 = deviceId; if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)) { ALOGE("Could not add device fd to epoll instance. errno=%d", errno); delete device; return -1; } // Enable wake-lock behavior on kernels that support it. // TODO: Only need this for devices that can really wake the system. bool usingSuspendBlockIoctl = !ioctl(fd, EVIOCSSUSPENDBLOCK, 1); // Tell the kernel that we want to use the monotonic clock for reporting timestamps // associated with input events. This is important because the input system // uses the timestamps extensively and assumes they were recorded using the monotonic // clock. // // In older kernel, before Linux 3.4, there was no way to tell the kernel which // clock to use to input event timestamps. The standard kernel behavior was to // record a real time timestamp, which isn't what we want. Android kernels therefore // contained a patch to the evdev_event() function in drivers/input/evdev.c to // replace the call to do_gettimeofday() with ktime_get_ts() to cause the monotonic // clock to be used instead of the real time clock. // // As of Linux 3.4, there is a new EVIOCSCLOCKID ioctl to set the desired clock. // Therefore, we no longer require the Android-specific kernel patch described above // as long as we make sure to set select the monotonic clock. We do that here. int clockId = CLOCK_MONOTONIC; bool usingClockIoctl = !ioctl(fd, EVIOCSCLOCKID, &clockId); ALOGI("New device: id=%d, fd=%d, path='%s', name='%s', classes=0x%x, " "configuration='%s', keyLayout='%s', keyCharacterMap='%s', builtinKeyboard=%s, " "usingSuspendBlockIoctl=%s, usingClockIoctl=%s", deviceId, fd, devicePath, device->identifier.name.string(), device->classes, device->configurationFile.string(), device->keyMap.keyLayoutFile.string(), device->keyMap.keyCharacterMapFile.string(), toString(mBuiltInKeyboardId == deviceId), toString(usingSuspendBlockIoctl), toString(usingClockIoctl)); addDeviceLocked(device); return 0; }
struct Device { Device* next; int fd; // may be -1 if device is virtual const int32_t id; const String8 path; const InputDeviceIdentifier identifier; uint32_t classes; uint8_t keyBitmask[(KEY_MAX + 1) / 8]; uint8_t absBitmask[(ABS_MAX + 1) / 8]; uint8_t relBitmask[(REL_MAX + 1) / 8]; uint8_t swBitmask[(SW_MAX + 1) / 8]; uint8_t ledBitmask[(LED_MAX + 1) / 8]; uint8_t ffBitmask[(FF_MAX + 1) / 8]; uint8_t propBitmask[(INPUT_PROP_MAX + 1) / 8]; String8 configurationFile; PropertyMap* configuration; VirtualKeyMap* virtualKeyMap; KeyMap keyMap; sp<KeyCharacterMap> overlayKeyMap; sp<KeyCharacterMap> combinedKeyMap; bool ffEffectPlaying; int16_t ffEffectId; // initially -1 int32_t controllerNumber; int32_t timestampOverrideSec; int32_t timestampOverrideUsec; Device(int fd, int32_t id, const String8& path, const InputDeviceIdentifier& identifier); ~Device(); void close(); inline bool isVirtual() const { return fd < 0; } const sp<KeyCharacterMap>& getKeyCharacterMap() const { if (combinedKeyMap != NULL) { return combinedKeyMap; } return keyMap.keyCharacterMap; } }
// Load the keymap for the device. status_t EventHub::loadKeyMapLocked(Device* device) { return device->keyMap.load(device->identifier, device->configuration); }其实进入loadKeyMapLocked有两各入口,createVirtualKeyboardLocked和openDeviceLocked,后者则是我们上面分析的一条路径。
status_t KeyMap::load(const InputDeviceIdentifier& deviceIdenfifier, const PropertyMap* deviceConfiguration) { // Use the configured key layout if available. if (deviceConfiguration) { String8 keyLayoutName; if (deviceConfiguration->tryGetProperty(String8("keyboard.layout"), keyLayoutName)) { status_t status = loadKeyLayout(deviceIdenfifier, keyLayoutName); if (status == NAME_NOT_FOUND) { ALOGE("Configuration for keyboard device '%s' requested keyboard layout '%s' but " "it was not found.", deviceIdenfifier.name.string(), keyLayoutName.string()); } } String8 keyCharacterMapName; if (deviceConfiguration->tryGetProperty(String8("keyboard.characterMap"), keyCharacterMapName)) { status_t status = loadKeyCharacterMap(deviceIdenfifier, keyCharacterMapName); if (status == NAME_NOT_FOUND) { ALOGE("Configuration for keyboard device '%s' requested keyboard character " "map '%s' but it was not found.", deviceIdenfifier.name.string(), keyLayoutName.string()); } } if (isComplete()) { return OK; } } // Try searching by device identifier. if (probeKeyMap(deviceIdenfifier, String8::empty())) { return OK; } // Fall back on the Generic key map. // TODO Apply some additional heuristics here to figure out what kind of // generic key map to use (US English, etc.) for typical external keyboards. if (probeKeyMap(deviceIdenfifier, String8("Generic"))) { return OK; } // Try the Virtual key map as a last resort. if (probeKeyMap(deviceIdenfifier, String8("Virtual"))) { return OK; } // Give up! ALOGE("Could not determine key map for device '%s' and no default key maps were found!", deviceIdenfifier.name.string()); return NAME_NOT_FOUND; }接着进入loadKeyLayout
status_t KeyMap::loadKeyLayout(const InputDeviceIdentifier& deviceIdentifier, const String8& name) { String8 path(getPath(deviceIdentifier, name, INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_LAYOUT)); if (path.isEmpty()) { return NAME_NOT_FOUND; } status_t status = KeyLayoutMap::load(path, &keyLayoutMap); if (status) { return status; } keyLayoutFile.setTo(path); return OK; }
/* Types of input device configuration files. */ enum InputDeviceConfigurationFileType { INPUT_DEVICE_CONFIGURATION_FILE_TYPE_CONFIGURATION = 0, /* .idc file */ INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_LAYOUT = 1, /* .kl file */ INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_CHARACTER_MAP = 2, /* .kcm file */ };INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_LAYOUT就代表着.kl 类型文件,紧接着进入KeyLayoutMap::load(path, &keyLayoutMap)
status_t KeyLayoutMap::load(const String8& filename, sp<KeyLayoutMap>* outMap) { outMap->clear(); Tokenizer* tokenizer; status_t status = Tokenizer::open(filename, &tokenizer); if (status) { ALOGE("Error %d opening key layout map file %s.", status, filename.string()); } else { sp<KeyLayoutMap> map = new KeyLayoutMap(); if (!map.get()) { ALOGE("Error allocating key layout map."); status = NO_MEMORY; } else { #if DEBUG_PARSER_PERFORMANCE nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC); #endif Parser parser(map.get(), tokenizer); status = parser.parse(); #if DEBUG_PARSER_PERFORMANCE nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime; ALOGD("Parsed key layout map file '%s' %d lines in %0.3fms.", tokenizer->getFilename().string(), tokenizer->getLineNumber(), elapsedTime / 1000000.0); #endif if (!status) { *outMap = map; } } delete tokenizer; } return status; }
status_t KeyLayoutMap::Parser::parse() { while (!mTokenizer->isEof()) { #if DEBUG_PARSER ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(), mTokenizer->peekRemainderOfLine().string()); #endif mTokenizer->skipDelimiters(WHITESPACE); if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') { String8 keywordToken = mTokenizer->nextToken(WHITESPACE); if (keywordToken == "key") { mTokenizer->skipDelimiters(WHITESPACE); status_t status = parseKey(); if (status) return status; } else if (keywordToken == "axis") { mTokenizer->skipDelimiters(WHITESPACE); status_t status = parseAxis(); if (status) return status; } else { ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().string(), keywordToken.string()); return BAD_VALUE; } mTokenizer->skipDelimiters(WHITESPACE); if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') { ALOGE("%s: Expected end of line or trailing comment, got '%s'.", mTokenizer->getLocation().string(), mTokenizer->peekRemainderOfLine().string()); return BAD_VALUE; } } mTokenizer->nextLine(); } return NO_ERROR; }