目錄
-
- 一、前言
- 二、awtk-linux-fb
- 三、如何支援滑鼠滾輪事件
-
- 3.1 判斷滑鼠驅動是否支援滾輪事件
- 3.2 找到正确的滑鼠裝置檔案名
- 3.3 适配滑鼠滾輪事件
-
- 3.3.1 捕捉滾輪事件并将其轉化後分發給AWTK
- 3.3.2 适配其他嵌入式 Linux 平台或其他事件
一、前言
近期嘗試了在嵌入式 Linux 上适配滑鼠滾輪事件,其難點主要在于從滑鼠驅動檔案中擷取滾輪事件,本文做個記錄。
注意:本文基于 AWTK 針對 arm-linux 平台的移植适配滑鼠滾輪事件。
AWTK 是為嵌入式系統開發的 GUI 引擎庫,GitHub 位址:https://github.com/zlgopen/awtk。
awtk-linux-fb 是 AWTK 針對 arm-linux 平台的移植,GitHub 位址:https://github.com/zlgopen/awtk-linux-fb。
二、awtk-linux-fb
由于不同的嵌入式 linux 硬體其滑鼠驅動檔案對滾輪事件的表現不同,甚至部分硬體的驅動并不支援滾輪事件,是以,滑鼠滾輪事件并不作為通用功能點直接加到 awtk-linux-fb 的源碼裡面。
此處,以樹莓派為例,講解如何讓 awtk-linux-fb 支援滑鼠滾輪事件,其他嵌入式 Linux 平台操作類似。
三、如何支援滑鼠滾輪事件
3.1 判斷滑鼠驅動是否支援滾輪事件
在終端中執行以下指令檢視輸入驅動的具體屬性:
cat /proc/bus/input/devices
例如,樹莓派中滑鼠驅動的屬性如下,其中有 “B: REL = xxx” 的字樣,即表示該滑鼠驅動支援相對坐标事件(EV_REL),其中包括滑鼠滾輪事件:
相對坐标事件 (REL) 的類型通常有 REL_X、REL_Y、REL_WHEEL,分别表示滑鼠在 x、y 方向上移動和滑鼠滾輪滾動。
I: Bus=0003 Vendor=093a Product=2510 Version=0111
N: Name="PixArt USB Optical Mouse"
P: Phys=usb-3f980000.usb-1.1.3/input0
S: Sysfs=/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.1/1-1.1.3/1-1.1.3:1.0/0003:093A:2510.0004/input/input4
U: Uniq=
H: Handlers=mouse0 event3
B: PROP=0
B: EV=17
B: KEY=70000 0 0 0 0 0 0 0 0
B: REL=903
B: MSC=10
3.2 找到正确的滑鼠裝置檔案名
根據上述滑鼠驅動檔案屬性,可知滑鼠裝置檔案有兩個,分别是 /dev/input/mouse0 和 /dev/input/event3,通過 “hexdump /dev/input/xxx” 指令找到能正确識别滾輪事件的滑鼠裝置檔案名。
例如,在終端中執行以下指令:
然後,滾動滑鼠滾輪,有輸出相關資料,并且向上滾動與向下滾動時,其輸出資訊不同,即表明該滑鼠裝置檔案能正确識别滾輪事件。
也可通過指令 “cat /dev/input/event3 | od -t x1 -w16” 來檢視指定格式的輸出,od 指令的使用方法請上網搜尋。
3.3 适配滑鼠滾輪事件
awtk-linux-fb 在樹莓派中,滑鼠消息處理線程是 awtk-port/input_thread/mouse_thread.c 檔案中的 input_dispatch_one_event() 函數,是以隻需在該函數中捕捉滑鼠驅動檔案的滾輪事件,轉化成 AWTK 的 EVT_WHEEL 事件,再調用 input_dispatch() 函數将其分發給 AWTK 即可。
3.3.1 捕捉滾輪事件并将其轉化後分發給AWTK
滑鼠裝置檔案傳回的滾輪事件 type 為 EV_REL,其中 code 對應 REL_WHEEL(垂直滾動)和 REL_HWHEEL(水準滾輪),事件的 value 對應前後左右的方向和滾動的次數(機關)。
Linux 驅動事件詳情請參閱:https://www.kernel.org/doc/Documentation/input/event-codes.txt。
此處僅以 REL_WHEEL 垂直滾動為例,向上滾動時,value 為正數;向下滾動時,value 為負數。滾動一次,value的絕對值即為 1 ,滾動兩次,絕對值即為 2。
假設每滾動一次,滾動的距離為 #define MIN_WHEEL_DELTA 12,那麼捕捉滾輪事件,并将其轉化為 EVT_WHEEL 事件分發給 AWTK 的的代碼如下:
// awtk-port/input_thread/mouse_thread.c
...
/* 滾動一次的最小距離 */
#define MIN_WHEEL_DELTA 12
/* 設定滑鼠滾輪事件 */
static ret_t input_dispatch_set_mouse_wheel_event(run_info_t* info, event_queue_req_t* req, int32_t dy) {
if (dy > 0) {
req->wheel_event.dy = tk_max(MIN_WHEEL_DELTA, dy);
} else if (dy < 0) {
req->wheel_event.dy = tk_min(-MIN_WHEEL_DELTA, dy);
}
req->event.type = EVT_WHEEL;
return RET_OK;
}
static ret_t input_dispatch_one_event(run_info_t* info) {
...
else if (ret == sizeof(info->data.e)) {
switch (info->data.e.type) {
...
case EV_REL: {
switch (info->data.e.code) {
...
/* 從滑鼠裝置檔案中捕捉滑鼠滾輪事件 */
case REL_WHEEL: {
int32_t dy = MIN_WHEEL_DELTA * info->data.e.value;
/* 将該事件轉化為 AWTK 的 EVT_WHEEL 事件 */
input_dispatch_set_mouse_wheel_event(info, req, dy);
break;
}
...
}
if (req->event.type == EVT_NONE) {
req->event.type = EVT_POINTER_MOVE;
}
break;
}
case EV_SYN: {
switch (req->event.type) {
case EVT_KEY_UP:
case EVT_KEY_DOWN:
case EVT_CONTEXT_MENU:
case EVT_POINTER_DOWN:
case EVT_POINTER_MOVE:
case EVT_POINTER_UP:
case EVT_WHEEL: { /* 将轉化後的滾輪事件(EVT_WHEEL)分發給AWTK */
return input_dispatch(info);
...
}
}
return RET_OK;
}
...
3.3.2 适配其他嵌入式 Linux 平台或其他事件
其他嵌入式 Linux 平台操作支援滑鼠滾輪事件以及其他事件的步驟一樣:
1. 從裝置檔案中捕捉目标事件;
2. 将目标事件轉化為AWTK的事件;
3. 分發給AWTK進行處理。
需要注意的是若新增其他滑鼠事件,還需修改 awtk-prot/main_loop_linux.c 中的 input_dispatch_to_main_loop() 函數,根據消息類型設定 event_queue_req_t 中的 event.size 屬性,代碼如下:
// awtk-port/main_loop_linux.c
...
ret_t input_dispatch_to_main_loop(void* ctx, const event_queue_req_t* evt, const char* msg) {
main_loop_t* l = (main_loop_t*)ctx;
event_queue_req_t event = *evt;
event_queue_req_t* e = &event;
if (l != NULL && l->queue_event != NULL) {
switch (e->event.type) {
case EVT_KEY_DOWN:
case EVT_KEY_UP:
case EVT_KEY_LONG_PRESS: {
e->event.size = sizeof(e->key_event);
break;
}
case EVT_CONTEXT_MENU:
case EVT_POINTER_DOWN:
case EVT_POINTER_MOVE:
case EVT_POINTER_UP: {
e->event.size = sizeof(e->pointer_event);
break;
}
/* 設定的滾輪消息 event.size 屬性 */
case EVT_WHEEL: {
e->event.size = sizeof(e->wheel_event);
break;
}
default:
break;
}
main_loop_queue_event(l, e);
input_dispatch_print(ctx, e, msg);
} else {
return RET_BAD_PARAMS;
}
return RET_OK;
}
...