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。

#ifdefCONFIG_MACH_YYYstatic ssize_t virtual_keys_show(struct kobject *kobj,             struct kobj_attribute *attr, char *buf){        return sprintf(buf,        /*leaguer old tp*/                    __stringify(EV_KEY) ":" __stringify(KEY_MENU) ":100:519:20:20"               ":" __stringify(EV_KEY) ":" __stringify(KEY_HOME) ":60:519:20:20"                ":" __stringify(EV_KEY) ":" __stringify(KEY_BACK) ":0:519:20:20"                /*leaguer new tp*/                ":" __stringify(EV_KEY) ":" __stringify(KEY_MENU) ":159:513:6:6"                ":" __stringify(EV_KEY) ":" __stringify(KEY_HOME) ":195:513:6:6"                ":" __stringify(EV_KEY) ":" __stringify(KEY_BACK) ":230:513:6:6"                /*lingju tp*/                ":" __stringify(EV_KEY) ":" __stringify(KEY_MENU) ":208:533:6:6"                ":" __stringify(EV_KEY) ":" __stringify(KEY_HOME) ":240:533:6:6"                ":" __stringify(EV_KEY) ":" __stringify(KEY_BACK) ":272:533:6:6"                "\n");}#elif defined(CONFIG_MACH_XXXX)static ssize_t virtual_keys_show(struct kobject *kobj,             struct kobj_attribute *attr, char *buf){        return sprintf(buf,                        __stringify(EV_KEY) ":" __stringify(KEY_MENU)  ":50:530:20:20"                ":" __stringify(EV_KEY) ":" __stringify(KEY_HOME) ":100:530:20:20"                ":" __stringify(EV_KEY) ":" __stringify(KEY_BACK) ":150:530:20:20"                ":" __stringify(EV_KEY) ":" __stringify(KEY_SEARCH) ":200:530:20:20"               "\n");}#elsestatic ssize_t virtual_keys_show(struct kobject *kobj,             struct kobj_attribute *attr, char *buf){        return sprintf(buf,                        __stringify(EV_KEY) ":" __stringify(KEY_MENU)  ":50:532:70:35"                ":" __stringify(EV_KEY) ":" __stringify(KEY_HOME) ":155:532:70:35"                ":" __stringify(EV_KEY) ":" __stringify(KEY_BACK) ":255:532:70:35"                "\n");}#endifstatic struct kobj_attribute virtual_keys_attr = {.attr = {#if defined(CONFIG_MACH_XXXX).name = "virtualkeys.gt106m_tp",#else.name = "virtualkeys.ft5x0x_ts",#endif.mode = S_IRUGO,},.show = &virtual_keys_show,};static struct attribute *virtual_keys_attrs[] = {&virtual_keys_attr.attr,NULL};static struct attribute_group virtual_keys_attr_group = {.attrs = virtual_keys_attrs,};static void virtual_keys_init(void){int ret;struct kobject *kobj = kobject_create_and_add("board_properties", NULL);if (kobj)ret = sysfs_create_group(kobj, &virtual_keys_attr_group);if (!kobj || ret)atxxtp_err("failed to create board_properties\n");}#endif

二、硬件key驱动需要做什么?

申请input设备,注册设备类型,设置一些属性,当然重点还是在报值上,把key值转换为point上报。

把key转换成相应的坐标,转换如下:

static int gt106m_tp_point[MAX_BUTTON_CNT][2] = { {200,530}, {150,530}, {100,530}, {50,530} };

