MS Active Accessibility 接口技术

CSS状态伪类:构建可访问、跨端、合规的交互基础 CSS状态伪类(如:hover、:focus、:active)是Web交互的核心机制,其本质是浏览器对用户输入意图的原生响应层,而非简单的视觉装饰。它们基于HTML语义触发,遵循指针事件与焦点管理的底层逻辑,在桌面、触屏及辅助技术环境中表现各异。正确实现不仅能提升点击信心与导航效率,更是满足WCAG 2.1‘焦点可见性’和‘状态一致性’等可访问性要求的技术前提。本文聚焦链接与按钮的状态链设计,覆盖多端适配、ARIA协同、`:focus-visible`渐进增强及`:has()`等现代组合用法,为构建鲁棒、包 阅读详情

Microsoft© Active Accessibility 2.0 is a COM-based technology that improves the

way accessibility aids work with applications running on Microsoft Windows?. It

provides dynamic-link libraries that are incorporated into the operating system

as well as a COM interface and application programming elements that provide

reliable methods for exposing information about user interface elements.     

一.基础

Microsoft© Active Accessibility 是一种相对较新的技术(1.0版在1997年5月份推出)。目的是方便身患残疾的人士使用电脑――可用于放大器、屏幕阅读器,以及触觉型鼠标。同样还可以用来开发驱动其它软件的应用程序,其模拟用户输入的能力尤其适合测试软件的开发。

Active Accessibility 的主要思想是提供一种以程序方式访问UI元素信息或操作这些UI元素的功能。支持这种功能的 UI(User Interface) 元素是可访问的。在大多数情况下,这意味着一个UI元素支持 IAccessible 接口。你也可以说在 Active Accessibility 的世界里,一个可访问的UI元素可表示为 IAccessible 接口。

每当你需要得到有关一个元素的信息,在其上执行一个动作,或者使用 Active Accessibility 做其它的什么,你通常需要通过使用代表这个元素的 IAccessible 接口的一种方法或者属性来引用这个元素。


二.Active Accessibility 原理

Active Accessibility? 的核心功能由 OLEACC.DLL 提供的。每次当你调用一个函数来返回一个 IAccessible 接口指针,其与一个UI元素相对应,OLEACC.DLL就检查此元素是否内在支持 IAccessible。内在的支持意思是该元素的 IAccessible 是用程序实现的。

当一个UI元素不能内在的支持 IAccessible 时,OLEACC.DLL 检查该元素的Windows 类名。如果该类是一个 USER 或者 COMCTL32 支持的类,OLEACC.DLL 就创建一个代理为 UI 元素实现 IAccessible 接口。大多数--但不是全部--COMCTL32 控件都具有被 OLEACC.DLL 支持的 IAccessible 接口。

内在支持 IAccessible 的 UI 元素的例子是定制控件,owner-drawn 和无窗口的控件。因为开发者创建的程序包含这些UI元素,同样就实现了这些元素的接口,他们有责任为这些方法和属性提供正确的支持。

如果你用标准控件,这也意味着你不必重写你的应用,这些应用自动与Active Accessibility兼容。

Active Accessibility 名字是基于 Win32 控件的名字给出的,角色基于控件的功能定义。


三.如何得到 IAccessible 接口指针

每当你需要有关一个元素的信息,在其上执行一个动作,或者使用 Active Accessibility 做其它的什么,你只需要通过使用代表这个元素的 IAccessible 接口的一种方法或者属性来引用这个元素。

有几种方法取得代表一个可访问 UI 元素的 IAccessible 接口的指针。最普通的方法是使用 Active Accessibility 提供的一种函数,例如 AccessibleObjectFromPoint,AccessibleObjectFromWindow 等等,或者使用 IAccessible 支持的方法,例如 get_accChild,get_accParent。

IAccessible 接口支持允许你得到各 UI 元素信息的属性,而其中对于例子程序最重要的属性是名字、角色和状态。

