Release 970509
[wine/multimedia.git] / windows / message.c
blob751212ce4a01cac7a8397e55bb1be7aac04cbf80
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 "options.h"
27 #include "stddebug.h"
28 /* #define DEBUG_MSG */
29 #include "debug.h"
31 #define WM_NCMOUSEFIRST WM_NCMOUSEMOVE
32 #define WM_NCMOUSELAST WM_NCMBUTTONDBLCLK
34 typedef enum { SYSQ_MSG_ABANDON, SYSQ_MSG_SKIP,
35 SYSQ_MSG_ACCEPT, SYSQ_MSG_CONTINUE } SYSQ_STATUS;
37 extern MESSAGEQUEUE *pCursorQueue; /* queue.c */
38 extern MESSAGEQUEUE *pActiveQueue;
40 DWORD MSG_WineStartTicks; /* Ticks at Wine startup */
42 static UINT32 doubleClickSpeed = 452;
43 static INT32 debugSMRL = 0; /* intertask SendMessage() recursion level */
45 /***********************************************************************
46 * MSG_CheckFilter
48 BOOL32 MSG_CheckFilter(WORD uMsg, DWORD filter)
50 if( filter )
51 return (uMsg >= LOWORD(filter) && uMsg <= HIWORD(filter));
52 return TRUE;
55 /***********************************************************************
56 * MSG_TranslateMouseMsg
58 * Translate an mouse hardware event into a real mouse message.
59 * Return value indicates whether the translated message must be passed
60 * to the user, left in the queue, or skipped entirely (in this case
61 * HIWORD contains hit test code).
63 static DWORD MSG_TranslateMouseMsg( HWND16 hTopWnd, DWORD filter,
64 MSG16 *msg, BOOL32 remove, WND* pWndScope )
66 static DWORD dblclk_time_limit = 0;
67 static UINT16 clk_message = 0;
68 static HWND16 clk_hwnd = 0;
69 static POINT16 clk_pos = { 0, 0 };
71 WND *pWnd;
72 HWND16 hWnd;
73 INT16 ht, hittest, sendSC = 0;
74 UINT16 message = msg->message;
75 POINT16 screen_pt, pt;
76 HANDLE16 hQ = GetTaskQueue(0);
77 MESSAGEQUEUE *queue = (MESSAGEQUEUE *)GlobalLock16(hQ);
78 BOOL32 eatMsg = FALSE;
79 BOOL32 mouseClick = ((message == WM_LBUTTONDOWN) ||
80 (message == WM_RBUTTONDOWN) ||
81 (message == WM_MBUTTONDOWN))?1:0;
82 SYSQ_STATUS ret = 0;
84 /* Find the window */
86 ht = hittest = HTCLIENT;
87 hWnd = GetCapture16();
88 if( !hWnd )
90 ht = hittest = WINPOS_WindowFromPoint( pWndScope, msg->pt, &pWnd );
91 if( !pWnd ) pWnd = WIN_GetDesktop();
92 hWnd = pWnd->hwndSelf;
93 sendSC = 1;
95 else
97 pWnd = WIN_FindWndPtr(hWnd);
98 ht = EVENT_GetCaptureInfo();
101 /* stop if not the right queue */
103 if (pWnd->hmemTaskQ != hQ)
105 /* Not for the current task */
106 if (queue) QUEUE_ClearWakeBit( queue, QS_MOUSE );
107 /* Wake up the other task */
108 queue = (MESSAGEQUEUE *)GlobalLock16( pWnd->hmemTaskQ );
109 if (queue) QUEUE_SetWakeBit( queue, QS_MOUSE );
110 return SYSQ_MSG_ABANDON;
113 /* check if hWnd is within hWndScope */
115 if( hTopWnd && hWnd != hTopWnd )
116 if( !IsChild16(hTopWnd, hWnd) ) return SYSQ_MSG_CONTINUE;
118 if( mouseClick )
120 /* translate double clicks -
121 * note that ...MOUSEMOVEs can slip in between
122 * ...BUTTONDOWN and ...BUTTONDBLCLK messages */
124 if( pWnd->class->style & CS_DBLCLKS || ht != HTCLIENT )
126 if ((message == clk_message) && (hWnd == clk_hwnd) &&
127 (msg->time - dblclk_time_limit < doubleClickSpeed) &&
128 (abs(msg->pt.x - clk_pos.x) < SYSMETRICS_CXDOUBLECLK/2) &&
129 (abs(msg->pt.y - clk_pos.y) < SYSMETRICS_CYDOUBLECLK/2))
131 message += (WM_LBUTTONDBLCLK - WM_LBUTTONDOWN);
132 mouseClick++; /* == 2 */
136 screen_pt = pt = msg->pt;
138 if (hittest != HTCLIENT)
140 message += ((INT16)WM_NCMOUSEMOVE - WM_MOUSEMOVE);
141 msg->wParam = hittest;
143 else ScreenToClient16( hWnd, &pt );
145 /* check message filter */
147 if (!MSG_CheckFilter(message, filter)) return SYSQ_MSG_CONTINUE;
149 pCursorQueue = queue;
151 /* call WH_MOUSE */
153 if (HOOK_IsHooked( WH_MOUSE ))
155 MOUSEHOOKSTRUCT16 *hook = SEGPTR_NEW(MOUSEHOOKSTRUCT16);
156 if( hook )
158 hook->pt = screen_pt;
159 hook->hwnd = hWnd;
160 hook->wHitTestCode = hittest;
161 hook->dwExtraInfo = 0;
162 ret = HOOK_CallHooks16( WH_MOUSE, remove ? HC_ACTION : HC_NOREMOVE,
163 message, (LPARAM)SEGPTR_GET(hook) );
164 SEGPTR_FREE(hook);
166 if( ret ) return MAKELONG((INT16)SYSQ_MSG_SKIP, hittest);
169 if ((hittest == HTERROR) || (hittest == HTNOWHERE))
170 eatMsg = sendSC = 1;
171 else if( remove && mouseClick )
173 HWND32 hwndTop = WIN_GetTopParent( hWnd );
175 if( mouseClick == 1 )
177 /* set conditions */
178 dblclk_time_limit = msg->time;
179 clk_message = msg->message;
180 clk_hwnd = hWnd;
181 clk_pos = screen_pt;
182 } else
183 /* got double click - zero them out */
184 dblclk_time_limit = clk_hwnd = 0;
186 if( sendSC )
188 /* Send the WM_PARENTNOTIFY,
189 * note that even for double/nonclient clicks
190 * notification message is still WM_L/M/RBUTTONDOWN.
193 WIN_SendParentNotify( hWnd, msg->message, 0,
194 MAKELPARAM( screen_pt.x, screen_pt.y ) );
196 /* Activate the window if needed */
198 if (hWnd != GetActiveWindow16() && hWnd != GetDesktopWindow16())
200 LONG ret = SendMessage16( hWnd, WM_MOUSEACTIVATE, hwndTop,
201 MAKELONG( hittest, message ) );
203 if ((ret == MA_ACTIVATEANDEAT) || (ret == MA_NOACTIVATEANDEAT))
204 eatMsg = TRUE;
206 if (((ret == MA_ACTIVATE) || (ret == MA_ACTIVATEANDEAT))
207 && hwndTop != GetActiveWindow16() )
208 if (!WINPOS_SetActiveWindow( hwndTop, TRUE , TRUE ))
209 eatMsg = TRUE;
212 } else sendSC = (remove && sendSC);
214 /* Send the WM_SETCURSOR message */
216 if (sendSC)
217 SendMessage16( hWnd, WM_SETCURSOR, (WPARAM16)hWnd,
218 MAKELONG( hittest, message ));
219 if (eatMsg) return MAKELONG( (UINT16)SYSQ_MSG_SKIP, hittest);
221 msg->hwnd = hWnd;
222 msg->message = message;
223 msg->lParam = MAKELONG( pt.x, pt.y );
224 return SYSQ_MSG_ACCEPT;
228 /***********************************************************************
229 * MSG_TranslateKbdMsg
231 * Translate an keyboard hardware event into a real message.
233 static DWORD MSG_TranslateKbdMsg( HWND16 hTopWnd, DWORD filter,
234 MSG16 *msg, BOOL32 remove )
236 WORD message = msg->message;
237 HWND16 hWnd = GetFocus16();
238 WND *pWnd;
240 /* Should check Ctrl-Esc and PrintScreen here */
242 if (!hWnd)
244 /* Send the message to the active window instead, */
245 /* translating messages to their WM_SYS equivalent */
247 hWnd = GetActiveWindow16();
249 if( message < WM_SYSKEYDOWN )
250 message += WM_SYSKEYDOWN - WM_KEYDOWN;
252 pWnd = WIN_FindWndPtr( hWnd );
253 if (pWnd && (pWnd->hmemTaskQ != GetTaskQueue(0)))
255 /* Not for the current task */
256 MESSAGEQUEUE *queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(0) );
257 if (queue) QUEUE_ClearWakeBit( queue, QS_KEY );
258 /* Wake up the other task */
259 queue = (MESSAGEQUEUE *)GlobalLock16( pWnd->hmemTaskQ );
260 if (queue) QUEUE_SetWakeBit( queue, QS_KEY );
261 return SYSQ_MSG_ABANDON;
264 if (hTopWnd && hWnd != hTopWnd)
265 if (!IsChild16(hTopWnd, hWnd)) return SYSQ_MSG_CONTINUE;
266 if (!MSG_CheckFilter(message, filter)) return SYSQ_MSG_CONTINUE;
268 msg->hwnd = hWnd;
269 msg->message = message;
271 return (HOOK_CallHooks16( WH_KEYBOARD, remove ? HC_ACTION : HC_NOREMOVE,
272 msg->wParam, msg->lParam )
273 ? SYSQ_MSG_SKIP : SYSQ_MSG_ACCEPT);
277 /***********************************************************************
278 * MSG_JournalRecordMsg
280 * Build an EVENTMSG structure and call JOURNALRECORD hook
282 static void MSG_JournalRecordMsg( MSG16 *msg )
284 EVENTMSG16 *event = SEGPTR_NEW(EVENTMSG16);
285 if (!event) return;
286 event->message = msg->message;
287 event->time = msg->time;
288 if ((msg->message >= WM_KEYFIRST) && (msg->message <= WM_KEYLAST))
290 event->paramL = (msg->wParam & 0xFF) | (HIWORD(msg->lParam) << 8);
291 event->paramH = msg->lParam & 0x7FFF;
292 if (HIWORD(msg->lParam) & 0x0100)
293 event->paramH |= 0x8000; /* special_key - bit */
294 HOOK_CallHooks16( WH_JOURNALRECORD, HC_ACTION, 0,
295 (LPARAM)SEGPTR_GET(event) );
297 else if ((msg->message >= WM_MOUSEFIRST) && (msg->message <= WM_MOUSELAST))
299 event->paramL = LOWORD(msg->lParam); /* X pos */
300 event->paramH = HIWORD(msg->lParam); /* Y pos */
301 ClientToScreen16( msg->hwnd, (LPPOINT16)&event->paramL );
302 HOOK_CallHooks16( WH_JOURNALRECORD, HC_ACTION, 0,
303 (LPARAM)SEGPTR_GET(event) );
305 else if ((msg->message >= WM_NCMOUSEFIRST) &&
306 (msg->message <= WM_NCMOUSELAST))
308 event->paramL = LOWORD(msg->lParam); /* X pos */
309 event->paramH = HIWORD(msg->lParam); /* Y pos */
310 event->message += WM_MOUSEMOVE-WM_NCMOUSEMOVE;/* give no info about NC area */
311 HOOK_CallHooks16( WH_JOURNALRECORD, HC_ACTION, 0,
312 (LPARAM)SEGPTR_GET(event) );
314 SEGPTR_FREE(event);
317 /***********************************************************************
318 * MSG_JournalPlayBackMsg
320 * Get an EVENTMSG struct via call JOURNALPLAYBACK hook function
322 static int MSG_JournalPlayBackMsg(void)
324 EVENTMSG16 *tmpMsg;
325 long wtime,lParam;
326 WORD keyDown,i,wParam,result=0;
328 if ( HOOK_IsHooked( WH_JOURNALPLAYBACK ) )
330 tmpMsg = SEGPTR_NEW(EVENTMSG16);
331 wtime=HOOK_CallHooks16( WH_JOURNALPLAYBACK, HC_GETNEXT, 0,
332 (LPARAM)SEGPTR_GET(tmpMsg));
333 /* dprintf_msg(stddeb,"Playback wait time =%ld\n",wtime); */
334 if (wtime<=0)
336 wtime=0;
337 if ((tmpMsg->message>= WM_KEYFIRST) && (tmpMsg->message <= WM_KEYLAST))
339 wParam=tmpMsg->paramL & 0xFF;
340 lParam=MAKELONG(tmpMsg->paramH&0x7ffff,tmpMsg->paramL>>8);
341 if (tmpMsg->message == WM_KEYDOWN || tmpMsg->message == WM_SYSKEYDOWN)
343 for (keyDown=i=0; i<256 && !keyDown; i++)
344 if (InputKeyStateTable[i] & 0x80)
345 keyDown++;
346 if (!keyDown)
347 lParam |= 0x40000000;
348 AsyncKeyStateTable[wParam]=InputKeyStateTable[wParam] |= 0x80;
350 else /* WM_KEYUP, WM_SYSKEYUP */
352 lParam |= 0xC0000000;
353 AsyncKeyStateTable[wParam]=InputKeyStateTable[wParam] &= ~0x80;
355 if (InputKeyStateTable[VK_MENU] & 0x80)
356 lParam |= 0x20000000;
357 if (tmpMsg->paramH & 0x8000) /*special_key bit*/
358 lParam |= 0x01000000;
359 hardware_event( tmpMsg->message, wParam, lParam,0, 0, tmpMsg->time, 0 );
361 else
363 if ((tmpMsg->message>= WM_MOUSEFIRST) && (tmpMsg->message <= WM_MOUSELAST))
365 switch (tmpMsg->message)
367 case WM_LBUTTONDOWN:MouseButtonsStates[0]=AsyncMouseButtonsStates[0]=1;break;
368 case WM_LBUTTONUP: MouseButtonsStates[0]=AsyncMouseButtonsStates[0]=0;break;
369 case WM_MBUTTONDOWN:MouseButtonsStates[1]=AsyncMouseButtonsStates[1]=1;break;
370 case WM_MBUTTONUP: MouseButtonsStates[1]=AsyncMouseButtonsStates[1]=0;break;
371 case WM_RBUTTONDOWN:MouseButtonsStates[2]=AsyncMouseButtonsStates[2]=1;break;
372 case WM_RBUTTONUP: MouseButtonsStates[2]=AsyncMouseButtonsStates[2]=0;break;
374 AsyncKeyStateTable[VK_LBUTTON]= InputKeyStateTable[VK_LBUTTON] = MouseButtonsStates[0] << 8;
375 AsyncKeyStateTable[VK_MBUTTON]= InputKeyStateTable[VK_MBUTTON] = MouseButtonsStates[1] << 8;
376 AsyncKeyStateTable[VK_RBUTTON]= InputKeyStateTable[VK_RBUTTON] = MouseButtonsStates[2] << 8;
377 SetCursorPos32(tmpMsg->paramL,tmpMsg->paramH);
378 lParam=MAKELONG(tmpMsg->paramL,tmpMsg->paramH);
379 wParam=0;
380 if (MouseButtonsStates[0]) wParam |= MK_LBUTTON;
381 if (MouseButtonsStates[1]) wParam |= MK_MBUTTON;
382 if (MouseButtonsStates[2]) wParam |= MK_RBUTTON;
383 hardware_event( tmpMsg->message, wParam, lParam,
384 tmpMsg->paramL, tmpMsg->paramH, tmpMsg->time, 0 );
387 HOOK_CallHooks16( WH_JOURNALPLAYBACK, HC_SKIP, 0,
388 (LPARAM)SEGPTR_GET(tmpMsg));
390 else
392 if( tmpMsg->message == WM_QUEUESYNC )
393 if (HOOK_IsHooked( WH_CBT ))
394 HOOK_CallHooks16( WH_CBT, HCBT_QS, 0, 0L);
396 result= QS_MOUSE | QS_KEY; /* ? */
398 SEGPTR_FREE(tmpMsg);
400 return result;
403 /***********************************************************************
404 * MSG_PeekHardwareMsg
406 * Peek for a hardware message matching the hwnd and message filters.
408 static BOOL32 MSG_PeekHardwareMsg( MSG16 *msg, HWND16 hwnd, DWORD filter,
409 BOOL32 remove )
411 DWORD status = SYSQ_MSG_ACCEPT;
412 MESSAGEQUEUE *sysMsgQueue = QUEUE_GetSysQueue();
413 int i, kbd_msg, pos = sysMsgQueue->nextMessage;
415 /* If the queue is empty, attempt to fill it */
416 if (!sysMsgQueue->msgCount && XPending(display))
417 EVENT_WaitXEvent( FALSE, FALSE );
419 for (i = kbd_msg = 0; i < sysMsgQueue->msgCount; i++, pos++)
421 if (pos >= sysMsgQueue->queueSize) pos = 0;
422 *msg = sysMsgQueue->messages[pos].msg;
424 /* Translate message */
426 if ((msg->message >= WM_MOUSEFIRST) && (msg->message <= WM_MOUSELAST))
428 HWND32 hWndScope = (HWND32)sysMsgQueue->messages[pos].extraInfo;
430 status = MSG_TranslateMouseMsg(hwnd, filter, msg, remove,
431 (Options.managed && IsWindow32(hWndScope) )
432 ? WIN_FindWndPtr(hWndScope) : WIN_GetDesktop() );
433 kbd_msg = 0;
435 else if ((msg->message >= WM_KEYFIRST) && (msg->message <= WM_KEYLAST))
437 status = MSG_TranslateKbdMsg(hwnd, filter, msg, remove);
438 kbd_msg = 1;
440 else /* Non-standard hardware event */
442 HARDWAREHOOKSTRUCT16 *hook;
443 if ((hook = SEGPTR_NEW(HARDWAREHOOKSTRUCT16)))
445 BOOL32 ret;
446 hook->hWnd = msg->hwnd;
447 hook->wMessage = msg->message;
448 hook->wParam = msg->wParam;
449 hook->lParam = msg->lParam;
450 ret = HOOK_CallHooks16( WH_HARDWARE,
451 remove ? HC_ACTION : HC_NOREMOVE,
452 0, (LPARAM)SEGPTR_GET(hook) );
453 SEGPTR_FREE(hook);
454 if (ret)
456 QUEUE_RemoveMsg( sysMsgQueue, pos );
457 continue;
459 status = SYSQ_MSG_ACCEPT;
463 switch (LOWORD(status))
465 case SYSQ_MSG_ACCEPT:
466 break;
468 case SYSQ_MSG_SKIP:
469 if (HOOK_IsHooked( WH_CBT ))
470 if( kbd_msg )
471 HOOK_CallHooks16( WH_CBT, HCBT_KEYSKIPPED,
472 msg->wParam, msg->lParam );
473 else
475 MOUSEHOOKSTRUCT16 *hook = SEGPTR_NEW(MOUSEHOOKSTRUCT16);
476 if (hook)
478 hook->pt = msg->pt;
479 hook->hwnd = msg->hwnd;
480 hook->wHitTestCode = HIWORD(status);
481 hook->dwExtraInfo = 0;
482 HOOK_CallHooks16( WH_CBT, HCBT_CLICKSKIPPED ,msg->message,
483 (LPARAM)SEGPTR_GET(hook) );
484 SEGPTR_FREE(hook);
488 if (remove)
489 QUEUE_RemoveMsg( sysMsgQueue, pos );
490 /* continue */
492 case SYSQ_MSG_CONTINUE:
493 continue;
495 case SYSQ_MSG_ABANDON:
496 return FALSE;
499 if (remove)
501 if (HOOK_IsHooked( WH_JOURNALRECORD )) MSG_JournalRecordMsg( msg );
502 QUEUE_RemoveMsg( sysMsgQueue, pos );
504 return TRUE;
506 return FALSE;
510 /**********************************************************************
511 * SetDoubleClickTime16 (USER.20)
513 void SetDoubleClickTime16( UINT16 interval )
515 SetDoubleClickTime32( interval );
519 /**********************************************************************
520 * SetDoubleClickTime32 (USER32.479)
522 BOOL32 SetDoubleClickTime32( UINT32 interval )
524 doubleClickSpeed = interval ? interval : 500;
525 return TRUE;
529 /**********************************************************************
530 * GetDoubleClickTime16 (USER.21)
532 UINT16 GetDoubleClickTime16(void)
534 return doubleClickSpeed;
538 /**********************************************************************
539 * GetDoubleClickTime32 (USER32.238)
541 UINT32 GetDoubleClickTime32(void)
543 return doubleClickSpeed;
547 /***********************************************************************
548 * MSG_SendMessage
550 * Implementation of an inter-task SendMessage.
552 static LRESULT MSG_SendMessage( HQUEUE16 hDestQueue, HWND16 hwnd, UINT16 msg,
553 WPARAM16 wParam, LPARAM lParam )
555 INT32 prevSMRL = debugSMRL;
556 QSMCTRL qCtrl = { 0, 1};
557 MESSAGEQUEUE *queue, *destQ;
559 if (!(queue = (MESSAGEQUEUE*)GlobalLock16( GetTaskQueue(0) ))) return 0;
560 if (!(destQ = (MESSAGEQUEUE*)GlobalLock16( hDestQueue ))) return 0;
562 if (IsTaskLocked() || !IsWindow32(hwnd)) return 0;
564 debugSMRL+=4;
565 dprintf_sendmsg(stddeb,"%*sSM: %s [%04x] (%04x -> %04x)\n",
566 prevSMRL, "", SPY_GetMsgName(msg), msg, queue->self, hDestQueue );
568 if( !(queue->wakeBits & QS_SMPARAMSFREE) )
570 dprintf_sendmsg(stddeb,"\tIntertask SendMessage: sleeping since unreplied SendMessage pending\n");
571 queue->changeBits &= ~QS_SMPARAMSFREE;
572 QUEUE_WaitBits( QS_SMPARAMSFREE );
575 /* resume sending */
577 queue->hWnd = hwnd;
578 queue->msg = msg;
579 queue->wParam = wParam;
580 queue->lParam = lParam;
581 queue->hPrevSendingTask = destQ->hSendingTask;
582 destQ->hSendingTask = GetTaskQueue(0);
584 queue->wakeBits &= ~QS_SMPARAMSFREE;
586 dprintf_sendmsg(stddeb,"%*ssm: smResultInit = %08x\n", prevSMRL, "", (unsigned)&qCtrl);
588 queue->smResultInit = &qCtrl;
590 QUEUE_SetWakeBit( destQ, QS_SENDMESSAGE );
592 /* perform task switch and wait for the result */
594 while( qCtrl.bPending )
596 if (!(queue->wakeBits & QS_SMRESULT))
598 queue->changeBits &= ~QS_SMRESULT;
599 DirectedYield( destQ->hTask );
600 QUEUE_WaitBits( QS_SMRESULT );
601 dprintf_sendmsg(stddeb,"\tsm: have result!\n");
603 /* got something */
605 dprintf_sendmsg(stddeb,"%*ssm: smResult = %08x\n", prevSMRL, "", (unsigned)queue->smResult );
607 if (queue->smResult) { /* FIXME, smResult should always be set */
608 queue->smResult->lResult = queue->SendMessageReturn;
609 queue->smResult->bPending = FALSE;
611 queue->wakeBits &= ~QS_SMRESULT;
613 if( queue->smResult != &qCtrl )
614 dprintf_sendmsg(stddeb,"%*ssm: weird scenes inside the goldmine!\n", prevSMRL, "");
616 queue->smResultInit = NULL;
618 dprintf_sendmsg(stddeb,"%*sSM: [%04x] returning %08lx\n", prevSMRL, "", msg, qCtrl.lResult);
619 debugSMRL-=4;
621 return qCtrl.lResult;
625 /***********************************************************************
626 * ReplyMessage16 (USER.115)
628 void ReplyMessage16( LRESULT result )
630 MESSAGEQUEUE *senderQ;
631 MESSAGEQUEUE *queue;
633 if (!(queue = (MESSAGEQUEUE*)GlobalLock16( GetTaskQueue(0) ))) return;
635 dprintf_msg(stddeb,"ReplyMessage, queue %04x\n", queue->self);
637 while( (senderQ = (MESSAGEQUEUE*)GlobalLock16( queue->InSendMessageHandle)))
639 dprintf_msg(stddeb,"\trpm: replying to %04x (%04x -> %04x)\n",
640 queue->msg, queue->self, senderQ->self);
642 if( queue->wakeBits & QS_SENDMESSAGE )
644 QUEUE_ReceiveMessage( queue );
645 continue; /* ReceiveMessage() already called us */
648 if(!(senderQ->wakeBits & QS_SMRESULT) ) break;
649 OldYield();
651 if( !senderQ ) { dprintf_msg(stddeb,"\trpm: done\n"); return; }
653 senderQ->SendMessageReturn = result;
654 dprintf_msg(stddeb,"\trpm: smResult = %08x, result = %08lx\n",
655 (unsigned)queue->smResultCurrent, result );
657 senderQ->smResult = queue->smResultCurrent;
658 queue->InSendMessageHandle = 0;
660 QUEUE_SetWakeBit( senderQ, QS_SMRESULT );
661 DirectedYield( queue->hSendingTask );
665 /***********************************************************************
666 * MSG_PeekMessage
668 static BOOL32 MSG_PeekMessage( LPMSG16 msg, HWND16 hwnd, WORD first, WORD last,
669 WORD flags, BOOL32 peek )
671 int pos, mask;
672 MESSAGEQUEUE *msgQueue;
673 HQUEUE16 hQueue;
675 #ifdef CONFIG_IPC
676 DDE_TestDDE(hwnd); /* do we have dde handling in the window ?*/
677 DDE_GetRemoteMessage();
678 #endif /* CONFIG_IPC */
680 mask = QS_POSTMESSAGE | QS_SENDMESSAGE; /* Always selected */
681 if (first || last)
683 if ((first <= WM_KEYLAST) && (last >= WM_KEYFIRST)) mask |= QS_KEY;
684 if ( ((first <= WM_MOUSELAST) && (last >= WM_MOUSEFIRST)) ||
685 ((first <= WM_NCMOUSELAST) && (last >= WM_NCMOUSEFIRST)) ) mask |= QS_MOUSE;
686 if ((first <= WM_TIMER) && (last >= WM_TIMER)) mask |= QS_TIMER;
687 if ((first <= WM_SYSTIMER) && (last >= WM_SYSTIMER)) mask |= QS_TIMER;
688 if ((first <= WM_PAINT) && (last >= WM_PAINT)) mask |= QS_PAINT;
690 else mask |= QS_MOUSE | QS_KEY | QS_TIMER | QS_PAINT;
692 if (IsTaskLocked()) flags |= PM_NOYIELD;
694 while(1)
696 hQueue = GetTaskQueue(0);
697 msgQueue = (MESSAGEQUEUE *)GlobalLock16( hQueue );
698 if (!msgQueue) return FALSE;
699 msgQueue->changeBits = 0;
701 /* First handle a message put by SendMessage() */
703 while (msgQueue->wakeBits & QS_SENDMESSAGE)
704 QUEUE_ReceiveMessage( msgQueue );
706 /* Now handle a WM_QUIT message */
708 if (msgQueue->wPostQMsg &&
709 (!first || WM_QUIT >= first) &&
710 (!last || WM_QUIT <= last) )
712 msg->hwnd = hwnd;
713 msg->message = WM_QUIT;
714 msg->wParam = msgQueue->wExitCode;
715 msg->lParam = 0;
716 if (flags & PM_REMOVE) msgQueue->wPostQMsg = 0;
717 break;
720 /* Now find a normal message */
722 if (((msgQueue->wakeBits & mask) & QS_POSTMESSAGE) &&
723 ((pos = QUEUE_FindMsg( msgQueue, hwnd, first, last )) != -1))
725 QMSG *qmsg = &msgQueue->messages[pos];
726 *msg = qmsg->msg;
727 msgQueue->GetMessageTimeVal = msg->time;
728 msgQueue->GetMessagePosVal = *(DWORD *)&msg->pt;
729 msgQueue->GetMessageExtraInfoVal = qmsg->extraInfo;
731 if (flags & PM_REMOVE) QUEUE_RemoveMsg( msgQueue, pos );
732 break;
735 msgQueue->changeBits |= MSG_JournalPlayBackMsg();
737 /* Now find a hardware event */
739 if (((msgQueue->wakeBits & mask) & (QS_MOUSE | QS_KEY)) &&
740 MSG_PeekHardwareMsg( msg, hwnd, MAKELONG(first,last), flags & PM_REMOVE ))
742 /* Got one */
743 msgQueue->GetMessageTimeVal = msg->time;
744 msgQueue->GetMessagePosVal = *(DWORD *)&msg->pt;
745 msgQueue->GetMessageExtraInfoVal = 0; /* Always 0 for now */
746 break;
749 /* Check again for SendMessage */
751 while (msgQueue->wakeBits & QS_SENDMESSAGE)
752 QUEUE_ReceiveMessage( msgQueue );
754 /* Now find a WM_PAINT message */
756 if ((msgQueue->wakeBits & mask) & QS_PAINT)
758 WND* wndPtr;
759 msg->hwnd = WIN_FindWinToRepaint( hwnd , hQueue );
760 msg->message = WM_PAINT;
761 msg->wParam = 0;
762 msg->lParam = 0;
764 if ((wndPtr = WIN_FindWndPtr(msg->hwnd)))
766 if( wndPtr->dwStyle & WS_MINIMIZE &&
767 wndPtr->class->hIcon )
769 msg->message = WM_PAINTICON;
770 msg->wParam = 1;
773 if( !hwnd || msg->hwnd == hwnd || IsChild16(hwnd,msg->hwnd) )
775 if( wndPtr->flags & WIN_INTERNAL_PAINT && !wndPtr->hrgnUpdate)
777 wndPtr->flags &= ~WIN_INTERNAL_PAINT;
778 QUEUE_DecPaintCount( hQueue );
780 break;
785 /* Check for timer messages, but yield first */
787 if (!(flags & PM_NOYIELD))
789 UserYield();
790 while (msgQueue->wakeBits & QS_SENDMESSAGE)
791 QUEUE_ReceiveMessage( msgQueue );
793 if ((msgQueue->wakeBits & mask) & QS_TIMER)
795 if (TIMER_GetTimerMsg(msg, hwnd, hQueue, flags & PM_REMOVE)) break;
798 if (peek)
800 if (!(flags & PM_NOYIELD)) UserYield();
801 return FALSE;
803 msgQueue->wakeMask = mask;
804 QUEUE_WaitBits( mask );
807 /* We got a message */
808 if (flags & PM_REMOVE)
810 WORD message = msg->message;
812 if (message == WM_KEYDOWN || message == WM_SYSKEYDOWN)
814 BYTE *p = &QueueKeyStateTable[msg->wParam & 0xff];
816 if (!(*p & 0x80))
817 *p ^= 0x01;
818 *p |= 0x80;
820 else if (message == WM_KEYUP || message == WM_SYSKEYUP)
821 QueueKeyStateTable[msg->wParam & 0xff] &= ~0x80;
823 if (peek) return TRUE;
824 else return (msg->message != WM_QUIT);
828 /***********************************************************************
829 * MSG_InternalGetMessage
831 * GetMessage() function for internal use. Behave like GetMessage(),
832 * but also call message filters and optionally send WM_ENTERIDLE messages.
833 * 'hwnd' must be the handle of the dialog or menu window.
834 * 'code' is the message filter value (MSGF_??? codes).
836 BOOL32 MSG_InternalGetMessage( MSG16 *msg, HWND32 hwnd, HWND32 hwndOwner,
837 WPARAM32 code, WORD flags, BOOL32 sendIdle )
839 for (;;)
841 if (sendIdle)
843 if (!MSG_PeekMessage( msg, 0, 0, 0, flags, TRUE ))
845 /* No message present -> send ENTERIDLE and wait */
846 if (IsWindow32(hwndOwner))
847 SendMessage16( hwndOwner, WM_ENTERIDLE,
848 code, (LPARAM)hwnd );
849 MSG_PeekMessage( msg, 0, 0, 0, flags, FALSE );
852 else /* Always wait for a message */
853 MSG_PeekMessage( msg, 0, 0, 0, flags, FALSE );
855 /* Call message filters */
857 if (HOOK_IsHooked( WH_SYSMSGFILTER ) || HOOK_IsHooked( WH_MSGFILTER ))
859 MSG16 *pmsg = SEGPTR_NEW(MSG16);
860 if (pmsg)
862 BOOL32 ret;
863 *pmsg = *msg;
864 ret = ((BOOL16)HOOK_CallHooks16( WH_SYSMSGFILTER, code, 0,
865 (LPARAM)SEGPTR_GET(pmsg) ) ||
866 (BOOL16)HOOK_CallHooks16( WH_MSGFILTER, code, 0,
867 (LPARAM)SEGPTR_GET(pmsg) ));
868 SEGPTR_FREE(pmsg);
869 if (ret)
871 /* Message filtered -> remove it from the queue */
872 /* if it's still there. */
873 if (!(flags & PM_REMOVE))
874 MSG_PeekMessage( msg, 0, 0, 0, PM_REMOVE, TRUE );
875 continue;
880 return (msg->message != WM_QUIT);
885 /***********************************************************************
886 * PeekMessage16 (USER.109)
888 BOOL16 PeekMessage16( LPMSG16 msg, HWND16 hwnd, UINT16 first,
889 UINT16 last, UINT16 flags )
891 return MSG_PeekMessage( msg, hwnd, first, last, flags, TRUE );
895 /***********************************************************************
896 * GetMessage16 (USER.108)
898 BOOL16 GetMessage16( SEGPTR msg, HWND16 hwnd, UINT16 first, UINT16 last )
900 MSG16 *lpmsg = (MSG16 *)PTR_SEG_TO_LIN(msg);
901 MSG_PeekMessage( lpmsg,
902 hwnd, first, last, PM_REMOVE, FALSE );
904 dprintf_msg(stddeb,"message %04x, hwnd %04x, filter(%04x - %04x)\n", lpmsg->message,
905 hwnd, first, last );
906 HOOK_CallHooks16( WH_GETMESSAGE, HC_ACTION, 0, (LPARAM)msg );
907 return (lpmsg->message != WM_QUIT);
911 /***********************************************************************
912 * PostMessage16 (USER.110)
914 BOOL16 PostMessage16( HWND16 hwnd, UINT16 message, WPARAM16 wParam,
915 LPARAM lParam )
917 MSG16 msg;
918 WND *wndPtr;
920 msg.hwnd = hwnd;
921 msg.message = message;
922 msg.wParam = wParam;
923 msg.lParam = lParam;
924 msg.time = GetTickCount();
925 msg.pt.x = 0;
926 msg.pt.y = 0;
928 #ifdef CONFIG_IPC
929 if (DDE_PostMessage(&msg))
930 return TRUE;
931 #endif /* CONFIG_IPC */
933 if (hwnd == HWND_BROADCAST)
935 dprintf_msg(stddeb,"PostMessage // HWND_BROADCAST !\n");
936 for (wndPtr = WIN_GetDesktop()->child; wndPtr; wndPtr = wndPtr->next)
938 if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION)
940 dprintf_msg(stddeb,"BROADCAST Message to hWnd=%04x m=%04X w=%04X l=%08lX !\n",
941 wndPtr->hwndSelf, message, wParam, lParam);
942 PostMessage16( wndPtr->hwndSelf, message, wParam, lParam );
945 dprintf_msg(stddeb,"PostMessage // End of HWND_BROADCAST !\n");
946 return TRUE;
949 wndPtr = WIN_FindWndPtr( hwnd );
950 if (!wndPtr || !wndPtr->hmemTaskQ) return FALSE;
952 return QUEUE_AddMsg( wndPtr->hmemTaskQ, &msg, 0 );
956 /***********************************************************************
957 * PostMessage32A (USER32.418)
959 BOOL32 PostMessage32A( HWND32 hwnd, UINT32 message, WPARAM32 wParam,
960 LPARAM lParam )
962 /* FIXME */
963 return PostMessage16( hwnd, message, wParam, lParam );
967 /***********************************************************************
968 * PostMessage32W (USER32.419)
970 BOOL32 PostMessage32W( HWND32 hwnd, UINT32 message, WPARAM32 wParam,
971 LPARAM lParam )
973 /* FIXME */
974 return PostMessage16( hwnd, message, wParam, lParam );
978 /***********************************************************************
979 * PostAppMessage16 (USER.116)
981 BOOL16 PostAppMessage16( HTASK16 hTask, UINT16 message, WPARAM16 wParam,
982 LPARAM lParam )
984 MSG16 msg;
986 if (GetTaskQueue(hTask) == 0) return FALSE;
987 msg.hwnd = 0;
988 msg.message = message;
989 msg.wParam = wParam;
990 msg.lParam = lParam;
991 msg.time = GetTickCount();
992 msg.pt.x = 0;
993 msg.pt.y = 0;
995 return QUEUE_AddMsg( GetTaskQueue(hTask), &msg, 0 );
999 /***********************************************************************
1000 * SendMessage16 (USER.111)
1002 LRESULT SendMessage16( HWND16 hwnd, UINT16 msg, WPARAM16 wParam, LPARAM lParam)
1004 WND * wndPtr;
1005 WND **list, **ppWnd;
1006 LRESULT ret;
1008 #ifdef CONFIG_IPC
1009 MSG16 DDE_msg = { hwnd, msg, wParam, lParam };
1010 if (DDE_SendMessage(&DDE_msg)) return TRUE;
1011 #endif /* CONFIG_IPC */
1013 if (hwnd == HWND_BROADCAST)
1015 dprintf_msg(stddeb,"SendMessage // HWND_BROADCAST !\n");
1016 list = WIN_BuildWinArray( WIN_GetDesktop() );
1017 for (ppWnd = list; *ppWnd; ppWnd++)
1019 wndPtr = *ppWnd;
1020 if (!IsWindow32(wndPtr->hwndSelf)) continue;
1021 if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION)
1023 dprintf_msg(stddeb,"BROADCAST Message to hWnd=%04x m=%04X w=%04lX l=%08lX !\n",
1024 wndPtr->hwndSelf, msg, (DWORD)wParam, lParam);
1025 SendMessage16( wndPtr->hwndSelf, msg, wParam, lParam );
1028 HeapFree( SystemHeap, 0, list );
1029 dprintf_msg(stddeb,"SendMessage // End of HWND_BROADCAST !\n");
1030 return TRUE;
1033 if (HOOK_IsHooked( WH_CALLWNDPROC ))
1035 LPCWPSTRUCT16 pmsg;
1037 if ((pmsg = SEGPTR_NEW(CWPSTRUCT16)))
1039 pmsg->hwnd = hwnd;
1040 pmsg->message= msg;
1041 pmsg->wParam = wParam;
1042 pmsg->lParam = lParam;
1043 HOOK_CallHooks16( WH_CALLWNDPROC, HC_ACTION, 1,
1044 (LPARAM)SEGPTR_GET(pmsg) );
1045 hwnd = pmsg->hwnd;
1046 msg = pmsg->message;
1047 wParam = pmsg->wParam;
1048 lParam = pmsg->lParam;
1049 SEGPTR_FREE( pmsg );
1053 if (!(wndPtr = WIN_FindWndPtr( hwnd )))
1055 fprintf( stderr, "SendMessage16: invalid hwnd %04x\n", hwnd );
1056 return 0;
1058 if (QUEUE_IsDoomedQueue(wndPtr->hmemTaskQ))
1059 return 0; /* Don't send anything if the task is dying */
1060 if (wndPtr->hmemTaskQ != GetTaskQueue(0))
1061 return MSG_SendMessage( wndPtr->hmemTaskQ, hwnd, msg, wParam, lParam );
1063 SPY_EnterMessage( SPY_SENDMESSAGE16, hwnd, msg, wParam, lParam );
1064 ret = CallWindowProc16( (WNDPROC16)wndPtr->winproc,
1065 hwnd, msg, wParam, lParam );
1066 SPY_ExitMessage( SPY_RESULT_OK16, hwnd, msg, ret );
1067 return ret;
1070 /************************************************************************
1071 * MSG_CallWndProcHook32
1073 static void MSG_CallWndProcHook32( LPMSG32 pmsg, BOOL32 bUnicode )
1075 CWPSTRUCT32 cwp;
1077 cwp.lParam = pmsg->lParam;
1078 cwp.wParam = pmsg->wParam;
1079 cwp.message = pmsg->message;
1080 cwp.hwnd = pmsg->hwnd;
1082 if (bUnicode) HOOK_CallHooks32W(WH_CALLWNDPROC, HC_ACTION, 1, (LPARAM)&cwp);
1083 else HOOK_CallHooks32A( WH_CALLWNDPROC, HC_ACTION, 1, (LPARAM)&cwp );
1085 pmsg->lParam = cwp.lParam;
1086 pmsg->wParam = cwp.wParam;
1087 pmsg->message = cwp.message;
1088 pmsg->hwnd = cwp.hwnd;
1091 /***********************************************************************
1092 * SendMessage32A (USER32.453)
1094 LRESULT SendMessage32A(HWND32 hwnd, UINT32 msg, WPARAM32 wParam, LPARAM lParam)
1096 WND * wndPtr;
1097 WND **list, **ppWnd;
1098 LRESULT ret;
1100 if (hwnd == HWND_BROADCAST)
1102 list = WIN_BuildWinArray( WIN_GetDesktop() );
1103 for (ppWnd = list; *ppWnd; ppWnd++)
1105 wndPtr = *ppWnd;
1106 if (!IsWindow32(wndPtr->hwndSelf)) continue;
1107 if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION)
1108 SendMessage32A( wndPtr->hwndSelf, msg, wParam, lParam );
1110 HeapFree( SystemHeap, 0, list );
1111 return TRUE;
1114 if (HOOK_IsHooked( WH_CALLWNDPROC ))
1115 MSG_CallWndProcHook32( (LPMSG32)&hwnd, FALSE);
1117 if (!(wndPtr = WIN_FindWndPtr( hwnd )))
1119 fprintf( stderr, "SendMessage32A: invalid hwnd %08x\n", hwnd );
1120 return 0;
1123 if (QUEUE_IsDoomedQueue(wndPtr->hmemTaskQ))
1124 return 0; /* Don't send anything if the task is dying */
1126 if (wndPtr->hmemTaskQ != GetTaskQueue(0))
1128 fprintf( stderr, "SendMessage32A: intertask message [%04x] not supported\n", msg );
1129 return 0;
1132 SPY_EnterMessage( SPY_SENDMESSAGE32, hwnd, msg, wParam, lParam );
1133 ret = CallWindowProc32A( (WNDPROC32)wndPtr->winproc,
1134 hwnd, msg, wParam, lParam );
1135 SPY_ExitMessage( SPY_RESULT_OK32, hwnd, msg, ret );
1136 return ret;
1140 /***********************************************************************
1141 * SendMessage32W (USER32.458)
1143 LRESULT SendMessage32W(HWND32 hwnd, UINT32 msg, WPARAM32 wParam, LPARAM lParam)
1145 WND * wndPtr;
1146 WND **list, **ppWnd;
1147 LRESULT ret;
1149 if (hwnd == HWND_BROADCAST)
1151 list = WIN_BuildWinArray( WIN_GetDesktop() );
1152 for (ppWnd = list; *ppWnd; ppWnd++)
1154 wndPtr = *ppWnd;
1155 if (!IsWindow32(wndPtr->hwndSelf)) continue;
1156 if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION)
1157 SendMessage32W( wndPtr->hwndSelf, msg, wParam, lParam );
1159 HeapFree( SystemHeap, 0, list );
1160 return TRUE;
1163 if (HOOK_IsHooked( WH_CALLWNDPROC ))
1164 MSG_CallWndProcHook32( (LPMSG32)&hwnd, TRUE);
1166 if (!(wndPtr = WIN_FindWndPtr( hwnd )))
1168 fprintf( stderr, "SendMessage32W: invalid hwnd %08x\n", hwnd );
1169 return 0;
1171 if (QUEUE_IsDoomedQueue(wndPtr->hmemTaskQ))
1172 return 0; /* Don't send anything if the task is dying */
1173 if (wndPtr->hmemTaskQ != GetTaskQueue(0))
1175 fprintf( stderr, "SendMessage32W: intertask message not supported\n" );
1176 return 0;
1179 SPY_EnterMessage( SPY_SENDMESSAGE32, hwnd, msg, wParam, lParam );
1180 ret = CallWindowProc32W( (WNDPROC32)wndPtr->winproc,
1181 hwnd, msg, wParam, lParam );
1182 SPY_ExitMessage( SPY_RESULT_OK32, hwnd, msg, ret );
1183 return ret;
1187 /***********************************************************************
1188 * WaitMessage (USER.112) (USER32.577)
1190 void WaitMessage( void )
1192 QUEUE_WaitBits( QS_ALLINPUT );
1196 struct accent_char
1198 BYTE ac_accent;
1199 BYTE ac_char;
1200 BYTE ac_result;
1203 static const struct accent_char accent_chars[] =
1205 /* A good idea should be to read /usr/X11/lib/X11/locale/iso8859-x/Compose */
1206 {'`', 'A', '\300'}, {'`', 'a', '\340'},
1207 {'\'', 'A', '\301'}, {'\'', 'a', '\341'},
1208 {'^', 'A', '\302'}, {'^', 'a', '\342'},
1209 {'~', 'A', '\303'}, {'~', 'a', '\343'},
1210 {'"', 'A', '\304'}, {'"', 'a', '\344'},
1211 {'O', 'A', '\305'}, {'o', 'a', '\345'},
1212 {'0', 'A', '\305'}, {'0', 'a', '\345'},
1213 {'A', 'A', '\305'}, {'a', 'a', '\345'},
1214 {'A', 'E', '\306'}, {'a', 'e', '\346'},
1215 {',', 'C', '\307'}, {',', 'c', '\347'},
1216 {'`', 'E', '\310'}, {'`', 'e', '\350'},
1217 {'\'', 'E', '\311'}, {'\'', 'e', '\351'},
1218 {'^', 'E', '\312'}, {'^', 'e', '\352'},
1219 {'"', 'E', '\313'}, {'"', 'e', '\353'},
1220 {'`', 'I', '\314'}, {'`', 'i', '\354'},
1221 {'\'', 'I', '\315'}, {'\'', 'i', '\355'},
1222 {'^', 'I', '\316'}, {'^', 'i', '\356'},
1223 {'"', 'I', '\317'}, {'"', 'i', '\357'},
1224 {'-', 'D', '\320'}, {'-', 'd', '\360'},
1225 {'~', 'N', '\321'}, {'~', 'n', '\361'},
1226 {'`', 'O', '\322'}, {'`', 'o', '\362'},
1227 {'\'', 'O', '\323'}, {'\'', 'o', '\363'},
1228 {'^', 'O', '\324'}, {'^', 'o', '\364'},
1229 {'~', 'O', '\325'}, {'~', 'o', '\365'},
1230 {'"', 'O', '\326'}, {'"', 'o', '\366'},
1231 {'/', 'O', '\330'}, {'/', 'o', '\370'},
1232 {'`', 'U', '\331'}, {'`', 'u', '\371'},
1233 {'\'', 'U', '\332'}, {'\'', 'u', '\372'},
1234 {'^', 'U', '\333'}, {'^', 'u', '\373'},
1235 {'"', 'U', '\334'}, {'"', 'u', '\374'},
1236 {'\'', 'Y', '\335'}, {'\'', 'y', '\375'},
1237 {'T', 'H', '\336'}, {'t', 'h', '\376'},
1238 {'s', 's', '\337'}, {'"', 'y', '\377'},
1239 {'s', 'z', '\337'}, {'i', 'j', '\377'},
1240 /* iso-8859-2 uses this */
1241 {'<', 'L', '\245'}, {'<', 'l', '\265'}, /* caron */
1242 {'<', 'S', '\251'}, {'<', 's', '\271'},
1243 {'<', 'T', '\253'}, {'<', 't', '\273'},
1244 {'<', 'Z', '\256'}, {'<', 'z', '\276'},
1245 {'<', 'C', '\310'}, {'<', 'c', '\350'},
1246 {'<', 'E', '\314'}, {'<', 'e', '\354'},
1247 {'<', 'D', '\317'}, {'<', 'd', '\357'},
1248 {'<', 'N', '\322'}, {'<', 'n', '\362'},
1249 {'<', 'R', '\330'}, {'<', 'r', '\370'},
1250 {';', 'A', '\241'}, {';', 'a', '\261'}, /* ogonek */
1251 {';', 'E', '\312'}, {';', 'e', '\332'},
1252 {'\'', 'Z', '\254'}, {'\'', 'z', '\274'}, /* acute */
1253 {'\'', 'R', '\300'}, {'\'', 'r', '\340'},
1254 {'\'', 'L', '\305'}, {'\'', 'l', '\345'},
1255 {'\'', 'C', '\306'}, {'\'', 'c', '\346'},
1256 {'\'', 'N', '\321'}, {'\'', 'n', '\361'},
1257 /* collision whith S, from iso-8859-9 !!! */
1258 {',', 'S', '\252'}, {',', 's', '\272'}, /* cedilla */
1259 {',', 'T', '\336'}, {',', 't', '\376'},
1260 {'.', 'Z', '\257'}, {'.', 'z', '\277'}, /* dot above */
1261 {'/', 'L', '\243'}, {'/', 'l', '\263'}, /* slash */
1262 {'/', 'D', '\320'}, {'/', 'd', '\360'},
1263 {'(', 'A', '\303'}, {'(', 'a', '\343'}, /* breve */
1264 {'\275', 'O', '\325'}, {'\275', 'o', '\365'}, /* double acute */
1265 {'\275', 'U', '\334'}, {'\275', 'u', '\374'},
1266 {'0', 'U', '\332'}, {'0', 'u', '\372'}, /* ring above */
1267 /* iso-8859-3 uses this */
1268 {'/', 'H', '\241'}, {'/', 'h', '\261'}, /* slash */
1269 {'>', 'H', '\246'}, {'>', 'h', '\266'}, /* circumflex */
1270 {'>', 'J', '\254'}, {'>', 'j', '\274'},
1271 {'>', 'C', '\306'}, {'>', 'c', '\346'},
1272 {'>', 'G', '\330'}, {'>', 'g', '\370'},
1273 {'>', 'S', '\336'}, {'>', 's', '\376'},
1274 /* collision whith G( from iso-8859-9 !!! */
1275 {'(', 'G', '\253'}, {'(', 'g', '\273'}, /* breve */
1276 {'(', 'U', '\335'}, {'(', 'u', '\375'},
1277 /* collision whith I. from iso-8859-3 !!! */
1278 {'.', 'I', '\251'}, {'.', 'i', '\271'}, /* dot above */
1279 {'.', 'C', '\305'}, {'.', 'c', '\345'},
1280 {'.', 'G', '\325'}, {'.', 'g', '\365'},
1281 /* iso-8859-4 uses this */
1282 {',', 'R', '\243'}, {',', 'r', '\263'}, /* cedilla */
1283 {',', 'L', '\246'}, {',', 'l', '\266'},
1284 {',', 'G', '\253'}, {',', 'g', '\273'},
1285 {',', 'N', '\321'}, {',', 'n', '\361'},
1286 {',', 'K', '\323'}, {',', 'k', '\363'},
1287 {'~', 'I', '\245'}, {'~', 'i', '\265'}, /* tilde */
1288 {'-', 'E', '\252'}, {'-', 'e', '\272'}, /* macron */
1289 {'-', 'A', '\300'}, {'-', 'a', '\340'},
1290 {'-', 'I', '\317'}, {'-', 'i', '\357'},
1291 {'-', 'O', '\322'}, {'-', 'o', '\362'},
1292 {'-', 'U', '\336'}, {'-', 'u', '\376'},
1293 {'/', 'T', '\254'}, {'/', 't', '\274'}, /* slash */
1294 {'.', 'E', '\314'}, {'.', 'e', '\344'}, /* dot above */
1295 {';', 'I', '\307'}, {';', 'i', '\347'}, /* ogonek */
1296 {';', 'U', '\331'}, {';', 'u', '\371'},
1297 /* iso-8859-9 uses this */
1298 /* iso-8859-9 has really bad choosen G( S, and I. as they collide
1299 * whith the same letters on other iso-8859-x (that is they are on
1300 * different places :-( ), if you use turkish uncomment these and
1301 * comment out the lines in iso-8859-2 and iso-8859-3 sections
1302 * FIXME: should be dynamic according to chosen language
1303 * if/when Wine has turkish support.
1305 /* collision whith G( from iso-8859-3 !!! */
1306 /* {'(', 'G', '\320'}, {'(', 'g', '\360'}, */ /* breve */
1307 /* collision whith S, from iso-8859-2 !!! */
1308 /* {',', 'S', '\336'}, {',', 's', '\376'}, */ /* cedilla */
1309 /* collision whith I. from iso-8859-3 !!! */
1310 /* {'.', 'I', '\335'}, {'.', 'i', '\375'}, */ /* dot above */
1314 /***********************************************************************
1315 * MSG_DoTranslateMessage
1317 * Implementation of TranslateMessage.
1319 * TranslateMessage translates virtual-key messages into character-messages,
1320 * as follows :
1321 * WM_KEYDOWN/WM_KEYUP combinations produce a WM_CHAR or WM_DEADCHAR message.
1322 * ditto replacing WM_* with WM_SYS*
1323 * This produces WM_CHAR messages only for keys mapped to ASCII characters
1324 * by the keyboard driver.
1326 static BOOL32 MSG_DoTranslateMessage( UINT32 message, HWND32 hwnd,
1327 WPARAM32 wParam, LPARAM lParam )
1329 static int dead_char;
1330 BYTE wp[2];
1332 if ((debugging_msg && message != WM_MOUSEMOVE && message != WM_TIMER)
1333 || (debugging_key
1334 && message >= WM_KEYFIRST && message <= WM_KEYLAST))
1335 fprintf(stddeb, "TranslateMessage(%s, %04X, %08lX)\n",
1336 SPY_GetMsgName(message), wParam, lParam );
1338 if ((message != WM_KEYDOWN) && (message != WM_SYSKEYDOWN)) return FALSE;
1340 dprintf_key( stddeb, "Translating key %04X, scancode %04X\n",
1341 wParam, HIWORD(lParam) );
1343 /* FIXME : should handle ToAscii yielding 2 */
1344 switch (ToAscii32(wParam, HIWORD(lParam),
1345 QueueKeyStateTable,(LPWORD)wp, 0))
1347 case 1 :
1348 message = (message == WM_KEYDOWN) ? WM_CHAR : WM_SYSCHAR;
1349 /* Should dead chars handling go in ToAscii ? */
1350 if (dead_char)
1352 int i;
1354 if (wp[0] == ' ') wp[0] = dead_char;
1355 if (dead_char == 0xa2) dead_char = '(';
1356 else if (dead_char == 0xa8) dead_char = '"';
1357 else if (dead_char == 0xb2) dead_char = ';';
1358 else if (dead_char == 0xb4) dead_char = '\'';
1359 else if (dead_char == 0xb7) dead_char = '<';
1360 else if (dead_char == 0xb8) dead_char = ',';
1361 else if (dead_char == 0xff) dead_char = '.';
1362 for (i = 0; i < sizeof(accent_chars)/sizeof(accent_chars[0]); i++)
1363 if ((accent_chars[i].ac_accent == dead_char) &&
1364 (accent_chars[i].ac_char == wp[0]))
1366 wp[0] = accent_chars[i].ac_result;
1367 break;
1369 dead_char = 0;
1371 dprintf_key(stddeb, "1 -> PostMessage(%s)\n", SPY_GetMsgName(message));
1372 PostMessage16( hwnd, message, wp[0], lParam );
1373 return TRUE;
1375 case -1 :
1376 message = (message == WM_KEYDOWN) ? WM_DEADCHAR : WM_SYSDEADCHAR;
1377 dead_char = wp[0];
1378 dprintf_key( stddeb, "-1 -> PostMessage(%s)\n",
1379 SPY_GetMsgName(message));
1380 PostMessage16( hwnd, message, wp[0], lParam );
1381 return TRUE;
1383 return FALSE;
1387 /***********************************************************************
1388 * TranslateMessage16 (USER.113)
1390 BOOL16 TranslateMessage16( const MSG16 *msg )
1392 return MSG_DoTranslateMessage( msg->message, msg->hwnd,
1393 msg->wParam, msg->lParam );
1397 /***********************************************************************
1398 * TranslateMessage32 (USER32.555)
1400 BOOL32 TranslateMessage32( const MSG32 *msg )
1402 return MSG_DoTranslateMessage( msg->message, msg->hwnd,
1403 msg->wParam, msg->lParam );
1407 /***********************************************************************
1408 * DispatchMessage16 (USER.114)
1410 LONG DispatchMessage16( const MSG16* msg )
1412 WND * wndPtr;
1413 LONG retval;
1414 int painting;
1416 /* Process timer messages */
1417 if ((msg->message == WM_TIMER) || (msg->message == WM_SYSTIMER))
1419 if (msg->lParam)
1421 return CallWindowProc16( (WNDPROC16)msg->lParam, msg->hwnd,
1422 msg->message, msg->wParam, GetTickCount() );
1426 if (!msg->hwnd) return 0;
1427 if (!(wndPtr = WIN_FindWndPtr( msg->hwnd ))) return 0;
1428 if (!wndPtr->winproc) return 0;
1429 painting = (msg->message == WM_PAINT);
1430 if (painting) wndPtr->flags |= WIN_NEEDS_BEGINPAINT;
1432 SPY_EnterMessage( SPY_DISPATCHMESSAGE16, msg->hwnd, msg->message,
1433 msg->wParam, msg->lParam );
1434 retval = CallWindowProc16( (WNDPROC16)wndPtr->winproc,
1435 msg->hwnd, msg->message,
1436 msg->wParam, msg->lParam );
1437 SPY_ExitMessage( SPY_RESULT_OK16, msg->hwnd, msg->message, retval );
1439 if (painting && (wndPtr = WIN_FindWndPtr( msg->hwnd )) &&
1440 (wndPtr->flags & WIN_NEEDS_BEGINPAINT) && wndPtr->hrgnUpdate)
1442 fprintf(stderr, "BeginPaint not called on WM_PAINT for hwnd %04x!\n",
1443 msg->hwnd);
1444 wndPtr->flags &= ~WIN_NEEDS_BEGINPAINT;
1445 /* Validate the update region to avoid infinite WM_PAINT loop */
1446 ValidateRect32( msg->hwnd, NULL );
1448 return retval;
1452 /***********************************************************************
1453 * DispatchMessage32A (USER32.140)
1455 LONG DispatchMessage32A( const MSG32* msg )
1457 WND * wndPtr;
1458 LONG retval;
1459 int painting;
1461 /* Process timer messages */
1462 if ((msg->message == WM_TIMER) || (msg->message == WM_SYSTIMER))
1464 if (msg->lParam)
1466 /* HOOK_CallHooks32A( WH_CALLWNDPROC, HC_ACTION, 0, FIXME ); */
1467 return CallWindowProc32A( (WNDPROC32)msg->lParam, msg->hwnd,
1468 msg->message, msg->wParam, GetTickCount() );
1472 if (!msg->hwnd) return 0;
1473 if (!(wndPtr = WIN_FindWndPtr( msg->hwnd ))) return 0;
1474 if (!wndPtr->winproc) return 0;
1475 painting = (msg->message == WM_PAINT);
1476 if (painting) wndPtr->flags |= WIN_NEEDS_BEGINPAINT;
1477 /* HOOK_CallHooks32A( WH_CALLWNDPROC, HC_ACTION, 0, FIXME ); */
1479 SPY_EnterMessage( SPY_DISPATCHMESSAGE32, msg->hwnd, msg->message,
1480 msg->wParam, msg->lParam );
1481 retval = CallWindowProc32A( (WNDPROC32)wndPtr->winproc,
1482 msg->hwnd, msg->message,
1483 msg->wParam, msg->lParam );
1484 SPY_ExitMessage( SPY_RESULT_OK32, msg->hwnd, msg->message, retval );
1486 if (painting && (wndPtr = WIN_FindWndPtr( msg->hwnd )) &&
1487 (wndPtr->flags & WIN_NEEDS_BEGINPAINT) && wndPtr->hrgnUpdate)
1489 fprintf(stderr, "BeginPaint not called on WM_PAINT for hwnd %04x!\n",
1490 msg->hwnd);
1491 wndPtr->flags &= ~WIN_NEEDS_BEGINPAINT;
1492 /* Validate the update region to avoid infinite WM_PAINT loop */
1493 ValidateRect32( msg->hwnd, NULL );
1495 return retval;
1499 /***********************************************************************
1500 * DispatchMessage32W (USER32.141)
1502 LONG DispatchMessage32W( const MSG32* msg )
1504 WND * wndPtr;
1505 LONG retval;
1506 int painting;
1508 /* Process timer messages */
1509 if ((msg->message == WM_TIMER) || (msg->message == WM_SYSTIMER))
1511 if (msg->lParam)
1513 /* HOOK_CallHooks32W( WH_CALLWNDPROC, HC_ACTION, 0, FIXME ); */
1514 return CallWindowProc32W( (WNDPROC32)msg->lParam, msg->hwnd,
1515 msg->message, msg->wParam, GetTickCount() );
1519 if (!msg->hwnd) return 0;
1520 if (!(wndPtr = WIN_FindWndPtr( msg->hwnd ))) return 0;
1521 if (!wndPtr->winproc) return 0;
1522 painting = (msg->message == WM_PAINT);
1523 if (painting) wndPtr->flags |= WIN_NEEDS_BEGINPAINT;
1524 /* HOOK_CallHooks32W( WH_CALLWNDPROC, HC_ACTION, 0, FIXME ); */
1526 SPY_EnterMessage( SPY_DISPATCHMESSAGE32, msg->hwnd, msg->message,
1527 msg->wParam, msg->lParam );
1528 retval = CallWindowProc32W( (WNDPROC32)wndPtr->winproc,
1529 msg->hwnd, msg->message,
1530 msg->wParam, msg->lParam );
1531 SPY_ExitMessage( SPY_RESULT_OK32, msg->hwnd, msg->message, retval );
1533 if (painting && (wndPtr = WIN_FindWndPtr( msg->hwnd )) &&
1534 (wndPtr->flags & WIN_NEEDS_BEGINPAINT) && wndPtr->hrgnUpdate)
1536 fprintf(stderr, "BeginPaint not called on WM_PAINT for hwnd %04x!\n",
1537 msg->hwnd);
1538 wndPtr->flags &= ~WIN_NEEDS_BEGINPAINT;
1539 /* Validate the update region to avoid infinite WM_PAINT loop */
1540 ValidateRect32( msg->hwnd, NULL );
1542 return retval;
1546 /***********************************************************************
1547 * RegisterWindowMessage16 (USER.118)
1549 WORD RegisterWindowMessage16( SEGPTR str )
1551 dprintf_msg(stddeb, "RegisterWindowMessage16: %08lx\n", (DWORD)str );
1552 return GlobalAddAtom16( str );
1556 /***********************************************************************
1557 * RegisterWindowMessage32A (USER32.436)
1559 WORD RegisterWindowMessage32A( LPCSTR str )
1561 dprintf_msg(stddeb, "RegisterWindowMessage32A: %s\n", str );
1562 return GlobalAddAtom32A( str );
1566 /***********************************************************************
1567 * RegisterWindowMessage32W (USER32.437)
1569 WORD RegisterWindowMessage32W( LPCWSTR str )
1571 dprintf_msg(stddeb, "RegisterWindowMessage32W: %p\n", str );
1572 return GlobalAddAtom32W( str );
1576 /***********************************************************************
1577 * GetTickCount (USER.13) (KERNEL32.299)
1579 DWORD GetTickCount(void)
1581 struct timeval t;
1582 gettimeofday( &t, NULL );
1583 return ((t.tv_sec * 1000) + (t.tv_usec / 1000)) - MSG_WineStartTicks;
1587 /***********************************************************************
1588 * GetCurrentTime16 (USER.15)
1590 * (effectively identical to GetTickCount)
1592 DWORD GetCurrentTime16(void)
1594 return GetTickCount();
1598 /***********************************************************************
1599 * InSendMessage16 (USER.192)
1601 BOOL16 InSendMessage16(void)
1603 return InSendMessage32();
1607 /***********************************************************************
1608 * InSendMessage32 (USER32.319)
1610 BOOL32 InSendMessage32(void)
1612 MESSAGEQUEUE *queue;
1614 if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(0) )))
1615 return 0;
1616 return (BOOL32)queue->InSendMessageHandle;