Release 970112
[wine/multimedia.git] / windows / message.c
blob203d7e8754a97d84e48707032873b0cc843a1785
1 /*
2 * Message queues related functions
4 * Copyright 1993, 1994 Alexandre Julliard
5 */
7 #include <stdlib.h>
8 #include <string.h>
9 #include <ctype.h>
10 #include <sys/time.h>
11 #include <sys/types.h>
13 #include "message.h"
14 #include "win.h"
15 #include "gdi.h"
16 #include "sysmetrics.h"
17 #include "heap.h"
18 #include "hook.h"
19 #include "spy.h"
20 #include "winpos.h"
21 #include "atom.h"
22 #include "dde.h"
23 #include "queue.h"
24 #include "winproc.h"
25 #include "stddebug.h"
26 /* #define DEBUG_MSG */
27 #include "debug.h"
29 #define WM_NCMOUSEFIRST WM_NCMOUSEMOVE
30 #define WM_NCMOUSELAST WM_NCMBUTTONDBLCLK
32 #define HWND_BROADCAST16 ((HWND16)0xffff)
33 #define HWND_BROADCAST32 ((HWND32)0xffffffff)
35 typedef enum { SYSQ_MSG_ABANDON, SYSQ_MSG_SKIP,
36 SYSQ_MSG_ACCEPT, SYSQ_MSG_CONTINUE } SYSQ_STATUS;
38 extern BOOL MouseButtonsStates[3];
39 extern BOOL AsyncMouseButtonsStates[3];
40 extern BYTE InputKeyStateTable[256];
41 extern BYTE AsyncKeyStateTable[256];
43 BYTE QueueKeyStateTable[256];
45 extern MESSAGEQUEUE *pCursorQueue; /* queue.c */
46 extern MESSAGEQUEUE *pActiveQueue;
48 DWORD MSG_WineStartTicks; /* Ticks at Wine startup */
50 static WORD doubleClickSpeed = 452;
51 static INT32 debugSMRL = 0; /* intertask SendMessage() recursion level */
53 /***********************************************************************
54 * MSG_CheckFilter
56 BOOL32 MSG_CheckFilter(WORD uMsg, DWORD filter)
58 if( filter )
59 return (uMsg >= LOWORD(filter) && uMsg <= HIWORD(filter));
60 return TRUE;
63 /***********************************************************************
64 * MSG_TranslateMouseMsg
66 * Translate an mouse hardware event into a real mouse message.
67 * Return value indicates whether the translated message must be passed
68 * to the user, left in the queue, or skipped entirely (in this case
69 * HIWORD contains hit test code).
71 static DWORD MSG_TranslateMouseMsg( HWND16 hWndScope, DWORD filter,
72 MSG16 *msg, BOOL32 remove )
74 static DWORD dblclk_time_limit = 0;
75 static UINT16 clk_message = 0;
76 static HWND16 clk_hwnd = 0;
77 static POINT16 clk_pos = { 0, 0 };
79 WND *pWnd;
80 HWND16 hWnd;
81 INT16 ht, hittest, sendSC = 0;
82 UINT16 message = msg->message;
83 POINT16 screen_pt, pt;
84 HANDLE16 hQ = GetTaskQueue(0);
85 MESSAGEQUEUE *queue = (MESSAGEQUEUE *)GlobalLock16(hQ);
86 BOOL32 eatMsg = FALSE;
87 BOOL32 mouseClick = ((message == WM_LBUTTONDOWN) ||
88 (message == WM_RBUTTONDOWN) ||
89 (message == WM_MBUTTONDOWN))?1:0;
90 SYSQ_STATUS ret = 0;
92 /* Find the window */
94 ht = hittest = HTCLIENT;
95 hWnd = GetCapture16();
96 if( !hWnd )
98 sendSC = 1;
99 ht = hittest = WINPOS_WindowFromPoint( WIN_GetDesktop(), msg->pt, &pWnd );
100 if( !pWnd ) pWnd = WIN_GetDesktop();
101 hWnd = pWnd->hwndSelf;
103 else
105 pWnd = WIN_FindWndPtr(hWnd);
106 ht = EVENT_GetCaptureInfo();
109 /* stop if not the right queue */
111 if (pWnd->hmemTaskQ != hQ)
113 /* Not for the current task */
114 if (queue) QUEUE_ClearWakeBit( queue, QS_MOUSE );
115 /* Wake up the other task */
116 queue = (MESSAGEQUEUE *)GlobalLock16( pWnd->hmemTaskQ );
117 if (queue) QUEUE_SetWakeBit( queue, QS_MOUSE );
118 return SYSQ_MSG_ABANDON;
121 /* check if hWnd is within hWndScope */
123 if( hWndScope && hWnd != hWndScope )
124 if( !IsChild(hWndScope, hWnd) ) return SYSQ_MSG_CONTINUE;
126 if( mouseClick )
128 /* translate double clicks -
129 * note that ...MOUSEMOVEs can slip in between
130 * ...BUTTONDOWN and ...BUTTONDBLCLK messages */
132 if( pWnd->class->style & CS_DBLCLKS || ht != HTCLIENT )
134 if ((message == clk_message) && (hWnd == clk_hwnd) &&
135 (msg->time - dblclk_time_limit < doubleClickSpeed) &&
136 (abs(msg->pt.x - clk_pos.x) < SYSMETRICS_CXDOUBLECLK/2) &&
137 (abs(msg->pt.y - clk_pos.y) < SYSMETRICS_CYDOUBLECLK/2))
139 message += (WM_LBUTTONDBLCLK - WM_LBUTTONDOWN);
140 mouseClick++; /* == 2 */
144 screen_pt = pt = msg->pt;
146 if (hittest != HTCLIENT)
148 message += ((INT16)WM_NCMOUSEMOVE - WM_MOUSEMOVE);
149 msg->wParam = hittest;
151 else ScreenToClient16( hWnd, &pt );
153 /* check message filter */
155 if (!MSG_CheckFilter(message, filter)) return SYSQ_MSG_CONTINUE;
157 pCursorQueue = queue;
159 /* call WH_MOUSE */
161 if (HOOK_IsHooked( WH_MOUSE ))
163 MOUSEHOOKSTRUCT16 *hook = SEGPTR_NEW(MOUSEHOOKSTRUCT16);
164 if( hook )
166 hook->pt = screen_pt;
167 hook->hwnd = hWnd;
168 hook->wHitTestCode = hittest;
169 hook->dwExtraInfo = 0;
170 ret = HOOK_CallHooks16( WH_MOUSE, remove ? HC_ACTION : HC_NOREMOVE,
171 message, (LPARAM)SEGPTR_GET(hook) );
172 SEGPTR_FREE(hook);
174 if( ret ) return MAKELONG((INT16)SYSQ_MSG_SKIP, hittest);
177 if ((hittest == HTERROR) || (hittest == HTNOWHERE))
178 eatMsg = sendSC = 1;
179 else if( remove && mouseClick )
181 HWND hwndTop = WIN_GetTopParent( hWnd );
183 if( mouseClick == 1 )
185 /* set conditions */
186 dblclk_time_limit = msg->time;
187 clk_message = msg->message;
188 clk_hwnd = hWnd;
189 clk_pos = screen_pt;
190 } else
191 /* got double click - zero them out */
192 dblclk_time_limit = clk_hwnd = 0;
194 if( sendSC )
196 /* Send the WM_PARENTNOTIFY,
197 * note that even for double/nonclient clicks
198 * notification message is still WM_L/M/RBUTTONDOWN.
201 WIN_SendParentNotify( hWnd, msg->message, 0,
202 MAKELPARAM( screen_pt.x, screen_pt.y ) );
204 /* Activate the window if needed */
206 if (hWnd != GetActiveWindow() && hWnd != GetDesktopWindow16())
208 LONG ret = SendMessage16( hWnd, WM_MOUSEACTIVATE, hwndTop,
209 MAKELONG( hittest, message ) );
211 if ((ret == MA_ACTIVATEANDEAT) || (ret == MA_NOACTIVATEANDEAT))
212 eatMsg = TRUE;
214 if (((ret == MA_ACTIVATE) || (ret == MA_ACTIVATEANDEAT))
215 && hwndTop != GetActiveWindow() )
216 if (!WINPOS_SetActiveWindow( hwndTop, TRUE , TRUE ))
217 eatMsg = TRUE;
220 } else sendSC = (remove && sendSC);
222 /* Send the WM_SETCURSOR message */
224 if (sendSC)
225 SendMessage16( hWnd, WM_SETCURSOR, (WPARAM16)hWnd,
226 MAKELONG( hittest, message ));
227 if (eatMsg) return MAKELONG( (UINT16)SYSQ_MSG_SKIP, hittest);
229 msg->hwnd = hWnd;
230 msg->message = message;
231 msg->lParam = MAKELONG( pt.x, pt.y );
232 return SYSQ_MSG_ACCEPT;
236 /***********************************************************************
237 * MSG_TranslateKbdMsg
239 * Translate an keyboard hardware event into a real message.
241 static DWORD MSG_TranslateKbdMsg( HWND16 hWndScope, DWORD filter,
242 MSG16 *msg, BOOL32 remove )
244 WORD message = msg->message;
245 HWND16 hWnd = GetFocus16();
246 WND *pWnd;
248 /* Should check Ctrl-Esc and PrintScreen here */
250 if (!hWnd)
252 /* Send the message to the active window instead, */
253 /* translating messages to their WM_SYS equivalent */
255 hWnd = GetActiveWindow();
257 if( message < WM_SYSKEYDOWN )
258 message += WM_SYSKEYDOWN - WM_KEYDOWN;
260 pWnd = WIN_FindWndPtr( hWnd );
261 if (pWnd && (pWnd->hmemTaskQ != GetTaskQueue(0)))
263 /* Not for the current task */
264 MESSAGEQUEUE *queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(0) );
265 if (queue) QUEUE_ClearWakeBit( queue, QS_KEY );
266 /* Wake up the other task */
267 queue = (MESSAGEQUEUE *)GlobalLock16( pWnd->hmemTaskQ );
268 if (queue) QUEUE_SetWakeBit( queue, QS_KEY );
269 return SYSQ_MSG_ABANDON;
272 if (hWndScope && hWnd != hWndScope)
273 if (!IsChild(hWndScope, hWnd)) return SYSQ_MSG_CONTINUE;
274 if (!MSG_CheckFilter(message, filter)) return SYSQ_MSG_CONTINUE;
276 msg->hwnd = hWnd;
277 msg->message = message;
279 return (HOOK_CallHooks16( WH_KEYBOARD, remove ? HC_ACTION : HC_NOREMOVE,
280 msg->wParam, msg->lParam )
281 ? SYSQ_MSG_SKIP : SYSQ_MSG_ACCEPT);
285 /***********************************************************************
286 * MSG_JournalRecordMsg
288 * Build an EVENTMSG structure and call JOURNALRECORD hook
290 static void MSG_JournalRecordMsg( MSG16 *msg )
292 EVENTMSG16 *event = SEGPTR_NEW(EVENTMSG16);
293 if (!event) return;
294 event->message = msg->message;
295 event->time = msg->time;
296 if ((msg->message >= WM_KEYFIRST) && (msg->message <= WM_KEYLAST))
298 event->paramL = (msg->wParam & 0xFF) | (HIWORD(msg->lParam) << 8);
299 event->paramH = msg->lParam & 0x7FFF;
300 if (HIWORD(msg->lParam) & 0x0100)
301 event->paramH |= 0x8000; /* special_key - bit */
302 HOOK_CallHooks16( WH_JOURNALRECORD, HC_ACTION, 0,
303 (LPARAM)SEGPTR_GET(event) );
305 else if ((msg->message >= WM_MOUSEFIRST) && (msg->message <= WM_MOUSELAST))
307 event->paramL = LOWORD(msg->lParam); /* X pos */
308 event->paramH = HIWORD(msg->lParam); /* Y pos */
309 ClientToScreen16( msg->hwnd, (LPPOINT16)&event->paramL );
310 HOOK_CallHooks16( WH_JOURNALRECORD, HC_ACTION, 0,
311 (LPARAM)SEGPTR_GET(event) );
313 else if ((msg->message >= WM_NCMOUSEFIRST) &&
314 (msg->message <= WM_NCMOUSELAST))
316 event->paramL = LOWORD(msg->lParam); /* X pos */
317 event->paramH = HIWORD(msg->lParam); /* Y pos */
318 event->message += WM_MOUSEMOVE-WM_NCMOUSEMOVE;/* give no info about NC area */
319 HOOK_CallHooks16( WH_JOURNALRECORD, HC_ACTION, 0,
320 (LPARAM)SEGPTR_GET(event) );
322 SEGPTR_FREE(event);
325 /***********************************************************************
326 * MSG_JournalPlayBackMsg
328 * Get an EVENTMSG struct via call JOURNALPLAYBACK hook function
330 static int MSG_JournalPlayBackMsg(void)
332 EVENTMSG16 *tmpMsg;
333 long wtime,lParam;
334 WORD keyDown,i,wParam,result=0;
336 if ( HOOK_IsHooked( WH_JOURNALPLAYBACK ) )
338 tmpMsg = SEGPTR_NEW(EVENTMSG16);
339 wtime=HOOK_CallHooks16( WH_JOURNALPLAYBACK, HC_GETNEXT, 0,
340 (LPARAM)SEGPTR_GET(tmpMsg));
341 /* dprintf_msg(stddeb,"Playback wait time =%ld\n",wtime); */
342 if (wtime<=0)
344 wtime=0;
345 if ((tmpMsg->message>= WM_KEYFIRST) && (tmpMsg->message <= WM_KEYLAST))
347 wParam=tmpMsg->paramL & 0xFF;
348 lParam=MAKELONG(tmpMsg->paramH&0x7ffff,tmpMsg->paramL>>8);
349 if (tmpMsg->message == WM_KEYDOWN || tmpMsg->message == WM_SYSKEYDOWN)
351 for (keyDown=i=0; i<256 && !keyDown; i++)
352 if (InputKeyStateTable[i] & 0x80)
353 keyDown++;
354 if (!keyDown)
355 lParam |= 0x40000000;
356 AsyncKeyStateTable[wParam]=InputKeyStateTable[wParam] |= 0x80;
358 else /* WM_KEYUP, WM_SYSKEYUP */
360 lParam |= 0xC0000000;
361 AsyncKeyStateTable[wParam]=InputKeyStateTable[wParam] &= ~0x80;
363 if (InputKeyStateTable[VK_MENU] & 0x80)
364 lParam |= 0x20000000;
365 if (tmpMsg->paramH & 0x8000) /*special_key bit*/
366 lParam |= 0x01000000;
367 hardware_event( tmpMsg->message, wParam, lParam,0, 0, tmpMsg->time, 0 );
369 else
371 if ((tmpMsg->message>= WM_MOUSEFIRST) && (tmpMsg->message <= WM_MOUSELAST))
373 switch (tmpMsg->message)
375 case WM_LBUTTONDOWN:MouseButtonsStates[0]=AsyncMouseButtonsStates[0]=1;break;
376 case WM_LBUTTONUP: MouseButtonsStates[0]=AsyncMouseButtonsStates[0]=0;break;
377 case WM_MBUTTONDOWN:MouseButtonsStates[1]=AsyncMouseButtonsStates[1]=1;break;
378 case WM_MBUTTONUP: MouseButtonsStates[1]=AsyncMouseButtonsStates[1]=0;break;
379 case WM_RBUTTONDOWN:MouseButtonsStates[2]=AsyncMouseButtonsStates[2]=1;break;
380 case WM_RBUTTONUP: MouseButtonsStates[2]=AsyncMouseButtonsStates[2]=0;break;
382 AsyncKeyStateTable[VK_LBUTTON]= InputKeyStateTable[VK_LBUTTON] = MouseButtonsStates[0] << 8;
383 AsyncKeyStateTable[VK_MBUTTON]= InputKeyStateTable[VK_MBUTTON] = MouseButtonsStates[1] << 8;
384 AsyncKeyStateTable[VK_RBUTTON]= InputKeyStateTable[VK_RBUTTON] = MouseButtonsStates[2] << 8;
385 SetCursorPos(tmpMsg->paramL,tmpMsg->paramH);
386 lParam=MAKELONG(tmpMsg->paramL,tmpMsg->paramH);
387 wParam=0;
388 if (MouseButtonsStates[0]) wParam |= MK_LBUTTON;
389 if (MouseButtonsStates[1]) wParam |= MK_MBUTTON;
390 if (MouseButtonsStates[2]) wParam |= MK_RBUTTON;
391 hardware_event( tmpMsg->message, wParam, lParam,
392 tmpMsg->paramL, tmpMsg->paramH, tmpMsg->time, 0 );
395 HOOK_CallHooks16( WH_JOURNALPLAYBACK, HC_SKIP, 0,
396 (LPARAM)SEGPTR_GET(tmpMsg));
398 else
400 if( tmpMsg->message == WM_QUEUESYNC )
401 if (HOOK_IsHooked( WH_CBT ))
402 HOOK_CallHooks16( WH_CBT, HCBT_QS, 0, 0L);
404 result= QS_MOUSE | QS_KEY; /* ? */
406 SEGPTR_FREE(tmpMsg);
408 return result;
411 /***********************************************************************
412 * MSG_PeekHardwareMsg
414 * Peek for a hardware message matching the hwnd and message filters.
416 static BOOL32 MSG_PeekHardwareMsg( MSG16 *msg, HWND16 hwnd, DWORD filter, BOOL32 remove )
418 DWORD status = SYSQ_MSG_ACCEPT;
419 MESSAGEQUEUE *sysMsgQueue = QUEUE_GetSysQueue();
420 int i, kbd_msg, pos = sysMsgQueue->nextMessage;
422 /* If the queue is empty, attempt to fill it */
423 if (!sysMsgQueue->msgCount && XPending(display))
424 EVENT_WaitXEvent( FALSE, FALSE );
426 for (i = kbd_msg = 0; i < sysMsgQueue->msgCount; i++, pos++)
428 if (pos >= sysMsgQueue->queueSize) pos = 0;
429 *msg = sysMsgQueue->messages[pos].msg;
431 /* Translate message */
433 if ((msg->message >= WM_MOUSEFIRST) && (msg->message <= WM_MOUSELAST))
435 status = MSG_TranslateMouseMsg(hwnd, filter, msg, remove);
436 kbd_msg = 0;
438 else if ((msg->message >= WM_KEYFIRST) && (msg->message <= WM_KEYLAST))
440 status = MSG_TranslateKbdMsg(hwnd, filter, msg, remove);
441 kbd_msg = 1;
443 else /* Non-standard hardware event */
445 HARDWAREHOOKSTRUCT16 *hook;
446 if ((hook = SEGPTR_NEW(HARDWAREHOOKSTRUCT16)))
448 BOOL32 ret;
449 hook->hWnd = msg->hwnd;
450 hook->wMessage = msg->message;
451 hook->wParam = msg->wParam;
452 hook->lParam = msg->lParam;
453 ret = HOOK_CallHooks16( WH_HARDWARE,
454 remove ? HC_ACTION : HC_NOREMOVE,
455 0, (LPARAM)SEGPTR_GET(hook) );
456 SEGPTR_FREE(hook);
457 if (ret)
459 QUEUE_RemoveMsg( sysMsgQueue, pos );
460 continue;
462 status = SYSQ_MSG_ACCEPT;
466 switch (LOWORD(status))
468 case SYSQ_MSG_ACCEPT:
469 break;
471 case SYSQ_MSG_SKIP:
472 if (HOOK_IsHooked( WH_CBT ))
473 if( kbd_msg )
474 HOOK_CallHooks16( WH_CBT, HCBT_KEYSKIPPED,
475 msg->wParam, msg->lParam );
476 else
478 MOUSEHOOKSTRUCT16 *hook = SEGPTR_NEW(MOUSEHOOKSTRUCT16);
479 if (hook)
481 hook->pt = msg->pt;
482 hook->hwnd = msg->hwnd;
483 hook->wHitTestCode = HIWORD(status);
484 hook->dwExtraInfo = 0;
485 HOOK_CallHooks16( WH_CBT, HCBT_CLICKSKIPPED ,msg->message,
486 (LPARAM)SEGPTR_GET(hook) );
487 SEGPTR_FREE(hook);
491 if (remove)
492 QUEUE_RemoveMsg( sysMsgQueue, pos );
493 /* continue */
495 case SYSQ_MSG_CONTINUE:
496 continue;
498 case SYSQ_MSG_ABANDON:
499 return FALSE;
502 if (remove)
504 if (HOOK_IsHooked( WH_JOURNALRECORD )) MSG_JournalRecordMsg( msg );
505 QUEUE_RemoveMsg( sysMsgQueue, pos );
507 return TRUE;
509 return FALSE;
513 /**********************************************************************
514 * SetDoubleClickTime (USER.20)
516 void SetDoubleClickTime( WORD interval )
518 doubleClickSpeed = interval ? interval : 500;
522 /**********************************************************************
523 * GetDoubleClickTime (USER.21)
525 WORD GetDoubleClickTime()
527 return doubleClickSpeed;
531 /***********************************************************************
532 * MSG_SendMessage
534 * Implementation of an inter-task SendMessage.
536 static LRESULT MSG_SendMessage( HQUEUE16 hDestQueue, HWND hwnd, UINT msg,
537 WPARAM16 wParam, LPARAM lParam )
539 INT32 prevSMRL = debugSMRL;
540 QSMCTRL qCtrl = { 0, 1};
541 MESSAGEQUEUE *queue, *destQ;
543 if (!(queue = (MESSAGEQUEUE*)GlobalLock16( GetTaskQueue(0) ))) return 0;
544 if (!(destQ = (MESSAGEQUEUE*)GlobalLock16( hDestQueue ))) return 0;
546 if (IsTaskLocked() || !IsWindow(hwnd)) return 0;
548 debugSMRL+=4;
549 dprintf_sendmsg(stddeb,"%*sSM: %s [%04x] (%04x -> %04x)\n",
550 prevSMRL, "", SPY_GetMsgName(msg), msg, queue->self, hDestQueue );
552 if( !(queue->wakeBits & QS_SMPARAMSFREE) )
554 dprintf_sendmsg(stddeb,"\tIntertask SendMessage: sleeping since unreplied SendMessage pending\n");
555 queue->changeBits &= ~QS_SMPARAMSFREE;
556 QUEUE_WaitBits( QS_SMPARAMSFREE );
559 /* resume sending */
561 queue->hWnd = hwnd;
562 queue->msg = msg;
563 queue->wParam = wParam;
564 queue->lParam = lParam;
565 queue->hPrevSendingTask = destQ->hSendingTask;
566 destQ->hSendingTask = GetTaskQueue(0);
568 queue->wakeBits &= ~QS_SMPARAMSFREE;
570 dprintf_sendmsg(stddeb,"%*ssm: smResultInit = %08x\n", prevSMRL, "", (unsigned)&qCtrl);
572 queue->smResultInit = &qCtrl;
574 QUEUE_SetWakeBit( destQ, QS_SENDMESSAGE );
576 /* perform task switch and wait for the result */
578 while( qCtrl.bPending )
580 if (!(queue->wakeBits & QS_SMRESULT))
582 queue->changeBits &= ~QS_SMRESULT;
583 DirectedYield( destQ->hTask );
584 QUEUE_WaitBits( QS_SMRESULT );
585 dprintf_sendmsg(stddeb,"\tsm: have result!\n");
587 /* got something */
589 dprintf_sendmsg(stddeb,"%*ssm: smResult = %08x\n", prevSMRL, "", (unsigned)queue->smResult );
591 if (queue->smResult) { /* FIXME, smResult should always be set */
592 queue->smResult->lResult = queue->SendMessageReturn;
593 queue->smResult->bPending = FALSE;
595 queue->wakeBits &= ~QS_SMRESULT;
597 if( queue->smResult != &qCtrl )
598 dprintf_msg(stddeb,"%*ssm: weird scenes inside the goldmine!\n", prevSMRL, "");
600 queue->smResultInit = NULL;
602 dprintf_sendmsg(stddeb,"%*sSM: [%04x] returning %08lx\n", prevSMRL, "", msg, qCtrl.lResult);
603 debugSMRL-=4;
605 return qCtrl.lResult;
609 /***********************************************************************
610 * ReplyMessage (USER.115)
612 void ReplyMessage( LRESULT result )
614 MESSAGEQUEUE *senderQ;
615 MESSAGEQUEUE *queue;
617 if (!(queue = (MESSAGEQUEUE*)GlobalLock16( GetTaskQueue(0) ))) return;
619 dprintf_msg(stddeb,"ReplyMessage, queue %04x\n", queue->self);
621 while( (senderQ = (MESSAGEQUEUE*)GlobalLock16( queue->InSendMessageHandle)))
623 dprintf_msg(stddeb,"\trpm: replying to %04x (%04x -> %04x)\n",
624 queue->msg, queue->self, senderQ->self);
626 if( queue->wakeBits & QS_SENDMESSAGE )
628 QUEUE_ReceiveMessage( queue );
629 continue; /* ReceiveMessage() already called us */
632 if(!(senderQ->wakeBits & QS_SMRESULT) ) break;
633 OldYield();
635 if( !senderQ ) { dprintf_msg(stddeb,"\trpm: done\n"); return; }
637 senderQ->SendMessageReturn = result;
638 dprintf_msg(stddeb,"\trpm: smResult = %08x, result = %08lx\n",
639 (unsigned)queue->smResultCurrent, result );
641 senderQ->smResult = queue->smResultCurrent;
642 queue->InSendMessageHandle = 0;
644 QUEUE_SetWakeBit( senderQ, QS_SMRESULT );
645 DirectedYield( queue->hSendingTask );
649 /***********************************************************************
650 * MSG_PeekMessage
652 static BOOL MSG_PeekMessage( LPMSG16 msg, HWND hwnd, WORD first, WORD last,
653 WORD flags, BOOL peek )
655 int pos, mask;
656 MESSAGEQUEUE *msgQueue;
657 HQUEUE16 hQueue;
659 #ifdef CONFIG_IPC
660 DDE_TestDDE(hwnd); /* do we have dde handling in the window ?*/
661 DDE_GetRemoteMessage();
662 #endif /* CONFIG_IPC */
664 mask = QS_POSTMESSAGE | QS_SENDMESSAGE; /* Always selected */
665 if (first || last)
667 /* MSWord gets stuck if we do not check for nonclient mouse messages */
669 if ((first <= WM_KEYLAST) && (last >= WM_KEYFIRST)) mask |= QS_KEY;
670 if ( ((first <= WM_MOUSELAST) && (last >= WM_MOUSEFIRST)) ||
671 ((first <= WM_NCMOUSELAST) && (last >= WM_NCMOUSEFIRST)) ) mask |= QS_MOUSE;
672 if ((first <= WM_TIMER) && (last >= WM_TIMER)) mask |= QS_TIMER;
673 if ((first <= WM_SYSTIMER) && (last >= WM_SYSTIMER)) mask |= QS_TIMER;
674 if ((first <= WM_PAINT) && (last >= WM_PAINT)) mask |= QS_PAINT;
676 else mask |= QS_MOUSE | QS_KEY | QS_TIMER | QS_PAINT;
678 if (IsTaskLocked()) flags |= PM_NOYIELD;
680 while(1)
682 hQueue = GetTaskQueue(0);
683 msgQueue = (MESSAGEQUEUE *)GlobalLock16( hQueue );
684 if (!msgQueue) return FALSE;
685 msgQueue->changeBits = 0;
687 /* First handle a message put by SendMessage() */
689 while (msgQueue->wakeBits & QS_SENDMESSAGE)
690 QUEUE_ReceiveMessage( msgQueue );
692 /* Now handle a WM_QUIT message
694 * FIXME: PostQuitMessage() should post WM_QUIT and
695 * set QS_POSTMESSAGE wakebit instead of this.
698 if (msgQueue->wPostQMsg &&
699 (!first || WM_QUIT >= first) &&
700 (!last || WM_QUIT <= last) )
702 msg->hwnd = hwnd;
703 msg->message = WM_QUIT;
704 msg->wParam = msgQueue->wExitCode;
705 msg->lParam = 0;
706 if (flags & PM_REMOVE) msgQueue->wPostQMsg = 0;
707 break;
710 /* Now find a normal message */
712 if (((msgQueue->wakeBits & mask) & QS_POSTMESSAGE) &&
713 ((pos = QUEUE_FindMsg( msgQueue, hwnd, first, last )) != -1))
715 QMSG *qmsg = &msgQueue->messages[pos];
716 *msg = qmsg->msg;
717 msgQueue->GetMessageTimeVal = msg->time;
718 msgQueue->GetMessagePosVal = *(DWORD *)&msg->pt;
719 msgQueue->GetMessageExtraInfoVal = qmsg->extraInfo;
721 if (flags & PM_REMOVE) QUEUE_RemoveMsg( msgQueue, pos );
722 break;
725 msgQueue->changeBits |= MSG_JournalPlayBackMsg();
727 /* Now find a hardware event */
729 if (((msgQueue->wakeBits & mask) & (QS_MOUSE | QS_KEY)) &&
730 MSG_PeekHardwareMsg( msg, hwnd, MAKELONG(first,last), flags & PM_REMOVE ))
732 /* Got one */
733 msgQueue->GetMessageTimeVal = msg->time;
734 msgQueue->GetMessagePosVal = *(DWORD *)&msg->pt;
735 msgQueue->GetMessageExtraInfoVal = 0; /* Always 0 for now */
736 break;
739 /* Check again for SendMessage */
741 while (msgQueue->wakeBits & QS_SENDMESSAGE)
742 QUEUE_ReceiveMessage( msgQueue );
744 /* Now find a WM_PAINT message */
746 if ((msgQueue->wakeBits & mask) & QS_PAINT)
748 WND* wndPtr;
749 msg->hwnd = WIN_FindWinToRepaint( hwnd , hQueue );
750 msg->message = WM_PAINT;
751 msg->wParam = 0;
752 msg->lParam = 0;
754 if ((wndPtr = WIN_FindWndPtr(msg->hwnd)))
756 if( wndPtr->dwStyle & WS_MINIMIZE &&
757 wndPtr->class->hIcon )
759 msg->message = WM_PAINTICON;
760 msg->wParam = 1;
763 if( !hwnd || msg->hwnd == hwnd || IsChild(hwnd,msg->hwnd) )
765 if( wndPtr->flags & WIN_INTERNAL_PAINT && !wndPtr->hrgnUpdate)
767 wndPtr->flags &= ~WIN_INTERNAL_PAINT;
768 QUEUE_DecPaintCount( hQueue );
770 break;
775 /* Check for timer messages, but yield first */
777 if (!(flags & PM_NOYIELD))
779 UserYield();
780 while (msgQueue->wakeBits & QS_SENDMESSAGE)
781 QUEUE_ReceiveMessage( msgQueue );
783 if ((msgQueue->wakeBits & mask) & QS_TIMER)
785 if (TIMER_GetTimerMsg(msg, hwnd, hQueue, flags & PM_REMOVE)) break;
788 if (peek)
790 if (!(flags & PM_NOYIELD)) UserYield();
791 return FALSE;
793 msgQueue->wakeMask = mask;
794 QUEUE_WaitBits( mask );
797 /* We got a message */
798 if (flags & PM_REMOVE)
800 WORD message = msg->message;
802 if (message == WM_KEYDOWN || message == WM_SYSKEYDOWN)
804 BYTE *p = &QueueKeyStateTable[msg->wParam & 0xff];
806 if (!(*p & 0x80))
807 *p ^= 0x01;
808 *p |= 0x80;
810 else if (message == WM_KEYUP || message == WM_SYSKEYUP)
811 QueueKeyStateTable[msg->wParam & 0xff] &= ~0x80;
813 if (peek) return TRUE;
814 else return (msg->message != WM_QUIT);
818 /***********************************************************************
819 * MSG_InternalGetMessage
821 * GetMessage() function for internal use. Behave like GetMessage(),
822 * but also call message filters and optionally send WM_ENTERIDLE messages.
823 * 'hwnd' must be the handle of the dialog or menu window.
824 * 'code' is the message filter value (MSGF_??? codes).
826 BOOL32 MSG_InternalGetMessage( MSG16 *msg, HWND32 hwnd, HWND32 hwndOwner,
827 WPARAM32 code, WORD flags, BOOL32 sendIdle )
829 for (;;)
831 if (sendIdle)
833 if (!MSG_PeekMessage( msg, 0, 0, 0, flags, TRUE ))
835 /* No message present -> send ENTERIDLE and wait */
836 if (IsWindow(hwndOwner))
837 SendMessage16( hwndOwner, WM_ENTERIDLE,
838 code, (LPARAM)hwnd );
839 MSG_PeekMessage( msg, 0, 0, 0, flags, FALSE );
842 else /* Always wait for a message */
843 MSG_PeekMessage( msg, 0, 0, 0, flags, FALSE );
845 /* Call message filters */
847 if (HOOK_IsHooked( WH_SYSMSGFILTER ) || HOOK_IsHooked( WH_MSGFILTER ))
849 MSG16 *pmsg = SEGPTR_NEW(MSG16);
850 if (pmsg)
852 BOOL32 ret;
853 *pmsg = *msg;
854 ret = ((BOOL16)HOOK_CallHooks16( WH_SYSMSGFILTER, code, 0,
855 (LPARAM)SEGPTR_GET(pmsg) ) ||
856 (BOOL16)HOOK_CallHooks16( WH_MSGFILTER, code, 0,
857 (LPARAM)SEGPTR_GET(pmsg) ));
858 SEGPTR_FREE(pmsg);
859 if (ret)
861 /* Message filtered -> remove it from the queue */
862 /* if it's still there. */
863 if (!(flags & PM_REMOVE))
864 MSG_PeekMessage( msg, 0, 0, 0, PM_REMOVE, TRUE );
865 continue;
870 return (msg->message != WM_QUIT);
875 /***********************************************************************
876 * PeekMessage16 (USER.109)
878 BOOL16 PeekMessage16( LPMSG16 msg, HWND16 hwnd, UINT16 first,
879 UINT16 last, UINT16 flags )
881 return MSG_PeekMessage( msg, hwnd, first, last, flags, TRUE );
885 /***********************************************************************
886 * GetMessage (USER.108)
888 BOOL GetMessage( SEGPTR msg, HWND hwnd, UINT first, UINT last )
890 MSG16 *lpmsg = (MSG16 *)PTR_SEG_TO_LIN(msg);
891 MSG_PeekMessage( lpmsg,
892 hwnd, first, last, PM_REMOVE, FALSE );
894 dprintf_msg(stddeb,"message %04x, hwnd %04x, filter(%04x - %04x)\n", lpmsg->message,
895 hwnd, first, last );
896 HOOK_CallHooks16( WH_GETMESSAGE, HC_ACTION, 0, (LPARAM)msg );
897 return (lpmsg->message != WM_QUIT);
901 /***********************************************************************
902 * PostMessage (USER.110)
904 BOOL PostMessage( HWND hwnd, WORD message, WORD wParam, LONG lParam )
906 MSG16 msg;
907 WND *wndPtr;
909 msg.hwnd = hwnd;
910 msg.message = message;
911 msg.wParam = wParam;
912 msg.lParam = lParam;
913 msg.time = GetTickCount();
914 msg.pt.x = 0;
915 msg.pt.y = 0;
917 #ifdef CONFIG_IPC
918 if (DDE_PostMessage(&msg))
919 return TRUE;
920 #endif /* CONFIG_IPC */
922 if (hwnd == HWND_BROADCAST16)
924 dprintf_msg(stddeb,"PostMessage // HWND_BROADCAST !\n");
925 for (wndPtr = WIN_GetDesktop()->child; wndPtr; wndPtr = wndPtr->next)
927 if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION)
929 dprintf_msg(stddeb,"BROADCAST Message to hWnd=%04x m=%04X w=%04X l=%08lX !\n",
930 wndPtr->hwndSelf, message, wParam, lParam);
931 PostMessage( wndPtr->hwndSelf, message, wParam, lParam );
934 dprintf_msg(stddeb,"PostMessage // End of HWND_BROADCAST !\n");
935 return TRUE;
938 wndPtr = WIN_FindWndPtr( hwnd );
939 if (!wndPtr || !wndPtr->hmemTaskQ) return FALSE;
941 return QUEUE_AddMsg( wndPtr->hmemTaskQ, &msg, 0 );
944 /***********************************************************************
945 * PostAppMessage16 (USER.116)
947 BOOL16 PostAppMessage16( HTASK16 hTask, UINT16 message, WPARAM16 wParam,
948 LPARAM lParam )
950 MSG16 msg;
952 if (GetTaskQueue(hTask) == 0) return FALSE;
953 msg.hwnd = 0;
954 msg.message = message;
955 msg.wParam = wParam;
956 msg.lParam = lParam;
957 msg.time = GetTickCount();
958 msg.pt.x = 0;
959 msg.pt.y = 0;
961 return QUEUE_AddMsg( GetTaskQueue(hTask), &msg, 0 );
965 /***********************************************************************
966 * SendMessage16 (USER.111)
968 LRESULT SendMessage16( HWND16 hwnd, UINT16 msg, WPARAM16 wParam, LPARAM lParam)
970 WND * wndPtr;
971 WND **list, **ppWnd;
972 LRESULT ret;
974 #ifdef CONFIG_IPC
975 MSG16 DDE_msg = { hwnd, msg, wParam, lParam };
976 if (DDE_SendMessage(&DDE_msg)) return TRUE;
977 #endif /* CONFIG_IPC */
979 if (hwnd == HWND_BROADCAST16)
981 dprintf_msg(stddeb,"SendMessage // HWND_BROADCAST !\n");
982 list = WIN_BuildWinArray( WIN_GetDesktop() );
983 for (ppWnd = list; *ppWnd; ppWnd++)
985 wndPtr = *ppWnd;
986 if (!IsWindow(wndPtr->hwndSelf)) continue;
987 if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION)
989 dprintf_msg(stddeb,"BROADCAST Message to hWnd=%04x m=%04X w=%04lX l=%08lX !\n",
990 wndPtr->hwndSelf, msg, (DWORD)wParam, lParam);
991 SendMessage16( wndPtr->hwndSelf, msg, wParam, lParam );
994 HeapFree( SystemHeap, 0, list );
995 dprintf_msg(stddeb,"SendMessage // End of HWND_BROADCAST !\n");
996 return TRUE;
999 if (HOOK_IsHooked( WH_CALLWNDPROC ))
1001 struct msgstruct
1003 LPARAM lParam;
1004 WPARAM16 wParam;
1005 UINT16 wMsg;
1006 HWND16 hWnd;
1007 } *pmsg;
1009 if ((pmsg = SEGPTR_NEW(struct msgstruct)))
1011 pmsg->hWnd = hwnd;
1012 pmsg->wMsg = msg;
1013 pmsg->wParam = wParam;
1014 pmsg->lParam = lParam;
1015 HOOK_CallHooks16( WH_CALLWNDPROC, HC_ACTION, 1,
1016 (LPARAM)SEGPTR_GET(pmsg) );
1017 hwnd = pmsg->hWnd;
1018 msg = pmsg->wMsg;
1019 wParam = pmsg->wParam;
1020 lParam = pmsg->lParam;
1021 SEGPTR_FREE( pmsg );
1025 if (!(wndPtr = WIN_FindWndPtr( hwnd )))
1027 fprintf( stderr, "SendMessage16: invalid hwnd %04x\n", hwnd );
1028 return 0;
1030 if (QUEUE_IsDoomedQueue(wndPtr->hmemTaskQ))
1031 return 0; /* Don't send anything if the task is dying */
1032 if (wndPtr->hmemTaskQ != GetTaskQueue(0))
1033 return MSG_SendMessage( wndPtr->hmemTaskQ, hwnd, msg, wParam, lParam );
1035 SPY_EnterMessage( SPY_SENDMESSAGE16, hwnd, msg, wParam, lParam );
1036 ret = CallWindowProc16( (WNDPROC16)wndPtr->winproc,
1037 hwnd, msg, wParam, lParam );
1038 SPY_ExitMessage( SPY_RESULT_OK16, hwnd, msg, ret );
1039 return ret;
1043 /***********************************************************************
1044 * SendMessage32A (USER32.453)
1046 LRESULT SendMessage32A(HWND32 hwnd, UINT32 msg, WPARAM32 wParam, LPARAM lParam)
1048 WND * wndPtr;
1049 WND **list, **ppWnd;
1050 LRESULT ret;
1052 if (hwnd == HWND_BROADCAST32)
1054 list = WIN_BuildWinArray( WIN_GetDesktop() );
1055 for (ppWnd = list; *ppWnd; ppWnd++)
1057 wndPtr = *ppWnd;
1058 if (!IsWindow(wndPtr->hwndSelf)) continue;
1059 if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION)
1060 SendMessage32A( wndPtr->hwndSelf, msg, wParam, lParam );
1062 HeapFree( SystemHeap, 0, list );
1063 return TRUE;
1066 /* FIXME: call hooks */
1068 if (!(wndPtr = WIN_FindWndPtr( hwnd )))
1070 fprintf( stderr, "SendMessage32A: invalid hwnd %08x\n", hwnd );
1071 return 0;
1074 if (WINPROC_GetProcType( wndPtr->winproc ) == WIN_PROC_16)
1076 /* Use SendMessage16 for now to get hooks right */
1077 UINT16 msg16;
1078 WPARAM16 wParam16;
1079 if (WINPROC_MapMsg32ATo16( msg, wParam, &msg16, &wParam16, &lParam ) == -1)
1080 return 0;
1081 ret = SendMessage16( hwnd, msg16, wParam16, lParam );
1082 WINPROC_UnmapMsg32ATo16( msg, wParam16, lParam );
1083 return ret;
1086 if (QUEUE_IsDoomedQueue(wndPtr->hmemTaskQ))
1087 return 0; /* Don't send anything if the task is dying */
1089 if (wndPtr->hmemTaskQ != GetTaskQueue(0))
1091 fprintf( stderr, "SendMessage32A: intertask message not supported\n" );
1092 return 0;
1095 SPY_EnterMessage( SPY_SENDMESSAGE32, hwnd, msg, wParam, lParam );
1096 ret = CallWindowProc32A( (WNDPROC32)wndPtr->winproc,
1097 hwnd, msg, wParam, lParam );
1098 SPY_ExitMessage( SPY_RESULT_OK32, hwnd, msg, ret );
1099 return ret;
1103 /***********************************************************************
1104 * SendMessage32W (USER32.458)
1106 LRESULT SendMessage32W(HWND32 hwnd, UINT32 msg, WPARAM32 wParam, LPARAM lParam)
1108 WND * wndPtr;
1109 WND **list, **ppWnd;
1110 LRESULT ret;
1112 if (hwnd == HWND_BROADCAST32)
1114 list = WIN_BuildWinArray( WIN_GetDesktop() );
1115 for (ppWnd = list; *ppWnd; ppWnd++)
1117 wndPtr = *ppWnd;
1118 if (!IsWindow(wndPtr->hwndSelf)) continue;
1119 if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION)
1120 SendMessage32W( wndPtr->hwndSelf, msg, wParam, lParam );
1122 HeapFree( SystemHeap, 0, list );
1123 return TRUE;
1126 /* FIXME: call hooks */
1128 if (!(wndPtr = WIN_FindWndPtr( hwnd )))
1130 fprintf( stderr, "SendMessage32W: invalid hwnd %08x\n", hwnd );
1131 return 0;
1133 if (QUEUE_IsDoomedQueue(wndPtr->hmemTaskQ))
1134 return 0; /* Don't send anything if the task is dying */
1135 if (wndPtr->hmemTaskQ != GetTaskQueue(0))
1137 fprintf( stderr, "SendMessage32W: intertask message not supported\n" );
1138 return 0;
1141 SPY_EnterMessage( SPY_SENDMESSAGE32, hwnd, msg, wParam, lParam );
1142 ret = CallWindowProc32W( (WNDPROC32)wndPtr->winproc,
1143 hwnd, msg, wParam, lParam );
1144 SPY_ExitMessage( SPY_RESULT_OK32, hwnd, msg, ret );
1145 return ret;
1149 /***********************************************************************
1150 * WaitMessage (USER.112)
1152 void WaitMessage( void )
1154 QUEUE_WaitBits( QS_ALLINPUT );
1158 /***********************************************************************
1159 * TranslateMessage (USER.113)
1161 * TranlateMessage translate virtual-key messages into character-messages,
1162 * as follows :
1163 * WM_KEYDOWN/WM_KEYUP combinations produce a WM_CHAR or WM_DEADCHAR message.
1164 * ditto replacing WM_* with WM_SYS*
1165 * This produces WM_CHAR messages only for keys mapped to ASCII characters
1166 * by the keyboard driver.
1169 const struct accent_char
1171 BYTE ac_accent;
1172 BYTE ac_char;
1173 BYTE ac_result;
1174 } accent_chars[] =
1176 {'`', 'A', '\300'}, {'`', 'a', '\340'},
1177 {'\'', 'A', '\301'}, {'\'', 'a', '\341'},
1178 {'^', 'A', '\302'}, {'^', 'a', '\342'},
1179 {'~', 'A', '\303'}, {'~', 'a', '\343'},
1180 {'"', 'A', '\304'}, {'"', 'a', '\344'},
1181 {'O', 'A', '\305'}, {'o', 'a', '\345'},
1182 {'0', 'A', '\305'}, {'0', 'a', '\345'},
1183 {'A', 'A', '\305'}, {'a', 'a', '\345'},
1184 {'A', 'E', '\306'}, {'a', 'e', '\346'},
1185 {',', 'C', '\307'}, {',', 'c', '\347'},
1186 {'`', 'E', '\310'}, {'`', 'e', '\350'},
1187 {'\'', 'E', '\311'}, {'\'', 'e', '\351'},
1188 {'^', 'E', '\312'}, {'^', 'e', '\352'},
1189 {'"', 'E', '\313'}, {'"', 'e', '\353'},
1190 {'`', 'I', '\314'}, {'`', 'i', '\354'},
1191 {'\'', 'I', '\315'}, {'\'', 'i', '\355'},
1192 {'^', 'I', '\316'}, {'^', 'i', '\356'},
1193 {'"', 'I', '\317'}, {'"', 'i', '\357'},
1194 {'-', 'D', '\320'}, {'-', 'd', '\360'},
1195 {'~', 'N', '\321'}, {'~', 'n', '\361'},
1196 {'`', 'O', '\322'}, {'`', 'o', '\362'},
1197 {'\'', 'O', '\323'}, {'\'', 'o', '\363'},
1198 {'^', 'O', '\324'}, {'^', 'o', '\364'},
1199 {'~', 'O', '\325'}, {'~', 'o', '\365'},
1200 {'"', 'O', '\326'}, {'"', 'o', '\366'},
1201 {'/', 'O', '\330'}, {'/', 'o', '\370'},
1202 {'`', 'U', '\331'}, {'`', 'u', '\371'},
1203 {'\'', 'U', '\332'}, {'\'', 'u', '\372'},
1204 {'^', 'U', '\333'}, {'^', 'u', '\373'},
1205 {'"', 'U', '\334'}, {'"', 'u', '\374'},
1206 {'\'', 'Y', '\335'}, {'\'', 'y', '\375'},
1207 {'T', 'H', '\336'}, {'t', 'h', '\376'},
1208 {'s', 's', '\337'}, {'"', 'y', '\377'},
1209 {'s', 'z', '\337'}, {'i', 'j', '\377'},
1212 BOOL TranslateMessage( LPMSG16 msg )
1214 UINT message = msg->message;
1215 BYTE wparam[2];
1217 if ((debugging_msg
1218 && message != WM_MOUSEMOVE && message != WM_TIMER)
1219 || (debugging_key
1220 && message >= WM_KEYFIRST && message <= WM_KEYLAST))
1221 fprintf(stddeb, "TranslateMessage(%s, %04X, %08lX)\n",
1222 SPY_GetMsgName(msg->message), msg->wParam, msg->lParam);
1223 if ((message == WM_KEYDOWN) || (message == WM_SYSKEYDOWN))
1225 static dead_char;
1227 if (debugging_msg || debugging_key)
1228 fprintf(stddeb, "Translating key %04X, scancode %04X\n",
1229 msg->wParam, HIWORD(msg->lParam) );
1231 /* FIXME : should handle ToAscii yielding 2 */
1232 switch (ToAscii(msg->wParam, HIWORD(msg->lParam),
1233 (LPSTR)&QueueKeyStateTable, wparam, 0))
1235 case 1 :
1236 message = message == WM_KEYDOWN ? WM_CHAR : WM_SYSCHAR;
1237 /* Should dead chars handling go in ToAscii ? */
1238 if (dead_char)
1240 int i;
1242 if (wparam[0] == ' ')
1243 wparam[0] = dead_char;
1244 if (dead_char == 0xa8)
1245 dead_char = '"';
1246 else if (dead_char == 0xb4)
1247 dead_char = '\'';
1248 for (i = 0;
1249 i < sizeof(accent_chars) / sizeof(accent_chars[0]);
1250 i += 1)
1251 if (accent_chars[i].ac_accent == dead_char
1252 && accent_chars[i].ac_char == wparam[0])
1254 wparam[0] = accent_chars[i].ac_result;
1255 break;
1257 dead_char = 0;
1259 dprintf_key(stddeb, "1 -> PostMessage(%s)\n", SPY_GetMsgName(message));
1260 PostMessage( msg->hwnd, message, wparam[0], msg->lParam );
1261 return TRUE;
1262 case -1 :
1263 message = message == WM_KEYDOWN ? WM_DEADCHAR : WM_SYSDEADCHAR;
1264 dead_char = wparam[0];
1265 dprintf_key(stddeb, "-1 -> PostMessage(%s)\n", SPY_GetMsgName(message));
1266 PostMessage( msg->hwnd, message, wparam[0], msg->lParam );
1267 return TRUE;
1270 return FALSE;
1274 /***********************************************************************
1275 * DispatchMessage (USER.114)
1277 LONG DispatchMessage( const MSG16* msg )
1279 WND * wndPtr;
1280 LONG retval;
1281 int painting;
1283 /* Process timer messages */
1284 if ((msg->message == WM_TIMER) || (msg->message == WM_SYSTIMER))
1286 if (msg->lParam)
1288 /* HOOK_CallHooks16( WH_CALLWNDPROC, HC_ACTION, 0, FIXME ); */
1289 return CallWindowProc16( (WNDPROC16)msg->lParam, msg->hwnd,
1290 msg->message, msg->wParam, GetTickCount() );
1294 if (!msg->hwnd) return 0;
1295 if (!(wndPtr = WIN_FindWndPtr( msg->hwnd ))) return 0;
1296 if (!wndPtr->winproc) return 0;
1297 painting = (msg->message == WM_PAINT);
1298 if (painting) wndPtr->flags |= WIN_NEEDS_BEGINPAINT;
1299 /* HOOK_CallHooks16( WH_CALLWNDPROC, HC_ACTION, 0, FIXME ); */
1301 SPY_EnterMessage( SPY_DISPATCHMESSAGE16, msg->hwnd, msg->message,
1302 msg->wParam, msg->lParam );
1303 retval = CallWindowProc16( (WNDPROC16)wndPtr->winproc,
1304 msg->hwnd, msg->message,
1305 msg->wParam, msg->lParam );
1306 SPY_ExitMessage( SPY_RESULT_OK16, msg->hwnd, msg->message, retval );
1308 if (painting && (wndPtr = WIN_FindWndPtr( msg->hwnd )) &&
1309 (wndPtr->flags & WIN_NEEDS_BEGINPAINT) && wndPtr->hrgnUpdate)
1311 fprintf(stderr, "BeginPaint not called on WM_PAINT for hwnd %04x!\n",
1312 msg->hwnd);
1313 wndPtr->flags &= ~WIN_NEEDS_BEGINPAINT;
1314 /* Validate the update region to avoid infinite WM_PAINT loop */
1315 ValidateRect32( msg->hwnd, NULL );
1317 return retval;
1321 /***********************************************************************
1322 * RegisterWindowMessage16 (USER.118)
1324 WORD RegisterWindowMessage16( SEGPTR str )
1326 dprintf_msg(stddeb, "RegisterWindowMessage16: %08lx\n", (DWORD)str );
1327 return GlobalAddAtom16( str );
1331 /***********************************************************************
1332 * RegisterWindowMessage32A (USER32.436)
1334 WORD RegisterWindowMessage32A( LPCSTR str )
1336 dprintf_msg(stddeb, "RegisterWindowMessage32A: %s\n", str );
1337 return GlobalAddAtom32A( str );
1341 /***********************************************************************
1342 * RegisterWindowMessage32W (USER32.437)
1344 WORD RegisterWindowMessage32W( LPCWSTR str )
1346 dprintf_msg(stddeb, "RegisterWindowMessage32W: %p\n", str );
1347 return GlobalAddAtom32W( str );
1351 /***********************************************************************
1352 * GetTickCount (USER.13) (KERNEL32.299)
1354 DWORD GetTickCount(void)
1356 struct timeval t;
1357 gettimeofday( &t, NULL );
1358 return ((t.tv_sec * 1000) + (t.tv_usec / 1000)) - MSG_WineStartTicks;
1362 /***********************************************************************
1363 * GetCurrentTime (USER.15)
1365 * (effectively identical to GetTickCount)
1367 DWORD GetCurrentTime(void)
1369 return GetTickCount();
1373 /***********************************************************************
1374 * InSendMessage (USER.192)
1376 BOOL InSendMessage()
1378 MESSAGEQUEUE *queue;
1380 if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(0) )))
1381 return 0;
1382 return (BOOL)queue->InSendMessageHandle;