Active Accessibility SDK提供了一些方便的工具,其中的 Object Inspector 能显示光标指向的UI元素的属性。Object Inspector 显示了Active Accessibility 的世界如何因为具有支持一个选定窗口内的 IAccessible 接口的控制而变得通用了。除了搜索有关元素的信息和通过 IAccessible 接口控制元素以外,Active Accessibility? 还有两种对于例子程序非常有用的特性:监视UI元素发生的事件和模拟键盘、鼠标输入。由可访问的元素激发的事件称为 WinEvents,当可访问的元素创建或者名字、状态、位置或者键盘焦点发生变化时,就激发这些事件(事件机制类似于标准的 Windows 的 hook 机制。监视事件我们将在后面介绍。)。这些事件的清单见文件 WINABLE.H。每个事件的名字以 EVENT_OBJECT 或 EVENT_SYSTEM 开始。

好,我们言归正传,来介绍如何得到 IAccessible 接口指针。前面已经提到过 AccessibleObjectFromWindow 这个 Active Accessibility 提供的函数,从字面上大家可以看出是通过窗口来得到对应的 IAccessible 接口指针。

因为 IAccessible 接口的数量比窗口要多(因为大多数--但不是全部--COMCTL32 控件都有被 OLEACC.DLL 支持的 IAccessible 接口。),使用 Win32 函数来搜索一个窗口将会比使用 Active Accessibility 树搜索与该窗口相应的 IAccessible 接口要占用少得多的时间。这就意味着为了提高性能,你应该使用 FindWindow 和 EnumWindows 这样的 Win32 函数来找到与希望的UI元素最接近的窗口。当然,在权衡 Win32 函数和 Active Accessibility 函数时,上面的规则只是使用它们的一般标准而不能盲目的遵照执行,重要的是理解它们的本来意义。

下面结合代码介绍一下它的用法。

我们来得到下面运行窗口的 IAccessible 接口指针。


我们现在主要关注的信息是:Name、Role、Window className。

Name = "打开(O):"
Role = "可编辑文字"
Window className = "Edit"  

当开发自定义、owner drawn 或者无窗口的控件时,为同一窗口的每个"角色-名字"指定独一无二的表示是一个非常好的编程习惯。然而,如果由于某种原因,同一窗口中的2个 UI 元素具有同样的"角色-名字"对,那么就需要增加一个参数--windows 类--以唯一的来表示这个元素。

FindChild 函数显示了一个基于 Active Accessibility 父/子(你可以理解成父窗口/子窗口的关系,只是为了便于理解:-P)导航的搜索例程的实现。这个函数有6个参数。前4个包含传递给函数的信息,后2个包含了 IAccessible 接口/子ID对(见附录)。

下面我们开始取文本输入框的 IAccessible 接口指针。

IAccessible*	paccControl = NULL;//输入框的 IAccessible 接口
VARIANT		varControl;    		//子ID。

FindChild( paccMainWindow, 
           "打开(O):", 
           "可编辑文字", 
           "Edit", 
           &paccControl, 
           &varControl )    

第一个参数是先前得到的窗口 IAccessible 接口指针。

第二、三、四个参数分别是名字、角色、类。

后2个为返回参数包含了 IAccessible 接口/子ID对。下面是FindChild的实现。

