藍牙HID無線觸摸屏

寫在前面

主機:Android 5.0+ 內(nèi)核3.4
從機:SensorTile
先上一個效果圖


000405qi5vew2cf2abcjko.gif

原理解析

HID事件到Android屏幕上經(jīng)歷了如下過程:

HID => linux kernel input子系統(tǒng) => Android input子系統(tǒng)

HID是標準的輸入?yún)f(xié)議,對于不同的操作系統(tǒng)而言,也有自己的input子系統(tǒng)。

Android層要求

以Android為例,如果要想讓Android系統(tǒng)認為一個輸入設(shè)備是一個觸摸屏,需要該內(nèi)核設(shè)備上報:

// 對于單點觸控而言
ABS_X ABS_Y 和 BTN_TOUCH
// 對于多點觸控而言
ABS_MT_POSITION_X 和 ABS_MT_POSITION_Y 絕對軸 以及 BTN_TOUCH

且需要一個配置文件放到/system/usr/idc/中,如/system/usr/idc/HID.idc,內(nèi)容如下指定其為觸摸屏設(shè)備類型:

touch.deviceType = touchScreen

注:標明輸入設(shè)備為觸摸屏還有一個方法輸入設(shè)備報告存在 INPUT_PROP_DIRECT 輸入屬性,但是對于藍牙HID而言,在Android中的實現(xiàn)是基于uhid實現(xiàn)的,要這樣做比較難,所以一般會使用放配置文件的方式。輸入設(shè)備上報的鍵值和輸入屬性可以使用getevent -i查看。
理論依據(jù)來自:https://source.android.com/devices/input/touch-devices

內(nèi)核層要求

Android層要求中提到的ABS_X ABS_Y 和 BTN_TOUCH等等都是需要內(nèi)核去上報的鍵值,內(nèi)核中就需要要求HID設(shè)備按照一定要求上傳HID鍵值,因為內(nèi)核鍵值是由HID鍵值轉(zhuǎn)換過來的。

// drivers/hid/hid-input.c
    case HID_UP_DIGITIZER:
        switch (usage->hid & 0xff) {
        case 0x00: /* Undefined */
            goto ignore;

        case HID_DG_TIPPRESSURE: /* TipPressure */
            if (!test_bit(BTN_TOUCH, input->keybit)) {
                device->quirks |= HID_QUIRK_NOTOUCH;
                set_bit(EV_KEY, input->evbit);
                set_bit(BTN_TOUCH, input->keybit);
            }
            map_abs_clear(ABS_PRESSURE);
            break;

        case HID_DG_INRANGE: /* InRange */
            switch (field->physical & 0xff) {
            case 0x21: map_key(BTN_TOOL_MOUSE); break;
            case 0x22: map_key(BTN_TOOL_FINGER); break;
            default: map_key(BTN_TOOL_PEN); break;
            }
            break;

        case HID_DG_INVERT: /* Invert */
            map_key_clear(BTN_TOOL_RUBBER);
            break;

        case HID_DG_TOUCH: /* Touch */
        case HID_DG_TIPSWITCH: /* TipSwitch */
        case HID_DG_TIPSWITCH2: /* TipSwitch2 */
            device->quirks &= ~HID_QUIRK_NOTOUCH;
            map_key_clear(BTN_TOUCH);
            break;

        case HID_DG_BARRELSWITCH: /* BarrelSwitch */
            map_key_clear(BTN_STYLUS);
            break;

        case HID_DG_TABLETPICK: /* TabletPick */
            map_key_clear(BTN_STYLUS2);
            break;

        case HID_DG_CONTACTID: /* ContactID */
            device->quirks |= HID_QUIRK_MULTITOUCH;
            goto unknown;

        default:  goto unknown;
        }

由此可以看到HID描述符中需要按照以下要求:

  1. Usage PageDIGITIZER,對應內(nèi)核代碼中的HID_UP_DIGITIZER
  2. 需要包含HID_DG_TOUCH、HID_DG_TIPSWITCH、HID_DG_TIPSWITCH2三者其中之一,才能上報BTN_TOUCH;
  3. 如果包含了HID_DG_INRANGE則會上傳BTN_TOOL_PEN有可能會導致畫蛇添足;(我在實際測試中確實遇到這個問題,一個上報BTN_TOOL_PEN事件,而不上報BTN_TOUCH導致無法實現(xiàn)真正的點擊事件);
    根據(jù)這些分析,將微軟的Sample Report Descriptor for a Touch Digitizer Device (Windows 7)提到的HID描述符簡單的修整,得到了想要的的描述符:
        0x05, 0x0d,                         // USAGE_PAGE (Digitizers)
            0x09, 0x04,                         // USAGE (Touch Screen)
            0xa1, 0x01,                         // COLLECTION (Application)
            0x85, 0x01,                         //   REPORT_ID (Touch)
            0x09, 0x20,                         //   USAGE (Stylus)
            0xa1, 0x00,                         //   COLLECTION (Physical)
            0x09, 0x42,                         //     USAGE (Tip Switch)
            0x15, 0x00,                         //     LOGICAL_MINIMUM (0)
            0x25, 0x01,                         //     LOGICAL_MAXIMUM (1)
            0x75, 0x01,                         //     REPORT_SIZE (1)
            0x95, 0x01,                         //     REPORT_COUNT (1)
            0x81, 0x02,                         //     INPUT (Data,Var,Abs)
            0x95, 0x03,                         //     REPORT_COUNT (3)
            0x81, 0x03,                         //     INPUT (Cnst,Ary,Abs)
