天天看點

适配自定義按鍵

目錄

前言

1 weston架構下輸入管理流程

2 按鍵适配處理分析

3 亮滅屏分析

3.1 destop層面下的分析

3.2 compositor層面下的分析

4 總結

前言

在weston架構下,支援的輸入裝置通常是标準裝置,如:鍵盤、滑鼠、觸摸屏等。若要支援我們自定義的鍵盤,需要在weston架構下做适配。

1 weston架構下輸入管理流程

該部分我們參考ariesjzj大神的《輸入管理》章節部分,了解了第一部分之後,基于該部分在第二章中闡述适配的過程。

适配自定義按鍵

Weston中的輸入管理子產品與libinput對接,它實作了兩大部分的功能:一是對輸入裝置的維護,二是對輸入事件的處理。對于輸入事件既會在Weston中做處理,也會傳給相應的client。從事件處理模型上來看,libinput的主循環監聽udev monitor fd,它主要用于監聽裝置的添加删除事件。如果有裝置添加,會打開該裝置并把fd加入到libinput的主循環上。另一方面,Weston中會将libinput的epoll fd加入主循環。這樣形成級聯的epoll,無論是udev monitor還是input device的fd有事件來,都會通知到Weston和libinput的主循環。這些事件通過libinput中的事件緩沖隊列存儲,而Weston會作為消費者從中拿事件并根據事件類型進行處理。

2 按鍵适配處理分析

weston在嵌入式裝置中運作,常采用的指令為:weston --tty=1 --backend=drm-backend.so ,後端采取的是drm對接顯示硬體。drm-backend.so來自于weston/libweston/compositor_drm.c

drm_backend_create
  udev_input_init -> process_events(input);
                  -> udev_input_enable 
  wl_event_loop_add_fd 将input裝置添加到epoll中去監控
           

在udev_input_enable 中将輸入裝置的fd加入到epoll循環中,如果該裝置信号可讀,則觸發回調函數:libinput_source_dispatch

libinput_source_dispatch
       udev_input_dispatch
            process_events(input)
                  	第二個epoll循環:
                    while ((event = libinput_get_event(input->libinput))) {
		                  process_event(event);
		                  libinput_event_destroy(event);
	                }                  
           

 在process_event中處理了udev和evdev事件:

process_event(struct libinput_event *event)
{
	if (udev_input_process_event(event))  //裝置add和remove
		return;
	if (evdev_device_process_event(event)) //裝置資料讀取處理
		return;
}
           

evdev_device_process_event中處理了按鍵、滑鼠、觸摸事件,以按鍵處理為例:

evdev_device_process_event
     handle_keyboard_key //按鍵事件處理   
           notify_key
           

在notify_key中可以分析出,按鍵按下之後,螢幕就會被喚醒。如果在此處進行按鍵鍵值替換,就可以實作自定義的按鍵亮屏。

weston_log("key is: %d",key);
	
	if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
		weston_compositor_idle_inhibit(compositor);
	} else {
		weston_compositor_idle_release(compositor);
	}
           

3 亮滅屏分析

weston架構下實作亮滅屏應該從使用者層面分析,而非底層。比如使用者層面的滅屏步驟中包含:LCD螢幕下電、焦點失能、上鎖等一系列的操作,若隻是實作了簡單的LCD螢幕下電并不能真正的實作滅屏操作。

3.1 destop層面下的分析

那麼首先我們從使用者層面分析亮滅屏的操作,在/weston/desktop-shell/shell.c中,通過wet_shell_init初始化了亮滅屏的操作。如下所示:

shell->idle_listener.notify = idle_handler;//熄屏信号的回調函數
wl_signal_add(&ec->idle_signal, &shell->idle_listener);

shell->wake_listener.notify = wake_handler;//亮屏信号的回調函數
wl_signal_add(&ec->wake_signal, &shell->wake_listener);
           

idle_handler的實作為:

static void
idle_handler(struct wl_listener *listener, void *data)
{
	struct desktop_shell *shell =
		container_of(listener, struct desktop_shell, idle_listener);

	struct weston_seat *seat;

	wl_list_for_each(seat, &shell->compositor->seat_list, link)
		weston_seat_break_desktop_grabs(seat);

	shell_fade(shell, FADE_OUT);
	/* lock() is called from shell_fade_done_for_output() */
}
           

其中shell_fade最終實作了lock操作

shell_fade
   shell_fade_done_for_output
         lock(shell);
           