BOOL FindChild (IAccessible* paccParent, 
                         LPSTR szName, LPSTR szRole, 
                         LPSTR szClass, 
                         IAccessible** paccChild, 
                         VARIANT* pvarChild)
{
	HRESULT hr;
	long numChildren;
	unsigned long numFetched;
	VARIANT varChild;
	int index;
	IAccessible* pCAcc = NULL;
	IEnumVARIANT* pEnum = NULL;
	IDispatch* pDisp = NULL;
	BOOL found = false;
	char szObjName[256], szObjRole[256], szObjClass[256], szObjState[256];
	
		//得到父亲支持的IEnumVARIANT接口
	hr = paccParent -> QueryInterface(IID_IEnumVARIANT, (PVOID*) & pEnum);
	
	if(pEnum)
		pEnum -> Reset();
	
//取得父亲拥有的可访问的子的数目
	paccParent -> get_accChildCount(&numChildren);
	
//搜索并比较每一个子ID,找到名字、角色、类与输入相一致的。
	for(index = 1; index <= numChildren && !found; index++)
	{
		pCAcc = NULL;		
		// 如果支持IEnumVARIANT接口,得到下一个子ID
//以及其对应的 IDispatch 接口
		if (pEnum)
			hr = pEnum -> Next(1, &varChild, &numFetched);	
		else
	{
		//如果一个父亲不支持IEnumVARIANT接口,子ID就是它的序号
			varChild.vt = VT_I4;
			varChild.lVal = index;
		}
		
		// 找到此子ID对应的 IDispatch 接口
		if (varChild.vt == VT_I4)
		{
			//通过子ID序号得到对应的 IDispatch 接口
			pDisp = NULL;
			hr = paccParent -> get_accChild(varChild, &pDisp);
		}
		else
			//如果父支持IEnumVARIANT接口可以直接得到子IDispatch 接口
			pDisp = varChild.pdispVal;
		
		// 通过 IDispatch 接口得到子的 IAccessible 接口 pCAcc
		if (pDisp)
		{
			hr = pDisp->QueryInterface(IID_IAccessible, (void**)&pCAcc);
			hr = pDisp->Release();
		}
		
		// Get information about the child
		if(pCAcc)
		{
			//如果子支持IAccessible 接口,那么子ID就是CHILDID_SELF
			VariantInit(&varChild);
			varChild.vt = VT_I4;
			varChild.lVal = CHILDID_SELF;
			
			*paccChild = pCAcc;
		}
		else
			//如果子不支持IAccessible 接口
			*paccChild = paccParent;
		
		//跳过了有不可访问状态的元素
		GetObjectState(*paccChild, 
		               &varChild, 
		               szObjState, 
		               sizeof(szObjState));
		if(NULL != strstr(szObjState, "unavailable"))
		{
			if(pCAcc)
				pCAcc->Release();
			continue;
		}
		//通过get_accName得到Name
		GetObjectName(*paccChild, &varChild, szObjName, sizeof(szObjName));
		//通过get_accRole得到Role
		GetObjectRole(*paccChild, &varChild, szObjRole, sizeof(szObjRole));
		//通过WindowFromAccessibleObject和GetClassName得到Class
		GetObjectClass(*paccChild, szObjClass, sizeof(szObjClass));
		//以上实现代码比较简单,大家自己看代码吧。

			//如果这些参数与输入相符或输入为NULL
		if ((!szName || 
		     !strcmp(szName, szObjName)) && 
		     (!szRole || 
		      !strcmp(szRole, szObjRole)) && 
		     (!szClass || 
		      !strcmp(szClass, szObjClass)))
		{
			found = true;
			*pvarChild = varChild;
			break;
		}
		if(!found && pCAcc)
		{
			// 以这次得到的子接口为父递归调用
			found = FindChild(pCAcc, 
			                  szName, 
			                  szRole, 
			                  szClass, 
			                  paccChild, 
			                  pvarChild);
			if(*paccChild != pCAcc)
				pCAcc->Release();
		}
	}//End for
	
	// Clean up
	if(pEnum)
		pEnum -> Release();
	
	return found;
}

// UI元素的状态也表示成整型形式。因为一个状态可以有多个值,
//例如可选的、可做焦点的,该整数是反映这些值的位的或操作结果。
//将这些或数转换成相应的用逗号分割的状态字符串。
UINT GetObjectState(IAccessible* pacc, 
                    VARIANT* pvarChild, 
                    LPTSTR lpszState, 
                    UINT cchState)
{
    HRESULT hr;
    VARIANT varRetVal;
    *lpszState = 0;
    VariantInit(&varRetVal);
    hr = pacc->get_accState(*pvarChild, &varRetVal);
	if (!SUCCEEDED(hr))
        return(0);
	DWORD dwStateBit;
	int cChars = 0;
    if (varRetVal.vt == VT_I4)
	{
		// 根据返回的状态值生成以逗号连接的字符串。
        for (dwStateBit = STATE_SYSTEM_UNAVAILABLE; 
               dwStateBit < STATE_SYSTEM_ALERT_HIGH; 
               dwStateBit <<= 1)
        {
            if (varRetVal.lVal & dwStateBit)
            {
                cChars += GetStateText(dwStateBit, 
                                       lpszState + cChars, 
                                       cchState - cChars);
				*(lpszState + cChars++) = '','';
            }
        }
		if(cChars > 1)
			*(lpszState + cChars - 1) = ''\0'';
    }
    else if (varRetVal.vt == VT_BSTR)
    {
        WideCharToMultiByte(CP_ACP, 
                            0, 
                            varRetVal.bstrVal, 
                            -1, 
                            lpszState,
                            cchState, 
                            NULL, 
                            NULL);
    }
    VariantClear(&varRetVal);
    return(lstrlen(lpszState));
}