//          0x09, 0x32,                         //     USAGE (In Range)
//          0x09, 0x47,                         //     USAGE (Confidence)
//          0x95, 0x02,                         //     REPORT_COUNT (1)
//          0x81, 0x02,                         //     INPUT (Data,Var,Abs)
//          0x95, 0x0a,                         //     REPORT_COUNT (10)
//          0x81, 0x03,                         //     INPUT (Cnst,Ary,Abs)
            0x05, 0x01,                         //     USAGE_PAGE (Generic Desktop)
            0x26, 0xff, 0x7f,                   //     LOGICAL_MAXIMUM (32767)
            0x75, 0x10,                         //     REPORT_SIZE (16)
            0x95, 0x01,                         //     REPORT_COUNT (1)
            0xa4,                               //     PUSH
            0x55, 0x0d,                         //     UNIT_EXPONENT (-3)
            0x65, 0x00,                         //     UNIT (None)
            0x09, 0x30,                         //     USAGE (X)
            0x35, 0x00,                         //     PHYSICAL_MINIMUM (0)
            0x46, 0x00, 0x00,                   //     PHYSICAL_MAXIMUM (0)
            0x81, 0x02,                         //     INPUT (Data,Var,Abs)
            0x09, 0x31,                         //     USAGE (Y)
            0x46, 0x00, 0x00,                   //     PHYSICAL_MAXIMUM (0)
            0x81, 0x02,                         //     INPUT (Data,Var,Abs)
            0xb4,                               //     POP
//          0x05, 0x0d,                         //     USAGE PAGE (Digitizers)
//          0x09, 0x48,                         //     USAGE (Width)
//          0x09, 0x49,                         //     USAGE (Height)
//          0x95, 0x02,                         //     REPORT_COUNT (2)
//          0x81, 0x02,                         //     INPUT (Data,Var,Abs)
//          0x95, 0x01,                         //     REPORT_COUNT (1)
//          0x81, 0x03,                         //     INPUT (Cnst,Ary,Abs)
            0xc0,                               //   END_COLLECTION
            0xc0,                               // END_COLLECTION

使用uhid來測試該描述符,測試代碼,確實可以實現(xiàn)觸摸屏的效果了。
注:對于多點觸摸設(shè)備,那么描述符中需要包含HID_DG_CONTACTID即可,這里先不展開分析。

藍牙HID從機

這里使用的是ST的SensorTile,根據(jù)其提供的HID的Demo,修改對應的成對應的描述符,并在while循環(huán)里實現(xiàn)一個從左上角滑動到右下角的模擬操作,這樣就可以實現(xiàn)通過藍牙HID觸摸屏了。
具體的改動見:https://gitee.com/kangear/STM32CubeExpansion_BLE1_V2.8.0/commit/04e5e0af893c1099d1ce459307223735d3658e6d

展望

目前實現(xiàn)了單點觸摸屏,稍候會另起一個文章,講述如何實現(xiàn)多點觸摸屏,到那時才會是真正的藍牙HID觸摸屏。能實現(xiàn)之后,可以基于這個實現(xiàn)物理外掛,把手游的一些控制轉(zhuǎn)換成體感游戲等等。

<完>

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,062評論 25 709
  • 1:InputChannel提供函數(shù)創(chuàng)建底層的Pipe對象 2: 1)客戶端需要新建窗口 2)new ViewRo...
    自由人是工程師閱讀 5,715評論 0 18
  • 騎車20分鐘,上課上到八點半呢
    SPP164810閱讀 101評論 0 1
  • 別把今夜的夢叫醒 我想種一顆滿開花兒的樹在那里 悄悄地聽你呼吸 靜靜地看你嬉戲 怎奈何此生有太多唏噓 唯獨于夢中方...
    即是我閱讀 807評論 0 0
  • 今天,又一次深深地體驗了“操碎了別人的心肝”是堅決不能做的道理。 事情的經(jīng)過是這樣的,我介紹自己的一個學生去某銀行...
    藝涵JS閱讀 545評論 0 1

友情鏈接更多精彩內(nèi)容