Android hardware按键触感功能实现

笔者在最近一个项目中遇到一个问题就是客户要求硬件的几个key需要在触感功能打开的情况下使用有触感,android对于key是不做触感的,就是没有震动的。 办法还是有的,感觉好别扭,把key转化成虚拟按键的坐标报上去就可以了。 现在ctp上大多都有几个触摸键,可是客户选择的ctp为了降低成本统一结构,没有这几个键,而是用另外一个小模块来实现这几个键,这个几个键通过IIC读出来就是实际的键值不是坐标。下面就简单介绍一下做法吧!
一、虚拟键布局虚拟键需要布局在ctp有效范围之外,比如320X480的屏,你的虚拟键要在这有效范围之外。另外android默认从/sys /board_properties读取配置,另外需要注意的地方就是虚拟键属性里的name也是有固定格式的,virtualkeys.DEVICENAME,这个DEVICENAME不是指你手机设备的名称,而是指你input设备的名称,你有多个 input设备,这里需要绑定清楚,这个很重要,一般ctp上有这几个触摸键的情况下都是绑定ctp input设备的名称。定义按键区域的标准是:0x1:扫描码:X:Y:W:H,虚拟键之间用冒号隔开。注意X & Y是中心区域坐标。0x1表示是key。

  1. [color=#333333][font=Arial]#ifdef CONFIG_MACH_YYY
  2. static ssize_t virtual_keys_show(struct kobject *kobj,
  3. struct kobj_attribute *attr, char *buf)
  4. {
  5. return sprintf(buf,
  6. /*leaguer old tp*/
  7. __stringify(EV_KEY) ":" __stringify(KEY_MENU) ":100:519:20:20"
  8. ":" __stringify(EV_KEY) ":" __stringify(KEY_HOME) ":60:519:20:20"
  9. ":" __stringify(EV_KEY) ":" __stringify(KEY_BACK) ":0:519:20:20"
  10. /*leaguer new tp*/
  11. ":" __stringify(EV_KEY) ":" __stringify(KEY_MENU) ":159:513:6:6"
  12. ":" __stringify(EV_KEY) ":" __stringify(KEY_HOME) ":195:513:6:6"
  13. ":" __stringify(EV_KEY) ":" __stringify(KEY_BACK) ":230:513:6:6"
  14. /*lingju tp*/
  15. ":" __stringify(EV_KEY) ":" __stringify(KEY_MENU) ":208:533:6:6"
  16. ":" __stringify(EV_KEY) ":" __stringify(KEY_HOME) ":240:533:6:6"
  17. ":" __stringify(EV_KEY) ":" __stringify(KEY_BACK) ":272:533:6:6"
  18. "n");
  19. }
  20. #elif defined(CONFIG_MACH_XXXX)
  21. static ssize_t virtual_keys_show(struct kobject *kobj,
  22. struct kobj_attribute *attr, char *buf)
  23. {
  24. return sprintf(buf,
  25. __stringify(EV_KEY) ":" __stringify(KEY_MENU) ":50:530:20:20"
  26. ":" __stringify(EV_KEY) ":" __stringify(KEY_HOME) ":100:530:20:20"
  27. ":" __stringify(EV_KEY) ":" __stringify(KEY_BACK) ":150:530:20:20"
  28. ":" __stringify(EV_KEY) ":" __stringify(KEY_SEARCH) ":200:530:20:20"
  29. "n");
  30. }

  31. #else
  32. static ssize_t virtual_keys_show(struct kobject *kobj,
  33. struct kobj_attribute *attr, char *buf)
  34. {
  35. return sprintf(buf,
  36. __stringify(EV_KEY) ":" __stringify(KEY_MENU) ":50:532:70:35"
  37. ":" __stringify(EV_KEY) ":" __stringify(KEY_HOME) ":155:532:70:35"
  38. ":" __stringify(EV_KEY) ":" __stringify(KEY_BACK) ":255:532:70:35"
  39. "n");
  40. }
  41. #endif
  42. static struct kobj_attribute virtual_keys_attr = {
  43. .attr = {
  44. #if defined(CONFIG_MACH_XXXX)
  45. .name = "virtualkeys.gt106m_tp",
  46. #else
  47. .name = "virtualkeys.ft5x0x_ts",
  48. #endif
  49. .mode = S_IRUGO,
  50. },
  51. .show = &virtual_keys_show,
  52. };

  53. static struct attribute *virtual_keys_attrs[] = {
  54. &virtual_keys_attr.attr,
  55. NULL
  56. };

  57. static struct attribute_group virtual_keys_attr_group = {
  58. .attrs = virtual_keys_attrs,
  59. };

  60. static void virtual_keys_init(void)
  61. {
  62. int ret;
  63. struct kobject *kobj = kobject_create_and_add("board_properties", NULL);

  64. if (kobj)
  65. ret = sysfs_create_group(kobj, &virtual_keys_attr_group);

  66. if (!kobj || ret)
  67. atxxtp_err("failed to create board_propertiesn");
  68. }
  69. #endif[/font][/color]

二、硬件key驱动需要做什么?申请input设备,注册设备类型,设置一些属性,当然重点还是在报值上,把key值转换为point上报。把key转换成相应的坐标,转换如下:
static int gt106m_tp_point[MAX_BUTTON_CNT][2] = { {200,530}, {150,530}, {100,530}, {50,530} };

  1. gt106m_tp->input_dev = input_allocate_device();
  2. if (gt106m_tp->input_dev == NULL) {
  3. ret = -ENOMEM;
  4. gt106m_err( "input_allocate_device failed to request irq%d,"" error %dn", GPIO_TOUCHKEY_EINT, ret);
  5. goto exit_input_dev_alloc_failed;
  6. }
  7. gt106m_tp->input_dev->name = GT106M_NAME;
  8. s_input_dev = gt106m_tp->input_dev;

  9. input_set_abs_params(s_input_dev, ABS_MT_POSITION_X, 0, 320, 0, 0);
  10. input_set_abs_params(s_input_dev, ABS_MT_POSITION_Y, 0, 480, 0, 0);
  11. input_set_abs_params(s_input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);

  12. set_bit(ABS_MT_TOUCH_MAJOR, s_input_dev->absbit);
  13. set_bit(ABS_MT_POSITION_X, s_input_dev->absbit);
  14. set_bit(ABS_MT_POSITION_Y, s_input_dev->absbit);

  15. set_bit(EV_ABS, s_input_dev->evbit);
  16. set_bit(EV_KEY, s_input_dev->evbit);
  17. for(i = 0; i < MAX_BUTTON_CNT; i++)
  18. set_bit(gt106m_keycode[i], s_input_dev->keybit);

  19. ret = input_register_device(s_input_dev);
  20. if (ret) {
  21. gt106m_err( "input_register_device failed to request irq%d,"" error %dn", GPIO_TOUCHKEY_EINT, ret);
  22. goto exit_input_register_device_failed;
  23. }

键值转坐标上报如下:

  1. input_report_abs(s_input_dev, ABS_MT_TOUCH_MAJOR, 255);
  2. input_report_abs(s_input_dev, ABS_MT_POSITION_X, gt106m_tp_point[i][0]);
  3. input_report_abs(s_input_dev, ABS_MT_POSITION_Y, gt106m_tp_point[i][1]);
  4. input_mt_sync(s_input_dev);
  5. input_sync(s_input_dev);

  6. input_report_abs(s_input_dev, ABS_MT_TOUCH_MAJOR, 0);
  7. input_mt_sync(s_input_dev);
  8. input_sync(s_input_dev);

三、android上层如何处理虚拟键?
Frameworks/base/services/java/com/android/server下InputManager.java有取virtualkey的定义,如下

  1. public VirtualKeyDefinition[] getVirtualKeyDefinitions(String deviceName) {
  2. ArrayList<VirtualKeyDefinition> keys = new ArrayList<VirtualKeyDefinition>();

  3. try {
  4. FileInputStream fis = new FileInputStream(
  5. "/sys/board_properties/virtualkeys." + deviceName);
  6. InputStreamReader isr = new InputStreamReader(fis);
  7. BufferedReader br = new BufferedReader(isr, 2048);
  8. String str = br.readLine();
  9. if (str != null) {
  10. String[] it = str.split(":");
  11. if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "***** VIRTUAL KEYS: " + it);
  12. final int N = it.length-6;
  13. for (int i=0; i<=N; i+=6) {
  14. if (!"0x01".equals(it[i])) {
  15. Slog.w(TAG, "Unknown virtual key type at elem #"
  16. + i + ": " + it[i] + " for device " + deviceName);
  17. continue;
  18. }
  19. try {
  20. VirtualKeyDefinition key = new VirtualKeyDefinition();
  21. key.scanCode = Integer.parseInt(it[i+1]);
  22. key.centerX = Integer.parseInt(it[i+2]);
  23. key.centerY = Integer.parseInt(it[i+3]);
  24. key.width = Integer.parseInt(it[i+4]);
  25. key.height = Integer.parseInt(it[i+5]);
  26. if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "Virtual key "
  27. + key.scanCode + ": center=" + key.centerX + ","
  28. + key.centerY + " size=" + key.width + "x"
  29. + key.height);
  30. keys.add(key);
  31. } catch (NumberFormatException e) {
  32. Slog.w(TAG, "Bad number in virtual key definition at region "
  33. + i + " in: " + str + " for device " + deviceName, e);
  34. }
  35. }
  36. }
  37. br.close();
  38. } catch (FileNotFoundException e) {
  39. Slog.i(TAG, "No virtual keys found for device " + deviceName + ".");
  40. } catch (IOException e) {
  41. Slog.w(TAG, "Error reading virtual keys for device " + deviceName + ".", e);
  42. }

  43. return keys.toArray(new VirtualKeyDefinition[keys.size()]);
  44. }

