适配自定义按键

目录

 

前言

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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Android按键广播是指在Android系统中,当用户在设备上按下按键时,系统会通过广播的形式发送一个按键事件给应用程序。应用程序可以通过注册接收器来监听这些按键广播,从而进行相应的处理。 Android提供了一个名为KeyEvent的类来表示按键事件。该类包含了按下按键的键码和键标志等信息。通过监听按键广播,应用程序可以根据具体的按键事件做出相应的操作。 为了接收按键广播,应用程序需要在AndroidManifest.xml文件中注册一个接收器,并指定接收的广播类型为"android.intent.action.KEYCODE"。在接收器中,可以重写onReceive方法,该方法会在接收到按键广播时被调用。 例如,当用户按下音量键时,系统会发送ACTION_VOLUME_CHANGED广播。应用程序可以在接收器中注册对该广播的监听,并在接收到广播时执行相应的逻辑,例如调整音量大小。 使用按键广播可以实现很多功能,例如在游戏中监听用户的按键操作,实现游戏控制;或者在媒体播放器中监听用户的音量键按下事件,实现音量调节。 总之,Android按键广播提供了一种机制,让应用程序能够响应用户的按键操作。通过注册接收器并监听相应的广播,应用程序可以根据按键事件做出相应的处理,从而提升用户体验。 ### 回答2: Android 按键广播是指在Android系统中,当用户在设备上按下物理按键时,系统会发送相应的广播通知应用程序。通过接收这些广播,应用程序可以捕获按键事件,并根据需要进行相应的处理。 Android系统通过Intent来实现按键广播的传递。每个按键事件都会关联一个特定的Intent,并通过广播传递给应用程序。应用程序可以通过注册广播接收器来监听这些按键广播,在接收到相应广播时执行相应的逻辑。 在Android中,常见的按键广播包括: 1. ACTION_DOWN:当按键被按下时发送的广播。应用程序可以通过监听这个广播来捕获按键按下的事件响应。 2. ACTION_UP:当按键被释放时发送的广播。应用程序可以通过监听这个广播来捕获按键释放的事件响应。 3. ACTION_MULTIPLE:当按键被长时间按住并持续产生输入字符时发送的广播。 除了以上的基本按键广播,Android系统还提供了一些特定的按键广播,例如: 1. ACTION_MEDIA_BUTTON:用于媒体播放控制的按键广播,例如音量键、媒体控制键等。 2. ACTION_CAMERA_BUTTON:用于相机控制的按键广播,例如相机快门键。 我们可以通过在应用程序中注册BroadcastReceiver来监听某个特定的按键广播。当接收到对应广播时,我们就可以在广播接收器的onReceive()方法中编写相应的逻辑代码,例如改变UI界面、执行特定动作等。 总之,Android按键广播是一种通过发送广播通知应用程序的方式,来捕获和处理用户按键事件的方法。它能够实现按键与应用程序的交互,为用户提供更好的按键体验。 ### 回答3: Android按键广播是指在Android系统中,当用户按下设备上的硬按键(如返回键、菜单键、音量键等)时,系统会发送对应的广播消息,应用程序可以通过注册广播接收器来监听这些按键事件。通过捕获按键广播,可以在应用程序中做出相应的处理,例如在按下返回键时执行特定的操作。 开发者可以通过注册BroadcastReceiver并监听相关的Intent来接收按键广播。常见的按键广播Intent有ACTION_DOWN和ACTION_UP,分别表示按键按下和松开的事件。通过在BroadcastReceiver中重写onReceive()方法,开发者可以编写处理按键事件的逻辑。 在接收到按键广播后,开发者可以根据需要进行不同的处理。例如,当用户按下返回键时,可以确认用户是否希望退出应用程序,如果是,则执行退出操作;如果不是,则可以忽略该按键事件。另外,也可以根据不同的按键响应特定的功能,如音量键控制音量大小,菜单键打开菜单等。 需要注意的是,Android系统并不允许修改一些特定按键的默认行为,只能对按键事件进行监听和处理,而不能改变按键的功能。同时,不同的设备可能会有不同的按键布局和功能,因此开发者需要根据具体的设备进行适配处理。 总结来说,Android按键广播是一种方便开发者监听和处理按键事件的机制。通过注册广播接收器,并根据需要编写相应的逻辑,开发者可以自定义在应用程序中按下不同硬按键时的行为。这样,可以提供更好的用户体验并增加应用程序的功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值