好了!!我们已经成功得到文本框的 IAccessible 接口指针了!!现在你可以用这个接口指针为所欲为了!!!呵呵:)

在 IAccessible 接口上执行动作

有了表示一个可访问的 UI 元素的 IAccessible 接口/子ID对,你也有了搜索该元素一个名字(get_accName)、角色(get_accRole)、类和状态(get_accState)的方法。让我们看看你还可以干什么!get_accDescription 能取得UI元素的描述,get_accValue 能取得一个值。

最重要的函数之一是 accDoDefaultAction。每个可访问的UI元素都有一个缺省定义的动作。例如,一个按钮的缺省动作是"按下这个按钮",一个检查框的缺省动作是"不选"。为了确定一个元素的缺省动作,请参考 Active Accessibility 文档或者调用 get_accDefaultAction。

如果我想起动注册表编辑器,该怎么办呢?如果是我们手动做的话,无非是在文本输入框输入"regedit",然后按确定按钮,就这么简单。下面我们来看看用 Active Accessibility 是怎么来实现的。

//在文本输入框输入"regedit"
if(1 == FindChild (paccMainWindow, "打开(O):", 
                   "可编辑文字", 
                   "Edit", 
                   &paccControl, 
                   &varControl))
{
	//在这里修改文本编辑框的值
	hr = paccControl->put_accValue(varControl, 
	                                  CComBSTR("regedit"));
	paccControl->Release();
	VariantClear(&varControl);
}
		
// 找到确定按钮,并执行默认动作。
if(1 == FindChild (paccMainWindow, 
                   "确定", 
                   "按下按钮", 
                   "Button", 
                   &paccControl, 
                   &varControl))
{
	//这里执行按钮的默认动作,即"按下这个按钮"
	hr = paccControl->accDoDefaultAction(varControl);
	paccControl->Release();
	VariantClear(&varControl);
}
现在,你会发现已经成功启动了注册表编辑器!!


四.模拟鼠标和键盘操作

让我们假设你需要操作一个新的不完全支持 Windows 消息和 IAccessible 接口方法的 UI 元素。如果它不支持你需要的消息和方法,最简单的解决办法就是模拟键盘和鼠标输入。例如,你可以用Tab模拟转移到期望的控件。

使你能够实现这些的函数就是 SendInput 一个一般的USER API。虽然不属于Active Accessibility,把他们联合使用很自然。

SendInput 接受三个参数:要执行的鼠标键盘动作个数、INPUT结构数组和结构数组的大小。每个INPUT结构描述一个要执行的动作。注意,按下一个按钮和释放一个按钮是两个不同的动作,所以必须创建两个不同的INPUT结构。

下面的代码将模拟 ALT+F4 按键来关闭窗口。

INPUT input[4];	
memset(input, 0, sizeof(input));
//设置模拟键盘输入
input[0].type = input[1].type = input[2].type = input[3].type = INPUT_KEYBOARD;
input[0].ki.wVk  = input[2].ki.wVk = VK_MENU;
input[1].ki.wVk  = input[3].ki.wVk = VK_F4;

// 释放按键,这非常重要
input[2].ki.dwFlags = input[3].ki.dwFlags = KEYEVENTF_KEYUP;
SendInput(4, input, sizeof(INPUT));
五.监视WinEvents

