MS Active Accessibility 接口技术编程尝试

2023-11-03

MS 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 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 接口指针。 图一
HWND hWndMainWindow;
IAccessible *paccMainWindow = NULL;
HRESULT hr;
//得到标题为"运行"的窗口的句柄
if(NULL == (hWndMainWindow = FindWindow(NULL, "运行")))
{
	MessageBox(NULL, "没有发现窗口!", "错误", MB_OK);
}
else
{
	//通过窗口句柄得到窗口的 IAccessible 接口指针。
	if(S_OK == (hr = AccessibleObjectFromWindow(hWndMainWindow, 
	                                            OBJID_WINDOW, 
	                                            IID_IAccessible,
	                                            (void**)&paccMainWindow)))
	{
		//……我们可以通过这个指针paccMainWindow进行操作。
		paccMainWindow->Release();
        }
}    
    现在我们已经得到窗口的 IAccessible 接口指针了(paccMainWindow),那么,我们可以干什么呢?我们怎么得到窗口中某个控件的 IAccessible 接口指针呢?我们就以上面的运行窗口为例。看看如何得到文本框的 IAccessible 接口指针!!     首先我们启动 inspect32.exe,什么?你不知道这是什么东西?赶紧先下载个Active Accessibility SDK看看吧……     然后,把鼠标放到所关注的控件上(即上图中的文本输入框),你会得到如下信息: 图二 我们现在主要关注的信息是: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));
具体用法大家还是查MSDN吧,这里就不罗嗦了!!:) 监视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中的相关章节。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

