Touch Driver介绍

本文深入介绍了Touch Driver的加载过程、导出函数及其与GWES的交互。重点讨论了TouchPanelEnable、TouchPanelSetMode等关键函数,以及开机自动校准和使用微软校准工具进行校准的流程。Touch Driver采用PDD+MDD架构,OEM厂商只需关注PDD层。数据采集和校准过程中,Touch Panel与GWES之间的Callback函数起到了关键作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 Touch Driver介绍

一.相关知识介绍

1Touch 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,所有相关硬件有关的初始化以及数据采集中断线程的创建都是在这里完成。

         值得一提的是其传入参数是一个处理EventCallback函数,在数据采集中断线程中需要通过该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

         其中,TxTy是触摸屏坐标,而SxSy是显示设备坐标,其中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

 

         其中,TxTy是触摸屏坐标,而SxSy是显示设备坐标。

         该函数的功能就是根据采样点和屏幕上的十字号的值计算出A1B1C1A2B2C2

9> TouchPanelPowerHandler

         这个函数虽然简单,但是在设备电源管理中有用处。与其它Driver中的PowerHandle作用类似。

二.Touch DriverGWES的交互

1Touch 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);

}

         数据采集中断线程TouchPanelpISRCallback函数的调用参照后面的函数介绍。

2.触摸板坐标数据的采集

         想象一下,GWES不停的去向Touch Panel Driver索取坐标点,如果用户一直没有点击的话,这将是多么大的一种资源的浪费。所以在微软设计Touch DriverGWES的时候,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中通过TouchPanelGetDeviceCapsTPDC_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就行了。

         校准过程如下:

>> 获取校准基础信息

         调用TouchPanelGetDeviceCapsTPDC_CALIBRATION_POINT_COUNT_ID分支获取屏幕校准的坐标点数,在这里假设是5个;

>> GWES调用Touch Driver获取屏幕坐标点位置和触摸板坐标点位置

         GWES调用TouchPanelGetDeviceCapsTPDC_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等待TimerTouch中断事件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 )

            {

                //  值得一说的就是SampleFlagsTouchSampleDownFlag位是从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 );

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值