监视 WinEvents 非常像通过 Windows Hook 监视 Windows 消息。最重要的区别就是从另一个进程监视 UI 元素发出的 WinEvents 时,你不需要创建一个单独的DLL来注入那个进程的地址空间。

监视 WinEvents 有两种选择:通过设置 SetWinEventHook 函数的最后一个参数来确定是在上下文之外还是之内监视。如果是在上下文之外,不需要额外的DLL,回调函数运行在目标进程之外。如果是在上下文之内,回调函数必须放在额外的DLL,并注入目标进程的地址空间。第二种方法写代码比较麻烦,但是运行效率高。

好,现在回到上面的例子。上面例子能够执行的前提条件是能够找到标题为"运行"的窗口。现在可以先检查运行窗口是否存在,如果不存在就设置WinEvents 钩子去监视,直到"运行"窗口被创建。看下面代码:

if(NULL == (hWndMainWindow = FindWindow(NULL, szMainTitle)))
{
hEventHook = SetWinEventHook(
	EVENT_MIN,	// eventMin ID
	EVENT_MAX,	// eventMax ID
	NULL,		// always NULL for outprocess hook
	WinCreateNotifyProc,		// call back function
	0,				// idProcess
	0,				// idThread 
         // always the same for outproc hook
	WINEVENT_SKIPOWNPROCESS | WINEVENT_OUTOFCONTEXT);
}    

第一、二个参数用来指定监视事件的范围。第四个参数是定义的回调函数。

下面是回调函数:

void CALLBACK WinCreateNotifyProc(
 HWINEVENTHOOK  hEvent,
 DWORD   event,
 HWND    hwndMsg,
 LONG    idObject,
 LONG    idChild,
 DWORD   idThread,
 DWORD   dwmsEventTime
 )
{
	if( event != EVENT_OBJECT_CREATE)
		return;
	
	char bufferName[256];
	IAccessible *pacc=NULL;
	VARIANT varChild;
    VariantInit(&varChild);
	//得到触发事件的 UI 元素的 IAccessible 接口/子ID对
	HRESULT hr= AccessibleObjectFromEvent(hwndMsg, 
	                                      idObject, 
	                                      idChild, 
	                                      &pacc, 
	                                      &varChild);
	if(!SUCCEEDED(hr))
	{
		VariantClear(&varChild);
		return;
	}
	//得到 UI 元素的Name,并比较,如果是"运行"就发送消息给主线程。
	GetObjectName(pacc, &varChild, bufferName, sizeof(bufferName));
	if(strstr(bufferName, szMainTitle))
		PostThreadMessage(GetCurrentThreadId(), 
		                  WM_TARGET_WINDOW_FOUND, 
		                  0, 
		                  0);
	return;
}    

恩…………,一个应用基本成型了,虽然比较简单。就先写这么多吧,请关注后续介绍。

附录:

关于IAccessible 接口/子ID对:

让我们来考虑这样一个控件,他支持 IAccessible 接口并且包含一些子控件,比如 listbox 就包含很多 items 。有两种方法让他可以被访问:第一种,提供listbox的 IAccessible 接口和每一个 item 自己的 IAccessible 接口。另一种是只提供一个控件的 IAccessible 接口,这个接口能够提供基于某种识别方法来访问每一个子控件的功能。

第一种方法,需要为这个控件和每一个子控件创建单独的 COM 对象,这会比第二种方法(每一个子控件不支持自己的 IAccessible 接口,而是通过父接口来访问)增加内存消耗。第二种方法里,通过增加一个参数--子ID--同父的IAccessible 接口一起表示这个子控件。子ID 是一个 VT_I4 型的 VARIANT 值,包含一个由程序决定的独特的值,或只是一个子控件的序号。序号意味着第一个子控件的ID为1,第二个子控件的ID为2,依次增长!

这样,如果一个子控件不支持自己的 IAccessible 接口,而其父控件支持,那么这个子控件可以用它的父控件的 IAccessible 接口/子ID 对来表示。通常,一个支持 IAccessible 接口的父UI元素也是通过这样的 IAccessible 接口/子对表示的,这时候其子ID号为 CHILDID_SELF (就是0)。

