? ? ? ? 我在前幾章移植 lvgl 到linux上時講過注冊鼠標驅動部分,那時候使用的時默認提供的驅動,支持的鼠標功能很少,只有左鍵點擊,那時候我提過我們可以修改驅動使其支持,下面是具體的實現。
????????
?? ? ? ??
????????看上面代碼,我們當時是直接用的默認的模板驅動,而下面則是我專門針對鼠標寫的一個驅動。這里的 evdev_fd 是輸入設備的文件描述符,也就是說lvgl默認提供一種設備,所以大家如果有多個輸入設備的話需要再準備幾個獨立的文件描述符以及驅動。這里官方提供的默認驅動是支持多種輸入設備的(比如鼠標,鍵盤,觸摸屏),所以看這代碼比較多。而我們在這里專門針對鼠標進行開發驅動,使其支持我們要的效果。
首先我們打開 lv_hal_indev.h 這個文件,我們需要加上一些額外的定義,如圖:
? ? ? ? 然后我們再打開lv_api_map.h,如下圖添加,遵循 lvgl 的風格
? ? ? ? 然后我們再 evdev.c 文件中添加鼠標驅動函數,位置大家可自行添加,我這里添加到 evdev_read 的下邊,代碼部分如下,不是很難,重點是理解輸入設備的一些參數意義,這里使用的 struct input_event 這個結構體,大部分鼠標都支持,如果你的鼠標是自定義的格式,那么需要自行看手冊進行轉化。
void mouse_event_read(lv_indev_drv_t * drv, lv_indev_data_t * data)
{struct input_event in;while(read(evdev_fd, &in, sizeof(struct input_event)) > 0) {/* 發生鼠標移動,記錄其位置 */if(in.type == EV_REL) {if(in.code == REL_X) evdev_root_x += in.value;else if(in.code == REL_Y) evdev_root_y += in.value;else if(in.code == REL_WHEEL) data->enc_diff = in.value; /* 將鼠標滑輪滾動轉化為LVGL的編碼器事件 */}/* 按鍵事件(包括鼠標) */else if(in.type == EV_KEY) {switch(in.code) {/* 左鍵 */case BTN_LEFT:if(in.value == 0)evdev_button = LV_INDEV_STATE_REL;else if(in.value == 1)evdev_button = LV_INDEV_STATE_PR;break;/* 右鍵 */case BTN_RIGHT:if(in.value == 0)evdev_button = LV_INDEV_STATE_RIGHT_REL;else if(in.value == 1)evdev_button = LV_INDEV_STATE_RIGHT_PR;break;/* 中鍵 */case BTN_MIDDLE:if(in.value == 0)evdev_button = LV_INDEV_STATE_MIDDLE_REL;else if(in.value == 1)evdev_button = LV_INDEV_STATE_MIDDLE_PR;break;default:break;}}/* 保存值 */data->point.x = evdev_root_x;data->point.y = evdev_root_y;data->state = evdev_button;/* 邊界檢測 */if(data->point.x < 0) data->point.x = 0;if(data->point.y < 0) data->point.y = 0;if(data->point.x > drv->disp->driver->hor_res) data->point.x = drv->disp->driver->hor_res;if(data->point.y > drv->disp->driver->ver_res) data->point.y = drv->disp->driver->ver_res;}
}
? ? ? ? 下面我們在修改一下sdl模擬器的驅動,我們再模擬器上進行測試,下面紅框是修改部分
? ? ? ? 接下來我們看一下 lv_indev.c 輸入設備核心代碼,下面的這個函數是輸入設備的核心函數,是 30ms 的定時函數,這個定時時間由 LV_INDEV_DEF_READ_PERIOD 這個宏決定的。而紅框部分則是對輸入設備的數據結構體的初始化值,最后調用我們上面寫的驅動函數將讀取的鼠標值轉化為 lvgl 數據結構體。
? ? ? ? 而在往下看則是對不同輸入設備的具體處理,我們重點關注紅框部分的鼠標處理函數
? ? ? ? 這個就是處理鼠標的處理函數,先是對坐標進行了處理,由于我們判斷過了這里就不再重復判斷了,而最下面的判斷是用于鼠標發生了移動重新繪制鼠標的位置的作用。
? ? ? ? 再往下面部分就是對事件的判斷從而返給對象,紅框部分是新增的使其支持我們自定義的功能。這里需要強調一下,indev_proc_press 這個函數是初次按下執行一系列操作,比如LV_EVENT_PRESSED (第一下按下時調用)、?LV_EVENT_PRESSING (還在按)、LV_EVENT_PRESS_LOST (目標丟失)、LV_EVENT_LONG_PRESSED(長按)、LV_EVENT_LONG_PRESSED_REPEAT(仍長按)這些重要的中間過,對于右鍵來說是大部分是不需要的,但是我們要保持完整性且目標丟失我們也需要,所以右鍵也去調用了這個函數
? ? ? ? 對 indev_proc_press 這個處理按下(一種過程,并非結束)的函數進行處理,重點展示修改的代碼,下面“時間”打錯字了,是事件
? ? ? ? 然后就是?indev_proc_release 這個函數,主要是 LV_EVENT_RELEASED(釋放)、LV_EVENT_SHORT_CLICKED(短按)、LV_EVENT_CLICKED(點擊)這些事件,這里右鍵是不需要的,所以加個判斷,同時要加上右鍵事件以及雙擊事件的發送,這里改動比較多,大家需注意:
? ? ? ? 到這里成功實現了雙擊、右鍵、以及鼠標滑輪功能,我們創建個box簡單測試一下
static void event_cb(lv_event_t *e)
{lv_event_code_t code = lv_event_get_code(e);if(code == LV_EVENT_CLICKED) printf("左鍵點擊事件\n");else if(code == LV_EVENT_RIGHT_CLICKED) printf("右鍵點擊事件\n");else if(code == LV_EVENT_DOUBLE_CLICKED) printf("左鍵雙擊事件\n");else if(code == LV_EVENT_MOUSE_WHEEL_UP) printf("鼠標滑輪上滑事件\n");else if(code == LV_EVENT_MOUSE_WHEEL_DOWN) printf("鼠標滑輪下滑事件\n");
}void page_create(void)
{lv_obj_t* box = lv_obj_create(lv_scr_act());lv_obj_set_size(box, 60, 60);lv_obj_add_event_cb(box, event_cb, LV_EVENT_ALL, NULL);
}
? ? ? ? 下面是輸出打印
? ? ? ? 到這里就完結了,其實 lvgl 的知識聽龐大的,需要大家慢慢挖索,我不建議大家一股腦的看源代碼,而是有需求用到了再去查看,探索是枯燥的,但是忍受下來你會發現其實就是那么簡單,我這里只是以三種事件為例子,其實還有鼠標懸停提示這種事件,其實也不難,需要大家好好摸索,最后謝謝大家的觀看。
?