lock中實作的操作

static void
lock(struct desktop_shell *shell)
{
	struct workspace *ws = get_current_workspace(shell);

	if (shell->locked) {
		weston_compositor_sleep(shell->compositor);
		return;
	}

	shell->locked = true;

	/* Hide all surfaces by removing the fullscreen, panel and
	 * toplevel layers.  This way nothing else can show or receive
	 * input events while we are locked. */

	weston_layer_unset_position(&shell->panel_layer); //移除panel
	weston_layer_unset_position(&shell->fullscreen_layer); //移除fullscreen
	if (shell->showing_input_panels)
		weston_layer_unset_position(&shell->input_panel_layer); //不會接收到輸入事件
	weston_layer_unset_position(&ws->layer);

	weston_layer_set_position(&shell->lock_layer,  //鎖屏
				  WESTON_LAYER_POSITION_LOCK);

	weston_compositor_sleep(shell->compositor);   //進入睡眠狀态

	/* Remove the keyboard focus on all seats. This will be
	 * restored to the workspace's saved state via
	 * restore_focus_state when the compositor is unlocked */
	unfocus_all_seats(shell);  //焦點使能

	/* TODO: disable bindings that should not work while locked. */

	/* All this must be undone in resume_desktop(). */
}
           

是以上述的lock才是真正的實作了滅屏的一系列操作。

3.2 compositor層面下的分析

首先分析weston/compositor/main.c函數

weston_compositor_create
   wl_event_loop_add_timer(loop, idle_handler, ec);
           

使用wl_event_loop_add_timer建立了一個定時器事件,定時器觸發compositor中的idle_handler。

idle_handler的實作為:

static int
idle_handler(void *data)
{
	struct weston_compositor *compositor = data;

	if (compositor->idle_inhibit)
		return 1;

	compositor->state = WESTON_COMPOSITOR_IDLE;
	wl_signal_emit(&compositor->idle_signal, compositor); //發送idle_signal信号
	

	return 1;
}
           

所示wl_signal_emit發送WESTON_COMPOSITOR_IDLE信号,3.1節中的desktop-shell收到信号之後就執行完整的滅屏操作。

繼續分析main.c中的内容,其中有一段:

if (idle_time < 0)
	weston_config_section_get_int(section, "idle-time", &idle_time, -1);
if (idle_time < 0)
	idle_time = 300; /* default idle timeout, in seconds */

ec->idle_time = idle_time;
ec->default_pointer_grab = NULL;
ec->exit = handle_exit;
.
.
.
weston_compositor_wake(ec);
           

該事件作用是什麼呢?如果你對weston有比較深的了解,就會知道在weston預設滅屏事件為5分鐘。上述的代碼就是為了實作所述的功能。

首先設定了一個idle_time事件300,然後傳遞到weston_compositor_wake(ec)中去,weston_compositor_wake中的内容:

WL_EXPORT void
weston_compositor_wake(struct weston_compositor *compositor)
{
	uint32_t old_state = compositor->state;

	/* The state needs to be changed before emitting the wake
	 * signal because that may try to schedule a repaint which
	 * will not work if the compositor is still sleeping */
	compositor->state = WESTON_COMPOSITOR_ACTIVE;

	switch (old_state) {    //開始時候,如果處于熄屏的各種狀态,則喚醒;因為剛開機不需要滅屏
	case WESTON_COMPOSITOR_SLEEPING:
	case WESTON_COMPOSITOR_IDLE:
	case WESTON_COMPOSITOR_OFFSCREEN:
		weston_compositor_dpms(compositor, WESTON_DPMS_ON);
		wl_signal_emit(&compositor->wake_signal, compositor);
		/* fall through */
	default:   //開機之後,開啟5分鐘的定時滅屏操作
		wl_event_source_timer_update(compositor->idle_source,
					     compositor->idle_time * 1000);
	}
}
           

4 總結

如果需要滅屏,則狀态為WESTON_COMPOSITOR_SLEEPING;WESTON_COMPOSITOR_IDLE;WESTON_COMPOSITOR_OFFSCREEN;執行

compositor->state = WESTON_COMPOSITOR_IDLE;
wl_signal_emit(&compositor->idle_signal, compositor);
           

如果需要亮屏,則執行喚醒操作:

weston_compositor_wake(ec);
           

自定義輸入按鍵實作過程是一種 "自底向上" 的過程,上層destop-shell需要亮滅屏的操作是由底層的按鍵觸發實作的。