记住,子ID号总是相对于 IAccessible 接口的。例如,一个可访问的元素可以同相对于其父 IAccessible 接口的一个非子 CHILDID_SELF 的 ID 及其父IAccessible 接口表示,如果他支持 IAccessible 接口,此元素的子ID就是相对于自己 IAccessible 接口的CHILDID_SELF。

呵呵,翻译的有点别扭,意思就是说,如果这个控件支持 IAccessible 接口,那么它的子ID就是0(CHILDID_SELF),可以用它自己的 IAccessible 接口和0这个对来表示这个控件。如果控件不支持 IAccessible 接口,就用它父控件的 IAccessible 接口,和一个相对于父 IAccessible 接口的子ID来表示。哎呀!!不知道说明白没有。郁闷!!!!

注:

我也是刚开始学习怎么使用MSAA,但是苦于很难找到中文资料。希望这篇文章对大家能有所帮助。由于了解的还很肤浅,错误难免,望谅解!!:)

还有,这篇文章基本编译自Dmitri Klementiev的《Software Driving Software: Active Accessibility-Compliant Apps Give Programmers New Tools to Manipulate Software》,只是按自己的理解重新编排了一下,如果觉得不符合自己的学习习惯可以看原文。并且我的文章省略了很多东西,呵呵。

参考资料:

1、 Dmitri Klementiev写的《Software Driving Software: Active Accessibility-Compliant Apps Give Programmers New Tools to Manipulate Software》及其源程序。http://msdn.microsoft.com/msdnmag/issues/0400/aaccess/default.aspx

2、 MSDN中的相关章节。






嵌入式SD/TF卡通用协议-SDIO协议 为了驱动SD卡,首先的第一步就是观察SD卡引脚接线情况,通常我们在画原理图时,都是使用的SD卡卡槽与MCU进行接线。SD卡可以使用SDIO协议和SPI协议进行通信,这里我们主要介绍SDIO协议。下图中的TF卡只是容量小一点的SD卡。以F1C100S为例,接线图如下所示:我们发现上图中的TF卡使用的协议为SDIO协议,主要有4根数据线,1根命令线,1根时钟线组合而成。为了驱动这个SD/TF卡我们就需要去了解SDIO协议的时序。 阅读详情

相关推荐

灯塔问题:贪心与动态规划算法解析

区间覆盖问题是算法设计中的经典案例,常用于理解贪心算法与动态规划的核心差异。贪心算法通过局部最优选择逐步构建全局解,具有O(n log n)的高效时间复杂度,特别适合处理一维区间覆盖场景。动态规划则采用自底向上的填表法,虽然通用性更强但复杂度较高。在实际工程中,这类算法广泛应用于无线基站部署、监控设备布置等资源优化场景。通过分析灯塔问题的两种解法,可以深入掌握算法选择的关键因素,如问题规模、性能要求和实现复杂度。

weixin_28720573的博客 259

转贴:MS Active Accessibility 接口技术编程尝试 (自动化测试)

MS Active Accessibility 接口技术编程尝试 编译/崔传凯#include "COMDEF.H" 下载源代码 Microsoft© Active Accessibility 2.0 is a COM-based technology that improves

archerzhang的专栏 1021

别再为H5扫码头疼了!用Vue3 + vue-qrcode-reader,5分钟搞定移动端摄像头调用(附完整代码)

本文详细介绍了如何使用Vue3和vue-qrcode-reader快速实现移动端扫码功能,解决H5开发中常见的摄像头调用和兼容性问题。通过完整的代码示例和优化技巧,帮助开发者高效集成二维码识别功能,提升用户体验和开发效率。

weixin_33737134的博客 513

基于IAccessible接口的QQ窗口信息获取的实现

这个技术现在已经封装成DLL免费开放给大家使用了,详情请加群221487171 可以访问官方网站下载 http://www.guihelper.com/ 主要技术(Microsoft Active Accessibility)讲解: 以下是微软对于此技术的说明 Microsoft Active Accessibility Version 2.0 Purpose Microsoft® ...

