(一) 虚拟按键的描述可以见 韩超和梁泉的 《Android系统级深入开发——移植与调试》的第八章:

虚拟按键(Virtual Key)是Eclair版本开始增加的新特性。Virtual Key的功能是利用触摸屏,模拟按键发生的事件,这样就可以利用触摸屏的边缘,实现一些可以自定义的按键效果。

虚拟按键的实现效果如图8-5所示。

图8-5  虚拟按键的实现效果

在Android系统中,触摸屏设备发送的是RawInputEvent(原始输入事件),而按键发送的是KeyEvent(按键事件)。KeyEvent直接发送给应用程序层,RawInputEvent在Android的Java框架中被转换成MotionEvent发送给应用程序层。

在Android系统中虚拟按键的实现方法是:在某种情况下,将RawInputEvent转换成KeyEvent。

frameworks/base/services/Java/com/android/server目录中的InputDevice.Java文件负责处理虚拟按键的主要文件。

虚拟按键的处理相对简单,需要根据以下文件对虚拟按键的内容进行配置:

/sys/board_properties/virtualkeys.{devicename}

在InputDevice.Java文件中通过readVirtualKeys,对进行消息的转化。根据配置文件将RawInputEvent转换成按键相关的内容。

virtualkeys.{devicename}是虚拟按键的适配文件,需要在目标文件系统的/sys/board_ properties/目录中。

虚拟按键配置文件的格式如下所示:

0x1:扫描码:X:Y:W:H:0x1: ……

例如,在MSM的mahimahi平台上查看虚拟按键的配置文件如下所示:

# cat /sys/board_properties/virtualkeys.synaptics-rmi-touchscreen

0x01:158:55:835:90:55:0x01:139:172:835:125:55:0x01:102:298:835:115:55:0x01:217:412:835:95:55

由此可见,其中定义了4个区域的虚拟按键,它们的Y坐标相同,可见4个按键的矩形区域位于水平的一排。其转换的扫描码分别为158,139,102,217,分别对应于BACK(返回),MENU(菜单),HOME(主界面),SEARCH(搜索)这4个按键。

另外一个系统的虚拟按键的配置文件如下所示:

$ cat /sys/board_properties/virtualkeys.qtouch-touchscreen

0x01:139:90:936:116:104:0x01:102:252:936:116:104:0x01:158:402:936:116:104

其转换的扫描码分别为:139,102,158,分别对应于MENU(菜单),HOME(主界面),BACK(返回)这3个按键。

提示:使用虚拟按键转换成为的是按键的扫描码,不是按键码,因此依然需要经过按键布局文件的转化才能得到按键码。

(二)如果按照韩超和梁泉的《Android系统级深入开发——移植与调试》的第八章描述虚拟按键的实现过程如下:

1.硬件分析
我所使用的触摸屏分辨率是1158*768,可视区域大小是1024*768(这也是LCD屏的大小),在触摸屏两侧总有5个按键。
 
2.触摸屏按键驱动的修改
既然可视区域在触摸屏中间部位,因此需要在触摸屏驱动中修改input_set_abs_params()函数中的参数

  1. input_set_abs_params(input_dev, ABS_MT_POSITION_X, 61, 1085, 0, 0);
  2. input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, SCREEN_MAX_Y, 0, 0);

其中61是可视区域左侧x轴左边坐标,1085是右侧的。

3.Android框架层

Android上层通过读取触摸屏坐标并经过转算后来识别定义好的虚拟按键,代码位于frameworks/base/services/java/com/android/server/KeyInputQueue.java中:

static class Virtualkey{}是负责按键定位的方法;

private void readVirtualKeys(String deviceName)负责读取sys文件,这是最重要的代码,也是与底层sys文件系统沟通的桥梁,它会读取/sys/board_properties/virtualkeys.{deviceName}文件,deviceName一定要与触摸屏设备名称一致,不然会找不到指定的sys文件。

4.sys文件系统

前面讲到了readVirtualKeys会读取sys文件,这个sys文件就是定义虚拟按键的坐标以及键值,它的协议格式是一段字符串,每个按键有六项分别用冒号分割,按键按键之间也是用冒号分割,标准格式是:

键类型:键值:按键区域中心x坐标:按键区域中心y坐标:按键区域宽:按键区域高