Frameworks/base/libs/ui下InputReader.cpp下解析虚拟键,核心函数如下:

  1. void TouchInputMapper::configureVirtualKeysLocked() {
  2. assert(mRawAxes.x.valid && mRawAxes.y.valid);

  3. // Note: getVirtualKeyDefinitions is non-reentrant so we can continue holding the lock.
  4. Vector<VirtualKeyDefinition> virtualKeyDefinitions;
  5. getPolicy()->getVirtualKeyDefinitions(getDeviceName(), virtualKeyDefinitions);

  6. mLocked.virtualKeys.clear();

  7. if (virtualKeyDefinitions.size() == 0) {
  8. return;
  9. }

  10. mLocked.virtualKeys.setCapacity(virtualKeyDefinitions.size());

  11. int32_t touchScreenLeft = mRawAxes.x.minValue;
  12. int32_t touchScreenTop = mRawAxes.y.minValue;
  13. int32_t touchScreenWidth = mRawAxes.x.getRange();
  14. int32_t touchScreenHeight = mRawAxes.y.getRange();

  15. for (size_t i = 0; i < virtualKeyDefinitions.size(); i++) {
  16. const VirtualKeyDefinition& virtualKeyDefinition =
  17. virtualKeyDefinitions[i];

  18. mLocked.virtualKeys.add();
  19. VirtualKey& virtualKey = mLocked.virtualKeys.editTop();

  20. virtualKey.scanCode = virtualKeyDefinition.scanCode;
  21. int32_t keyCode;
  22. uint32_t flags;
  23. if (getEventHub()->scancodeToKeycode(getDeviceId(), virtualKey.scanCode,
  24. & keyCode, & flags)) {
  25. LOGW(INDENT "VirtualKey %d: could not obtain key code, ignoring",
  26. virtualKey.scanCode);
  27. mLocked.virtualKeys.pop(); // drop the key
  28. continue;
  29. }

  30. virtualKey.keyCode = keyCode;
  31. virtualKey.flags = flags;

  32. // convert the key definition's display coordinates into touch coordinates for a hit box
  33. int32_t halfWidth = virtualKeyDefinition.width / 2;
  34. int32_t halfHeight = virtualKeyDefinition.height / 2;

  35. virtualKey.hitLeft = (virtualKeyDefinition.centerX - halfWidth)
  36. * touchScreenWidth / mLocked.surfaceWidth + touchScreenLeft;
  37. virtualKey.hitRight= (virtualKeyDefinition.centerX + halfWidth)
  38. * touchScreenWidth / mLocked.surfaceWidth + touchScreenLeft;
  39. virtualKey.hitTop = (virtualKeyDefinition.centerY - halfHeight)
  40. * touchScreenHeight / mLocked.surfaceHeight + touchScreenTop;
  41. virtualKey.hitBottom = (virtualKeyDefinition.centerY + halfHeight)
  42. * touchScreenHeight / mLocked.surfaceHeight + touchScreenTop;

  43. }
  44. }