MS Active Accessibility 接口技术编程尝试 的相关文章

  • 将输入值应用于其所有 td insidehtml

    当所有 td 内部有输入时 是否可以更改所有 td 的 innerhtml 我的意思是获取输入的值并将其应用到它的 td innerhtml 例如 这里是表及其内部输入 table tr td td tr table
  • 类型错误:“str”对象无法使用 input() 调用[重复]

    这个问题在这里已经有答案了 我有以下代码 它应该询问用户 2 文件名 我在第二个函数中的 input 中遇到错误 但在第一个函数中没有 我不明白 这是错误 输出 getOutputFile 文件 splitRAW py 第 22 行 位于
  • HTML 时间输入类型 - 如何在单击任意位置而不仅仅是单击时钟图标时选择时间菜单视图

    I working on the time input type in HTML my problem is when I click on the small clock icon on the right side of the inp
  • 非数字输入导致死循环

    由于某种原因 如果用户输入了错误的数据类型 例如 j 或 循环将停止要求输入并继续显示 Enter an integer gt 一遍又一遍 如何让程序处理错误的输入 为什么输入非数字值会导致如此奇怪的行为 define SENTINEL 0
  • 如何测试具有多个输入调用的循环?

    我正在尝试测试一个依赖多个用户输入来返回某个值的函数 我已经在这里寻找了多个答案 但没有一个能够解决我的问题 我看到了参数化 模拟和猴子补丁的东西 但没有任何帮助 我认为很大程度上是因为我没有清楚地理解正在做的事情背后的概念 并且我无法适应
  • 旋转时键盘隐藏

    我正在开发 iPad 应用程序 在其中一个视图中 我有一个子视图 它在按钮点击事件时出现和消失 子视图包含一个UITextView 默认情况下 我将其设置为第一响应者 以便在视图出现时键盘立即出现 子视图也会消失UIKeyboardWill
  • 将 javascript 变量作为 onsubmit href 链接传递到表单/输入字段

    id 喜欢有一个输入框 用户可以在其中输入搜索词 该搜索词可能会传递给一个 javascript 函数 然后该函数将一些 url 段与搜索词组合起来 创建一个完整的 url 到目前为止 它在没有表单的情况下工作正常 但我想向其中添加一个表单
  • Java 数组返回奇怪的输出[重复]

    这个问题在这里已经有答案了 我正在为家庭作业问题创建一个方法 该方法返回数组中的最高值 我正在使用一个 for循环将数字输入到数组中 输入代码如下所示 int array new int n for i 0 i
  • 如何使用户输入与变量相关?

    我不知道如何准确地表达这个问题 但这就是我想要实现的目标 我正在使用堆栈实现河内塔插图 这是里面的main 功能 System out println Type the source pole number and the destinat
  • 如何处理错误的数据类型输入

    在C 中 如何处理错误的输入 例如 如果程序要求输入一个整数 那么当您键入一个字符时 它应该能够执行某些操作 然后循环重复输入 但是当您在需要整数时输入一个字符时 循环会无限循环 反之亦然 程序进入死循环的原因是std cin由于输入失败而
  • Ionic 2 获取离子输入值

    我正在使用 ionic 2 创建登录名 请不要只回答 您只需要添加 ngModules 属性 如果您认为这就是解决方案 请解释原因 解释一下 就像对孩子做的那样 我的代码在login ts import Component from ang
  • Python:如何从文件中的一行读取字符并将它们转换为浮点数和字符串,具体取决于它们是数字还是字母?

    我有一个如下所示的文件 1 1 C C 1 9873 2 347 3 88776 1 2 C Si 4 887 9 009 1 21 我想逐行读取文件的内容 当我使用的行上只有数字时 for line in readlines file d
  • 工具提示弹出窗口内的 Bootstrap 输入字段已从输出 html 中删除

    您好 我正在使用 bootstrap 4 3 1 并包含 popper 1 14 7 通常我可以在弹出窗口 工具提示的内容中添加输入字段 我从什么时候开始就不知道了 但是当我将输入字段放入内容中时 只有文本可见 当我查看源代码 编译后的 h
  • 使用 jQuery/JavaScript 将文本框值复制到剪贴板

    我有一个文本框和按钮 如下所示 div class col xs 11 style padding 20px 0 div
  • C - 直接从键盘缓冲区读取

    这是C语言中的一个问题 如何直接读取键盘缓冲区中的数据 我想直接访问数据并将其存储在变量中 变量应该是什么数据类型 我需要它用于我们研究所目前正在开发的操作系统 它被称为 ICS OS 我不太清楚具体细节 它在 x86 32 位机器上运行
  • ng-model 和值组合不适用于输入文本框

    我有两个输入文本框 我需要组合在两个文本框中输入的值并将其显示在第三个文本框中 如果我只使用value在第三个文本框中 Box 1
  • Android键盘点击搜索输入时出现和消失

    我在用谷歌地图 Js API当我搜索一个地方时 我的输入搜索栏工作正常 当我通过 iPhone 设备使用它时 它也工作得很好 但是当我通过Android 设备然后键盘立即出现和消失 我已经找到了一些关于当我按下搜索栏时 android 键盘
  • 将键码转换为相关的显示字符

    在 C Windows Forms 项目中 我有一个不提供 KeyPressed 事件的控件 它是一个 COM 控件 ESRI 映射 它仅提供 KeyUp 和 KeyDown 事件 包含关键事件参数 http msdn microsoft
  • 如何使用文本输入来定位?

    我想使用 jQuery 通过文本框转到锚点 例如 我想使用以下形式
  • 使用
    元素作为 JavaScript 代码的输入。这是最好的方法吗?

    各位 显然 我是编码新手 所以最近完成了一些有关 HTML 和 Javascript 的 Lynda 课程后 我的简单 HTML 页面遇到了困难 基本上 我想要的是使用 JavaScript 进行基本计算 让用户使用 HTML 输入两个数字