加载触摸屏以及创建sys文件的代码:

[cpp]  view plain copy
  1. <span style="font-size:13px;">#ifdef VIRTUAL_KEYS
  2. static ssize_t virtual_keys_show(struct kobject *kobj,
  3. struct kobj_attribute *attr, char *buf)
  4. {
  5. if (1) {
  6. return sprintf(buf,
  7. __stringify(EV_KEY) ":" __stringify(KEY_VOLUMEUP) ":1030:370:30:30"
  8. ":" __stringify(EV_KEY) ":" __stringify(KEY_VOLUMEDOWN) ":1030:470:30:30"
  9. ":" __stringify(EV_KEY) ":" __stringify(KEY_BACK) ":1030:18:30:30"
  10. ":" __stringify(EV_KEY) ":" __stringify(KEY_HOME) ":1030:136:30:30"
  11. ":" __stringify(EV_KEY) ":" __stringify(KEY_MENU) ":1030:236:30:30"
  12. "\n");
  13. } else {
  14. }
  15. }
  16. static struct kobj_attribute virtual_keys_attr = {
  17. .attr = {
  18. .name = "virtualkeys.xxxx",
  19. .mode = S_IRUGO,
  20. },
  21. .show = &virtual_keys_show,
  22. };
  23. static struct attribute *properties_attrs[] = {
  24. &virtual_keys_attr.attr,
  25. NULL
  26. };
  27. static struct attribute_group properties_attr_group = {
  28. .attrs = properties_attrs,
  29. };
  30. static void virtual_keys_init(void)
  31. {
  32. int ret;
  33. struct kobject *properties_kobj;
  34. properties_kobj = kobject_create_and_add("board_properties", NULL);
  35. if (properties_kobj)
  36. ret = sysfs_create_group(properties_kobj,
  37. &properties_attr_group);
  38. if (!properties_kobj || ret)
  39. pr_err("failed to create board_properties\n");
  40. }
  41. #endif
  42. </span>

