天天看点

适配自定义按键

目录

前言

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需要亮灭屏的操作是由底层的按键触发实现的。