Touch Driver介绍
Touch Driver介绍
一.相关知识介绍
1.Touch Driver的加载过程
GWES到[HKEY_LOCAL_MACHINE/HARDWARE/DEVICEMAP/TOUCH]的“Driver name”获取Driver DLL的名字,如果没有找到该键值,则使用默认名字Touch.dll。
Touch Driver的加载内容非常简单,就是调用一下导出函数TouchPanelEnable()。
2.导出函数介绍
与其它很多Driver类似,Touch Driver采用PDD+MDD双层架构,如下图所示:
OEM厂商只需要修改微软PDD层的代码,实现PDD层的API即可,必须实现的PDD层的API包括:
Programming element |
Description |
DdsiTouchPanelAttach |
This function executes when the MDD's DLL entry point receives a DLL_PROCESS_ATTACH message. |
DdsiTouchPanelDetach |
This function executes when the MDD's DLL entry point receives a DLL_PROCESS_DETACH message. |
DdsiTouchPanelDisable |
This function disables the touch screen device. |
DdsiTouchPanelEnable |
This function applies power to the touch screen device and initializes it for operation. |
DdsiTouchPanelGetDeviceCaps |
This function queries capabilities of the touch screen device. |
DdsiTouchPanelGetPoint |
This function returns the most recently acquired point and its associated tip state information. |
DdsiTouchPanelPowerHandler |
This function indicates to the driver that the system is entering or leaving the suspend state. |
DdsiTouchPanelSetMode |
This function sets information about the touch screen device. |
由于PDD层的代码非常简单,所以这里不做讨论。
下面对MDD层的API,同时也是Touch Panel Driver必须的导出的一些接口,做一些简单分析,很多东西是我个人理解,有可能是错误的。
1> TouchPanelGetDeviceCaps
获取Touch Driver的一些参数,根据GWES传入的Code不同,返回不同的信息给GWES。
>> TPDC_SAMPLE_RATE_ID
返回Touch Driver的采样速率给上层,包括当前速率,高速和慢速。
struct TPDC_SAMPLE_RATE {
INT SamplesPerSecondLow;
INT SamplesPerSecondHigh;
INT CurrentSampleRateSetting;
};
>> TPDC_CALIBRATION_POINT_COUNT_ID
告诉上层进行屏幕校准的时候采样点是多少。
struct TPDC_CALIBRATION_POINT_COUNT {
DDI_TOUCH_PANEL_CALIBRATION_FLAGS flags;
INT cCalibrationPoints;
};
>> TPDC_CALIBRATION_POINT_ID
告诉上层采样点总共有多少个,及其坐标位置。
struct TPDC_CALIBRATION_POINT {
INT PointNumber;
INT cDisplayWidth;
INT cDisplayHeight;
INT CalibrationX;
INT CalibrationY;
};
2> TouchPanelEnable
初始化Touch Driver,所有相关硬件有关的初始化以及数据采集中断线程的创建都是在这里完成。
值得一提的是其传入参数是一个处理Event的Callback函数,在数据采集中断线程中需要通过该Callback反馈给GWES坐标信息。所以这里需要将这个Callback函数指针给保存下来以供后续使用。
另外,该函数除了在初始化的时候调用,按照帮助文档的解释,在系统运行的某个时间还会再次调用,所以该函数中有一些中断处理的操作。小弟一介菜鸟,不知道啥时候会再次调用,呵呵。
3> TouchPanelDisable
无语了。
4> TouchPanelSetMode
根据Code的不同配置Touch Panel的不同工作状态,MDD层代码中主要有下面的一些分支:
>> TPSM_PRIORITY_HIGH_ID
重新配置IST优先级为高优先级。
>> TPSM_PRIORITY_NORMAL_ID
重新配置IST的优先级为正常优先级。
该线程的默认优先级是109,可以在注册表//Drivers//BuiltIn//Touch下的"Priority256"及"HighPriority256"进行配置
5> TouchPanelReadCalibrationPoint
由GWES直接调用,在校准屏幕的时候使用,后面会对该函数详细的讲述。
6> TouchPanelReadCalibrationAbort
终止校准屏幕的过程,方法是直接给校准屏幕的函数TouchPanelReadCalibrationPoint发送一个hCalibrationSampleAvailable Event,并由函数TouchPanelReadCalibrationPoint通知GWES里面的校准线程(是否有该线程,我不太确定,我是推测的)校准失败。
在GWES看来,它只通过TouchPanelReadCalibrationPoint的返回值来判断校准的正确与否,无论任何原因引起的校准没有完成,它都认为是失败,包括用户的Abort。
7> TouchPanelCalibrateAPoint
Touch Driver通过中断数据采集线程IST告诉GWES当前触摸点的坐标,方式是调用Callback函数,然后GWES再通过调用TouchPanelCalibrateAPoint()对坐标位置进行校准,是由TouchPanelpISR直接调用,不是由GWES直接调用。校准公式如下:
校准的公式如下:
Sx = A1*Tx + B1*Ty + C1
Sy = A2*Tx + B2*Ty + C2
其中,Tx和Ty是触摸屏坐标,而Sx和Sy是显示设备坐标,其中A1/B1/C1/A2/B2/C2是校准参数,在屏幕进行校准的时候计算出来,在GWES调用TouchPanelSetCalibration()的时候会使用到。
该函数的声明如下:
VOID TouchPanelCalibrateAPoint( INT32 UncalX, INT32 UncalY, INT32* pCalX, INT32* pCalY ); Parameters UncalX [in] Noncalibrated x-coordinate. UncalY [in] Noncalibrated y-coordinate. pCalX [out] Pointer to the returned calibrated x-coordinate. pCalY [out] Pointer to the returned calibrated y-coordinate. |
8> TouchPanelSetCalibration
该函数利用Touch Panel的采样点坐标和屏幕的显示坐标来计算Touch Panel Driver的校正参数。
Microsoft通过下列的方式来计算坐标点:
Sx = A1*Tx + B1*Ty + C1
Sy = A2*Tx + B2*Ty + C2
其中,Tx和Ty是触摸屏坐标,而Sx和Sy是显示设备坐标。
该函数的功能就是根据采样点和屏幕上的十字号的值计算出A1,B1,C1和A2,B2,C2。
9> TouchPanelPowerHandler
这个函数虽然简单,但是在设备电源管理中有用处。与其它Driver中的PowerHandle作用类似。
二.Touch Driver和GWES的交互
1.Touch Driver中的 Callback 函数
GWES调用TouchPanelEnable()初始化Touch Driver,并传入Callback函数指针pfnCallback作为实参。在TouchPanelEnable()中将会保存该Callback函数的指针,并在数据采集中断线程IST中调用该Callback函数,以通知GWES目前的坐标点。
函数TouchPanelEnable()中对该Callback函数的处理如下:
BOOL TouchPanelEnable( PFN_TOUCH_PANEL_CALLBACK pfnCallback ) { BOOL ReturnValue;
// // Do the 'attach' code. Normally, this would have been // done in the ThreadAttach block, but this driver is set // up to be statically linked to GWE, in which case none of // the DLL related calls would even be invoked. // TouchPanelpAttach();
EnterCriticalSection( &csMutex );
// // Insure the device is disabled and no one is attached to the logical // interrupt. // Power on the device. // Connect the logical interrupt to the device. //
InterruptDone( gIntrTouch ); InterruptDisable( gIntrTouch ); if( SYSINTR_NOP != gIntrTouchChanged ) { InterruptDone( gIntrTouchChanged ); InterruptDisable( gIntrTouchChanged ); }
v_pfnCgrPointCallback = pfnCallback; if (v_pfnCgrCallback != NULL) v_pfnPointCallback = v_pfnCgrCallback; else v_pfnPointCallback = pfnCallback;
ghevCalibrationActivity = NULL;
ReturnValue = DdsiTouchPanelEnable();
if (ReturnValue && !InterruptInitialize(gIntrTouch, hTouchPanelEvent, NULL, 0)) { DEBUGMSG(ZONE_ERROR, (TEXT("TouchPanelEnable: InterruptInitialize(gIntrTouch %d failed/r/n"), gIntrTouch)); DdsiTouchPanelDisable(); ReturnValue = FALSE; } if ( ( SYSINTR_NOP != gIntrTouchChanged ) && ReturnValue && !InterruptInitialize( gIntrTouchChanged, hTouchPanelEvent, NULL, 0)) { DEBUGMSG(ZONE_ERROR, (TEXT("TouchPanelEnable: InterruptInitialize(gIntrTouchChanged %d failed/r/n"), gIntrTouchChanged)); InterruptDisable(gIntrTouch); DdsiTouchPanelDisable(); ReturnValue = FALSE; } if (ReturnValue) { // Create the ISR thread. If creation fails, perform cleanup and return failure. // bTerminate=FALSE; if (!(hThread = CreateThread( NULL, 0, TouchPanelpISR, 0, 0, NULL))) { TouchPanelpDetach(); InterruptDisable(gIntrTouch); if( SYSINTR_NOP != gIntrTouchChanged ) InterruptDisable(gIntrTouchChanged); DdsiTouchPanelDisable(); ReturnValue = FALSE; } else { // Get thread priority from registry TouchPanelpGetPriority(&gThreadPriority, &gThreadHighPriority);
// Set our interrupt thread's priority CeSetThreadPriority(hThread, gThreadPriority); } } LeaveCriticalSection(&csMutex); return(ReturnValue); } |
数据采集中断线程TouchPanelpISR对Callback函数的调用参照后面的函数介绍。
2.触摸板坐标数据的采集
想象一下,GWES不停的去向Touch Panel Driver索取坐标点,如果用户一直没有点击的话,这将是多么大的一种资源的浪费。所以在微软设计Touch Driver和GWES的时候,Touch Driver主动地去通知GWES触摸板的坐标,而不是反过来GWES主动地去向Touch Driver索取触摸板的坐标。其它与用户输入和显示有关的驱动也是这样的设计思路,这种设计思路和系统设备管理器的设计思路恰好相反,NND,微软太有才了。
不扯了,言归正传。
GWES通过调用函数TouchPanelEnable()初始化Touch Driver。在函数TouchPanelEnable()中将会创建线程TouchPanelpISR,该线程负责触摸板坐标的采集和使用Callback函数通知GWES Touch Panel采集的结果。其默认优先级是109,可以在注册表//Drivers//BuiltIn//Touch下的"Priority256"及"HighPriority256"进行配置,并通过TouchPanelSetMode()改变其优先级。
其实触摸板坐标的采集全部都是在TouchPanelpISR中完成,有关该函数的操作,可以参照后面对该函数的详细解释。
3.校准Touch Panel的过程描述
在前面介绍函数TouchPanelCalibrateAPoint()的时候,曾经提到下面的一个公式:
Sx = A1*Tx + B1*Ty + C1
Sy = A2*Tx + B2*Ty + C2
校准屏幕的目的就是确定A1/B1/C1/A2/B2/C2的值。
校准屏幕分为即开机自动校准和利用校准工具校准。
1> 开机自动校准
注册表项HKEY_LOCAL_MACHINE/HARDWARE/DEVICEMAP/TOUCH的"CalibrationData"下保存着默认的屏幕校准数据。
每次开机启动后,GWES会从该注册表项下获取默认的屏幕校准数据,具体校准数据的采样点数与GWES中通过TouchPanelGetDeviceCaps的TPDC_CALIBRATION_POINT_COUNT_ID分支获取的采样点数相同。从MDD层的代码中没有找到获取该默认值的代码,我猜测可能是GWES直接去获取该值。
当GWES获取到该值后,将会去调用函数TouchPanelSetCalibration()来对Touch Panel进行校准,以此来获取A1/B1/C1/A2/B2/C2的值,并存放到Driver的全局变量v_CalcParam中。
顺便在此列出来v_CalcParam的类型定义:
typedef struct { INT32 a1; INT32 b1; INT32 c1; INT32 a2; INT32 b2; INT32 c2; INT32 delta; } CALIBRATION_PARAMETER, *PCALIBRATION_PARAMETER; |
2> 使用微软校准工具进行校准
通过添加SYSGEN_TOUCH对应的Feature可以在OS中添加该校准工具,其实就是在控制面板中看到的屏幕校准工具。当然,你也可以自己写一个校准工具,直接调用API就行了。
校准过程如下:
>> 获取校准基础信息
调用TouchPanelGetDeviceCaps的TPDC_CALIBRATION_POINT_COUNT_ID分支获取屏幕校准的坐标点数,在这里假设是5个;
>> GWES调用Touch Driver获取屏幕坐标点位置和触摸板坐标点位置
GWES调用TouchPanelGetDeviceCaps的TPDC_CALIBRATION_POINT_ID分支获取第1个校准点的屏幕坐标位置(注意:并不是触摸板的坐标位置),然后由GWES调用Display Driver在屏幕上画出十字号,接着GWES调用函数TouchPanelReadCalibrationPoint()获取触摸板坐标点位置。
按照相同的方法依次对剩余的四个坐标点做类似操作。
>> 校准
GWES将前面一步获取的屏幕坐标点和触摸板坐标点传递给Touch Driver,由函数TouchPanelSetCalibration()进行校准参数的计算,并将结果写入到全局变量v_CalcParam中。
下面详细的介绍一下与校准屏幕有关的线程TouchPanelpISR和函数TouchPanelReadCalibrationPoint()。
当校准屏幕应用程序运行的时候,GWES将会直接去调用获取完Touch Panel支持的采样点个数后,将会直接去调用TouchPanelReadCalibrationPoint()。该函数的主要用途是告知IST需要校准屏幕,并等待IST中校准屏幕的结果,每校准一个坐标点,该函数和IST会通过Event联系一次。
函数TouchPanelReadCalibrationPoint()的详细解释如下:
/*++
@func VOID | TouchPanelReadCalibrationPoint | Initates the process of getting a calibration point. This function causes the device driver to foward the last valid x and y coordinates between the tip states of initial down and up to the calibration callback function. The tip state of the forwarded coordinates is reported as initial down.
@parm LONG | UcalX | The uncalibrated X coordinate under calibration. @parm LONG | UcalY | The uncalibrated Y coordinate under calibration.
@rdesc If the function succeeds, TRUE; otherwise FALSE. Extended error information is available via the GetLastError function.
--*/ BOOL TouchPanelReadCalibrationPoint( INT *pRawX, INT *pRawY ) { BOOL retval; HANDLE hevActivity = NULL; DWORD dwStatus; HKEY hk;
NKDbgPrintfW(L"++TouchPanelReadCalibrationPoint()/r/n");
if(!pRawX || !pRawY ) { SetLastError(ERROR_INVALID_PARAMETER); return ( FALSE ) ; }
// Get a path to the GWES activity event. We need to set it ourselves // because calibration is essentially a modal loop and doesn't put // events onto the user input queue, which is where this event gets // set inside GWES. // 从注册表项"System//GWE"下获取ActivityEvent的键值,它用来和GWES直接进行通信,不知道具体做些什么工作 // 如果有人知道的话,欢迎告诉我 dwStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"System//GWE", 0, 0, &hk); if(dwStatus == ERROR_SUCCESS) { WCHAR szEventPath[MAX_PATH]; DWORD dwSize = sizeof(szEventPath); DWORD dwType;
// Read the path to the event and open it -- do this on every call // to this API so that we're not forced to keep an event open that // is almost never used. dwStatus = RegQueryValueEx(hk, L"ActivityEvent", NULL, &dwType, (LPBYTE) szEventPath, &dwSize); NKDbgPrintfW(L"Event name: %s/r/n", szEventPath); szEventPath[MAX_PATH - 1] = 0; // enforce null termination if(dwStatus == ERROR_SUCCESS && dwType == REG_SZ) { hevActivity = OpenEvent(EVENT_ALL_ACCESS, FALSE, szEventPath); } RegCloseKey(hk); }
EnterCriticalSection( &csMutex );
// // If a calibration is already active, error. //
if ( CalibrationState ) { SetLastError( ERROR_POSSIBLE_DEADLOCK ); LeaveCriticalSection( &csMutex ); if(hevActivity != NULL) { CloseHandle(hevActivity); } return ( FALSE ); }
// // Set sample count and active flag. // Wait for calibration to happen. // Update the memory with the x and y coordinates. // Clear active flag. // We be done. // 标志呀,啥也不说了,非常重要,控制IST的 CalibrationState = CalibrationWaiting;
// let the IST know about the event // 时间呀 ghevCalibrationActivity = hevActivity;
LeaveCriticalSection( &csMutex );
// 等待IST校准数据获取的结果,如果IST数据获取结束将会通过该Event通知该函数 WaitForSingleObject( hCalibrationSampleAvailable, INFINITE ); EnterCriticalSection( &csMutex );
*pRawX = lCalibrationXCoord; *pRawY = lCalibrationYCoord;
// 可以看到,该函数反馈给GWES的结果就是简单的False或者True retval = ( CalibrationState == CalibrationValid ); CalibrationState = CalibrationInactive;
// done with the event ghevCalibrationActivity = NULL;
LeaveCriticalSection( &csMutex );
// close the event handle CloseHandle(hevActivity);
NKDbgPrintfW(L"--TouchPanelReadCalibrationPoint(x: 0x%8x, y: 0x%8x, retval= 0x%x)/r/n", *pRawX, *pRawY, retval);
return retval; } |
线程TouchPanelpISR比较复杂,主要用途是进行采样点坐标的采集,并在采样点数据采集完毕的时候通过Event hCalibrationSampleAvailable告知TouchPanelReadCalibrationPoint()。两个条件下该线程采集坐标数据成功:一是PDD函数DdsiTouchPanelGetPoint()采集有效数据连续满足( ABS(DeltaX) > CAL_DELTA_RESET )&& ( ABS(DeltaY) > CAL_DELTA_RESET )超过CAL_HOLD_STEADY_TIME,二是PDD函数DdsiTouchPanelGetPoint()采集的有效数据且满足( ABS(DeltaX) > CAL_DELTA_RESET )&& ( ABS(DeltaY) > CAL_DELTA_RESET )的个数超过MIN_CAL_COUNT。
如果在上述过程中,发现任意一次PDD函数DdsiTouchPanelGetPoint()采集的数据是无效的,则进行下一次循环,没啥影响。但是如果采集的有效数据不能够满足( ABS(DeltaX) > CAL_DELTA_RESET )&& ( ABS(DeltaY) > CAL_DELTA_RESET ),则一切推倒重来,舍弃之前所有的坐标采样数据。
/*++
Autodoc Information:
@func ULONG | TouchPanelpISR | This routine is the thread which handles touch panel events. The event that this thread synchronizes on is signaled by the PDD based on the sampling rate, typically 10ms.
@rdesc Never returns.
--*/ static ULONG TouchPanelpISR( PVOID Reserved //@parm Reserved, not used. ) { TOUCH_PANEL_SAMPLE_FLAGS SampleFlags = 0; INT32 RawX, CalX; INT32 RawY, CalY; UINT32 MaxX = DisplayWidth * X_SCALE_FACTOR; UINT32 MaxY = DisplayHeight * Y_SCALE_FACTOR; UINT32 CurrentDown = 0; static LONG CX; static LONG CY; static LONG XBase; static LONG YBase; static int CalibrationSampleCount; static BOOL fSetBase; static DWORD BaseTime; static BOOL fGotSample;
PFN_TOUCH_PANEL_CALLBACK pfnCallback;
// Need to be all kmode so that we can write to shared memory. // SetKMode(TRUE);
NKDbgPrintfW(L"TouchPanelpISR/r/n"); while ( !bTerminate ) {
// IST等待Timer和Touch中断事件hTouchPanelEvent唤醒 // gdwTouchIstTimeout = INFINITE WaitForSingleObject( hTouchPanelEvent, gdwTouchIstTimeout ); EnterCriticalSection( &csMutex ); DEBUGMSG(ZONE_THREAD, (TEXT("TCH_INTR/r/n")) );
// Give the pdd the down state of the previous sample // CurrentDown:不用说了吧,就是记录Touch是否被按下,添加这个Flag的目的主要是为了配合Timer中断 if ( CurrentDown ) SampleFlags |= TouchSamplePreviousDownFlag; else SampleFlags &= ~TouchSamplePreviousDownFlag;
// 废话少说,先得到触摸屏坐标点再说,同时在SampleFlags返回一些标记,包括坐标点是否有效等等 DdsiTouchPanelGetPoint( &SampleFlags, &RawX, &RawY ); // Get the point info
NKDbgPrintfW(L"(0) 0x%8x/r/n", SampleFlags); // 坐标点不合法,下次再说吧 if ( SampleFlags & TouchSampleIgnore ) { // do nothing, not a valid sample LeaveCriticalSection( &csMutex ); continue; }
if ( SampleFlags & TouchSampleValidFlag ) { // Set the previous down state for our use, since the pdd may not // have preserved it. // 下面的四行代码和前面一段类似,为啥?微软怎么会这么傻呢? // 看了半天,原来是MDD层代码不信任PDD层的API DdsiTouchPanelGetPoint,担心该函数会将SampleFlags得值给Rewrite if ( CurrentDown ) SampleFlags |= TouchSamplePreviousDownFlag; else SampleFlags &= ~TouchSamplePreviousDownFlag;
CurrentDown = SampleFlags & TouchSampleDownFlag; }
// 这里的CalibrationState是一个全局变量,当GWES调用TouchPanelReadCalibrationPoint获取用户的校准坐标的时候,会将其赋值为CalibrationWaiting // 所以,也只有在校准屏幕的时候程序才会走到这里 if ( CalibrationState ) { // // At this point we know that calibration is active. // // Typically, the user touches the panel then converges to the // displayed crosshair. When the tip state transitions to // the up state, we forward the last valid point to the callback // function. // DEBUGMSG(ZONE_SAMPLES, (TEXT("**** Calibration point (%d, %d), flags 0x%4.4X/r/n"), RawX, RawY, SampleFlags) );
// Skip if not valid. // 下面这三行代码纯属多余,必须砍掉,呵呵 if ( !(SampleFlags & TouchSampleValidFlag) ) { LeaveCriticalSection( &csMutex ); continue; } NKDbgPrintfW(L"(1) 0x%8x/r/n", SampleFlags); // Signal the Power Manager activity event if one has been set up // ghevCalibrationActivity是一个和TouchPanelReadCalibrationPoint进行通信的Event Handle // 该事件就是"System//GWE"下的"ActivityEvent"配置的那个事件,在TouchPanelReadCalibrationPoint中会去创建该事件 // 这种类似的操作也是GWES中应用比较多的一种操作 if ( ghevCalibrationActivity != NULL) { // 我猜测GWES需要这个事件做一些操作,可能会需要用该事件去告之它ISR中已经知道了要校准屏幕,现在可以为GWES提供相关的服务了 SetEvent(ghevCalibrationActivity); }
// Must see down transition. // 符合下面的条件其实就是: // 1. 校准屏幕第一次采集到有效数据; // 所以,第二次采集到有效数据的话,这里的条件就不符合了 if ( (SampleFlags & (TouchSampleDownFlag|TouchSamplePreviousDownFlag)) == TouchSampleDownFlag ) { CalibrationState = CalibrationDown; // fSetBase用来表示是否需要设置Base时间,一般的校准屏幕时间对每个采样点的校准是由时间限制的,如果超过时间的话,自动采样结束 fSetBase = TRUE; // 变量CalibrationSampleCount用来记录采样点的个数 CalibrationSampleCount = 0; // fGotSample用来标记数据是否已经采集结束 fGotSample = FALSE; }
NKDbgPrintfW(L"(2) 0x%8x/r/n", SampleFlags); // Only look at stuff if we saw a down transition. if ( (CalibrationState == CalibrationDown) && !fGotSample ) { // 值得一说的就是SampleFlags的TouchSampleDownFlag位是从PDD层返回来的,而不是在IST里面进行赋值的 if ( SampleFlags & TouchSampleDownFlag ) { long DeltaX, DeltaY;
// 哈哈,拿到一次有效的数据 CalibrationSampleCount++; CX = RawX; CY = RawY; if ( fSetBase ) { XBase = CX; YBase = CY; BaseTime = GetTickCount(); fSetBase = FALSE; } DeltaX = CX - XBase; DeltaY = CY - YBase; // 超过采样点采样时间,自动采样 // 意思就是说,如果你拿着笔针在一个采样点上点击超过.5s依然没有拿起来的话,采样自动结束 if ( (GetTickCount() - BaseTime) > CAL_HOLD_STEADY_TIME ) { fGotSample = TRUE; } // 如果第二次采样点与第一次采样点的偏差超过CAL_DELTA_RESET的话,需要重新开始数据的采集 // 意思就是说,如果你在十字号上触摸<1.5后,在不抬起来的情况下移动笔针,则你将发现.5s后自动数据采集才结束 else if ( ( ABS(DeltaX) > CAL_DELTA_RESET ) || ( ABS(DeltaY) > CAL_DELTA_RESET ) ) { RETAILMSG(1, (TEXT("M %ld,%ld %ld,%ld %ld,%ld"), XBase,YBase, CX,CY, DeltaX,DeltaY)); fSetBase = TRUE; } } else { NKDbgPrintfW(L"%d/%d/r/n", CalibrationSampleCount, MIN_CAL_COUNT); // They lifted the pen, see if we will accept coordinate. // 当最后一次抬起笔针的时候,程序将会走到这里 // 针对最后笔针最后一次抬起,将会做两种处理: // 1. 如果采样点个数已经>MIN_CAL_COUNT的话,结束当前采样点的采样,并通知校准线程 // 2. 如果采样点不足的话,则将开启下一次全新的采样过程,也即舍弃之前所有的采样点坐标 if ( CalibrationSampleCount >= MIN_CAL_COUNT ) { fGotSample = TRUE; } else { CalibrationState = CalibrationWaiting; } }
if ( fGotSample ) { CalibrationState = CalibrationValid; lCalibrationXCoord = CX; lCalibrationYCoord = CY; SetEvent(hCalibrationSampleAvailable); } } LeaveCriticalSection( &csMutex ); } else { // 获取Callback函数指针,供后续调用 // 该Callback函数在TouchPanelEnable中由GWES传递 pfnCallback = v_pfnPointCallback; if ( pfnCallback != NULL ) { // 这里由PDD层代码告诉MDD层,是否需要对触摸板坐标进行校准,如果屏幕的线性度很好,就可以不需要这个步骤 if( SampleFlags & TouchSampleIsCalibratedFlag ) { // Sample already calibrated by PDD CalX = RawX; CalY = RawY; } else { // Not previously calibrated, do it now. TouchPanelCalibrateAPoint( RawX, RawY, &CalX, &CalY ); SampleFlags |= TouchSampleIsCalibratedFlag; }
LeaveCriticalSection( &csMutex );
// Bounds check this value if( CalX < 0 ) CalX = 0; else if( MaxX && ((UINT32)CalX >= MaxX) ) CalX = MaxX - X_SCALE_FACTOR; if( CalY < 0 ) CalY = 0; else if( MaxY && ((UINT32)CalY >= MaxY) ) CalY = MaxY - Y_SCALE_FACTOR ;
DEBUGMSG( ZONE_SAMPLES, (TEXT("**** Queuing point (%d, %d), flags 0x%4.4X/r/n"), CalX, CalY, SampleFlags) );
// 采集到数据后,通过Callback函数告知GWES (pfnCallback)( SampleFlags, CalX, CalY); } else { LeaveCriticalSection( &csMutex ); }
} } ExitThread(1); return ( TRUE ); } |
Touch Driver介绍相关推荐
- 高通Q+A Virtio hypervisor touch框架介绍(share-device)
背景 大家都知道现在高通芯片在汽车行业的座舱域运用比较热门,但是这种现象不是突然冒出来的,高通最早在2015年左右就开始推广他们的第一代座舱芯片820A.而在2018年左右开始推广他们的第二代产品(6 ...
- Linux SDIO WIFI Marvell8801/Marvell88w8801(六) --- Marvell Linux Wi-Fi driver介绍-WIFI插入卡槽内发生的事情
代码工程的GITHUB连接:点进进入GITHUB仓库 https://github.com/sj15712795029/stm32f1_marvell88w8801_marvell8801_wifi ...
- Touch driver porting
1>将驱动code加入源码kernel目录,touch driver是drivers/input/touchscreen 可以直接放到这里,也可以新建个目录放进去,看自己喜好-我是建了个目录,会 ...
- Wave Driver介绍-7(驱动中对音量的控制操作-非硬件音量控制)
http://blog.csdn.net/daydayupfromnowon/article/details/6009333 下面一步步的描述驱动中对音量控制的调整过程: 第一步:wave drive ...
- 移动web——touch事件介绍
基本概念 1.在移动web端点击事件或者滑动屏幕.捏合等动作都是由touchstar.touchmove.touchend这三个事件组合在一起使用的 2.click事件在移动端会有0.2秒的延迟,下面 ...
- ILITEK touch driver
流水帐式的记录一下调试过程: 大致需要修改的文件及目录: a: msm8960-perf_OT310-eth-cdrom-fuse_defconfig: +# CONFIG_TOUCHSCREEN_I ...
- Sencha Touch框架介绍
Sencha Touch框架是世界上第一个基于HTML 5的Mobile App框架,也是目前为止所发现的最强大的应用于移动平台的框架,它将自己定位为框架(Framework)而不是类库(Librar ...
- Wave Driver介绍-5(Waveform Audio Driver Test测试Case描述)
http://blog.csdn.net/daydayupfromnowon/article/details/6003500 因为要对Audio Driver做CETK测试,所以今天了解了一下CETK ...
- 3D Touch介绍: 一个数字压力器App和Quick Actions
随着iPhone 6s and 6s Plus的发布,苹果介绍了全新的手机交互方式:重按手势.你应该知道,这个特性其实早已应用在苹果手表和MacBook产品中,名字叫Force Touch.它给用户交 ...
最新文章
- tfs连不上团队资源管理器问题
- 判断一个python字符串中是否包含中文字符
- 一个简单IOC与DI示例
- 20211222 AB和BA具有相同的非零特征值;如果A和B均方,且AB=I,那么BA=I,A、B均可逆
- Matlab各种随机数汇总
- 浅谈Spring IOC和DI及Spring工厂类
- 【英语学习】【English L06】U04 Adventure L1 I want to watch a ballet show there
- pytorch maskrcnn实战
- 阿里云mysql勒索病毒处理_勒索病毒数据库恢复
- Unity UI框架的搭建
- 理想汽车IPO,与特斯拉之间还差了20个蔚来
- 记忆网络之End-To-End Memory Networks
- Android学习方向
- 网页文字无法复制?学会这6种方法,想要的文字都能手到擒来
- 容我缓缓神,记一次气的心脏病发作的经历
- 奔跑吧美少女!试试你能跑多远?
- 怎么判断两个对象相等
- TX-LCN分布式事务使用方案
- 新手必看——微软认证考试
- 奇虎360 2014校园招聘面试
热门文章
- RedHat Enterprise Linux之raid5磁盘阵列
- HP, That's A Dream Or Not?
- bootstrap的分页
- handler和thread之间如何传输数据_使用Mac OS X如何开启和配置防火墙
- mysql分表那些事儿
- Ext Ajax:如何调用Ext.Ajax.request方法和使用Java Servlet进行处理
- c语言重新进入for循环,大佬们帮帮忙 帮我改改 怎样能在输入Y后 再次进行for循环...
- 2021宿州市地区高考成绩排名查询,2021年宿州市所有的高中排名,宿州市高中高考成绩排名出炉...
- mac用vscode打开html,Mac 命令行打开VsCode
- springboot启动不打印日志信息_SpringBoot日志操作【全局异常捕获消息处理--日志控制台输出+日志文件记录】...