原创

C

C++

windows sdk

无障碍

C/C++应用无障碍化之支持tab键浏览

2020-07-31 Friday 12:30

前言

正常人操作电脑,只需一眼便能得知屏幕上的内容,要想激活某个控件,例如按钮等,只需将鼠标拖动过去点击即可。
但对于盲人而言,却十分繁琐。
盲人使用屏幕阅读器操作电脑,当在某个软件中时,会使用tab键进行浏览,每按下一次tab键,就会将当前焦点移动到下一个控件,同时语音会朗读出其标签等信息。
如果想浏览上一个控件,则可以使用shift+tab键,进行反向浏览。
因此,可以说盲人就是靠着tab键浏览软件界面的。
而tab键浏览并不是屏幕阅读器支持的,需要软件本身支持,因此本篇文章,我们就来介绍下C/C++写的应用如何支持tab键浏览!

实现原理

支持tab键浏览的原理,其实就是在窗口的消息处理函数中处理tab键、shift+tab键的按下消息。
例如可以使用如下代码

	switch (message)
	{
// 判断是按键按下消息
	case WM_KEYDOWN:
		switch (wParam)
		{
// 判断按键为tab键
		case VK_TAB:
// 判断是否同时按下shift键
			if (GetKeyState(VK_SHIFT) < 0)
// 此处将焦点移动到上一个控件,实现反向浏览
			else
// 此处将焦点移动到下一个控件,实现正序浏览
			return 0;
		}
		break;
	}

得知原理后,我们就可以开始处理焦点移动了。
不过此处还氛围两种情况:

1.每个控件都有单独窗口句柄

如果是此种情况,则可以直接调用SetFocus函数,将下一个或上一个控件的窗口句柄传入,及会将焦点移动过去。
如果为了方便起见,我们还可以使用GetWindow函数,传入GW_HWNDPREV标识,返回值为上一个同层级控件的句柄,也可以传入GW_HWNDLAST获取出最后一个控件、GW_HWNDNEXT下一个控件、GW_HWNDFIRST第一个控件。

2.控件都无单独窗口句柄

此种情况一般只有最外层的容器存在窗口句柄,所以就无法使用SetFocus函数来进行焦点的移动了。
我们需要调用NotifyWinEvent函数,来通知焦点的变化,函数原型如下:

void NotifyWinEvent(
  DWORD event,
  HWND  hwnd,
  LONG  idObject,
  LONG  idChild
);

第一个参数为事件类型,此处我们使用EVENT_OBJECT_FOCUS表示是焦点变化事件。
第二个参数为窗口句柄。
第三个为触发事件的对象ID,一般我们直接传入OBJID_CLIENT即可。
第四个为此事件是对象本身触发,还是其子控件触发。
要实现焦点的浏览,我们主要就是靠第四个参数,用它来标明当前浏览到了哪一个控件。
首先我们内部需要给每个控件都设置一个独立的ID,而当触发焦点变化事件的时候,就将此ID传入第四个参数。
当然,紧这样是不够的,我们还需要让容器窗口实现IAccessible接口,在get_accName、get_accRole等方法中根据varChild的lVal属性,去返回相对应控件的标签、类型等。
至于具体实现,可参考之前的文章:
C/C++中给控件设置标签方法

后续

虽然让软件支持无障碍需要一定的工作量,但就是因为有了无障碍的存在,才让无数残疾人可以平等的享受科技带来的便利。
愿无障碍可以加入到每一款软件的开发流程中。
开发多一点,障碍少一点!


随手打赏
关闭

感谢您的支持!

扫码打赏,你说多少就多少
打赏二维码

打开

支付宝

扫一扫,即可进行扫码打赏哦