Windows Mobile 触摸屏(Touch Panel)截获
转自 http://blog.csdn.net/jinhaijian/archive/2008/09/26/2985378.aspx
为了做全屏手写功能,需要把鼠标的事件全部截获过来,研究了一个星期左右,发现有三种方法可以实现。而且对每种方法已经写了测试代码。根据三种方法效果的好坏排序:
1. 用英文手写识别(TRNSCRBR)Touch的拦截代码,这种方法实现是上上策,这个是微软为手写专门在Touch 驱动中加的。
2. 自己写一个伪Touch驱动,让GWES加载这个Touch驱动,在你的Touch驱动中再调用原来的驱动。
3. 用QASetWindowsJournalHook来获取键盘和鼠标事件, 从QA打头可以看出这个API用来QA来用的,它是用来记录键盘和鼠标的事件,并不能截获,我试了很久,最后找出一种比较BT的方法,就是在收到WM_LBUTTON的时候,用SetWindowsPos设置一个窗体到TOPMOST,这样其他的窗体就收不到WM_LBUTTON的消息。但是Mouse消息还是能够收到。所以才把这种方法定到最后的方案。
上面说了这三种方法,想必大家想知道是如何实现的吧。我们就一个个的来,先说第一个。
1. 利用微软手写识别驱动
由于项目比较紧,这种方法我目前还没有完全试验成功,但我可以这个方法肯定是可行的,只要给点时间肯定是可以的。不说废话了,还是把我知道的东东介绍给大家吧。
先来介绍一下Windows CE Touch Panel的驱动。微软的Touch驱动是一个本地驱动,非流驱动。分为MDD层和PDD层。对于PDD层我们不需要了解,它导出了如下的函数供MDD调用(DDIS接口)。
DdsiTouchPanelAttach
DdsiTouchPanelDetach
DdsiTouchPanelDisable
DdsiTouchPanelEnable
DdsiTouchPanelGetDeviceCaps
DdsiTouchPanelGetPoint
DdsiTouchPanelPowerHandler
微软把与驱动无关的代码放到了MDD层中,这部分代码都开源的,我们可以直接研究它的代码,看我们如何来实现。由于微软不提供相应的截获鼠标的文档,所以我只能看驱动代码,从中得到方法。 微软的MDD层由几个独立的模块来协同完成。
l Touch Panel校准算法:源码在PUBLIC/COMMON/OAK/DRIVERS/TCH_CAL下,这部分跟我们没有多大关系,就不细介绍了。
l Touch Panel校准UI:源码在PUBLIC/COMMON/OAK/DRIVERS/CALIBRUI
l Touch Panel DDI接口:C:/WM605/PUBLIC/COMMON/OAK/DRIVERS/TOUCH,这个目录下又分了三个子目录
1. TCHMAIN:实现DDI接口。
TouchPanelGetDeviceCaps
TouchPanelEnable
TouchPanelDisable
TouchPanelSetMode
TouchPanelReadCalibrationPoint
TouchPanelReadCalibrationAbort
TouchPanelSetCalibration
TouchPanelCalibrateAPoint
TouchPanelPowerHandler
这里面最重要的一段代码就在TouchPanelEnable中,只所以重要,是跟我们实现Touch截获有关。看一下这个函数里的代码
extern PFN_TOUCH_PANEL_CALLBACK v_pfnCgrPointCallback;
extern PFN_TOUCH_PANEL_CALLBACK v_pfnCgrCallback;
...
BOOL
TouchPanelEnable(
PFN_TOUCH_PANEL_CALLBACK pfnCallback
)
{
...
v_pfnCgrPointCallback = pfnCallback;
if (v_pfnCgrCallback != NULL)
v_pfnPointCallback = v_pfnCgrCallback;
else
v_pfnPointCallback = pfnCallback;
...
}
说明下PFN_TOUCH_PANEL_CALLBACK ,每次Touch得到一个点后都会调用它指向的函数。v_pfnCgrPointCallback用来指向TouchPanelEnable原始的函数入口、而v_pfnPointCallback用来指向我们自己的入口。当我们把v_pfnCgrCallback指向自己写的函数时。
2. BASIC:没有微软手写驱动的时,这里面的代码就只有DLLMain的功能
3. TRNSCRBR:要想把TRNSCRBR编译到驱动中,需要在BSP的设置加WCESHELLFE_MODULES_TRANSCRIBER 或者SHELLW_MODULES_CGRTOUCH。最终导出如下函数:
TouchReset
TouchRegisterWindow
TouchUnregisterWindow
TouchSetValue
TouchGetValue
TouchCreateEvent
TouchGetFocusWnd
TouchGetLastTouchFocusWnd
TouchGetQueuePtr
下面详细来讲下关于TRNSCRBR截获Touch Panle的方法。先看一下它导出的函数.
void TouchReset(BOOL bSetAllValuesToDefault): TRNSCRBR定义了一些配置,通过这个函数来Reset到默认。
BOOL TouchRegisterWindow(HWND hClientWnd); 注册Wnd到Touch驱动,Touch把键盘消息发送给这个窗口了。
void TouchUnregisterWindow(HWND hClientWnd); 取消注册,Touch把消息发送给系统
void TouchSetValue(DWORD dwName, DWORD dwValue); 设置配置
LRESULT TouchGetValue(DWORD dwName, DWORD dwValue); 得到有个配置
void TouchCreateEvent(int iX, int iY); 发送Mouse 消息给系统
LPVOID TouchGetQueuePtr(); 从队列中读取一个POINT。
HWND TouchGetFocusWnd();
HWND TouchGetLastTouchFocusWnd();
所以你建立一个自己的窗体,然后设置窗体的属性。在Touch驱动中,它会根据你窗体设置的属性来发送哪些mouse消息给你。
/ / set flags
_iClientFlags = (int)GetWindowLong(_hClientWnd, 0);
//just adjust
if((_iClientFlags&TABLET_TEST_FIRST_POINT)!=0 &&
!SendMessage(_hClientWnd, WM_PEGREC_FIRSTPOINT, 0, MAKELPARAM(X, Y)))
{
_iClientFlags = TABLET_ALL_TO_SYSTEM;
}
…
很是奇怪,一般的窗体是不能SetWindowLong(hWnd,0,XXX)。只有对于对话框才有设置这个属性。#define DWL_MSGRESULT 0。但是对话框有一个问题,当你SendMessage给对话框时,返回值总为空。所以上面的SendMessage(_hClientWnd, WM_PEGREC_FIRSTPOINT, 0, MAKELPARAM(X, Y)返回为FALSE。这样导致把_iClientFlags位置为TABLET_ALL_TO_SYSTEM,这样所有的消息都发给了系统。还有即使是用对话框,调用SetWindowLong(hDlg, 0, 0x2FD); 但是GetWindowLong(_hClientWnd,0),返回始终为空。
下面是SetWindowLong需要设置的内容(pegc_def.h 内)。
// TCHSTUB strokes dispatch modes (set in window longs)
#define TABLET_SILENT 0x0000
#define TABLET_ALL_TO_CLIENT 0x0001
#define TABLET_ALL_TO_SYSTEM 0x0002
#define TABLET_CLICK_TO_SYSTEM 0x0004
#define TABLET_STARTDELAY_TO_SYSTEM 0x0008
#define TABLET_INTERDELAY_TO_SYSTEM 0x0010
#define TABLET_SEND_RELEASE_MSG 0x0020
#define TABLET_SEND 0x0040
#define TABLET_NEED_PERMITION 0x0080
#define TABLET_SAVE_FOCUS_WND 0x0100
#define TABLET_TEST_FIRST_POINT 0x0200
我现在调用TouchRegisterWindow后,要么只截获Touch Down的消息,mouse和up都没有截获,或者是把系统的所以消息都屏蔽了。哪位有兴趣可以研究一下。在模拟器上是可以试的。模拟器的PDD代码目录在PLATFORM/DEVICEEMULATOR/SRC/DRIVERS/TOUCH下,需要把MDD的代码合成在一起,通过打印信息就可以看出效果了。这个方法没有实现,还讲了这么多的废话,哈哈。
我把Touch的MDD层代码放到了TouchMDD中了。
2. 编写伪Touch驱动。
这个方法跟上面的方法其实是一个方法,只是微软来写和我们自己的区别。微软写的太复杂了,搞得我没有搞定上面的方法。可能是微软为了更好的扩展和其他应用吧。但是我们只给自己的应用用的话,那就很简单了。看代码吧
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch ( ul_reason_for_call )
{
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls((HMODULE) hModule);
g_hInstTouch = LoadLibrary(TOUCH_DLL);
break;
case DLL_PROCESS_DETACH:
if(NULL != g_hInstTouch)
FreeLibrary(g_hInstTouch);
break;
}
return TRUE;
}
在DllMain中,把Touch.dll Load进来。我们只要看TouchPanelEnable和自己的一个callback函数。
// 原始Callback
PFN_TOUCH_PANEL_CALLBACK pfnOrgTouchPanelCallback = NULL;
HWND g_sipWnd = NULL;
HWND g_hwWnd = NULL;
#define HW_CLASSNAME L"CeSipEng"
INT xSaved = 0;
INT ySaved = 0;
int iMinX = 4;
int iMinY = 4;
BOOL hwTouchPanelCallback(
TOUCH_PANEL_SAMPLE_FLAGS Flags,
INT X,
INT Y
)
{
if(NULL == g_sipWnd)
{
g_sipWnd = FindWindow(L"SipWndClass", NULL);
}
g_hwWnd = GetWindow(g_sipWnd, GW_CHILD);
if(IsWindowVisible(g_hwWnd))
{
TCHAR szClassName[32];
GetClassName(g_hwWnd, szClassName, 32);
if(wcsicmp(szClassName, HW_CLASSNAME) == 0)
{
// down
if(Flags == (TouchSampleDownFlag | TouchSampleIsCalibratedFlag | TouchSampleValidFlag))
{
SendMessage(g_hwWnd, WM_LBUTTONDOWN, 0, MAKELPARAM(X,Y));
}
// mouse
else if(Flags == (TouchSampleDownFlag | TouchSamplePreviousDownFlag | TouchSampleIsCalibratedFlag |
TouchSampleValidFlag) &&
xSaved - X > iMinX || X - xSaved > iMinX &&
ySaved - Y > iMinY || Y - ySaved > iMinY)
{
SendMessage(g_hwWnd, WM_MOUSEMOVE, 0, MAKELPARAM(X,Y));
}
// up
else if(Flags ==(TouchSampleIsCalibratedFlag |
TouchSampleValidFlag | TouchSamplePreviousDownFlag))
{
SendMessage(g_hwWnd, WM_LBUTTONUP, 0, MAKELPARAM(X,Y));
}
xSaved = X;
ySaved = Y;
return TRUE;
}
Else
// 发送给系统
return pfnOrgTouchPanelCallback(Flags, X,Y);
}
//发送给系统
return pfnOrgTouchPanelCallback(Flags, X,Y);
}
BOOL
TouchPanelEnable(
PFN_TOUCH_PANEL_CALLBACK pfnCallback
)
{
if(g_hInstTouch)
{
if (NULL == pfnTouchPanelEnable)
{
pfnTouchPanelEnable = (PFN_TOUCH_PANEL_ENABLE)GetProcAddress(g_hInstTouch,
TEXT("TouchPanelEnable"));
}
// 保存原来的Callback
pfnOrgTouchPanelCallback = pfnCallback;
// 传入自己的Callback
return pfnTouchPanelEnable(hwTouchPanelCallback);
}
return FALSE;
}
其他的函数跟TouchPanelEnable一样的形式,就是GetProcAddress一下,然后再Call一下。
差点忘记,把自己的写的注册到系统,让GWES.exe调用。
[HKEY_LOCAL_MACHINE/HARDWARE/DEVICEMAP/TOUCH]
“DriverName”=”MyTouch.dll”
我把伪Touch的代码放到了MyTouch中
3. QASetWindowsJournalHook
这个函数在pwinuser.h中。微软在Windows CE中支持键盘HOOK、键盘/鼠标的记录、键盘/鼠标的回放,看pwinuser.h中的定义
#define WH_JOURNALRECORD 0
#define WH_JOURNALPLAYBACK 1
#define WH_KEYBOARD_LL 20
写累了,直接看代码
EVENTMSG evtMsg;
ZeroMemory(&evtMsg, sizeof(EVENTMSG));
g_hHook = QASetWindowsJournalHook(WH_JOURNALRECORD, KeyboardProc, &evtMsg);
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
switch (nCode)
{
case HC_ACTION:
{
EVENTMSG *mesg = (EVENTMSG *)lParam;
UINT message = mesg->message;
if(message == WM_LBUTTONDOWN)//pressed
{
//DEBUGMSG (ZONE_FUNCTION, (TEXT("WM_LBUTTONDOWN/r/n")));
}
else if(message == WM_MOUSEMOVE)
{
//DEBUGMSG (ZONE_FUNCTION, (TEXT("WM_MOUSEMOVE/r/n")));
}
else if(message == WM_LBUTTONUP)
{
//DEBUGMSG (ZONE_FUNCTION, (TEXT("WM_LBUTTONUP/r/n")));
}
POINT pt = {0};
pt.x = LOWORD(mesg->paramL);
pt.y = HIWORD(mesg->paramL);
if(message == WM_LBUTTONDOWN )
{
HWND hWnd = WindowFromPoint(pt);
if(pMouseSpy != NULL && pt.y < 600)
{
// 用SetWindowsPos来设置到最前台,这样窗体就接收不到Down消息。
SetWindowPos(pMouseSpy->m_hWnd, HWND_TOPMOST,pt.x -10, pt.y -10, 20, 20, SWP_SHOWWINDOW);
}
}
}
return TRUE;
default:
break;
}
}
这里SetWindowPos(pMouseSpy->m_hWnd, HWND_TOPMOST,pt.x -10, pt.y -10, 20, 20, SWP_SHOWWINDOW);,这个很重要很重要,是我试了很多方法才把WM_LBUTTONDOWN消息给屏蔽掉。但是WM_MOUSEMOVE和WM_LBUTTONUP用这种方法是不能过滤掉的。有人会问,在窗体 (pMouseSpy->m_hWnd) 的WM_LBUTTONDOWN中去SetCapture不就OK了,哈哈,不行的。这个窗体虽然是TOPMOST的,但是也是收不到WM_LBUTTONDOWN消息的。又有人说,我们可以PostMessage(pMouseSpy->m_hWnd, WM_LBUTTONDOWN, 0,mesg->paramL)。SetWindowPos后,发送WM_LBUTTONDOWN消息,但是WM_LBUTTONDOWN先于SetWindowPos发送的WM_WINDOWPOSCHANGED的消息,还是没用。
最后,当你不用的时候用QAUnhookWindowsJournalHook(WH_JOURNALRECORD);释放掉。
OK了, So Long No Write, 写的不好,请见谅。
Windows Mobile 触摸屏(Touch Panel)截获相关推荐
- 在Windows Mobile手机上运行Android
Interested in Android but think you need to buy a new phone to try it out? Actually, your Windows Mo ...
- Gesture APIs-Furthering Windows Mobile 6.5 Touch Gesture Framework
Windows mobile 6.5开发者工具包在6月初就已经面世了.它给广大技术爱好者带来的新特性包括Widgets和Gesture API.在Widgets应用上,已经有开发人员进行了探索和尝试, ...
- Fennec Alpha 1 for Windows Mobile available
记得我之前介绍过火狐即将推出浏览器这件事,本周Mozilla正式发布了Fennec Alpha 1. 这款名为Fennec的手机浏览器之前仅能在诺基亚N810网络平台上运作,不过Mozill ...
- Windows Mobile 开发常见问题集(转自zsu_darkwind的专栏)
Windows Mobile 开发常见问题集 1.Q:新建项目的时候选择哪个项目类型才能创建智能设备的应用程序? A:在Visual Studio的新建项目对话框中选择Visual C#或者Visua ...
- windows mobile ?
windows mobile <!-- 发表评论(0) --> 概述 WindowsMobile,是Microsoft用于PocketPC和Smartphone的软件平台.WindowsM ...
- 使用.NET 框架压缩版开发Windows Mobile 2003 for Smartphone
发布日期: 11/30/2004 | 更新日期: 11/30/2004 Andreas Sjöström, Christian Forsberg businessanyplace.net 适用于: M ...
- Windows Mobile 7 梦幻之旅系列1之- What’s New?
(本文全文直译自InsideMicrosoft,仅供学习参考,如引用请表明译文出处,谢谢) 微软正在开发新一代的智能手机平台Windows Mobile 7,它将是一个革命性的智能手机操 ...
- Windows Mobile 6 中为开发人员提供的新功能(1)
Windows Mobile 6 中为开发人员提供的新功能(1) 2007年06月10日 星期日 10:29 Jim Wilson,JW Hedgehog, Inc. 摘要 Windows Mobil ...
- Windows Mobile logo测试介绍
首先声明本文转自:http://softtest.chinaitlab.com/sji/744369.html 一.Windows Mobile简介 Windows Mobile是微软主要针对手机市场 ...
- Windows Mobile 7(Photon) 梦幻之旅系列-前言
关于微软正在开发的下一代移动操作系统-Windows M ...
最新文章
- linux中将文本中的单词换掉的指令_为什么说从PDF中提取文本是一件困难的事?...
- Spring学习笔记之一----基于XML的Spring IOC配置
- Android ImageView图片代码实现按屏幕宽度等比例缩放
- Javascript 浏览器探测
- 写在《ASP.NET MVC 4 Web 编程》即将出版之际!献给有节操的程序员!
- Oracle 数据库基础学习 (二)
- js字体溢出字体变小_可变字体:它们是什么,以及如何使用它们
- 跟我唱简谱v5.3 中文免费版
- 【知识必备】RxJava+Retrofit二次封装最佳结合体验,打造懒人封装框架~
- 微信小程序清除缓存(ios和安卓的解决方法)
- CAN总线和CANOpen协议栈总结
- oracle表数据导出成unl文件,oracle的文本导入、导出技巧
- 6-1 计算捐款总量 (10分)
- make命令和makefile文件
- us域名在哪里注册_us域名,什么是us域名,注册us域名有什么优势
- [ubuntu14.04 amd64 ]搜狗拼音輸入法安裝
- 20220124英语学习
- “佐藤可士和”的超整理术 整理真的可以让人愉悦
- ML模型特点以及区别
- [日推荐]『每日故宫lite』不去北京也能游故宫!
热门文章
- 聚类——密度聚类(DBSCAN、OPTICS、DENCLUE)
- word批量转换pdf
- xbox one 手柄按键测试软件,Xbox One手柄映射工具(ReWASD)
- android陀螺仪 cemu,CEMU安卓手柄陀螺仪教程
- android蓝牙 助手源码,蓝牙串口助手(Android Studio源码)
- BPSK_QPSK_16QAM _64QAM _MATLAB
- 如何下载行政区划地图
- oracle中rollup函数与mysql中with rollup区别
- 数据结构与算法:二路归并排序(合并排序)
- 中国气象数据(站点)