Release 970202
[wine/multimedia.git] / windows / message.c
blob4ceb269daba32060d5dbd6bfebdbff54509a755a
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 "keyboard.h"
20 #include "spy.h"
21 #include "winpos.h"
22 #include "atom.h"
23 #include "dde.h"
24 #include "queue.h"
25 #include "winproc.h"
26 #include "stddebug.h"
27 /* #define DEBUG_MSG */
28 #include "debug.h"
30 #define WM_NCMOUSEFIRST WM_NCMOUSEMOVE
31 #define WM_NCMOUSELAST WM_NCMBUTTONDBLCLK
33 #define HWND_BROADCAST16 ((HWND16)0xffff)
34 #define HWND_BROADCAST32 ((HWND32)0xffffffff)
36 typedef enum { SYSQ_MSG_ABANDON, SYSQ_MSG_SKIP,
37 SYSQ_MSG_ACCEPT, SYSQ_MSG_CONTINUE } SYSQ_STATUS;
39 extern MESSAGEQUEUE *pCursorQueue; /* queue.c */
40 extern MESSAGEQUEUE *pActiveQueue;
42 DWORD MSG_WineStartTicks; /* Ticks at Wine startup */
44 static WORD doubleClickSpeed = 452;
45 static INT32 debugSMRL = 0; /* intertask SendMessage() recursion level */
47 /***********************************************************************
48 * MSG_CheckFilter
50 BOOL32 MSG_CheckFilter(WORD uMsg, DWORD filter)
52 if( filter )
53 return (uMsg >= LOWORD(filter) && uMsg <= HIWORD(filter));
54 return TRUE;
57 /***********************************************************************
58 * MSG_TranslateMouseMsg
60 * Translate an mouse hardware event into a real mouse message.
61 * Return value indicates whether the translated message must be passed
62 * to the user, left in the queue, or skipped entirely (in this case
63 * HIWORD contains hit test code).
65 static DWORD MSG_TranslateMouseMsg( HWND16 hWndScope, DWORD filter,
66 MSG16 *msg, BOOL32 remove )
68 static DWORD dblclk_time_limit = 0;
69 static UINT16 clk_message = 0;
70 static HWND16 clk_hwnd = 0;
71 static POINT16 clk_pos = { 0, 0 };
73 WND *pWnd;
74 HWND16 hWnd;
75 INT16 ht, hittest, sendSC = 0;
76 UINT16 message = msg->message;
77 POINT16 screen_pt, pt;
78 HANDLE16 hQ = GetTaskQueue(0);
79 MESSAGEQUEUE *queue = (MESSAGEQUEUE *)GlobalLock16(hQ);
80 BOOL32 eatMsg = FALSE;
81 BOOL32 mouseClick = ((message == WM_LBUTTONDOWN) ||
82 (message == WM_RBUTTONDOWN) ||
83 (message == WM_MBUTTONDOWN))?1:0;
84 SYSQ_STATUS ret = 0;
86 /* Find the window */
88 ht = hittest = HTCLIENT;
89 hWnd = GetCapture16();
90 if( !hWnd )
92 sendSC = 1;
93 ht = hittest = WINPOS_WindowFromPoint( WIN_GetDesktop(), msg->pt, &pWnd );
94 if( !pWnd ) pWnd = WIN_GetDesktop();
95 hWnd = pWnd->hwndSelf;
97 else
99 pWnd = WIN_FindWndPtr(hWnd);
100 ht = EVENT_GetCaptureInfo();
103 /* stop if not the right queue */
105 if (pWnd->hmemTaskQ != hQ)
107 /* Not for the current task */
108 if (queue) QUEUE_ClearWakeBit( queue, QS_MOUSE );
109 /* Wake up the other task */
110 queue = (MESSAGEQUEUE *)GlobalLock16( pWnd->hmemTaskQ );
111 if (queue) QUEUE_SetWakeBit( queue, QS_MOUSE );
112 return SYSQ_MSG_ABANDON;
115 /* check if hWnd is within hWndScope */
117 if( hWndScope && hWnd != hWndScope )
118 if( !IsChild16(hWndScope, hWnd) ) return SYSQ_MSG_CONTINUE;
120 if( mouseClick )
122 /* translate double clicks -
123 * note that ...MOUSEMOVEs can slip in between
124 * ...BUTTONDOWN and ...BUTTONDBLCLK messages */
126 if( pWnd->class->style & CS_DBLCLKS || ht != HTCLIENT )
128 if ((message == clk_message) && (hWnd == clk_hwnd) &&
129 (msg->time - dblclk_time_limit < doubleClickSpeed) &&
130 (abs(msg->pt.x - clk_pos.x) < SYSMETRICS_CXDOUBLECLK/2) &&
131 (abs(msg->pt.y - clk_pos.y) < SYSMETRICS_CYDOUBLECLK/2))
133 message += (WM_LBUTTONDBLCLK - WM_LBUTTONDOWN);
134 mouseClick++; /* == 2 */
138 screen_pt = pt = msg->pt;
140 if (hittest != HTCLIENT)
142 message += ((INT16)WM_NCMOUSEMOVE - WM_MOUSEMOVE);
143 msg->wParam = hittest;
145 else ScreenToClient16( hWnd, &pt );
147 /* check message filter */
149 if (!MSG_CheckFilter(message, filter)) return SYSQ_MSG_CONTINUE;
151 pCursorQueue = queue;
153 /* call WH_MOUSE */
155 if (HOOK_IsHooked( WH_MOUSE ))
157 MOUSEHOOKSTRUCT16 *hook = SEGPTR_NEW(MOUSEHOOKSTRUCT16);
158 if( hook )
160 hook->pt = screen_pt;
161 hook->hwnd = hWnd;
162 hook->wHitTestCode = hittest;
163 hook->dwExtraInfo = 0;
164 ret = HOOK_CallHooks16( WH_MOUSE, remove ? HC_ACTION : HC_NOREMOVE,
165 message, (LPARAM)SEGPTR_GET(hook) );
166 SEGPTR_FREE(hook);
168 if( ret ) return MAKELONG((INT16)SYSQ_MSG_SKIP, hittest);
171 if ((hittest == HTERROR) || (hittest == HTNOWHERE))
172 eatMsg = sendSC = 1;
173 else if( remove && mouseClick )
175 HWND hwndTop = WIN_GetTopParent( hWnd );
177 if( mouseClick == 1 )
179 /* set conditions */
180 dblclk_time_limit = msg->time;
181 clk_message = msg->message;
182 clk_hwnd = hWnd;
183 clk_pos = screen_pt;
184 } else
185 /* got double click - zero them out */
186 dblclk_time_limit = clk_hwnd = 0;
188 if( sendSC )
190 /* Send the WM_PARENTNOTIFY,
191 * note that even for double/nonclient clicks
192 * notification message is still WM_L/M/RBUTTONDOWN.
195 WIN_SendParentNotify( hWnd, msg->message, 0,
196 MAKELPARAM( screen_pt.x, screen_pt.y ) );
198 /* Activate the window if needed */
200 if (hWnd != GetActiveWindow16() && hWnd != GetDesktopWindow16())
202 LONG ret = SendMessage16( hWnd, WM_MOUSEACTIVATE, hwndTop,
203 MAKELONG( hittest, message ) );
205 if ((ret == MA_ACTIVATEANDEAT) || (ret == MA_NOACTIVATEANDEAT))
206 eatMsg = TRUE;
208 if (((ret == MA_ACTIVATE) || (ret == MA_ACTIVATEANDEAT))
209 && hwndTop != GetActiveWindow16() )
210 if (!WINPOS_SetActiveWindow( hwndTop, TRUE , TRUE ))
211 eatMsg = TRUE;
214 } else sendSC = (remove && sendSC);
216 /* Send the WM_SETCURSOR message */
218 if (sendSC)
219 SendMessage16( hWnd, WM_SETCURSOR, (WPARAM16)hWnd,
220 MAKELONG( hittest, message ));
221 if (eatMsg) return MAKELONG( (UINT16)SYSQ_MSG_SKIP, hittest);
223 msg->hwnd = hWnd;
224 msg->message = message;
225 msg->lParam = MAKELONG( pt.x, pt.y );
226 return SYSQ_MSG_ACCEPT;
230 /***********************************************************************
231 * MSG_TranslateKbdMsg
233 * Translate an keyboard hardware event into a real message.
235 static DWORD MSG_TranslateKbdMsg( HWND16 hWndScope, DWORD filter,
236 MSG16 *msg, BOOL32 remove )
238 WORD message = msg->message;
239 HWND16 hWnd = GetFocus16();
240 WND *pWnd;
242 /* Should check Ctrl-Esc and PrintScreen here */
244 if (!hWnd)
246 /* Send the message to the active window instead, */
247 /* translating messages to their WM_SYS equivalent */
249 hWnd = GetActiveWindow16();
251 if( message < WM_SYSKEYDOWN )
252 message += WM_SYSKEYDOWN - WM_KEYDOWN;
254 pWnd = WIN_FindWndPtr( hWnd );
255 if (pWnd && (pWnd->hmemTaskQ != GetTaskQueue(0)))
257 /* Not for the current task */
258 MESSAGEQUEUE *queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(0) );
259 if (queue) QUEUE_ClearWakeBit( queue, QS_KEY );
260 /* Wake up the other task */
261 queue = (MESSAGEQUEUE *)GlobalLock16( pWnd->hmemTaskQ );
262 if (queue) QUEUE_SetWakeBit( queue, QS_KEY );
263 return SYSQ_MSG_ABANDON;
266 if (hWndScope && hWnd != hWndScope)
267 if (!IsChild16(hWndScope, hWnd)) return SYSQ_MSG_CONTINUE;
268 if (!MSG_CheckFilter(message, filter)) return SYSQ_MSG_CONTINUE;
270 msg->hwnd = hWnd;
271 msg->message = message;
273 return (HOOK_CallHooks16( WH_KEYBOARD, remove ? HC_ACTION : HC_NOREMOVE,
274 msg->wParam, msg->lParam )
275 ? SYSQ_MSG_SKIP : SYSQ_MSG_ACCEPT);
279 /***********************************************************************
280 * MSG_JournalRecordMsg
282 * Build an EVENTMSG structure and call JOURNALRECORD hook
284 static void MSG_JournalRecordMsg( MSG16 *msg )
286 EVENTMSG16 *event = SEGPTR_NEW(EVENTMSG16);
287 if (!event) return;
288 event->message = msg->message;
289 event->time = msg->time;
290 if ((msg->message >= WM_KEYFIRST) && (msg->message <= WM_KEYLAST))
292 event->paramL = (msg->wParam & 0xFF) | (HIWORD(msg->lParam) << 8);
293 event->paramH = msg->lParam & 0x7FFF;
294 if (HIWORD(msg->lParam) & 0x0100)
295 event->paramH |= 0x8000; /* special_key - bit */
296 HOOK_CallHooks16( WH_JOURNALRECORD, HC_ACTION, 0,
297 (LPARAM)SEGPTR_GET(event) );
299 else if ((msg->message >= WM_MOUSEFIRST) && (msg->message <= WM_MOUSELAST))
301 event->paramL = LOWORD(msg->lParam); /* X pos */
302 event->paramH = HIWORD(msg->lParam); /* Y pos */
303 ClientToScreen16( msg->hwnd, (LPPOINT16)&event->paramL );
304 HOOK_CallHooks16( WH_JOURNALRECORD, HC_ACTION, 0,
305 (LPARAM)SEGPTR_GET(event) );
307 else if ((msg->message >= WM_NCMOUSEFIRST) &&
308 (msg->message <= WM_NCMOUSELAST))
310 event->paramL = LOWORD(msg->lParam); /* X pos */
311 event->paramH = HIWORD(msg->lParam); /* Y pos */
312 event->message += WM_MOUSEMOVE-WM_NCMOUSEMOVE;/* give no info about NC area */
313 HOOK_CallHooks16( WH_JOURNALRECORD, HC_ACTION, 0,
314 (LPARAM)SEGPTR_GET(event) );
316 SEGPTR_FREE(event);
319 /***********************************************************************
320 * MSG_JournalPlayBackMsg
322 * Get an EVENTMSG struct via call JOURNALPLAYBACK hook function
324 static int MSG_JournalPlayBackMsg(void)
326 EVENTMSG16 *tmpMsg;
327 long wtime,lParam;
328 WORD keyDown,i,wParam,result=0;
330 if ( HOOK_IsHooked( WH_JOURNALPLAYBACK ) )
332 tmpMsg = SEGPTR_NEW(EVENTMSG16);
333 wtime=HOOK_CallHooks16( WH_JOURNALPLAYBACK, HC_GETNEXT, 0,
334 (LPARAM)SEGPTR_GET(tmpMsg));
335 /* dprintf_msg(stddeb,"Playback wait time =%ld\n",wtime); */
336 if (wtime<=0)
338 wtime=0;
339 if ((tmpMsg->message>= WM_KEYFIRST) && (tmpMsg->message <= WM_KEYLAST))
341 wParam=tmpMsg->paramL & 0xFF;
342 lParam=MAKELONG(tmpMsg->paramH&0x7ffff,tmpMsg->paramL>>8);
343 if (tmpMsg->message == WM_KEYDOWN || tmpMsg->message == WM_SYSKEYDOWN)
345 for (keyDown=i=0; i<256 && !keyDown; i++)
346 if (InputKeyStateTable[i] & 0x80)
347 keyDown++;
348 if (!keyDown)
349 lParam |= 0x40000000;
350 AsyncKeyStateTable[wParam]=InputKeyStateTable[wParam] |= 0x80;
352 else /* WM_KEYUP, WM_SYSKEYUP */
354 lParam |= 0xC0000000;
355 AsyncKeyStateTable[wParam]=InputKeyStateTable[wParam] &= ~0x80;
357 if (InputKeyStateTable[VK_MENU] & 0x80)
358 lParam |= 0x20000000;
359 if (tmpMsg->paramH & 0x8000) /*special_key bit*/
360 lParam |= 0x01000000;
361 hardware_event( tmpMsg->message, wParam, lParam,0, 0, tmpMsg->time, 0 );
363 else
365 if ((tmpMsg->message>= WM_MOUSEFIRST) && (tmpMsg->message <= WM_MOUSELAST))
367 switch (tmpMsg->message)
369 case WM_LBUTTONDOWN:MouseButtonsStates[0]=AsyncMouseButtonsStates[0]=1;break;
370 case WM_LBUTTONUP: MouseButtonsStates[0]=AsyncMouseButtonsStates[0]=0;break;
371 case WM_MBUTTONDOWN:MouseButtonsStates[1]=AsyncMouseButtonsStates[1]=1;break;
372 case WM_MBUTTONUP: MouseButtonsStates[1]=AsyncMouseButtonsStates[1]=0;break;
373 case WM_RBUTTONDOWN:MouseButtonsStates[2]=AsyncMouseButtonsStates[2]=1;break;
374 case WM_RBUTTONUP: MouseButtonsStates[2]=AsyncMouseButtonsStates[2]=0;break;
376 AsyncKeyStateTable[VK_LBUTTON]= InputKeyStateTable[VK_LBUTTON] = MouseButtonsStates[0] << 8;
377 AsyncKeyStateTable[VK_MBUTTON]= InputKeyStateTable[VK_MBUTTON] = MouseButtonsStates[1] << 8;
378 AsyncKeyStateTable[VK_RBUTTON]= InputKeyStateTable[VK_RBUTTON] = MouseButtonsStates[2] << 8;
379 SetCursorPos(tmpMsg->paramL,tmpMsg->paramH);
380 lParam=MAKELONG(tmpMsg->paramL,tmpMsg->paramH);
381 wParam=0;
382 if (MouseButtonsStates[0]) wParam |= MK_LBUTTON;
383 if (MouseButtonsStates[1]) wParam |= MK_MBUTTON;
384 if (MouseButtonsStates[2]) wParam |= MK_RBUTTON;
385 hardware_event( tmpMsg->message, wParam, lParam,
386 tmpMsg->paramL, tmpMsg->paramH, tmpMsg->time, 0 );
389 HOOK_CallHooks16( WH_JOURNALPLAYBACK, HC_SKIP, 0,
390 (LPARAM)SEGPTR_GET(tmpMsg));
392 else
394 if( tmpMsg->message == WM_QUEUESYNC )
395 if (HOOK_IsHooked( WH_CBT ))
396 HOOK_CallHooks16( WH_CBT, HCBT_QS, 0, 0L);
398 result= QS_MOUSE | QS_KEY; /* ? */
400 SEGPTR_FREE(tmpMsg);
402 return result;
405 /***********************************************************************
406 * MSG_PeekHardwareMsg
408 * Peek for a hardware message matching the hwnd and message filters.
410 static BOOL32 MSG_PeekHardwareMsg( MSG16 *msg, HWND16 hwnd, DWORD filter, BOOL32 remove )
412 DWORD status = SYSQ_MSG_ACCEPT;
413 MESSAGEQUEUE *sysMsgQueue = QUEUE_GetSysQueue();
414 int i, kbd_msg, pos = sysMsgQueue->nextMessage;
416 /* If the queue is empty, attempt to fill it */
417 if (!sysMsgQueue->msgCount && XPending(display))
418 EVENT_WaitXEvent( FALSE, FALSE );
420 for (i = kbd_msg = 0; i < sysMsgQueue->msgCount; i++, pos++)
422 if (pos >= sysMsgQueue->queueSize) pos = 0;
423 *msg = sysMsgQueue->messages[pos].msg;
425 /* Translate message */
427 if ((msg->message >= WM_MOUSEFIRST) && (msg->message <= WM_MOUSELAST))
429 status = MSG_TranslateMouseMsg(hwnd, filter, msg, remove);
430 kbd_msg = 0;
432 else if ((msg->message >= WM_KEYFIRST) && (msg->message <= WM_KEYLAST))
434 status = MSG_TranslateKbdMsg(hwnd, filter, msg, remove);
435 kbd_msg = 1;
437 else /* Non-standard hardware event */
439 HARDWAREHOOKSTRUCT16 *hook;
440 if ((hook = SEGPTR_NEW(HARDWAREHOOKSTRUCT16)))
442 BOOL32 ret;
443 hook->hWnd = msg->hwnd;
444 hook->wMessage = msg->message;
445 hook->wParam = msg->wParam;
446 hook->lParam = msg->lParam;
447 ret = HOOK_CallHooks16( WH_HARDWARE,
448 remove ? HC_ACTION : HC_NOREMOVE,
449 0, (LPARAM)SEGPTR_GET(hook) );
450 SEGPTR_FREE(hook);
451 if (ret)
453 QUEUE_RemoveMsg( sysMsgQueue, pos );
454 continue;
456 status = SYSQ_MSG_ACCEPT;
460 switch (LOWORD(status))
462 case SYSQ_MSG_ACCEPT:
463 break;
465 case SYSQ_MSG_SKIP:
466 if (HOOK_IsHooked( WH_CBT ))
467 if( kbd_msg )
468 HOOK_CallHooks16( WH_CBT, HCBT_KEYSKIPPED,
469 msg->wParam, msg->lParam );
470 else
472 MOUSEHOOKSTRUCT16 *hook = SEGPTR_NEW(MOUSEHOOKSTRUCT16);
473 if (hook)
475 hook->pt = msg->pt;
476 hook->hwnd = msg->hwnd;
477 hook->wHitTestCode = HIWORD(status);
478 hook->dwExtraInfo = 0;
479 HOOK_CallHooks16( WH_CBT, HCBT_CLICKSKIPPED ,msg->message,
480 (LPARAM)SEGPTR_GET(hook) );
481 SEGPTR_FREE(hook);
485 if (remove)
486 QUEUE_RemoveMsg( sysMsgQueue, pos );
487 /* continue */
489 case SYSQ_MSG_CONTINUE:
490 continue;
492 case SYSQ_MSG_ABANDON:
493 return FALSE;
496 if (remove)
498 if (HOOK_IsHooked( WH_JOURNALRECORD )) MSG_JournalRecordMsg( msg );
499 QUEUE_RemoveMsg( sysMsgQueue, pos );
501 return TRUE;
503 return FALSE;
507 /**********************************************************************
508 * SetDoubleClickTime (USER.20)
510 void SetDoubleClickTime( WORD interval )
512 doubleClickSpeed = interval ? interval : 500;
516 /**********************************************************************
517 * GetDoubleClickTime (USER.21)
519 WORD GetDoubleClickTime()
521 return doubleClickSpeed;
525 /***********************************************************************
526 * MSG_SendMessage
528 * Implementation of an inter-task SendMessage.
530 static LRESULT MSG_SendMessage( HQUEUE16 hDestQueue, HWND hwnd, UINT msg,
531 WPARAM16 wParam, LPARAM lParam )
533 INT32 prevSMRL = debugSMRL;
534 QSMCTRL qCtrl = { 0, 1};
535 MESSAGEQUEUE *queue, *destQ;
537 if (!(queue = (MESSAGEQUEUE*)GlobalLock16( GetTaskQueue(0) ))) return 0;
538 if (!(destQ = (MESSAGEQUEUE*)GlobalLock16( hDestQueue ))) return 0;
540 if (IsTaskLocked() || !IsWindow(hwnd)) return 0;
542 debugSMRL+=4;
543 dprintf_sendmsg(stddeb,"%*sSM: %s [%04x] (%04x -> %04x)\n",
544 prevSMRL, "", SPY_GetMsgName(msg), msg, queue->self, hDestQueue );
546 if( !(queue->wakeBits & QS_SMPARAMSFREE) )
548 dprintf_sendmsg(stddeb,"\tIntertask SendMessage: sleeping since unreplied SendMessage pending\n");
549 queue->changeBits &= ~QS_SMPARAMSFREE;
550 QUEUE_WaitBits( QS_SMPARAMSFREE );
553 /* resume sending */
555 queue->hWnd = hwnd;
556 queue->msg = msg;
557 queue->wParam = wParam;
558 queue->lParam = lParam;
559 queue->hPrevSendingTask = destQ->hSendingTask;
560 destQ->hSendingTask = GetTaskQueue(0);
562 queue->wakeBits &= ~QS_SMPARAMSFREE;
564 dprintf_sendmsg(stddeb,"%*ssm: smResultInit = %08x\n", prevSMRL, "", (unsigned)&qCtrl);
566 queue->smResultInit = &qCtrl;
568 QUEUE_SetWakeBit( destQ, QS_SENDMESSAGE );
570 /* perform task switch and wait for the result */
572 while( qCtrl.bPending )
574 if (!(queue->wakeBits & QS_SMRESULT))
576 queue->changeBits &= ~QS_SMRESULT;
577 DirectedYield( destQ->hTask );
578 QUEUE_WaitBits( QS_SMRESULT );
579 dprintf_sendmsg(stddeb,"\tsm: have result!\n");
581 /* got something */
583 dprintf_sendmsg(stddeb,"%*ssm: smResult = %08x\n", prevSMRL, "", (unsigned)queue->smResult );
585 if (queue->smResult) { /* FIXME, smResult should always be set */
586 queue->smResult->lResult = queue->SendMessageReturn;
587 queue->smResult->bPending = FALSE;
589 queue->wakeBits &= ~QS_SMRESULT;
591 if( queue->smResult != &qCtrl )
592 dprintf_msg(stddeb,"%*ssm: weird scenes inside the goldmine!\n", prevSMRL, "");
594 queue->smResultInit = NULL;
596 dprintf_sendmsg(stddeb,"%*sSM: [%04x] returning %08lx\n", prevSMRL, "", msg, qCtrl.lResult);
597 debugSMRL-=4;
599 return qCtrl.lResult;
603 /***********************************************************************
604 * ReplyMessage (USER.115)
606 void ReplyMessage( LRESULT result )
608 MESSAGEQUEUE *senderQ;
609 MESSAGEQUEUE *queue;
611 if (!(queue = (MESSAGEQUEUE*)GlobalLock16( GetTaskQueue(0) ))) return;
613 dprintf_msg(stddeb,"ReplyMessage, queue %04x\n", queue->self);
615 while( (senderQ = (MESSAGEQUEUE*)GlobalLock16( queue->InSendMessageHandle)))
617 dprintf_msg(stddeb,"\trpm: replying to %04x (%04x -> %04x)\n",
618 queue->msg, queue->self, senderQ->self);
620 if( queue->wakeBits & QS_SENDMESSAGE )
622 QUEUE_ReceiveMessage( queue );
623 continue; /* ReceiveMessage() already called us */
626 if(!(senderQ->wakeBits & QS_SMRESULT) ) break;
627 OldYield();
629 if( !senderQ ) { dprintf_msg(stddeb,"\trpm: done\n"); return; }
631 senderQ->SendMessageReturn = result;
632 dprintf_msg(stddeb,"\trpm: smResult = %08x, result = %08lx\n",
633 (unsigned)queue->smResultCurrent, result );
635 senderQ->smResult = queue->smResultCurrent;
636 queue->InSendMessageHandle = 0;
638 QUEUE_SetWakeBit( senderQ, QS_SMRESULT );
639 DirectedYield( queue->hSendingTask );
643 /***********************************************************************
644 * MSG_PeekMessage
646 static BOOL MSG_PeekMessage( LPMSG16 msg, HWND hwnd, WORD first, WORD last,
647 WORD flags, BOOL peek )
649 int pos, mask;
650 MESSAGEQUEUE *msgQueue;
651 HQUEUE16 hQueue;
653 #ifdef CONFIG_IPC
654 DDE_TestDDE(hwnd); /* do we have dde handling in the window ?*/
655 DDE_GetRemoteMessage();
656 #endif /* CONFIG_IPC */
658 mask = QS_POSTMESSAGE | QS_SENDMESSAGE; /* Always selected */
659 if (first || last)
661 /* MSWord gets stuck if we do not check for nonclient mouse messages */
663 if ((first <= WM_KEYLAST) && (last >= WM_KEYFIRST)) mask |= QS_KEY;
664 if ( ((first <= WM_MOUSELAST) && (last >= WM_MOUSEFIRST)) ||
665 ((first <= WM_NCMOUSELAST) && (last >= WM_NCMOUSEFIRST)) ) mask |= QS_MOUSE;
666 if ((first <= WM_TIMER) && (last >= WM_TIMER)) mask |= QS_TIMER;
667 if ((first <= WM_SYSTIMER) && (last >= WM_SYSTIMER)) mask |= QS_TIMER;
668 if ((first <= WM_PAINT) && (last >= WM_PAINT)) mask |= QS_PAINT;
670 else mask |= QS_MOUSE | QS_KEY | QS_TIMER | QS_PAINT;
672 if (IsTaskLocked()) flags |= PM_NOYIELD;
674 while(1)
676 hQueue = GetTaskQueue(0);
677 msgQueue = (MESSAGEQUEUE *)GlobalLock16( hQueue );
678 if (!msgQueue) return FALSE;
679 msgQueue->changeBits = 0;
681 /* First handle a message put by SendMessage() */
683 while (msgQueue->wakeBits & QS_SENDMESSAGE)
684 QUEUE_ReceiveMessage( msgQueue );
686 /* Now handle a WM_QUIT message
688 * FIXME: PostQuitMessage() should post WM_QUIT and
689 * set QS_POSTMESSAGE wakebit instead of this.
692 if (msgQueue->wPostQMsg &&
693 (!first || WM_QUIT >= first) &&
694 (!last || WM_QUIT <= last) )
696 msg->hwnd = hwnd;
697 msg->message = WM_QUIT;
698 msg->wParam = msgQueue->wExitCode;
699 msg->lParam = 0;
700 if (flags & PM_REMOVE) msgQueue->wPostQMsg = 0;
701 break;
704 /* Now find a normal message */
706 if (((msgQueue->wakeBits & mask) & QS_POSTMESSAGE) &&
707 ((pos = QUEUE_FindMsg( msgQueue, hwnd, first, last )) != -1))
709 QMSG *qmsg = &msgQueue->messages[pos];
710 *msg = qmsg->msg;
711 msgQueue->GetMessageTimeVal = msg->time;
712 msgQueue->GetMessagePosVal = *(DWORD *)&msg->pt;
713 msgQueue->GetMessageExtraInfoVal = qmsg->extraInfo;
715 if (flags & PM_REMOVE) QUEUE_RemoveMsg( msgQueue, pos );
716 break;
719 msgQueue->changeBits |= MSG_JournalPlayBackMsg();
721 /* Now find a hardware event */
723 if (((msgQueue->wakeBits & mask) & (QS_MOUSE | QS_KEY)) &&
724 MSG_PeekHardwareMsg( msg, hwnd, MAKELONG(first,last), flags & PM_REMOVE ))
726 /* Got one */
727 msgQueue->GetMessageTimeVal = msg->time;
728 msgQueue->GetMessagePosVal = *(DWORD *)&msg->pt;
729 msgQueue->GetMessageExtraInfoVal = 0; /* Always 0 for now */
730 break;
733 /* Check again for SendMessage */
735 while (msgQueue->wakeBits & QS_SENDMESSAGE)
736 QUEUE_ReceiveMessage( msgQueue );
738 /* Now find a WM_PAINT message */
740 if ((msgQueue->wakeBits & mask) & QS_PAINT)
742 WND* wndPtr;
743 msg->hwnd = WIN_FindWinToRepaint( hwnd , hQueue );
744 msg->message = WM_PAINT;
745 msg->wParam = 0;
746 msg->lParam = 0;
748 if ((wndPtr = WIN_FindWndPtr(msg->hwnd)))
750 if( wndPtr->dwStyle & WS_MINIMIZE &&
751 wndPtr->class->hIcon )
753 msg->message = WM_PAINTICON;
754 msg->wParam = 1;
757 if( !hwnd || msg->hwnd == hwnd || IsChild16(hwnd,msg->hwnd) )
759 if( wndPtr->flags & WIN_INTERNAL_PAINT && !wndPtr->hrgnUpdate)
761 wndPtr->flags &= ~WIN_INTERNAL_PAINT;
762 QUEUE_DecPaintCount( hQueue );
764 break;
769 /* Check for timer messages, but yield first */
771 if (!(flags & PM_NOYIELD))
773 UserYield();
774 while (msgQueue->wakeBits & QS_SENDMESSAGE)
775 QUEUE_ReceiveMessage( msgQueue );
777 if ((msgQueue->wakeBits & mask) & QS_TIMER)
779 if (TIMER_GetTimerMsg(msg, hwnd, hQueue, flags & PM_REMOVE)) break;
782 if (peek)
784 if (!(flags & PM_NOYIELD)) UserYield();
785 return FALSE;
787 msgQueue->wakeMask = mask;
788 QUEUE_WaitBits( mask );
791 /* We got a message */
792 if (flags & PM_REMOVE)
794 WORD message = msg->message;
796 if (message == WM_KEYDOWN || message == WM_SYSKEYDOWN)
798 BYTE *p = &QueueKeyStateTable[msg->wParam & 0xff];
800 if (!(*p & 0x80))
801 *p ^= 0x01;
802 *p |= 0x80;
804 else if (message == WM_KEYUP || message == WM_SYSKEYUP)
805 QueueKeyStateTable[msg->wParam & 0xff] &= ~0x80;
807 if (peek) return TRUE;
808 else return (msg->message != WM_QUIT);
812 /***********************************************************************
813 * MSG_InternalGetMessage
815 * GetMessage() function for internal use. Behave like GetMessage(),
816 * but also call message filters and optionally send WM_ENTERIDLE messages.
817 * 'hwnd' must be the handle of the dialog or menu window.
818 * 'code' is the message filter value (MSGF_??? codes).
820 BOOL32 MSG_InternalGetMessage( MSG16 *msg, HWND32 hwnd, HWND32 hwndOwner,
821 WPARAM32 code, WORD flags, BOOL32 sendIdle )
823 for (;;)
825 if (sendIdle)
827 if (!MSG_PeekMessage( msg, 0, 0, 0, flags, TRUE ))
829 /* No message present -> send ENTERIDLE and wait */
830 if (IsWindow(hwndOwner))
831 SendMessage16( hwndOwner, WM_ENTERIDLE,
832 code, (LPARAM)hwnd );
833 MSG_PeekMessage( msg, 0, 0, 0, flags, FALSE );
836 else /* Always wait for a message */
837 MSG_PeekMessage( msg, 0, 0, 0, flags, FALSE );
839 /* Call message filters */
841 if (HOOK_IsHooked( WH_SYSMSGFILTER ) || HOOK_IsHooked( WH_MSGFILTER ))
843 MSG16 *pmsg = SEGPTR_NEW(MSG16);
844 if (pmsg)
846 BOOL32 ret;
847 *pmsg = *msg;
848 ret = ((BOOL16)HOOK_CallHooks16( WH_SYSMSGFILTER, code, 0,
849 (LPARAM)SEGPTR_GET(pmsg) ) ||
850 (BOOL16)HOOK_CallHooks16( WH_MSGFILTER, code, 0,
851 (LPARAM)SEGPTR_GET(pmsg) ));
852 SEGPTR_FREE(pmsg);
853 if (ret)
855 /* Message filtered -> remove it from the queue */
856 /* if it's still there. */
857 if (!(flags & PM_REMOVE))
858 MSG_PeekMessage( msg, 0, 0, 0, PM_REMOVE, TRUE );
859 continue;
864 return (msg->message != WM_QUIT);
869 /***********************************************************************
870 * PeekMessage16 (USER.109)
872 BOOL16 PeekMessage16( LPMSG16 msg, HWND16 hwnd, UINT16 first,
873 UINT16 last, UINT16 flags )
875 return MSG_PeekMessage( msg, hwnd, first, last, flags, TRUE );
879 /***********************************************************************
880 * GetMessage (USER.108)
882 BOOL GetMessage( SEGPTR msg, HWND hwnd, UINT first, UINT last )
884 MSG16 *lpmsg = (MSG16 *)PTR_SEG_TO_LIN(msg);
885 MSG_PeekMessage( lpmsg,
886 hwnd, first, last, PM_REMOVE, FALSE );
888 dprintf_msg(stddeb,"message %04x, hwnd %04x, filter(%04x - %04x)\n", lpmsg->message,
889 hwnd, first, last );
890 HOOK_CallHooks16( WH_GETMESSAGE, HC_ACTION, 0, (LPARAM)msg );
891 return (lpmsg->message != WM_QUIT);
895 /***********************************************************************
896 * PostMessage (USER.110)
898 BOOL PostMessage( HWND hwnd, WORD message, WORD wParam, LONG lParam )
900 MSG16 msg;
901 WND *wndPtr;
903 msg.hwnd = hwnd;
904 msg.message = message;
905 msg.wParam = wParam;
906 msg.lParam = lParam;
907 msg.time = GetTickCount();
908 msg.pt.x = 0;
909 msg.pt.y = 0;
911 #ifdef CONFIG_IPC
912 if (DDE_PostMessage(&msg))
913 return TRUE;
914 #endif /* CONFIG_IPC */
916 if (hwnd == HWND_BROADCAST16)
918 dprintf_msg(stddeb,"PostMessage // HWND_BROADCAST !\n");
919 for (wndPtr = WIN_GetDesktop()->child; wndPtr; wndPtr = wndPtr->next)
921 if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION)
923 dprintf_msg(stddeb,"BROADCAST Message to hWnd=%04x m=%04X w=%04X l=%08lX !\n",
924 wndPtr->hwndSelf, message, wParam, lParam);
925 PostMessage( wndPtr->hwndSelf, message, wParam, lParam );
928 dprintf_msg(stddeb,"PostMessage // End of HWND_BROADCAST !\n");
929 return TRUE;
932 wndPtr = WIN_FindWndPtr( hwnd );
933 if (!wndPtr || !wndPtr->hmemTaskQ) return FALSE;
935 return QUEUE_AddMsg( wndPtr->hmemTaskQ, &msg, 0 );
938 /***********************************************************************
939 * PostAppMessage16 (USER.116)
941 BOOL16 PostAppMessage16( HTASK16 hTask, UINT16 message, WPARAM16 wParam,
942 LPARAM lParam )
944 MSG16 msg;
946 if (GetTaskQueue(hTask) == 0) return FALSE;
947 msg.hwnd = 0;
948 msg.message = message;
949 msg.wParam = wParam;
950 msg.lParam = lParam;
951 msg.time = GetTickCount();
952 msg.pt.x = 0;
953 msg.pt.y = 0;
955 return QUEUE_AddMsg( GetTaskQueue(hTask), &msg, 0 );
959 /***********************************************************************
960 * SendMessage16 (USER.111)
962 LRESULT SendMessage16( HWND16 hwnd, UINT16 msg, WPARAM16 wParam, LPARAM lParam)
964 WND * wndPtr;
965 WND **list, **ppWnd;
966 LRESULT ret;
968 #ifdef CONFIG_IPC
969 MSG16 DDE_msg = { hwnd, msg, wParam, lParam };
970 if (DDE_SendMessage(&DDE_msg)) return TRUE;
971 #endif /* CONFIG_IPC */
973 if (hwnd == HWND_BROADCAST16)
975 dprintf_msg(stddeb,"SendMessage // HWND_BROADCAST !\n");
976 list = WIN_BuildWinArray( WIN_GetDesktop() );
977 for (ppWnd = list; *ppWnd; ppWnd++)
979 wndPtr = *ppWnd;
980 if (!IsWindow(wndPtr->hwndSelf)) continue;
981 if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION)
983 dprintf_msg(stddeb,"BROADCAST Message to hWnd=%04x m=%04X w=%04lX l=%08lX !\n",
984 wndPtr->hwndSelf, msg, (DWORD)wParam, lParam);
985 SendMessage16( wndPtr->hwndSelf, msg, wParam, lParam );
988 HeapFree( SystemHeap, 0, list );
989 dprintf_msg(stddeb,"SendMessage // End of HWND_BROADCAST !\n");
990 return TRUE;
993 if (HOOK_IsHooked( WH_CALLWNDPROC ))
995 struct msgstruct
997 LPARAM lParam;
998 WPARAM16 wParam;
999 UINT16 wMsg;
1000 HWND16 hWnd;
1001 } *pmsg;
1003 if ((pmsg = SEGPTR_NEW(struct msgstruct)))
1005 pmsg->hWnd = hwnd;
1006 pmsg->wMsg = msg;
1007 pmsg->wParam = wParam;
1008 pmsg->lParam = lParam;
1009 HOOK_CallHooks16( WH_CALLWNDPROC, HC_ACTION, 1,
1010 (LPARAM)SEGPTR_GET(pmsg) );
1011 hwnd = pmsg->hWnd;
1012 msg = pmsg->wMsg;
1013 wParam = pmsg->wParam;
1014 lParam = pmsg->lParam;
1015 SEGPTR_FREE( pmsg );
1019 if (!(wndPtr = WIN_FindWndPtr( hwnd )))
1021 fprintf( stderr, "SendMessage16: invalid hwnd %04x\n", hwnd );
1022 return 0;
1024 if (QUEUE_IsDoomedQueue(wndPtr->hmemTaskQ))
1025 return 0; /* Don't send anything if the task is dying */
1026 if (wndPtr->hmemTaskQ != GetTaskQueue(0))
1027 return MSG_SendMessage( wndPtr->hmemTaskQ, hwnd, msg, wParam, lParam );
1029 SPY_EnterMessage( SPY_SENDMESSAGE16, hwnd, msg, wParam, lParam );
1030 ret = CallWindowProc16( (WNDPROC16)wndPtr->winproc,
1031 hwnd, msg, wParam, lParam );
1032 SPY_ExitMessage( SPY_RESULT_OK16, hwnd, msg, ret );
1033 return ret;
1037 /***********************************************************************
1038 * SendMessage32A (USER32.453)
1040 LRESULT SendMessage32A(HWND32 hwnd, UINT32 msg, WPARAM32 wParam, LPARAM lParam)
1042 WND * wndPtr;
1043 WND **list, **ppWnd;
1044 LRESULT ret;
1046 if (hwnd == HWND_BROADCAST32)
1048 list = WIN_BuildWinArray( WIN_GetDesktop() );
1049 for (ppWnd = list; *ppWnd; ppWnd++)
1051 wndPtr = *ppWnd;
1052 if (!IsWindow(wndPtr->hwndSelf)) continue;
1053 if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION)
1054 SendMessage32A( wndPtr->hwndSelf, msg, wParam, lParam );
1056 HeapFree( SystemHeap, 0, list );
1057 return TRUE;
1060 /* FIXME: call hooks */
1062 if (!(wndPtr = WIN_FindWndPtr( hwnd )))
1064 fprintf( stderr, "SendMessage32A: invalid hwnd %08x\n", hwnd );
1065 return 0;
1068 if (WINPROC_GetProcType( wndPtr->winproc ) == WIN_PROC_16)
1070 /* Use SendMessage16 for now to get hooks right */
1071 UINT16 msg16;
1072 WPARAM16 wParam16;
1073 if (WINPROC_MapMsg32ATo16( msg, wParam, &msg16, &wParam16, &lParam ) == -1)
1074 return 0;
1075 ret = SendMessage16( hwnd, msg16, wParam16, lParam );
1076 WINPROC_UnmapMsg32ATo16( msg, wParam16, lParam );
1077 return ret;
1080 if (QUEUE_IsDoomedQueue(wndPtr->hmemTaskQ))
1081 return 0; /* Don't send anything if the task is dying */
1083 if (wndPtr->hmemTaskQ != GetTaskQueue(0))
1085 fprintf( stderr, "SendMessage32A: intertask message not supported\n" );
1086 return 0;
1089 SPY_EnterMessage( SPY_SENDMESSAGE32, hwnd, msg, wParam, lParam );
1090 ret = CallWindowProc32A( (WNDPROC32)wndPtr->winproc,
1091 hwnd, msg, wParam, lParam );
1092 SPY_ExitMessage( SPY_RESULT_OK32, hwnd, msg, ret );
1093 return ret;
1097 /***********************************************************************
1098 * SendMessage32W (USER32.458)
1100 LRESULT SendMessage32W(HWND32 hwnd, UINT32 msg, WPARAM32 wParam, LPARAM lParam)
1102 WND * wndPtr;
1103 WND **list, **ppWnd;
1104 LRESULT ret;
1106 if (hwnd == HWND_BROADCAST32)
1108 list = WIN_BuildWinArray( WIN_GetDesktop() );
1109 for (ppWnd = list; *ppWnd; ppWnd++)
1111 wndPtr = *ppWnd;
1112 if (!IsWindow(wndPtr->hwndSelf)) continue;
1113 if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION)
1114 SendMessage32W( wndPtr->hwndSelf, msg, wParam, lParam );
1116 HeapFree( SystemHeap, 0, list );
1117 return TRUE;
1120 /* FIXME: call hooks */
1122 if (!(wndPtr = WIN_FindWndPtr( hwnd )))
1124 fprintf( stderr, "SendMessage32W: invalid hwnd %08x\n", hwnd );
1125 return 0;
1127 if (QUEUE_IsDoomedQueue(wndPtr->hmemTaskQ))
1128 return 0; /* Don't send anything if the task is dying */
1129 if (wndPtr->hmemTaskQ != GetTaskQueue(0))
1131 fprintf( stderr, "SendMessage32W: intertask message not supported\n" );
1132 return 0;
1135 SPY_EnterMessage( SPY_SENDMESSAGE32, hwnd, msg, wParam, lParam );
1136 ret = CallWindowProc32W( (WNDPROC32)wndPtr->winproc,
1137 hwnd, msg, wParam, lParam );
1138 SPY_ExitMessage( SPY_RESULT_OK32, hwnd, msg, ret );
1139 return ret;
1143 /***********************************************************************
1144 * WaitMessage (USER.112)
1146 void WaitMessage( void )
1148 QUEUE_WaitBits( QS_ALLINPUT );
1152 /***********************************************************************
1153 * TranslateMessage (USER.113)
1155 * TranlateMessage translate virtual-key messages into character-messages,
1156 * as follows :
1157 * WM_KEYDOWN/WM_KEYUP combinations produce a WM_CHAR or WM_DEADCHAR message.
1158 * ditto replacing WM_* with WM_SYS*
1159 * This produces WM_CHAR messages only for keys mapped to ASCII characters
1160 * by the keyboard driver.
1163 const struct accent_char
1165 BYTE ac_accent;
1166 BYTE ac_char;
1167 BYTE ac_result;
1168 } accent_chars[] =
1170 {'`', 'A', '\300'}, {'`', 'a', '\340'},
1171 {'\'', 'A', '\301'}, {'\'', 'a', '\341'},
1172 {'^', 'A', '\302'}, {'^', 'a', '\342'},
1173 {'~', 'A', '\303'}, {'~', 'a', '\343'},
1174 {'"', 'A', '\304'}, {'"', 'a', '\344'},
1175 {'O', 'A', '\305'}, {'o', 'a', '\345'},
1176 {'0', 'A', '\305'}, {'0', 'a', '\345'},
1177 {'A', 'A', '\305'}, {'a', 'a', '\345'},
1178 {'A', 'E', '\306'}, {'a', 'e', '\346'},
1179 {',', 'C', '\307'}, {',', 'c', '\347'},
1180 {'`', 'E', '\310'}, {'`', 'e', '\350'},
1181 {'\'', 'E', '\311'}, {'\'', 'e', '\351'},
1182 {'^', 'E', '\312'}, {'^', 'e', '\352'},
1183 {'"', 'E', '\313'}, {'"', 'e', '\353'},
1184 {'`', 'I', '\314'}, {'`', 'i', '\354'},
1185 {'\'', 'I', '\315'}, {'\'', 'i', '\355'},
1186 {'^', 'I', '\316'}, {'^', 'i', '\356'},
1187 {'"', 'I', '\317'}, {'"', 'i', '\357'},
1188 {'-', 'D', '\320'}, {'-', 'd', '\360'},
1189 {'~', 'N', '\321'}, {'~', 'n', '\361'},
1190 {'`', 'O', '\322'}, {'`', 'o', '\362'},
1191 {'\'', 'O', '\323'}, {'\'', 'o', '\363'},
1192 {'^', 'O', '\324'}, {'^', 'o', '\364'},
1193 {'~', 'O', '\325'}, {'~', 'o', '\365'},
1194 {'"', 'O', '\326'}, {'"', 'o', '\366'},
1195 {'/', 'O', '\330'}, {'/', 'o', '\370'},
1196 {'`', 'U', '\331'}, {'`', 'u', '\371'},
1197 {'\'', 'U', '\332'}, {'\'', 'u', '\372'},
1198 {'^', 'U', '\333'}, {'^', 'u', '\373'},
1199 {'"', 'U', '\334'}, {'"', 'u', '\374'},
1200 {'\'', 'Y', '\335'}, {'\'', 'y', '\375'},
1201 {'T', 'H', '\336'}, {'t', 'h', '\376'},
1202 {'s', 's', '\337'}, {'"', 'y', '\377'},
1203 {'s', 'z', '\337'}, {'i', 'j', '\377'},
1206 BOOL TranslateMessage( LPMSG16 msg )
1208 UINT message = msg->message;
1209 BYTE wparam[2];
1211 if ((debugging_msg
1212 && message != WM_MOUSEMOVE && message != WM_TIMER)
1213 || (debugging_key
1214 && message >= WM_KEYFIRST && message <= WM_KEYLAST))
1215 fprintf(stddeb, "TranslateMessage(%s, %04X, %08lX)\n",
1216 SPY_GetMsgName(msg->message), msg->wParam, msg->lParam);
1217 if ((message == WM_KEYDOWN) || (message == WM_SYSKEYDOWN))
1219 static dead_char;
1221 if (debugging_msg || debugging_key)
1222 fprintf(stddeb, "Translating key %04X, scancode %04X\n",
1223 msg->wParam, HIWORD(msg->lParam) );
1225 /* FIXME : should handle ToAscii yielding 2 */
1226 switch (ToAscii32(msg->wParam, HIWORD(msg->lParam),
1227 QueueKeyStateTable,(LPWORD)wparam, 0))
1229 case 1 :
1230 message = message == WM_KEYDOWN ? WM_CHAR : WM_SYSCHAR;
1231 /* Should dead chars handling go in ToAscii ? */
1232 if (dead_char)
1234 int i;
1236 if (wparam[0] == ' ')
1237 wparam[0] = dead_char;
1238 if (dead_char == 0xa8)
1239 dead_char = '"';
1240 else if (dead_char == 0xb4)
1241 dead_char = '\'';
1242 for (i = 0;
1243 i < sizeof(accent_chars) / sizeof(accent_chars[0]);
1244 i += 1)
1245 if (accent_chars[i].ac_accent == dead_char
1246 && accent_chars[i].ac_char == wparam[0])
1248 wparam[0] = accent_chars[i].ac_result;
1249 break;
1251 dead_char = 0;
1253 dprintf_key(stddeb, "1 -> PostMessage(%s)\n", SPY_GetMsgName(message));
1254 PostMessage( msg->hwnd, message, wparam[0], msg->lParam );
1255 return TRUE;
1256 case -1 :
1257 message = message == WM_KEYDOWN ? WM_DEADCHAR : WM_SYSDEADCHAR;
1258 dead_char = wparam[0];
1259 dprintf_key(stddeb, "-1 -> PostMessage(%s)\n", SPY_GetMsgName(message));
1260 PostMessage( msg->hwnd, message, wparam[0], msg->lParam );
1261 return TRUE;
1264 return FALSE;
1268 /***********************************************************************
1269 * DispatchMessage (USER.114)
1271 LONG DispatchMessage( const MSG16* msg )
1273 WND * wndPtr;
1274 LONG retval;
1275 int painting;
1277 /* Process timer messages */
1278 if ((msg->message == WM_TIMER) || (msg->message == WM_SYSTIMER))
1280 if (msg->lParam)
1282 /* HOOK_CallHooks16( WH_CALLWNDPROC, HC_ACTION, 0, FIXME ); */
1283 return CallWindowProc16( (WNDPROC16)msg->lParam, msg->hwnd,
1284 msg->message, msg->wParam, GetTickCount() );
1288 if (!msg->hwnd) return 0;
1289 if (!(wndPtr = WIN_FindWndPtr( msg->hwnd ))) return 0;
1290 if (!wndPtr->winproc) return 0;
1291 painting = (msg->message == WM_PAINT);
1292 if (painting) wndPtr->flags |= WIN_NEEDS_BEGINPAINT;
1293 /* HOOK_CallHooks16( WH_CALLWNDPROC, HC_ACTION, 0, FIXME ); */
1295 SPY_EnterMessage( SPY_DISPATCHMESSAGE16, msg->hwnd, msg->message,
1296 msg->wParam, msg->lParam );
1297 retval = CallWindowProc16( (WNDPROC16)wndPtr->winproc,
1298 msg->hwnd, msg->message,
1299 msg->wParam, msg->lParam );
1300 SPY_ExitMessage( SPY_RESULT_OK16, msg->hwnd, msg->message, retval );
1302 if (painting && (wndPtr = WIN_FindWndPtr( msg->hwnd )) &&
1303 (wndPtr->flags & WIN_NEEDS_BEGINPAINT) && wndPtr->hrgnUpdate)
1305 fprintf(stderr, "BeginPaint not called on WM_PAINT for hwnd %04x!\n",
1306 msg->hwnd);
1307 wndPtr->flags &= ~WIN_NEEDS_BEGINPAINT;
1308 /* Validate the update region to avoid infinite WM_PAINT loop */
1309 ValidateRect32( msg->hwnd, NULL );
1311 return retval;
1315 /***********************************************************************
1316 * RegisterWindowMessage16 (USER.118)
1318 WORD RegisterWindowMessage16( SEGPTR str )
1320 dprintf_msg(stddeb, "RegisterWindowMessage16: %08lx\n", (DWORD)str );
1321 return GlobalAddAtom16( str );
1325 /***********************************************************************
1326 * RegisterWindowMessage32A (USER32.436)
1328 WORD RegisterWindowMessage32A( LPCSTR str )
1330 dprintf_msg(stddeb, "RegisterWindowMessage32A: %s\n", str );
1331 return GlobalAddAtom32A( str );
1335 /***********************************************************************
1336 * RegisterWindowMessage32W (USER32.437)
1338 WORD RegisterWindowMessage32W( LPCWSTR str )
1340 dprintf_msg(stddeb, "RegisterWindowMessage32W: %p\n", str );
1341 return GlobalAddAtom32W( str );
1345 /***********************************************************************
1346 * GetTickCount (USER.13) (KERNEL32.299)
1348 DWORD GetTickCount(void)
1350 struct timeval t;
1351 gettimeofday( &t, NULL );
1352 return ((t.tv_sec * 1000) + (t.tv_usec / 1000)) - MSG_WineStartTicks;
1356 /***********************************************************************
1357 * GetCurrentTime (USER.15)
1359 * (effectively identical to GetTickCount)
1361 DWORD GetCurrentTime(void)
1363 return GetTickCount();
1367 /***********************************************************************
1368 * InSendMessage (USER.192)
1370 BOOL InSendMessage()
1372 MESSAGEQUEUE *queue;
1374 if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(0) )))
1375 return 0;
1376 return (BOOL)queue->InSendMessageHandle;