gt106m_tp->input_dev = input_allocate_device();if (gt106m_tp->input_dev == NULL) {ret = -ENOMEM;gt106m_err( "input_allocate_device failed to request irq%d,"" error %d\n", GPIO_TOUCHKEY_EINT, ret);goto exit_input_dev_alloc_failed;}gt106m_tp->input_dev->name = GT106M_NAME;s_input_dev = gt106m_tp->input_dev;input_set_abs_params(s_input_dev, ABS_MT_POSITION_X, 0, 320, 0, 0);input_set_abs_params(s_input_dev, ABS_MT_POSITION_Y, 0, 480, 0, 0);input_set_abs_params(s_input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);set_bit(ABS_MT_TOUCH_MAJOR, s_input_dev->absbit);set_bit(ABS_MT_POSITION_X, s_input_dev->absbit);set_bit(ABS_MT_POSITION_Y, s_input_dev->absbit);set_bit(EV_ABS, s_input_dev->evbit);set_bit(EV_KEY, s_input_dev->evbit);for(i = 0; i < MAX_BUTTON_CNT; i++)set_bit(gt106m_keycode[i], s_input_dev->keybit);ret = input_register_device(s_input_dev);if (ret) {gt106m_err( "input_register_device failed to request irq%d,"" error %d\n", GPIO_TOUCHKEY_EINT, ret);goto  exit_input_register_device_failed;}

键值转坐标上报如下:

          input_report_abs(s_input_dev, ABS_MT_TOUCH_MAJOR, 255);          input_report_abs(s_input_dev, ABS_MT_POSITION_X, gt106m_tp_point[i][0]);          input_report_abs(s_input_dev, ABS_MT_POSITION_Y, gt106m_tp_point[i][1]);          input_mt_sync(s_input_dev);          input_sync(s_input_dev);          input_report_abs(s_input_dev, ABS_MT_TOUCH_MAJOR, 0);          input_mt_sync(s_input_dev);          input_sync(s_input_dev);

三、android上层如何处理虚拟键?

Frameworks/base/services/java/com/android/server下InputManager.java有取virtualkey的定义,如下

        public VirtualKeyDefinition[] getVirtualKeyDefinitions(String deviceName) {            ArrayList<VirtualKeyDefinition> keys = new ArrayList<VirtualKeyDefinition>();                        try {                FileInputStream fis = new FileInputStream(                        "/sys/board_properties/virtualkeys." + deviceName);                InputStreamReader isr = new InputStreamReader(fis);                BufferedReader br = new BufferedReader(isr, 2048);                String str = br.readLine();                if (str != null) {                    String[] it = str.split(":");                    if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "***** VIRTUAL KEYS: " + it);                    final int N = it.length-6;                    for (int i=0; i<=N; i+=6) {                        if (!"0x01".equals(it[i])) {                            Slog.w(TAG, "Unknown virtual key type at elem #"                                    + i + ": " + it[i] + " for device " + deviceName);                            continue;                        }                        try {                            VirtualKeyDefinition key = new VirtualKeyDefinition();                            key.scanCode = Integer.parseInt(it[i+1]);                            key.centerX = Integer.parseInt(it[i+2]);                            key.centerY = Integer.parseInt(it[i+3]);                            key.width = Integer.parseInt(it[i+4]);                            key.height = Integer.parseInt(it[i+5]);                            if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "Virtual key "                                    + key.scanCode + ": center=" + key.centerX + ","                                    + key.centerY + " size=" + key.width + "x"                                    + key.height);                            keys.add(key);                        } catch (NumberFormatException e) {                            Slog.w(TAG, "Bad number in virtual key definition at region "                                    + i + " in: " + str + " for device " + deviceName, e);                        }                    }                }                br.close();            } catch (FileNotFoundException e) {                Slog.i(TAG, "No virtual keys found for device " + deviceName + ".");            } catch (IOException e) {                Slog.w(TAG, "Error reading virtual keys for device " + deviceName + ".", e);            }                        return keys.toArray(new VirtualKeyDefinition[keys.size()]);        }


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

