原址:http://blog.csdn.net/andyhuabing/article/details/7099592
买了个Logitech 的游戏手柄Gamepad F310需要移植到Android系统中,所以花了两天时间详细预研一下需要主要开发的逻辑过程。
1、首先在pc和Linux上测试:
pc上需要安装Logitech公司的驱动程序
针对普通linux平台上安装情况:
ubuntu 下使用游戏手柄:
1, 安装手柄驱动:
# modprobe joydev
2. 安装手柄测试软件:
# sudo apt-get install joystick
3. 测试手柄:
# jstest /dev/js0
或者
# jstest /dev/input/js0
2、使用usb直连方式,首先必须能够检测到设备,使用linux kernel2.6.35版本,配置如下:
make menuconfig
General setup —>
Device Drivers —>
Input device support –>
主要配置如下:
最重要的配置是: JoyStick interface
这里最重要是是X-Box gamepad support
基本上加了如上的一些配置后,插上usb joystick 可以工作了,我的工作log如下:
修改了kernel配置,目前可以正常工作了:
$ usb 1-2.2: new full speed USB device using hiusb-ehci and address 4
usb 1-2.2: New USB device found, idVendor=046d, idProduct=c21d
usb 1-2.2: New USB device strings: Mfr=1, Product=2, SerialNumber=3
usb 1-2.2: Product: Gamepad F310
usb 1-2.2: Manufacturer: Logitech
usb 1-2.2: SerialNumber: 991241BC
input: Generic X-Box pad as /devices/platform/hiusb-ehci.0/usb1/1-2/1-2.2/1-2.2:1.0/input/input1
插上时:
$ ls -l
crw-rw—- root input 13, 65 1970-01-02 08:02 event1
crw-rw—- root input 13, 0 1970-01-02 08:02 js0
crw-rw—- root input 13, 64 1970-01-01 08:00 event0
crw-rw—- root input 13, 32 1970-01-01 08:00 mouse0
crw-rw—- root input 13, 63 1970-01-01 08:00 mice
拔掉以后:
$ ls -l
crw-rw—- root input 13, 64 1970-01-01 08:00 event0
crw-rw—- root input 13, 32 1970-01-01 08:00 mouse0
crw-rw—- root input 13, 63 1970-01-01 08:00 mice
明显多了两个设备结点js0及event1 ,这此就是针对joystick设备的读取结点名称
在android中可以使用getevent使用getevent可以最直接地获得按键的扫描码,对于Android系统中用户输入设备的调试,可以从源头确定底层输入设备传递上来的信息。
代码在/system/core/toolbox/getevent.c代码中
# getevent
getevent
add device 1: /dev/input/event1
name: "Generic X-Box pad"
could not get driver version for /dev/input/js0, Invalid argument
add device 2: /dev/input/event0
name: "Hi3716_keypad"
could not get driver version for /dev/input/mouse0, Not a typewriter
could not get driver version for /dev/input/mice, Not a typewriter
node type code value
EV_KEY + key code + up/down
/dev/input/event1: 0001 0133 00000001 // X button
/dev/input/event1: 0000 0000 00000000
/dev/input/event1: 0001 0133 00000000
/dev/input/event1: 0000 0000 00000000
/dev/input/event1: 0001 0134 00000001 // Y button
/dev/input/event1: 0000 0000 00000000
/dev/input/event1: 0001 0134 00000000
/dev/input/event1: 0000 0000 00000000
/dev/input/event1: 0001 0131 00000001 // E button
/dev/input/event1: 0000 0000 00000000
/dev/input/event1: 0001 0131 00000000
/dev/input/event1: 0000 0000 00000000
/dev/input/event1: 0001 0130 00000001 // A button
/dev/input/event1: 0000 0000 00000000
/dev/input/event1: 0001 0130 00000000
/dev/input/event1: 0000 0000 00000000
/dev/input/event1: 0001 0116 00000001 // Back button
/dev/input/event1: 0000 0000 00000000
/dev/input/event1: 0001 0116 00000000
/dev/input/event1: 0000 0000 00000000
dev/input/event1: 0001 013b 00000001 // Start button
dev/input/event1: 0000 0000 00000000
dev/input/event1: 0001 013b 00000000
dev/input/event1: 0000 0000 00000000
EV_ABS + scan code + axis
/dev/input/event1: 0003 0001 ffff8000 // 上
/dev/input/event1: 0000 0000 00000000
/dev/input/event1: 0003 0001 ffffff7f
/dev/input/event1: 0000 0000 00000000
/dev/input/event1: 0003 0001 00007fff // 下
/dev/input/event1: 0000 0000 00000000
/dev/input/event1: 0003 0001 ffffff7f
/dev/input/event1: 0000 0000 00000000
/dev/input/event1: 0003 0000 ffff8000 // 左
/dev/input/event1: 0000 0000 00000000
/dev/input/event1: 0003 0000 00000080
/dev/input/event1: 0000 0000 00000000
/dev/input/event1: 0003 0000 00007fff // 右
/dev/input/event1: 0000 0000 00000000
/dev/input/event1: 0003 0000 00000080
/dev/input/event1: 0000 0000 00000000
简音的测试case代码:
[cpp] view plaincopy print?
- #include <linux/input.h>
- #include <linux/joystick.h>
- int main(void) {
- int js_fd;
- struct js_event js;
- int n, type = 0;
- int axis_value, button_value;
- int number_of_axis, number_of_buttons;
- js_fd = open("/dev/input/js0", O_RDONLY); //打开 设备文件
- if (js_fd == NULL) {
- printf("open joystick device failed");
- return -1;
- }
- while (1) {
- n = read(js_fd, &js, sizeof(struct js_event));
- if (n < 0 || n != sizeof(struct js_event)) {
- printf("read data failed");
- usleep(10 * 1000);
- continue;
- }
- type = js.type & (~JS_EVENT_INIT);
- switch (type) {
- case JS_EVENT_AXIS:
- number_of_axis = js.number;
- axis_value = js.value;
- printf("number:%2d:value:%6d\n", number_of_axis, axis_value);
- break;
- case JS_EVENT_BUTTON:
- number_of_buttons = js.number;
- button_value = js.value;
- printf("number:%2d:value:%2d\n", number_of_buttons, button_value);
- break;
- }
- usleep(10 * 1000);
- }
- return 0;
- }
3、框架代码修改
可参考android4.0代码,这个版本已经完整的支持这个功能了,移植主要的eventhub.cpp文件及inputreader中的JoystickInputMapper 即可:
如下:
// 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;
}
}
}
一般的按键button走KeyboardInputMapper流程,只有对于EV_ABS的Axis() 使用这个JoystickInputMapper处理。
补充说明:
1、获取手柄的一些额外参数:
ioctl(fd, JSIOCGAXES, &number_of_axes); //游戏轴数目,默认情况下轴0,1,2代表x轴,y轴,z轴
ioctl(fd, JSIOCGBUTTONS, &number_of_btns); // 游戏按扭数目
ioctl(fd, JSIOCGNAME(sizeof(js_name_str)), js_name_str); // 游戏手柄名称
2、数值,读取jsX时轴值:
轴值范围: -32767 ~ 32767
比如:
[cpp] view plaincopy print?
- int *axis = NULL;
- int *button = NULL;
- struct js_event jse;
- axis = (int*)calloc(number_of_axes,sizeof(int));
- button = (int*)calloc(number_of_btns,sizeof(int);
- read(fd,&jse,sizeof(struct js_event));
- switch(jse.type & ~JS_EVENT_INIT)
- {
- case JS_EVENT_AXIS:
- if ((jse->number & 1) == 0) {
- axes[jse.number / 2].x = jse.value;
- }
- else {
- axes[jse.number / 2].y = jse.value;
- }
- break;
- case JS_EVENT_BUTTON:
- if (jse->value) {
- buttons_state |= (1 << jse->number);
- }
- else {
- buttons_state &= ~(1 << jse->number);
- }
- break;
- default:
- break;
- }
3、读取eventX — 由joystick设备产生的数值:
EV_ABS + code + axis
分析如下:
首先表示其type = EV_ABS 绝对值 , code值代表x轴(0),y轴(1),z轴值(2),value代表坐标值,这里会涉及到相应的值转换问题,走AMOTION_EVENT_ACTION_MOVE路线。
核心代码如下:
[cpp] view plaincopy print?
- <span style="font-size:18px;"> switch (rawEvent->type) {
- case EV_ABS: {
- ssize_t index = mAxes.indexOfKey(rawEvent->scanCode);
- if (index >= 0) {
- Axis& axis = mAxes.editValueAt(index);
- float newValue, highNewValue;
- switch (axis.axisInfo.mode) {
- case AxisInfo::MODE_INVERT:
- newValue = (axis.rawAxisInfo.maxValue – rawEvent->value)
- * axis.scale + axis.offset;
- highNewValue = 0.0f;
- break;
- case AxisInfo::MODE_SPLIT:
- if (rawEvent->value < axis.axisInfo.splitValue) {
- newValue = (axis.axisInfo.splitValue – rawEvent->value)
- * axis.scale + axis.offset;
- highNewValue = 0.0f;
- } else if (rawEvent->value > axis.axisInfo.splitValue) {
- newValue = 0.0f;
- highNewValue = (rawEvent->value – axis.axisInfo.splitValue)
- * axis.highScale + axis.highOffset;
- } else {
- newValue = 0.0f;
- highNewValue = 0.0f;
- }
- break;
- default:
- newValue = rawEvent->value * axis.scale + axis.offset;
- highNewValue = 0.0f;
- break;
- }
- axis.newValue = newValue;
- axis.highNewValue = highNewValue;
- }
- break;
- }
- case EV_SYN:
- switch (rawEvent->scanCode) {
- case SYN_REPORT:
- sync(rawEvent->when, false /*force*/);
- break;
- }
- break;
- }
- }</span>