其中.name = "virtualkeys.xxxx"的xxxx就是触摸屏设备名称,也就是前面说到的{deviceName},virtual_keys_init()函数可以在触摸屏probe函数中调用。另外,我将可视区域左侧的两侧按键移到了右侧实现,因此五个按键区域中心x坐标都是一样,这部分要在触摸屏驱动增加x轴坐标调整,这部分我就不再说明。以上步骤完成后可以使用 cat /sys/board_properties/virtualkeys.{deviceName}查看虚拟按键的配置文件,并试试按下触摸屏上按键是否有反应,如果坐标不正确还要进行耐心地校准。

  1. 具体的可以去HTC网站(http://htcdev.com/devcenter/downloads)上下载HTC手机的linux源码,HTC很多款手机的BACK,MENU,HOME,SEARCH电容屏虚拟按键都是采用这种方式实现的。
  1. (三)但是我用的是四线电阻触摸屏,用上面的方式好像没有任何反应,所以我采用最直接的方式用input_event发送按键消息,就是在触摸屏处理芯片TSC2007驱动中当读到一定范围内的触摸事件就发送按键消息:这种方式只要修改TSC2007驱动的几个地方:
  1. 1.定义全局局部变量用于记录是否有虚拟按键按下

    [cpp]  view plain copy
    1. static int backkeydown=0;
    2. static int homekeydown=0;
    3. static int menukeydown=0;

    2..在prope函数中添加

    [cpp]  view plain copy
    1. set_bit(EV_SYN, input_dev->evbit);
    2. set_bit(KEY_HOME, input_dev->keybit);
    3. //set_bit(KEY_SEARCH, input_dev->keybit);
    4. set_bit(KEY_BACK, input_dev->keybit);
    5. set_bit(KEY_MENU, input_dev->keybit);

    3.在中断处理work里面添加按键按下消息

    [cpp]  view plain copy
    1. if((tc.y>=81)&&(tc.y<=181))
    2. {
    3. if((tc.x>=2711)&&(tc.x<=2832))
    4. {
    5. if(backkeydown==0)
    6. {
    7. input_event(input, EV_KEY,KEY_BACK, 1);
    8. backkeydown=1;
    9. //printk("back key down\n");
    10. }
    11. }
    12. else if((tc.x>=1891)&&(tc.x<=1933))
    13. {
    14. if(homekeydown==0)
    15. {
    16. input_event(input, EV_KEY,KEY_HOME, 1);
    17. homekeydown=1;
    18. //printk("home key down\n");
    19. }
    20. }
    21. else if((tc.x>=1088)&&(tc.x<=1143))
    22. {
    23. if(menukeydown==0)
    24. {
    25. input_event(input, EV_KEY,KEY_MENU, 1);
    26. menukeydown=1;
    27. //printk("menu key down\n");
    28. }
    29. }
    30. }

4.在tsc2007_send_up_event函数中添加按键释放消息

[cpp]  view plain copy
  1. if(backkeydown==1)
  2. {
  3. backkeydown=0;
  4. input_event(input, EV_KEY, KEY_BACK, 0);
  5. //printk("back key up\n");
  6. }
  7. if(homekeydown==1)
  8. {
  9. homekeydown=0;
  10. input_event(input, EV_KEY, KEY_HOME, 0);
  11. //printk("home key up\n");
  12. }
  13. if(menukeydown==1)
  14. {
  15. menukeydown=0;
  16. input_event(input, EV_KEY, KEY_MENU, 0);
  17. //printk("menu key up\n");
  18. }

整个修改后的TSC2007驱动如下:

[cpp]  view plain copy
  1. /*
  2. * drivers/input/touchscreen/tsc2007.c
  3. *
  4. * Copyright (c) 2008 MtekVision Co., Ltd.
  5. *  Kwangwoo Lee <kwlee@mtekvision.com>
  6. *
  7. * Using code from:
  8. *  - ads7846.c
  9. *  Copyright (c) 2005 David Brownell
  10. *  Copyright (c) 2006 Nokia Corporation
  11. *  - corgi_ts.c
  12. *  Copyright (C) 2004-2005 Richard Purdie
  13. *  - omap_ts.[hc], ads7846.h, ts_osk.c
  14. *  Copyright (C) 2002 MontaVista Software
  15. *  Copyright (C) 2004 Texas Instruments
  16. *  Copyright (C) 2005 Dirk Behme
  17. *
  18. *  This program is free software; you can redistribute it and/or modify
  19. *  it under the terms of the GNU General Public License version 2 as
  20. *  published by the Free Software Foundation.
  21. */
  22. #include <linux/module.h>
  23. #include <linux/slab.h>
  24. #include <linux/input.h>
  25. #include <linux/interrupt.h>
  26. #include <linux/i2c.h>
  27. #include <linux/i2c/tsc2007.h>
  28. #define TS_POLL_DELAY           1 /* ms delay between samples */
  29. #define TS_POLL_PERIOD          1 /* ms delay between samples */
  30. #define TSC2007_MEASURE_TEMP0       (0x0 << 4)
  31. #define TSC2007_MEASURE_AUX     (0x2 << 4)
  32. #define TSC2007_MEASURE_TEMP1       (0x4 << 4)
  33. #define TSC2007_ACTIVATE_XN     (0x8 << 4)
  34. #define TSC2007_ACTIVATE_YN     (0x9 << 4)
  35. #define TSC2007_ACTIVATE_YP_XN      (0xa << 4)
  36. #define TSC2007_SETUP           (0xb << 4)
  37. #define TSC2007_MEASURE_X       (0xc << 4)
  38. #define TSC2007_MEASURE_Y       (0xd << 4)
  39. #define TSC2007_MEASURE_Z1      (0xe << 4)
  40. #define TSC2007_MEASURE_Z2      (0xf << 4)
  41. #define TSC2007_POWER_OFF_IRQ_EN    (0x0 << 2)
  42. #define TSC2007_ADC_ON_IRQ_DIS0     (0x1 << 2)
  43. #define TSC2007_ADC_OFF_IRQ_EN      (0x2 << 2)
  44. #define TSC2007_ADC_ON_IRQ_DIS1     (0x3 << 2)
  45. #define TSC2007_12BIT           (0x0 << 1)
  46. #define TSC2007_8BIT            (0x1 << 1)
  47. #define MAX_12BIT           ((1 << 12) - 1)
  48. #define ADC_ON_12BIT    (TSC2007_12BIT | TSC2007_ADC_ON_IRQ_DIS0)
  49. #define READ_Y      (ADC_ON_12BIT | TSC2007_MEASURE_Y)
  50. #define READ_Z1     (ADC_ON_12BIT | TSC2007_MEASURE_Z1)
  51. #define READ_Z2     (ADC_ON_12BIT | TSC2007_MEASURE_Z2)
  52. #define READ_X      (ADC_ON_12BIT | TSC2007_MEASURE_X)
  53. #define PWRDOWN     (TSC2007_12BIT | TSC2007_POWER_OFF_IRQ_EN)
  54. static int backkeydown=0;
  55. static int homekeydown=0;
  56. static int menukeydown=0;
  57. struct ts_event {
  58. u16 x;
  59. u16 y;
  60. u16 z1, z2;
  61. };
  62. struct tsc2007 {
  63. struct input_dev    *input;
  64. char            phys[32];
  65. struct delayed_work work;
  66. struct i2c_client   *client;
  67. u16         model;
  68. u16         x_plate_ohms;
  69. bool            pendown;
  70. int         irq;
  71. int         (*get_pendown_state)(void);
  72. void            (*clear_penirq)(void);
  73. };
  74. static inline int tsc2007_xfer(struct tsc2007 *tsc, u8 cmd)
  75. {
  76. s32 data;
  77. u16 val;
  78. data = i2c_smbus_read_word_data(tsc->client, cmd);
  79. if (data < 0) {
  80. dev_err(&tsc->client->dev, "i2c io error: %d\n", data);
  81. return data;
  82. }
  83. /* The protocol and raw data format from i2c interface:
  84. * S Addr Wr [A] Comm [A] S Addr Rd [A] [DataLow] A [DataHigh] NA P
  85. * Where DataLow has [D11-D4], DataHigh has [D3-D0 << 4 | Dummy 4bit].
  86. */
  87. val = swab16(data) >> 4;
  88. dev_dbg(&tsc->client->dev, "data: 0x%x, val: 0x%x\n", data, val);
  89. return val;
  90. }
  91. static void tsc2007_read_values(struct tsc2007 *tsc, struct ts_event *tc)
  92. {
  93. /* y- still on; turn on only y+ (and ADC) */
  94. tc->y = tsc2007_xfer(tsc, READ_Y);
  95. /* turn y- off, x+ on, then leave in lowpower */
  96. tc->x = tsc2007_xfer(tsc, READ_X);
  97. /* turn y+ off, x- on; we'll use formula #1 */
  98. tc->z1 = tsc2007_xfer(tsc, READ_Z1);
  99. tc->z2 = tsc2007_xfer(tsc, READ_Z2);
  100. //printk("x=%d,y=%d\n",tc->x,tc->y);
  101. /* Prepare for next touch reading - power down ADC, enable PENIRQ */
  102. tsc2007_xfer(tsc, PWRDOWN);
  103. }
  104. static u32 tsc2007_calculate_pressure(struct tsc2007 *tsc, struct ts_event *tc)
  105. {
  106. u32 rt = 0;
  107. /* range filtering */
  108. if (tc->x == MAX_12BIT)
  109. tc->x = 0;
  110. if (likely(tc->x && tc->z1)) {
  111. /* compute touch pressure resistance using equation #1 */
  112. rt = tc->z2 - tc->z1;
  113. rt *= tc->x;
  114. rt *= tsc->x_plate_ohms;
  115. rt /= tc->z1;
  116. rt = (rt + 2047) >> 12;
  117. }
  118. return rt;
  119. }
  120. static void tsc2007_send_up_event(struct tsc2007 *tsc)
  121. {
  122. struct input_dev *input = tsc->input;
  123. dev_dbg(&tsc->client->dev, "UP\n");
  124. if(backkeydown==1)
  125. {
  126. backkeydown=0;
  127. input_event(input, EV_KEY, KEY_BACK, 0);
  128. //printk("back key up\n");
  129. }
  130. if(homekeydown==1)
  131. {
  132. homekeydown=0;
  133. input_event(input, EV_KEY, KEY_HOME, 0);
  134. //printk("home key up\n");
  135. }
  136. if(menukeydown==1)
  137. {
  138. menukeydown=0;
  139. input_event(input, EV_KEY, KEY_MENU, 0);
  140. //printk("menu key up\n");
  141. }
  142. input_report_key(input, BTN_TOUCH, 0);
  143. input_report_abs(input, ABS_PRESSURE, 0);
  144. input_sync(input);
  145. }
  146. static void tsc2007_work(struct work_struct *work)
  147. {
  148. struct tsc2007 *ts =
  149. container_of(to_delayed_work(work), struct tsc2007, work);
  150. struct ts_event tc;
  151. u32 rt;
  152. /*
  153. * NOTE: We can't rely on the pressure to determine the pen down
  154. * state, even though this controller has a pressure sensor.
  155. * The pressure value can fluctuate for quite a while after
  156. * lifting the pen and in some cases may not even settle at the
  157. * expected value.
  158. *
  159. * The only safe way to check for the pen up condition is in the
  160. * work function by reading the pen signal state (it's a GPIO
  161. * and IRQ). Unfortunately such callback is not always available,
  162. * in that case we have rely on the pressure anyway.
  163. */
  164. if (ts->get_pendown_state) {
  165. if (unlikely(!ts->get_pendown_state())) {
  166. tsc2007_send_up_event(ts);
  167. ts->pendown = false;
  168. goto out;
  169. }
  170. dev_dbg(&ts->client->dev, "pen is still down\n");
  171. }
  172. tsc2007_read_values(ts, &tc);
  173. rt = tsc2007_calculate_pressure(ts, &tc);
  174. if (rt > MAX_12BIT) {
  175. /*
  176. * Sample found inconsistent by debouncing or pressure is
  177. * beyond the maximum. Don't report it to user space,
  178. * repeat at least once more the measurement.
  179. */
  180. dev_dbg(&ts->client->dev, "ignored pressure %d\n", rt);
  181. goto out;
  182. }
  183. if (rt) {
  184. struct input_dev *input = ts->input;
  185. if((tc.y>=81)&&(tc.y<=181))
  186. {
  187. if((tc.x>=2711)&&(tc.x<=2832))
  188. {
  189. if(backkeydown==0)
  190. {
  191. input_event(input, EV_KEY,KEY_BACK, 1);
  192. backkeydown=1;
  193. //printk("back key down\n");
  194. }
  195. }
  196. else if((tc.x>=1891)&&(tc.x<=1933))
  197. {
  198. if(homekeydown==0)
  199. {
  200. input_event(input, EV_KEY,KEY_HOME, 1);
  201. homekeydown=1;
  202. //printk("home key down\n");
  203. }
  204. }
  205. else if((tc.x>=1088)&&(tc.x<=1143))
  206. {
  207. if(menukeydown==0)
  208. {
  209. input_event(input, EV_KEY,KEY_MENU, 1);
  210. menukeydown=1;
  211. //printk("menu key down\n");
  212. }
  213. }
  214. }
  215. if (!ts->pendown) {
  216. dev_dbg(&ts->client->dev, "DOWN\n");
  217. input_report_key(input, BTN_TOUCH, 1);
  218. ts->pendown = true;
  219. }
  220. input_report_abs(input, ABS_X, tc.x);
  221. input_report_abs(input, ABS_Y, tc.y);
  222. input_report_abs(input, ABS_PRESSURE, rt);
  223. input_sync(input);
  224. dev_dbg(&ts->client->dev, "point(%4d,%4d), pressure (%4u)\n",
  225. tc.x, tc.y, rt);
  226. } else if (!ts->get_pendown_state && ts->pendown) {
  227. /*
  228. * We don't have callback to check pendown state, so we
  229. * have to assume that since pressure reported is 0 the
  230. * pen was lifted up.
  231. */
  232. tsc2007_send_up_event(ts);
  233. ts->pendown = false;
  234. }
  235. out:
  236. if (ts->pendown)
  237. schedule_delayed_work(&ts->work,
  238. msecs_to_jiffies(TS_POLL_PERIOD));
  239. else
  240. enable_irq(ts->irq);
  241. }
  242. static irqreturn_t tsc2007_irq(int irq, void *handle)
  243. {
  244. struct tsc2007 *ts = handle;
  245. if (!ts->get_pendown_state || likely(ts->get_pendown_state())) {
  246. disable_irq_nosync(ts->irq);
  247. schedule_delayed_work(&ts->work,
  248. msecs_to_jiffies(TS_POLL_DELAY));
  249. }
  250. if (ts->clear_penirq)
  251. ts->clear_penirq();
  252. return IRQ_HANDLED;
  253. }
  254. static void tsc2007_free_irq(struct tsc2007 *ts)
  255. {
  256. free_irq(ts->irq, ts);
  257. if (cancel_delayed_work_sync(&ts->work)) {
  258. /*
  259. * Work was pending, therefore we need to enable
  260. * IRQ here to balance the disable_irq() done in the
  261. * interrupt handler.
  262. */
  263. enable_irq(ts->irq);
  264. }
  265. }
  266. static int __devinit tsc2007_probe(struct i2c_client *client,
  267. const struct i2c_device_id *id)
  268. {
  269. struct tsc2007 *ts;
  270. struct tsc2007_platform_data *pdata = pdata = client->dev.platform_data;
  271. struct input_dev *input_dev;
  272. int err;
  273. if (!pdata) {
  274. dev_err(&client->dev, "platform data is required!\n");
  275. return -EINVAL;
  276. }
  277. if (!i2c_check_functionality(client->adapter,
  278. I2C_FUNC_SMBUS_READ_WORD_DATA))
  279. return -EIO;
  280. ts = kzalloc(sizeof(struct tsc2007), GFP_KERNEL);
  281. input_dev = input_allocate_device();
  282. if (!ts || !input_dev) {
  283. err = -ENOMEM;
  284. goto err_free_mem;
  285. }
  286. ts->client = client;
  287. ts->irq = client->irq;
  288. ts->input = input_dev;
  289. INIT_DELAYED_WORK(&ts->work, tsc2007_work);
  290. ts->model             = pdata->model;
  291. ts->x_plate_ohms      = pdata->x_plate_ohms;
  292. ts->get_pendown_state = pdata->get_pendown_state;
  293. ts->clear_penirq      = pdata->clear_penirq;
  294. snprintf(ts->phys, sizeof(ts->phys),
  295. "%s/input0", dev_name(&client->dev));
  296. input_dev->name = "TSC2007";
  297. input_dev->phys = ts->phys;
  298. input_dev->id.vendor = 0x0001;
  299. input_dev->id.product = 0x0001;
  300. input_dev->id.version = 0x0100;
  301. input_dev->id.bustype = BUS_I2C;
  302. input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
  303. input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
  304. set_bit(EV_SYN, input_dev->evbit);
  305. set_bit(KEY_HOME, input_dev->keybit);
  306. //set_bit(KEY_SEARCH, input_dev->keybit);
  307. set_bit(KEY_BACK, input_dev->keybit);
  308. set_bit(KEY_MENU, input_dev->keybit);
  309. input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, 0, 0);
  310. input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0);
  311. input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, 0, 0);
  312. if (pdata->init_platform_hw)
  313. pdata->init_platform_hw();
  314. err = request_irq(ts->irq, tsc2007_irq, 0,
  315. client->dev.driver->name, ts);
  316. if (err < 0) {
  317. dev_err(&client->dev, "irq %d busy?\n", ts->irq);
  318. goto err_free_mem;
  319. }
  320. /* Prepare for touch readings - power down ADC and enable PENIRQ */
  321. err = tsc2007_xfer(ts, PWRDOWN);
  322. if (err < 0)
  323. goto err_free_irq;
  324. err = input_register_device(input_dev);
  325. if (err)
  326. goto err_free_irq;
  327. i2c_set_clientdata(client, ts);
  328. return 0;
  329. err_free_irq:
  330. tsc2007_free_irq(ts);
  331. if (pdata->exit_platform_hw)
  332. pdata->exit_platform_hw();
  333. err_free_mem:
  334. input_free_device(input_dev);
  335. kfree(ts);
  336. return err;
  337. }
  338. static int __devexit tsc2007_remove(struct i2c_client *client)
  339. {
  340. struct tsc2007  *ts = i2c_get_clientdata(client);
  341. struct tsc2007_platform_data *pdata = client->dev.platform_data;
  342. tsc2007_free_irq(ts);
  343. if (pdata->exit_platform_hw)
  344. pdata->exit_platform_hw();
  345. input_unregister_device(ts->input);
  346. kfree(ts);
  347. return 0;
  348. }
  349. static struct i2c_device_id tsc2007_idtable[] = {
  350. { "tsc2007", 0 },
  351. { }
  352. };
  353. MODULE_DEVICE_TABLE(i2c, tsc2007_idtable);
  354. static struct i2c_driver tsc2007_driver = {
  355. .driver = {
  356. .owner  = THIS_MODULE,
  357. .name   = "tsc2007"
  358. },
  359. .id_table   = tsc2007_idtable,
  360. .probe      = tsc2007_probe,
  361. .remove     = __devexit_p(tsc2007_remove),
  362. };
  363. static int __init tsc2007_init(void)
  364. {
  365. return i2c_add_driver(&tsc2007_driver);
  366. }
  367. static void __exit tsc2007_exit(void)
  368. {
  369. i2c_del_driver(&tsc2007_driver);
  370. }
  371. module_init(tsc2007_init);
  372. module_exit(tsc2007_exit);
  373. MODULE_AUTHOR("Kwangwoo Lee <kwlee@mtekvision.com>");
  374. MODULE_DESCRIPTION("TSC2007 TouchScreen Driver");
  375. MODULE_LICENSE("GPL");