weixin_30810239的博客 1173

【开源教程25】疯壳·开源编队无人机-定高、定点、悬停

【开源教程25】疯壳·开源编队无人机-定高、定点、悬停

efans_Mike的博客 1650

【系统架构设计师-2023年真题】综合知识-答案及详解

要实现多任务间的协同工作,操作系统必须提供任务间的通信手段。嵌入式操作系统一般都会提供多任务间通信的方法,其中()是任务间最直接、最明显的通信方法,也是访问共享的数据结构,即不同的任务都可以访问同一地址空间。()作为一种更高级的通信方式,能够在同一处理器的各个任务间传递任意长度(理论上只受物理内存和机器字长限制)的信息。(1)A. 共享内存 B. Socket C. 消息传递 D. 信号量(2)A. 共享内存 B. Socket C. 消息传递 D. 信号量【答案】A、C关于星型拓扑结构,下列说法正确的是(

数据知道的博客 1万+

Active Accessibility

   下载源代码 Microsoft© Active Accessibility 2.0 is a COM-based technology that improves the way accessibility aids work with applications running on Microsoft Windows?. It provides dynamic-link

z0007202的专栏 6700

uniapp [安卓苹果App端] - 实现获取手机日历读写权限+调用本机日历数据及操作功能+日历中插入事项事件提醒,检测权限手机日历权限是否开启并引导用户同意授权,uniApp app端开启日历授权

uni-app,权限,手机日历权限,安卓Android,苹果ios,uniapp安卓android获取本机日历读写权限使用,uni-app获取日历权限并实现插入事项事件功能 uniapp苹果IOS系统不支持怎么办,判断权限,权限被拒绝了怎么办,获取日历权限报错,读取日历数据农历阴历并操作插入移除,给用户手机日历中放入一条提示,UniApp调用日历进行读写,打包上架后如何获取,安卓ios权限检测,安卓和ios权限获取,uniapp的APP端日历读写权限与使用示例代码,如何开启日历权限,日历的新增事项和删除,判

🏆 前端领域优质创作者 1万+

使用IAccessible接口,遍历DirectUI窗口控件的问题?

前一段时间,做一个程序,需要完成一个小功能,即对鼠标监视,当左键单击某个文件选中时,获得该文件文件名称。 折腾了好久,最终在windowsXP下完美实现了。实现的思路是: 1、下鼠标钩子,获得鼠标左键clickup事件。 2、使用FindPointWindow,获得鼠标位置窗口句柄。 3、使用SendMessage,向该窗口(SysListView32)发送信息,获得选中文件序号及文件名称

路在何方 1万+

IPD流程中的RR\OR\IR\PB\SR\AR\CR等名词汇总(基于新的产品包需求架构)

RR:Raw Requirement,原始需求=》IR:Initial Requirement,初始需求=》SR:System Requirement,系统需求=》AR:Allocated Requirement,分配需求=》CR:Process Change Requirement,流程变更需求。

a1809032425的博客 3188

RK3568笔记十七:LVGL v8.2移植

若该文为原创文章,转载请注明原文出处。本文介绍嵌入式图形库移植到Linux开发板ATK-RK3568上的步骤。

4230

MS Active Accessibility 接口技术编程尝试

MS Active Accessibility 接口技术编程尝试 编译/崔传凯 下载源代码 Microsoft© Active Accessibility 2.0 is a COM-based technology that improves the way accessibility

冰峰 的专栏 2035

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

在windows下模拟鼠标键盘输入的几种方法 (附带源代码)

在windows下模拟鼠标键盘输入的几种方法    最近小叮咚使用的服务器(第3方的asp服务器,不是iis)在启动后总是不能自动运行,可能里面有Bug,需要点击启动按钮后才能连接到internet上.    为了保证小叮咚的稳定运行,我把我的机器(放在家)配置成每小时启动一次,启动后自动运行服务器软件    这个软件没有类似: /run 等的命令行启动方式,于是我想,能不能用程序自动实现 模

我要去桂林-田春峰 1万+

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

基于ie内核的浏览器的解决办法

<br />IE 报 R6025 pure virtual function call 错误对话框的原因<br />症状<br />当您在运行 Microsoft Windows XP 在计算机上运行 Microsoft Internet Explorer 6 时, 您可能会收到类似于以下的错误信息:<br />Runtime Error !<br />程序 C:/PROGRAM FILES/INTERNET EXPLORER/IEXPLORE.EXE<br />R6025<br />pure virtua

499

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

Azure AD vs Keycloak:身份管理终极对决,桌面点击自动化技术MSAA,UIA-Microsoft Active Accessibility-UI Automation。

Azure AD 是微软推出的云原生身份认证服务,深度集成 Microsoft 生态;Keycloak 是开源的 IAM 解决方案,支持高度自定义和跨平台部署。两者在协议支持、集成能力、管理复杂度等方面存在显著差异。

vjzb1xfm的博客 460

Mac mini上安装OpenClaw:本地AI操作代理深度部署指南

OpenClaw是一款面向macOS的本地化智能操作代理框架,本质是将自然语言指令实时转化为键盘鼠标操作、应用调用与跨应用数据流转。其技术原理依赖于系统级权限集成——包括辅助功能(Accessibility)、输入监控(Input Monitoring)和全盘访问(Full Disk Access),并深度适配ARM64架构与macOS底层API机制。相比云端自动化工具,OpenClaw具备低延迟(M1/M2机型稳定<80ms)、高隐私性与强上下文感知能力,适用于游戏误触防护、文件批量处理、邮件附件归档及N

weixin_30416871的博客 379

MSAA --> UIA (转)

 MSAA --> UIA English version:http://blogs.msdn.com/lixiong/archive/2009/03/28/msaa-uia-brief-explanation.aspx 名词解释MSAA:http://msdn.microsoft.com/en-us/library/ms971310.aspx 说穿了,MSAA

Tian的学习笔记 3788

Gemini Mac版深度解析:原生屏幕理解与macOS交互范式升级

屏幕理解是多模态AI落地操作系统的关键技术,其核心在于将视觉界面实时转化为结构化语义数据,而非简单OCR识别。它依赖Accessibility API、Metal纹理捕获和窗口关系图谱等系统级能力,实现低延迟、高保真的上下文建模。该技术显著提升办公自动化、代码审查、学术精读等场景的准确率与效率,尤其在Apple Silicon设备上依托Neural Engine达成实时处理。Gemini Mac版作为典型代表,展示了原生开发如何突破WebView封装瓶颈,真正实现‘所见即所问’的交互范式迁移。

weixin_33979203的博客 454

MSAA, UIA brief explanation

MSAA, UIA brief explanation 2014-07-24 Reference [1] MSAA, UIA brief explanation [2] Testing Tools [3] MS UI Automation简介 [4] UI Automation Overview [5]使用UI Automation库用于UI自动化测试 [6] UI Aut...

weixin_33827731的博客 99

MSAA in TestComplete

<br /><br />原文来源:http://msdn.microsoft.com/zh-cn/library/ms971350.aspx<br />发布日期 : 12/17/2004 | 更新日期 : 12/17/2004<br />Microsoft Corporation<br />摘要:本概述描述了 Microsoft Active Accessibility 如何帮助软件开发人员使其程序与辅助功能更兼容,并帮助辅助功能开发人员能够使辅助功能更可靠。本页内容<br />简介<br />Acti

vagabond1的专栏 593

MSAA VS UIA

MSAA --> UIA   English version: http://blogs.msdn.com/lixiong/archive/2009/03/28/msaa-uia-brief-explanation.aspx   名词解释MSAA: http://msdn.microsoft.com/en-us/library/ms971310.aspx   说穿了,MSAA就

xinke453的专栏 2158
上一篇: 一个基于线程池的WSAEventSelect模型服务器设计
下一篇: libnids中TCP/IP栈实现细节分析(上)——TCP会话重组
jiangfeng999
博客等级 码龄23年 122粉丝 64原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值