android把超过有效范围的坐标跟virtualkey去对比,如果在定义里面就报上相应的key。

  1. bool TouchInputMapper::configureSurfaceLocked() 函数中:
  2. // Configure X and Y factors.
  3. if (mRawAxes.x.valid && mRawAxes.y.valid) {
  4. mLocked.xOrigin = mRawAxes.x.minValue;
  5. mLocked.yOrigin = mRawAxes.y.minValue;
  6. mLocked.xScale = float(width) / mRawAxes.x.getRange();
  7. mLocked.yScale = float(height) / mRawAxes.y.getRange();
  8. mLocked.xPrecision = 1.0f / mLocked.xScale;
  9. mLocked.yPrecision = 1.0f / mLocked.yScale;

  10. configureVirtualKeysLocked();
  11. } else {
  12. LOGW(INDENT "Touch device did not report support for X or Y axis!");
  13. mLocked.xOrigin = 0;
  14. mLocked.yOrigin = 0;
  15. mLocked.xScale = 1.0f;
  16. mLocked.yScale = 1.0f;
  17. mLocked.xPrecision = 1.0f;
  18. mLocked.yPrecision = 1.0f;
  19. }

结果以上几步,就可以完成这个功能的开发。如果ctp上的触摸键,也一样的,有效ctp的触摸键是报的坐标,有效ctp直接也是报的key,如果要支持触感的话,还是得转换成坐标报上去。
罗罗嗦嗦说了这么多,从上到下,怎么转换在哪转换大概都分析了一下,希望对以后的项目有类似需求的工作有所帮助。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值