触笔触摸屏幕->
产生中断->
中断处理获得触摸物理坐标->
/**************************************************************************/
这里也可以在程序建立一个任务,来不断地调用GUI_TOUCH_Exec函数
这里是需要调用四次的,每次读取一次x或是y。
第一次读取,调用_StoreUnstable(x, y)函数。这个函数中包含一个消除抖动的过程,处理的也很巧妙。
第二次读取已经去掉抖动了。调用GUI_TOUCH_StoreUnstable函数
/**************************************************************************/
其后(仍在中断处理函数中)的处理过程:
GUI_TOUCH_Exec->GUI_TOUCH_StoreUnstable(x, y) ->
GUI_TOUCH_StoreState(x, y)在此函数中,改写局部静态变量static GUI_PID_STATE _State如下:
if ((x >= 0) && (y >= 0)) {
_State.Pressed = 1;
_State.x = x;
_State.y = y;
} else {
_State.Pressed = 0;
}
->
GUI_TOUCH_StoreStateEx(&_State),做如下事:
if (memcmp(pState, &_State, sizeof(_State))) {
_State = *pState;
GUI_PID_StoreState(pState);
}
->
void GUI_PID_StoreState(const GUI_PID_STATE *pState) {
_PID_Load();
if (memcmp(&_State, pState, sizeof(_State))) {
_State = *pState;
GUI_X_SIGNAL_EVENT();
}
}
->
static void _PID_Load(void) {
#if (GUI_WINSUPPORT)
WM_pfHandlePID = WM_HandlePID;
#endif
}
->
中断返回->
/**************************************************************************/
GUI_Exec()函数可以通过GUI_WaitKey()来调用。
/**************************************************************************/
进入以下函数,循环执行:
GUI_Exec()->GUI_Exec1()->WM_Exec()->WM_Exec1()->
在WM_Exec1()函数中做如下判断:
if (WM_pfHandlePID) {
if (WM_pfHandlePID())//因此实际调用函数WM_HandlePID;
return 1; /* We have done something ... */
}
让我们分析函数WM_HandlePID:(位于WMTouch.c中)
1)GUI_PID_GetState(&StateNew);//获得刚刚触摸的状态
2)CHWin.hWin = _Screen2Win(&StateNew);//判断被触摸的是哪个东东!具体如下:
static WM_HWIN _Screen2Win(GUI_PID_STATE* pState) {
if (WM__hCapture == 0) {
return WM_Screen2hWin(pState->x, pState->y);
}
return WM__hCapture;
}
->
WM_HWIN WM_Screen2hWin(int x, int y) {
WM_HWIN r;
WM_LOCK();
r = _Screen2hWin(WM__FirstWin, 0, x, y);//yhm20061211AC, WM__FirstWin = hNew; in //func _AddToLinList
WM_UNLOCK();
return r; //yhm20061211AC,return the handle of the obj which is hitted!!!
}
->
static WM_HWIN _Screen2hWin(WM_HWIN hWin, WM_HWIN hStop, int x, int y) {
WM_Obj* pWin = WM_HANDLE2PTR(hWin);
WM_HWIN hChild;
WM_HWIN hHit;
/* First check if the coordinates are in the given window. If not, return 0 */
if (WM__IsInWindow(pWin, x, y) == 0) {
return 0;
}
/* If the coordinates are in a child, search deeper ... */
for (hChild = pWin->hFirstChild; hChild && (hChild != hStop); ) {
WM_Obj* pChild = WM_HANDLE2PTR(hChild);
if ((hHit = _Screen2hWin(hChild, hStop, x, y)) != 0) {
hWin = hHit; /* Found a window */
}
hChild = pChild->hNext;
}
return hWin; /* No Child affected ... The parent is the right one */
}
3) WM__IsInModalArea(CHWin.hWin)//判断是否模态?
是:
看状态是否改变,if ((WM_PID__StateLast.Pressed != StateNew.Pressed) && CHWin.hWin)
是:
Msg.MsgId = WM_PID_STATE_CHANGED;
WM__SendMessageIfEnabled(CHWin.hWin, &Msg);
以按钮为例,这时按钮的默认回调函数:BUTTON_Callback就会收到这个消息
并调用WIDGET_HandleActive(hObj, pMsg),在此函数中有如下代码:
case WM_PID_STATE_CHANGED:
if (pWidget->State & WIDGET_STATE_FOCUSSABLE) {
const WM_PID_STATE_CHANGED_INFO * pInfo = (const WM_PID_STATE_CHANGED_INFO*)pMsg->Data.p;
if (pInfo->State) { //如果是按下,这设置焦点
WM_SetFocus(hObj);
}
}
返回到WM_HandlePID,接下来处理触摸事件:Msg.MsgId = WM_TOUCH;其中包括按下和提起两个触摸事件,首先判断上次触摸的窗体和这次是否是同一个,如果不是,则先发送WM_TOUCH消息给上次触摸的窗体:
if (StateNew.Pressed) {
/* Moved out -> no longer in this window
* Send a NULL pointer as data
*/
Msg.Data.p = NULL;//留意这里
//Uart_Printf("Move out/n");
}
WM__SendTouchMessage(WM__CHWinLast.hWin, &Msg);
WM__CHWinLast.hWin = 0;
在WM__SendTouchMessage函数中,还会把这个消息发送给上次触摸的窗体的所有父窗体呢!你看:
void WM__SendPIDMessage(WM_HWIN hWin, WM_MESSAGE* pMsg) {
WM_MESSAGE Msg;
/* Send message to the affected window */
Msg = *pMsg; /* Save message as it may be modified in callback (as return value) */
WM__SendMessageIfEnabled(hWin, &Msg);
/* Send notification to all ancestors.
We need to check if the window which has received the last message still exists,
since it may have deleted itself and its parent as result of the message.
*/
Msg.hWinSrc = hWin;
Msg.MsgId = WM_TOUCH_CHILD;
while (WM_IsWindow(hWin)) {
hWin = WM_GetParent(hWin);
if (hWin) {
Msg.Data.p = pMsg; /* Needs to be set for each window, as callback is allowed to modify it */
WM__SendMessageIfEnabled(hWin, &Msg); /* Send message to the ancestors */
}
}
}
假设上次触摸的窗体也是一个按钮,则,这时BUTTON_Callback就会收到这个消息:
case WM_TOUCH:
_OnTouch(hObj, pObj, pMsg);
_OnTouch函数如下:
static void _OnTouch(BUTTON_Handle hObj, BUTTON_Obj* pObj, WM_MESSAGE*pMsg) {
const GUI_PID_STATE* pState = (const GUI_PID_STATE*)pMsg->Data.p;
#if BUTTON_REACT_ON_LEVEL
if (!pMsg->Data.p) { /* Mouse moved out */
_ButtonReleased(hObj, pObj, WM_NOTIFICATION_MOVED_OUT);
}
#else
if (pMsg->Data.p) { /* Something happened in our area (pressed or released) */
if (pState->Pressed) {
if ((pObj->Widget.State & BUTTON_STATE_PRESSED) == 0){
_ButtonPressed(hObj, pObj);
}
} else {
/* React only if button was pressed before ... avoid problems with moving / hiding windows above (such as dropdown) */
if (pObj->Widget.State & BUTTON_STATE_PRESSED) {
_ButtonReleased(hObj, pObj, WM_NOTIFICATION_RELEASED);
}
}
} else {//在这个函数中将执行这个调用,因为pMsg->Data.p==NULL
_ButtonReleased(hObj, pObj, WM_NOTIFICATION_MOVED_OUT);
}
#endif
其中_ButtonReleased函数如下:
static void _ButtonReleased(BUTTON_Handle hObj, BUTTON_Obj* pObj, int Notification) {
WIDGET_AndState(hObj, BUTTON_STATE_PRESSED);
if (pObj->Widget.Win.Status & WM_SF_ISVIS) {
WM_NotifyParent(hObj, Notification);
}
if (Notification == WM_NOTIFICATION_RELEASED) {
GUI_DEBUG_LOG("BUTTON: Hit/n");
GUI_StoreKey(pObj->Widget.Id);
}
}
由于调用了WM_NotifyParent函数,因此按钮的父窗体就会收到WM_NOTIFICATION_MOVED_OUT这个消息,我们假设其父是个FRAMEWIN_Obj,
则FRAMEWIN_Obj的回调函数FRAMEWIN__cbClient以及用户自定义回调函数会处理这个消息。为什么会是这样,因为,对一个对话框,其结构如下:
首先,如果是按下,则保存窗体句柄WM__CHWinLast.hWin = CHWin.hWin;然后发送消息: Msg.Data.p = (void*)&StateNew;
WM__SendTouchMessage (CHWin.hWin, &Msg);
按照上面的分析,一直调用,再次进入BUTTON.C中的_OnTouch函数:
此时,pMsg->Data.p!=NULL,因此执行如下操作:
if (pMsg->Data.p) { /* Something happened in our area (pressed or released) */
if (pState->Pressed) {
if ((pObj->Widget.State & BUTTON_STATE_PRESSED) == 0){ //如果不是按下状态
_ButtonPressed(hObj, pObj);
}
} else {
/* React only if button was pressed before ... avoid problems with moving / hiding windows above (such as dropdown) */
if (pObj->Widget.State & BUTTON_STATE_PRESSED) { //如果是按下状态
_ButtonReleased(hObj, pObj, WM_NOTIFICATION_RELEASED);
}
}
/***********************************************************************************************/
_ButtonReleased(hObj, pObj, WM_NOTIFICATION_RELEASED);这个函数中,调用了
void GUI_StoreKey(int Key) {
if (!_Key) {
_Key = Key;
}
GUI_X_SIGNAL_EVENT();
}
而在GUI_WaitKey中会调用
int GUI_GetKey(void) {
int r = _Key;
_Key = 0;
return r;
}
/************************************************************************************************/
static void _ButtonPressed (BUTTON_Handle hObj, BUTTON_Obj* pObj) {
WIDGET_OrState(hObj, BUTTON_STATE_PRESSED);
if (pObj->Widget.Win.Status & WM_SF_ISVIS) {
WM_NotifyParent(hObj, WM_NOTIFICATION_CLICKED);// 产生单击事件
}
}
此时,我们就可以在应用程序自定义的回调函数中处理按钮的按下和提起事件了。例如:
case WM_NOTIFY_PARENT:
Id = WM_GetId(pMsg->hWinSrc); /* Id of widget */
NCode = pMsg->Data.v; /* Notification code */
switch (NCode) {
case WM_NOTIFICATION_RELEASED: /* React only if released */
if (Id == GUI_ID_OK) { /* OK Button */
GUI_MessageBox("This text is shown/nin a message box",
"Caption/Title", GUI_MESSAGEBOX_CF_MOVEABLE);
}
if (Id == GUI_ID_CANCEL) { /* Cancel Button */
GUI_EndDialog(hWin, 1);
}
break;
}
break;