void TouchInputMapper::configureVirtualKeysLocked() {    assert(mRawAxes.x.valid && mRawAxes.y.valid);    // Note: getVirtualKeyDefinitions is non-reentrant so we can continue holding the lock.    Vector<VirtualKeyDefinition> virtualKeyDefinitions;    getPolicy()->getVirtualKeyDefinitions(getDeviceName(), virtualKeyDefinitions);    mLocked.virtualKeys.clear();    if (virtualKeyDefinitions.size() == 0) {        return;    }    mLocked.virtualKeys.setCapacity(virtualKeyDefinitions.size());    int32_t touchScreenLeft = mRawAxes.x.minValue;    int32_t touchScreenTop = mRawAxes.y.minValue;    int32_t touchScreenWidth = mRawAxes.x.getRange();    int32_t touchScreenHeight = mRawAxes.y.getRange();    for (size_t i = 0; i < virtualKeyDefinitions.size(); i++) {        const VirtualKeyDefinition& virtualKeyDefinition =                virtualKeyDefinitions[i];        mLocked.virtualKeys.add();        VirtualKey& virtualKey = mLocked.virtualKeys.editTop();        virtualKey.scanCode = virtualKeyDefinition.scanCode;        int32_t keyCode;        uint32_t flags;        if (getEventHub()->scancodeToKeycode(getDeviceId(), virtualKey.scanCode,                & keyCode, & flags)) {            LOGW(INDENT "VirtualKey %d: could not obtain key code, ignoring",                    virtualKey.scanCode);            mLocked.virtualKeys.pop(); // drop the key            continue;        }        virtualKey.keyCode = keyCode;        virtualKey.flags = flags;        // convert the key definition's display coordinates into touch coordinates for a hit box        int32_t halfWidth = virtualKeyDefinition.width / 2;        int32_t halfHeight = virtualKeyDefinition.height / 2;        virtualKey.hitLeft = (virtualKeyDefinition.centerX - halfWidth)                * touchScreenWidth / mLocked.surfaceWidth + touchScreenLeft;        virtualKey.hitRight= (virtualKeyDefinition.centerX + halfWidth)                * touchScreenWidth / mLocked.surfaceWidth + touchScreenLeft;        virtualKey.hitTop = (virtualKeyDefinition.centerY - halfHeight)                * touchScreenHeight / mLocked.surfaceHeight + touchScreenTop;        virtualKey.hitBottom = (virtualKeyDefinition.centerY + halfHeight)                * touchScreenHeight / mLocked.surfaceHeight + touchScreenTop;    }}

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

bool TouchInputMapper::configureSurfaceLocked() 函数中:        // Configure X and Y factors.        if (mRawAxes.x.valid && mRawAxes.y.valid) {            mLocked.xOrigin = mRawAxes.x.minValue;            mLocked.yOrigin = mRawAxes.y.minValue;            mLocked.xScale = float(width) / mRawAxes.x.getRange();            mLocked.yScale = float(height) / mRawAxes.y.getRange();            mLocked.xPrecision = 1.0f / mLocked.xScale;            mLocked.yPrecision = 1.0f / mLocked.yScale;            configureVirtualKeysLocked();        } else {            LOGW(INDENT "Touch device did not report support for X or Y axis!");            mLocked.xOrigin = 0;            mLocked.yOrigin = 0;            mLocked.xScale = 1.0f;            mLocked.yScale = 1.0f;            mLocked.xPrecision = 1.0f;            mLocked.yPrecision = 1.0f;        }



结果以上几步,就可以完成这个功能的开发。如果ctp上的触摸键,也一样的,有效ctp的触摸键是报的坐标,有效ctp直接也是报的key,如果要支持触感的话,还是得转换成坐标报上去。

罗罗嗦嗦说了这么多,从上到下,怎么转换在哪转换大概都分析了一下,希望对以后的项目有类似需求的工作有所帮助。





更多相关文章

  1. Android获取设备唯一标识解决方案
  2. Android完整实现Find My Phone功能 可远程对手机加密
  3. 自定义View之滑动事件
  4. Android(安卓)Q Beta 正式发布 | 精于形,安于内
  5. 如何将旧手机数据转移至iPhone7?旧Android数据转移到新iPhone全攻
  6. 为何Android设备份额远超iOS,上网流量却差一倍?iPad是最大变量
  7. 如何查看Android设备上的分区信息
  8. android适配各种机型及其分辨率
  9. Android零基础入门第2节:Android(安卓)系统架构和应用组件那些事

随机推荐

  1. Android-屏幕设备截屏
  2. android真机调试方法
  3. android 使用activity自定义下拉选择列表
  4. Android音量seekbar制作
  5. Android(安卓)OpenGL学习笔记(一)
  6. 下载android的linux内核的方法
  7. live555 for Android
  8. Android ViewGroup/View 事件分发机制详
  9. Android NDK的C++11标准支持
  10. 源码分析android 系统framework(一)之Activ