实践证明上述方式完全可行,这里我没有指定TSC2007的kl和kcm文件,android系统会自动选择默认的\android\sdk\emulator\keymaps\目录下的qwerty.kl和qwerty.kcm文件,如果你的系统不能正常收到按键消息,你首先可以用android的getevent看看驱动是否能正常发送按键消息给上层,如果能正常收到触摸屏驱动发送的按键消息,上层android系统不能收到的原因就是kl和kcm文件不对。

5.另外附上加载TSC2007驱动的代码
[cpp]  view plain copy
  1. /* TouchScreen */
  2. #define IRQ1 1
  3. unsigned int tsc2007_int;
  4. unsigned int tsc2007_irq_no;
  5. static int ts_get_pendown_state(void)
  6. {
  7. int result=!(imapx_gpio_getpin(tsc2007_int, IG_NORMAL));
  8. //printk("%d\n",result);
  9. return result;
  10. }
  11. static int ts_init(void)
  12. {
  13. //printk("====ts_init===\n");
  14. tsc2007_int  = __imapx_name_to_gpio(CONFIG_TP_TSC2007_INT);
  15. if(tsc2007_int == IMAPX_GPIO_ERROR) {
  16. printk(KERN_ERR "failed to get tsc2007_int pin.\n");
  17. return -1;
  18. }
  19. tsc2007_irq_no = imapx_gpio_to_irq(tsc2007_int);
  20. imapx_gpio_setcfg(tsc2007_int, IG_INPUT, IG_NORMAL);
  21. imapx_gpio_setirq(tsc2007_int, FILTER_MAX, IG_FALL, 1);
  22. return 0;
  23. }
  24. struct tsc2007_platform_data tsc2007_info = {
  25. .model          = 2007,
  26. .x_plate_ohms       = 180,
  27. .get_pendown_state  = ts_get_pendown_state,
  28. .init_platform_hw   = ts_init,
  29. };
  30. static struct i2c_board_info ts_i2c_clients = {
  31. I2C_BOARD_INFO("tsc2007", 0x48),
  32. .type       = "tsc2007",
  33. .platform_data  = &tsc2007_info,
  34. .irq        = IRQ1,
  35. };
  36. static int __init imap_arch_init(void)
  37. {
  38. int ret;
  39. // do the correct init for cpu
  40. if (cpu == NULL)
  41. panic("imap_arch_init: NULL cpu\n");
  42. ret = (cpu->init)();
  43. if (ret != 0)
  44. return ret;
  45. ret = platform_add_devices(imap_uart_devs, nr_uarts);
  46. if (ret != 0)
  47. return ret;
  48. /*瑙︽懜灞?/
  49. i2c_register_board_info(1, &ts_i2c_clients, 1);
  50. /*瑙︽懜灞忚櫄鎷熸寜閿?/
  51. //virtual_keys_init();
  52. printk(KERN_INFO "leaving imap_arch_init\n");
  53. return ret;
  54. }
----------------------------------------------------------------------------------------------------------------------------------------

电容屏/电阻屏Android虚拟按键实现的两种方法相关推荐

  1. android 图片叠加xml,Android实现图片叠加效果的两种方法

    本文实例讲述了Android实现图片叠加效果的两种方法.,具体如下: 效果图: 第一种: 第二种: 第一种是通过canvas画出来的效果: public void first(View v) { // ...

  2. Android4清理代码缓存,Android清除应用缓存的两种方法

    第一种 使用ActivityManager中的clearApplicationUserData方法,代码如下: ActivityManager am = (ActivityManager) getSy ...

  3. Android实现圆形图像的两种方法(Glide和Picasso)

    Android实现圆形图像的两种方法 先上效果图 Glide Picasso CircleTransform.java(圆形图片工具类) 先上效果图 Glide 在app的build.gradle中引 ...

  4. android 画布叠加,Android实现图片叠加效果的两种方法

    本文实例讲述了Android实现图片叠加效果的两种方法.分享给大家供大家参考,具体如下: 效果图: 第一种: 第二种: 第一种是通过canvas画出来的效果: public void first(Vi ...

  5. Android中添加背景音乐的两种方法

    前些天在尝试自己写一个Android小游戏--flybird 基本功能实现了,就想添加声音,然后上网查了查,大多是一样,可是用到我这,有些却不可以用,所以我还用了两种方法. 下面谈谈这两种方法. 方法 ...

  6. Android发送短信的两种方法

    Android发送短信代码的两种方法 Android发送短信代码的两种方法 有两种方法可以实现发送短信: 其一是使用intent-startActivity,URI数据格式为"smsto:n ...

  7. android相册如何加背景音乐,Android中添加背景音乐的两种方法

    前些天在尝试自己写一个Android小游戏--flybird 基本功能实现了,就想添加声音,然后上网查了查,大多是一样,可是用到我这,有些却不可以用,所以我还用了两种方法. 下面谈谈这两种方法. 方法 ...

  8. Android设备设置代理的两种方法

    本文将介绍两种给给android设备设置网络代理的方法,一种是直接在网络设置中操作,另一种是通过adb指令操作 第一种最常用的通过设置页面操作(此处以夜神模拟器为例讲解,其他设备操作方式基本类似) 操 ...

  9. android 虚拟按键 增减和删除的方法

    首先说明,该操作是在命令行下操作,不需要重新烧写系统,需要先进入系统,然后通过串口命令行操作. 进入system目录,命令是cd /system,然后使用vi命令打开build.prop这个文件,命令 ...

最新文章

  1. linux系统程序PPT,Linux 系统应用与程序设计 问题.ppt
  2. HDU4514(非连通图的环判断与图中最长链)
  3. 打印机共享无法正常打印的处理思路
  4. python 内置函数 builtins_python学习笔记(七)——内置函数
  5. git-SSH连接配置
  6. const int *p说明不能修改_随时随地学习C语言之6—const修饰的变量真的不能修改吗?...
  7. netback于kthread遇到cpu affinity问题
  8. Linux学习13-CentOS安装ab做压力测试
  9. 视频教程-2020软考--网络规划设计师【综合知识】视频精讲-软考
  10. Matlab帮助文档打开和命令窗口中文显示设置
  11. 欧创芯原装OC 5209芯片降压型 LED 恒流驱动器,SOT89-5 封装
  12. wifi信号衰减与距离关系_无线传输距离计算公式
  13. MyBatis 第二扇门
  14. android控件显示在最上层,「总是可见的时钟和备忘录」永远显示在屏幕最上层的贴心助手(Android)...
  15. 【软件测试】如何测试人工智能软件?
  16. 后端开发、C++开发面经分类整理
  17. 五十一个经典小故事2
  18. 网龙入股大数据智能教育平台 -- “爱多分”
  19. 我的10年计算机之路
  20. wireshark检测广播风暴_带你走进网络世界:一文读懂广播风暴

热门文章

  1. Matlab之矩阵分析基本应用(一)
  2. 搜集的一些javascript小技巧!
  3. MotoSimEG-VRC软件:机器人虚拟仿真动画3DPDF文件输出方法
  4. 数电 cmos反相器的工作原理 静态特性
  5. 收到iPhone X之后该怎么晒?
  6. 双光子荧光成像_双光子荧光显微镜
  7. cortex-R52 CPU的功耗管理之power gating(电源门控)
  8. 云网融合 — 云网业务统一承载技术
  9. Nginx的基本匹配规则与配置.m3u8视频源
  10. NREC-手动修改直纹面,可线铣编程