随机推荐

  • 在linux上强制停止进程应该用哪个命令,如何在Linux系统中使用命令终止无响应进程...

    有多种工具可用于从命令行终止无响应或挂起的进程 包括kill pkill和killall 这些命令通过向这些无响应的进程发送特定信号来工作 您将需要进程ID或PID信息 以便可以向他们发送所需的终止信号 您可以使用命令来检索无响应进程的PP
  • java两个jsonobject对象合并_Java:将两个json对象与主键合并在一起

    假设我在内存中有两个 JSONObject数组 每个对象都有一个在两个数组中相似的键 数组1 name Big Melons Co location Inner City Dubai id 1A name Pear Flavored Jui
  • CGI与FastCGI

    当我们在谈到cgi的时候 我们在讨论什么 最早的Web服务器简单地响应浏览器发来的HTTP请求 并将存储在服务器上的HTML文件返回给浏览器 也就是静态html 事物总是不 断发展 网站也越来越复杂 所以出现动态技术 但是服务器并不能直接运
  • [激光原理与应用-48]:《焊接质量检测》-5-德擎先进激光过程诊断系统ALPAS分析

    目录 第1章 概述 第2章 产品特性与功能 2 1 传感器 2 2 主机数据分析系统 第3章 工作原理 第4章 系统组成 第5章 案例分析 第1章 概述 先进激光过程诊断系统 ALPAS Advanced Laser Process Ass
  • 高德地图key验证失败:[INVALID_USER_SCODE]

    高德地图key验证失败 INVALID USER SCODE key错误 错误出现原因 如果是在非打包情况下 电脑直接安装 调试 调试版安全码SHA1 一定要填写 否则会报key错误 不填只能打包成apk文件再安装 如果修改了依然报错 那么
  • 解决垃圾回收难题,提升Android应用性能的技巧

    Android应用程序在运行过程中可能会遇到内存溢出 Memory Out of Bounds 和内存泄漏 Memory Leak 的问题 这些问题会导致应用程序性能下降 响应变慢甚至崩溃 内存溢出 Memory Out of Bounds
  • springboot部署到服务器遇到的SSL证书问题

    错误 javax net ssl SSLException java lang RuntimeException Unexpected error java security InvalidAlgorithmParameterExcepti
  • Pycharm使用教程 (非常实用)

    一 PyChram下载 官网 http www jetbrains com pycharm Windows http www jetbrains com pycharm download section windows Linux http
  • 【STL】模板概念+STL介绍

    模板 Template 模板就是C 实现代码重用机制的一种工具 它可以实现类型参数化 即把类型定义为参数 从而实现了真正的代码可重用性 可以使用模板来定义函数和类 当你定义一个如下函数 想要计算一个数的平方 int square int x
  • sql中用什么替代in

    IN和EXISTS 有时候会将一列和一系列值相比较 最简单的办法就是在where子句中使用子查询 在where子句中可以使用两种格式的子查询 第一种格式是使用IN操作符 where column in select from where 第
  • CVE-2019-0708 远程桌面代码执行漏洞复现

    0X00 靶机 漏洞环境 我当时就是虚拟机装了Windows7 SP1的系统 一下就ojbk 你们没有 就下载装吧 使用VM安装Windows7 SP1模拟受害机 Windows7 SP1下载链接 这里的靶机是使用清水表哥提供的win7sp
  • SOA:原理•方法•实践,第 1 部分: SOA 的基本概念

    SOA 原理方法实践 的第 1 章从概念上对 SOA 给出一个全面而精炼的总体描述 首先说明 SOA 的特点 以及使用 SOA 对系统进行架构决策和设计的必要性 然后介绍了 SOA 的参考体系结构 设计原则及相关技术的简介 查看本系列更多内
  • Android性能优化 _ 大图做帧动画卡?优化帧动画之 SurfaceView滑动窗口式帧复用

    ps 粗斜体表示引导方案逐步进化的关键点 SurfaceView逐帧解析 帧复用 简单回顾下上一篇的内容 原生帧动画在播放前解析所有帧 对内存压力大 SurfaceView可以精细地控制帧动画每一帧的绘制 在每一帧绘制前才解析当前帧 且解析
  • java常用部署脚本

    记一个工作中常用的java部署脚本 首先进入linux 1 使用下面代码段 vim run sh 2 然后按 i 进入编辑模式 3 拷贝下面脚本代码 bin sh chkconfig 2345 99 10 description Start
  • 西门子S7-1200 PLC进行项目选型要了解这些

    西门子S7 1200 PLC是西门子S7系列PLC产品中一员 S7系列产品包含有 S7 200 Smart 200 S7 1200 S7 300 S7 1500 S7 400等系列PLC 其中S7 200 Smart 200 S7 1200
  • Java多线程编程详解(第零章)

    Java多线程编程详解 0 参考书籍 Java并发编程实战 Java并发编程实战 本文是关于以上两本书的读书笔记以及一些个人思考 0 关于并发与多线程的简介 编写正确的程序很难 而编写正确的并发程序则难上加难 与串行程序相比 在并发程序中存
  • 如何针对单个表单项去掉验证和添加验证?

    this refs conpanyForm clearValidate district 清除校验 this refs conpanyForm validate district 添加校验
  • Ubuntu安装notepad++

    习惯了Windows的代码编写输入方式 转回Ubuntu vim编程总有点不习惯和不方便 即使vim功能很强大 我还是喜欢Windows的代码编写输入方式 简简单单 安装个notepadqq就行了 Ubuntu版notepad 安装方式 s
  • vue vue-json-viewer 展示 JSON 格式数据

    1 下载 vue json viewer npm 下载 vue json viewer Vue2 npm install vue json viewer 2 save Vue3 npm install vue json viewer 3 s
  • MS Active Accessibility 接口技术编程尝试

    MS Active Accessibility 接口技术编程尝试 编译 崔传凯 下载源代码 Microsoft Active Accessibility 2 0 is a COM based technology that improves