Release 970329
[wine/multimedia.git] / windows / message.c
blob38deb9e5eedddceb2c3b569d29df2238ad31f782
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 typedef enum { SYSQ_MSG_ABANDON, SYSQ_MSG_SKIP,
34 SYSQ_MSG_ACCEPT, SYSQ_MSG_CONTINUE } SYSQ_STATUS;
36 extern MESSAGEQUEUE *pCursorQueue; /* queue.c */
37 extern MESSAGEQUEUE *pActiveQueue;
39 DWORD MSG_WineStartTicks; /* Ticks at Wine startup */
41 static UINT32 doubleClickSpeed = 452;
42 static INT32 debugSMRL = 0; /* intertask SendMessage() recursion level */
44 /***********************************************************************
45 * MSG_CheckFilter
47 BOOL32 MSG_CheckFilter(WORD uMsg, DWORD filter)
49 if( filter )
50 return (uMsg >= LOWORD(filter) && uMsg <= HIWORD(filter));
51 return TRUE;
54 /***********************************************************************
55 * MSG_TranslateMouseMsg
57 * Translate an mouse hardware event into a real mouse message.
58 * Return value indicates whether the translated message must be passed
59 * to the user, left in the queue, or skipped entirely (in this case
60 * HIWORD contains hit test code).
62 static DWORD MSG_TranslateMouseMsg( HWND16 hWndScope, DWORD filter,
63 MSG16 *msg, BOOL32 remove )
65 static DWORD dblclk_time_limit = 0;
66 static UINT16 clk_message = 0;
67 static HWND16 clk_hwnd = 0;
68 static POINT16 clk_pos = { 0, 0 };
70 WND *pWnd;
71 HWND16 hWnd;
72 INT16 ht, hittest, sendSC = 0;
73 UINT16 message = msg->message;
74 POINT16 screen_pt, pt;
75 HANDLE16 hQ = GetTaskQueue(0);
76 MESSAGEQUEUE *queue = (MESSAGEQUEUE *)GlobalLock16(hQ);
77 BOOL32 eatMsg = FALSE;
78 BOOL32 mouseClick = ((message == WM_LBUTTONDOWN) ||
79 (message == WM_RBUTTONDOWN) ||
80 (message == WM_MBUTTONDOWN))?1:0;
81 SYSQ_STATUS ret = 0;
83 /* Find the window */
85 ht = hittest = HTCLIENT;
86 hWnd = GetCapture16();
87 if( !hWnd )
89 sendSC = 1;
90 ht = hittest = WINPOS_WindowFromPoint( WIN_GetDesktop(), msg->pt, &pWnd );
91 if( !pWnd ) pWnd = WIN_GetDesktop();
92 hWnd = pWnd->hwndSelf;
94 else
96 pWnd = WIN_FindWndPtr(hWnd);
97 ht = EVENT_GetCaptureInfo();
100 /* stop if not the right queue */
102 if (pWnd->hmemTaskQ != hQ)
104 /* Not for the current task */
105 if (queue) QUEUE_ClearWakeBit( queue, QS_MOUSE );
106 /* Wake up the other task */
107 queue = (MESSAGEQUEUE *)GlobalLock16( pWnd->hmemTaskQ );
108 if (queue) QUEUE_SetWakeBit( queue, QS_MOUSE );
109 return SYSQ_MSG_ABANDON;
112 /* check if hWnd is within hWndScope */
114 if( hWndScope && hWnd != hWndScope )
115 if( !IsChild16(hWndScope, hWnd) ) return SYSQ_MSG_CONTINUE;
117 if( mouseClick )
119 /* translate double clicks -
120 * note that ...MOUSEMOVEs can slip in between
121 * ...BUTTONDOWN and ...BUTTONDBLCLK messages */
123 if( pWnd->class->style & CS_DBLCLKS || ht != HTCLIENT )
125 if ((message == clk_message) && (hWnd == clk_hwnd) &&
126 (msg->time - dblclk_time_limit < doubleClickSpeed) &&
127 (abs(msg->pt.x - clk_pos.x) < SYSMETRICS_CXDOUBLECLK/2) &&
128 (abs(msg->pt.y - clk_pos.y) < SYSMETRICS_CYDOUBLECLK/2))
130 message += (WM_LBUTTONDBLCLK - WM_LBUTTONDOWN);
131 mouseClick++; /* == 2 */
135 screen_pt = pt = msg->pt;
137 if (hittest != HTCLIENT)
139 message += ((INT16)WM_NCMOUSEMOVE - WM_MOUSEMOVE);
140 msg->wParam = hittest;
142 else ScreenToClient16( hWnd, &pt );
144 /* check message filter */
146 if (!MSG_CheckFilter(message, filter)) return SYSQ_MSG_CONTINUE;
148 pCursorQueue = queue;
150 /* call WH_MOUSE */
152 if (HOOK_IsHooked( WH_MOUSE ))
154 MOUSEHOOKSTRUCT16 *hook = SEGPTR_NEW(MOUSEHOOKSTRUCT16);
155 if( hook )
157 hook->pt = screen_pt;
158 hook->hwnd = hWnd;
159 hook->wHitTestCode = hittest;
160 hook->dwExtraInfo = 0;
161 ret = HOOK_CallHooks16( WH_MOUSE, remove ? HC_ACTION : HC_NOREMOVE,
162 message, (LPARAM)SEGPTR_GET(hook) );
163 SEGPTR_FREE(hook);
165 if( ret ) return MAKELONG((INT16)SYSQ_MSG_SKIP, hittest);
168 if ((hittest == HTERROR) || (hittest == HTNOWHERE))
169 eatMsg = sendSC = 1;
170 else if( remove && mouseClick )
172 HWND32 hwndTop = WIN_GetTopParent( hWnd );
174 if( mouseClick == 1 )
176 /* set conditions */
177 dblclk_time_limit = msg->time;
178 clk_message = msg->message;
179 clk_hwnd = hWnd;
180 clk_pos = screen_pt;
181 } else
182 /* got double click - zero them out */
183 dblclk_time_limit = clk_hwnd = 0;
185 if( sendSC )
187 /* Send the WM_PARENTNOTIFY,
188 * note that even for double/nonclient clicks
189 * notification message is still WM_L/M/RBUTTONDOWN.
192 WIN_SendParentNotify( hWnd, msg->message, 0,
193 MAKELPARAM( screen_pt.x, screen_pt.y ) );
195 /* Activate the window if needed */
197 if (hWnd != GetActiveWindow16() && hWnd != GetDesktopWindow16())
199 LONG ret = SendMessage16( hWnd, WM_MOUSEACTIVATE, hwndTop,
200 MAKELONG( hittest, message ) );
202 if ((ret == MA_ACTIVATEANDEAT) || (ret == MA_NOACTIVATEANDEAT))
203 eatMsg = TRUE;
205 if (((ret == MA_ACTIVATE) || (ret == MA_ACTIVATEANDEAT))
206 && hwndTop != GetActiveWindow16() )
207 if (!WINPOS_SetActiveWindow( hwndTop, TRUE , TRUE ))
208 eatMsg = TRUE;
211 } else sendSC = (remove && sendSC);
213 /* Send the WM_SETCURSOR message */
215 if (sendSC)
216 SendMessage16( hWnd, WM_SETCURSOR, (WPARAM16)hWnd,
217 MAKELONG( hittest, message ));
218 if (eatMsg) return MAKELONG( (UINT16)SYSQ_MSG_SKIP, hittest);
220 msg->hwnd = hWnd;
221 msg->message = message;
222 msg->lParam = MAKELONG( pt.x, pt.y );
223 return SYSQ_MSG_ACCEPT;
227 /***********************************************************************
228 * MSG_TranslateKbdMsg
230 * Translate an keyboard hardware event into a real message.
232 static DWORD MSG_TranslateKbdMsg( HWND16 hWndScope, DWORD filter,
233 MSG16 *msg, BOOL32 remove )
235 WORD message = msg->message;
236 HWND16 hWnd = GetFocus16();
237 WND *pWnd;
239 /* Should check Ctrl-Esc and PrintScreen here */
241 if (!hWnd)
243 /* Send the message to the active window instead, */
244 /* translating messages to their WM_SYS equivalent */
246 hWnd = GetActiveWindow16();
248 if( message < WM_SYSKEYDOWN )
249 message += WM_SYSKEYDOWN - WM_KEYDOWN;
251 pWnd = WIN_FindWndPtr( hWnd );
252 if (pWnd && (pWnd->hmemTaskQ != GetTaskQueue(0)))
254 /* Not for the current task */
255 MESSAGEQUEUE *queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(0) );
256 if (queue) QUEUE_ClearWakeBit( queue, QS_KEY );
257 /* Wake up the other task */
258 queue = (MESSAGEQUEUE *)GlobalLock16( pWnd->hmemTaskQ );
259 if (queue) QUEUE_SetWakeBit( queue, QS_KEY );
260 return SYSQ_MSG_ABANDON;
263 if (hWndScope && hWnd != hWndScope)
264 if (!IsChild16(hWndScope, hWnd)) return SYSQ_MSG_CONTINUE;
265 if (!MSG_CheckFilter(message, filter)) return SYSQ_MSG_CONTINUE;
267 msg->hwnd = hWnd;
268 msg->message = message;
270 return (HOOK_CallHooks16( WH_KEYBOARD, remove ? HC_ACTION : HC_NOREMOVE,
271 msg->wParam, msg->lParam )
272 ? SYSQ_MSG_SKIP : SYSQ_MSG_ACCEPT);
276 /***********************************************************************
277 * MSG_JournalRecordMsg
279 * Build an EVENTMSG structure and call JOURNALRECORD hook
281 static void MSG_JournalRecordMsg( MSG16 *msg )
283 EVENTMSG16 *event = SEGPTR_NEW(EVENTMSG16);
284 if (!event) return;
285 event->message = msg->message;
286 event->time = msg->time;
287 if ((msg->message >= WM_KEYFIRST) && (msg->message <= WM_KEYLAST))
289 event->paramL = (msg->wParam & 0xFF) | (HIWORD(msg->lParam) << 8);
290 event->paramH = msg->lParam & 0x7FFF;
291 if (HIWORD(msg->lParam) & 0x0100)
292 event->paramH |= 0x8000; /* special_key - bit */
293 HOOK_CallHooks16( WH_JOURNALRECORD, HC_ACTION, 0,
294 (LPARAM)SEGPTR_GET(event) );
296 else if ((msg->message >= WM_MOUSEFIRST) && (msg->message <= WM_MOUSELAST))
298 event->paramL = LOWORD(msg->lParam); /* X pos */
299 event->paramH = HIWORD(msg->lParam); /* Y pos */
300 ClientToScreen16( msg->hwnd, (LPPOINT16)&event->paramL );
301 HOOK_CallHooks16( WH_JOURNALRECORD, HC_ACTION, 0,
302 (LPARAM)SEGPTR_GET(event) );
304 else if ((msg->message >= WM_NCMOUSEFIRST) &&
305 (msg->message <= WM_NCMOUSELAST))
307 event->paramL = LOWORD(msg->lParam); /* X pos */
308 event->paramH = HIWORD(msg->lParam); /* Y pos */
309 event->message += WM_MOUSEMOVE-WM_NCMOUSEMOVE;/* give no info about NC area */
310 HOOK_CallHooks16( WH_JOURNALRECORD, HC_ACTION, 0,
311 (LPARAM)SEGPTR_GET(event) );
313 SEGPTR_FREE(event);
316 /***********************************************************************
317 * MSG_JournalPlayBackMsg
319 * Get an EVENTMSG struct via call JOURNALPLAYBACK hook function
321 static int MSG_JournalPlayBackMsg(void)
323 EVENTMSG16 *tmpMsg;
324 long wtime,lParam;
325 WORD keyDown,i,wParam,result=0;
327 if ( HOOK_IsHooked( WH_JOURNALPLAYBACK ) )
329 tmpMsg = SEGPTR_NEW(EVENTMSG16);
330 wtime=HOOK_CallHooks16( WH_JOURNALPLAYBACK, HC_GETNEXT, 0,
331 (LPARAM)SEGPTR_GET(tmpMsg));
332 /* dprintf_msg(stddeb,"Playback wait time =%ld\n",wtime); */
333 if (wtime<=0)
335 wtime=0;
336 if ((tmpMsg->message>= WM_KEYFIRST) && (tmpMsg->message <= WM_KEYLAST))
338 wParam=tmpMsg->paramL & 0xFF;
339 lParam=MAKELONG(tmpMsg->paramH&0x7ffff,tmpMsg->paramL>>8);
340 if (tmpMsg->message == WM_KEYDOWN || tmpMsg->message == WM_SYSKEYDOWN)
342 for (keyDown=i=0; i<256 && !keyDown; i++)
343 if (InputKeyStateTable[i] & 0x80)
344 keyDown++;
345 if (!keyDown)
346 lParam |= 0x40000000;
347 AsyncKeyStateTable[wParam]=InputKeyStateTable[wParam] |= 0x80;
349 else /* WM_KEYUP, WM_SYSKEYUP */
351 lParam |= 0xC0000000;
352 AsyncKeyStateTable[wParam]=InputKeyStateTable[wParam] &= ~0x80;
354 if (InputKeyStateTable[VK_MENU] & 0x80)
355 lParam |= 0x20000000;
356 if (tmpMsg->paramH & 0x8000) /*special_key bit*/
357 lParam |= 0x01000000;
358 hardware_event( tmpMsg->message, wParam, lParam,0, 0, tmpMsg->time, 0 );
360 else
362 if ((tmpMsg->message>= WM_MOUSEFIRST) && (tmpMsg->message <= WM_MOUSELAST))
364 switch (tmpMsg->message)
366 case WM_LBUTTONDOWN:MouseButtonsStates[0]=AsyncMouseButtonsStates[0]=1;break;
367 case WM_LBUTTONUP: MouseButtonsStates[0]=AsyncMouseButtonsStates[0]=0;break;
368 case WM_MBUTTONDOWN:MouseButtonsStates[1]=AsyncMouseButtonsStates[1]=1;break;
369 case WM_MBUTTONUP: MouseButtonsStates[1]=AsyncMouseButtonsStates[1]=0;break;
370 case WM_RBUTTONDOWN:MouseButtonsStates[2]=AsyncMouseButtonsStates[2]=1;break;
371 case WM_RBUTTONUP: MouseButtonsStates[2]=AsyncMouseButtonsStates[2]=0;break;
373 AsyncKeyStateTable[VK_LBUTTON]= InputKeyStateTable[VK_LBUTTON] = MouseButtonsStates[0] << 8;
374 AsyncKeyStateTable[VK_MBUTTON]= InputKeyStateTable[VK_MBUTTON] = MouseButtonsStates[1] << 8;
375 AsyncKeyStateTable[VK_RBUTTON]= InputKeyStateTable[VK_RBUTTON] = MouseButtonsStates[2] << 8;
376 SetCursorPos32(tmpMsg->paramL,tmpMsg->paramH);
377 lParam=MAKELONG(tmpMsg->paramL,tmpMsg->paramH);
378 wParam=0;
379 if (MouseButtonsStates[0]) wParam |= MK_LBUTTON;
380 if (MouseButtonsStates[1]) wParam |= MK_MBUTTON;
381 if (MouseButtonsStates[2]) wParam |= MK_RBUTTON;
382 hardware_event( tmpMsg->message, wParam, lParam,
383 tmpMsg->paramL, tmpMsg->paramH, tmpMsg->time, 0 );
386 HOOK_CallHooks16( WH_JOURNALPLAYBACK, HC_SKIP, 0,
387 (LPARAM)SEGPTR_GET(tmpMsg));
389 else
391 if( tmpMsg->message == WM_QUEUESYNC )
392 if (HOOK_IsHooked( WH_CBT ))
393 HOOK_CallHooks16( WH_CBT, HCBT_QS, 0, 0L);
395 result= QS_MOUSE | QS_KEY; /* ? */
397 SEGPTR_FREE(tmpMsg);
399 return result;
402 /***********************************************************************
403 * MSG_PeekHardwareMsg
405 * Peek for a hardware message matching the hwnd and message filters.
407 static BOOL32 MSG_PeekHardwareMsg( MSG16 *msg, HWND16 hwnd, DWORD filter,
408 BOOL32 remove )
410 DWORD status = SYSQ_MSG_ACCEPT;
411 MESSAGEQUEUE *sysMsgQueue = QUEUE_GetSysQueue();
412 int i, kbd_msg, pos = sysMsgQueue->nextMessage;
414 /* If the queue is empty, attempt to fill it */
415 if (!sysMsgQueue->msgCount && XPending(display))
416 EVENT_WaitXEvent( FALSE, FALSE );
418 for (i = kbd_msg = 0; i < sysMsgQueue->msgCount; i++, pos++)
420 if (pos >= sysMsgQueue->queueSize) pos = 0;
421 *msg = sysMsgQueue->messages[pos].msg;
423 /* Translate message */
425 if ((msg->message >= WM_MOUSEFIRST) && (msg->message <= WM_MOUSELAST))
427 status = MSG_TranslateMouseMsg(hwnd, filter, msg, remove);
428 kbd_msg = 0;
430 else if ((msg->message >= WM_KEYFIRST) && (msg->message <= WM_KEYLAST))
432 status = MSG_TranslateKbdMsg(hwnd, filter, msg, remove);
433 kbd_msg = 1;
435 else /* Non-standard hardware event */
437 HARDWAREHOOKSTRUCT16 *hook;
438 if ((hook = SEGPTR_NEW(HARDWAREHOOKSTRUCT16)))
440 BOOL32 ret;
441 hook->hWnd = msg->hwnd;
442 hook->wMessage = msg->message;
443 hook->wParam = msg->wParam;
444 hook->lParam = msg->lParam;
445 ret = HOOK_CallHooks16( WH_HARDWARE,
446 remove ? HC_ACTION : HC_NOREMOVE,
447 0, (LPARAM)SEGPTR_GET(hook) );
448 SEGPTR_FREE(hook);
449 if (ret)
451 QUEUE_RemoveMsg( sysMsgQueue, pos );
452 continue;
454 status = SYSQ_MSG_ACCEPT;
458 switch (LOWORD(status))
460 case SYSQ_MSG_ACCEPT:
461 break;
463 case SYSQ_MSG_SKIP:
464 if (HOOK_IsHooked( WH_CBT ))
465 if( kbd_msg )
466 HOOK_CallHooks16( WH_CBT, HCBT_KEYSKIPPED,
467 msg->wParam, msg->lParam );
468 else
470 MOUSEHOOKSTRUCT16 *hook = SEGPTR_NEW(MOUSEHOOKSTRUCT16);
471 if (hook)
473 hook->pt = msg->pt;
474 hook->hwnd = msg->hwnd;
475 hook->wHitTestCode = HIWORD(status);
476 hook->dwExtraInfo = 0;
477 HOOK_CallHooks16( WH_CBT, HCBT_CLICKSKIPPED ,msg->message,
478 (LPARAM)SEGPTR_GET(hook) );
479 SEGPTR_FREE(hook);
483 if (remove)
484 QUEUE_RemoveMsg( sysMsgQueue, pos );
485 /* continue */
487 case SYSQ_MSG_CONTINUE:
488 continue;
490 case SYSQ_MSG_ABANDON:
491 return FALSE;
494 if (remove)
496 if (HOOK_IsHooked( WH_JOURNALRECORD )) MSG_JournalRecordMsg( msg );
497 QUEUE_RemoveMsg( sysMsgQueue, pos );
499 return TRUE;
501 return FALSE;
505 /**********************************************************************
506 * SetDoubleClickTime16 (USER.20)
508 void SetDoubleClickTime16( UINT16 interval )
510 SetDoubleClickTime32( interval );
514 /**********************************************************************
515 * SetDoubleClickTime32 (USER32.479)
517 BOOL32 SetDoubleClickTime32( UINT32 interval )
519 doubleClickSpeed = interval ? interval : 500;
520 return TRUE;
524 /**********************************************************************
525 * GetDoubleClickTime16 (USER.21)
527 UINT16 GetDoubleClickTime16(void)
529 return doubleClickSpeed;
533 /**********************************************************************
534 * GetDoubleClickTime32 (USER32.238)
536 UINT32 GetDoubleClickTime32(void)
538 return doubleClickSpeed;
542 /***********************************************************************
543 * MSG_SendMessage
545 * Implementation of an inter-task SendMessage.
547 static LRESULT MSG_SendMessage( HQUEUE16 hDestQueue, HWND16 hwnd, UINT16 msg,
548 WPARAM16 wParam, LPARAM lParam )
550 INT32 prevSMRL = debugSMRL;
551 QSMCTRL qCtrl = { 0, 1};
552 MESSAGEQUEUE *queue, *destQ;
554 if (!(queue = (MESSAGEQUEUE*)GlobalLock16( GetTaskQueue(0) ))) return 0;
555 if (!(destQ = (MESSAGEQUEUE*)GlobalLock16( hDestQueue ))) return 0;
557 if (IsTaskLocked() || !IsWindow32(hwnd)) return 0;
559 debugSMRL+=4;
560 dprintf_sendmsg(stddeb,"%*sSM: %s [%04x] (%04x -> %04x)\n",
561 prevSMRL, "", SPY_GetMsgName(msg), msg, queue->self, hDestQueue );
563 if( !(queue->wakeBits & QS_SMPARAMSFREE) )
565 dprintf_sendmsg(stddeb,"\tIntertask SendMessage: sleeping since unreplied SendMessage pending\n");
566 queue->changeBits &= ~QS_SMPARAMSFREE;
567 QUEUE_WaitBits( QS_SMPARAMSFREE );
570 /* resume sending */
572 queue->hWnd = hwnd;
573 queue->msg = msg;
574 queue->wParam = wParam;
575 queue->lParam = lParam;
576 queue->hPrevSendingTask = destQ->hSendingTask;
577 destQ->hSendingTask = GetTaskQueue(0);
579 queue->wakeBits &= ~QS_SMPARAMSFREE;
581 dprintf_sendmsg(stddeb,"%*ssm: smResultInit = %08x\n", prevSMRL, "", (unsigned)&qCtrl);
583 queue->smResultInit = &qCtrl;
585 QUEUE_SetWakeBit( destQ, QS_SENDMESSAGE );
587 /* perform task switch and wait for the result */
589 while( qCtrl.bPending )
591 if (!(queue->wakeBits & QS_SMRESULT))
593 queue->changeBits &= ~QS_SMRESULT;
594 DirectedYield( destQ->hTask );
595 QUEUE_WaitBits( QS_SMRESULT );
596 dprintf_sendmsg(stddeb,"\tsm: have result!\n");
598 /* got something */
600 dprintf_sendmsg(stddeb,"%*ssm: smResult = %08x\n", prevSMRL, "", (unsigned)queue->smResult );
602 if (queue->smResult) { /* FIXME, smResult should always be set */
603 queue->smResult->lResult = queue->SendMessageReturn;
604 queue->smResult->bPending = FALSE;
606 queue->wakeBits &= ~QS_SMRESULT;
608 if( queue->smResult != &qCtrl )
609 dprintf_sendmsg(stddeb,"%*ssm: weird scenes inside the goldmine!\n", prevSMRL, "");
611 queue->smResultInit = NULL;
613 dprintf_sendmsg(stddeb,"%*sSM: [%04x] returning %08lx\n", prevSMRL, "", msg, qCtrl.lResult);
614 debugSMRL-=4;
616 return qCtrl.lResult;
620 /***********************************************************************
621 * ReplyMessage16 (USER.115)
623 void ReplyMessage16( LRESULT result )
625 MESSAGEQUEUE *senderQ;
626 MESSAGEQUEUE *queue;
628 if (!(queue = (MESSAGEQUEUE*)GlobalLock16( GetTaskQueue(0) ))) return;
630 dprintf_msg(stddeb,"ReplyMessage, queue %04x\n", queue->self);
632 while( (senderQ = (MESSAGEQUEUE*)GlobalLock16( queue->InSendMessageHandle)))
634 dprintf_msg(stddeb,"\trpm: replying to %04x (%04x -> %04x)\n",
635 queue->msg, queue->self, senderQ->self);
637 if( queue->wakeBits & QS_SENDMESSAGE )
639 QUEUE_ReceiveMessage( queue );
640 continue; /* ReceiveMessage() already called us */
643 if(!(senderQ->wakeBits & QS_SMRESULT) ) break;
644 OldYield();
646 if( !senderQ ) { dprintf_msg(stddeb,"\trpm: done\n"); return; }
648 senderQ->SendMessageReturn = result;
649 dprintf_msg(stddeb,"\trpm: smResult = %08x, result = %08lx\n",
650 (unsigned)queue->smResultCurrent, result );
652 senderQ->smResult = queue->smResultCurrent;
653 queue->InSendMessageHandle = 0;
655 QUEUE_SetWakeBit( senderQ, QS_SMRESULT );
656 DirectedYield( queue->hSendingTask );
660 /***********************************************************************
661 * MSG_PeekMessage
663 static BOOL32 MSG_PeekMessage( LPMSG16 msg, HWND16 hwnd, WORD first, WORD last,
664 WORD flags, BOOL32 peek )
666 int pos, mask;
667 MESSAGEQUEUE *msgQueue;
668 HQUEUE16 hQueue;
670 #ifdef CONFIG_IPC
671 DDE_TestDDE(hwnd); /* do we have dde handling in the window ?*/
672 DDE_GetRemoteMessage();
673 #endif /* CONFIG_IPC */
675 mask = QS_POSTMESSAGE | QS_SENDMESSAGE; /* Always selected */
676 if (first || last)
678 if ((first <= WM_KEYLAST) && (last >= WM_KEYFIRST)) mask |= QS_KEY;
679 if ( ((first <= WM_MOUSELAST) && (last >= WM_MOUSEFIRST)) ||
680 ((first <= WM_NCMOUSELAST) && (last >= WM_NCMOUSEFIRST)) ) mask |= QS_MOUSE;
681 if ((first <= WM_TIMER) && (last >= WM_TIMER)) mask |= QS_TIMER;
682 if ((first <= WM_SYSTIMER) && (last >= WM_SYSTIMER)) mask |= QS_TIMER;
683 if ((first <= WM_PAINT) && (last >= WM_PAINT)) mask |= QS_PAINT;
685 else mask |= QS_MOUSE | QS_KEY | QS_TIMER | QS_PAINT;
687 if (IsTaskLocked()) flags |= PM_NOYIELD;
689 while(1)
691 hQueue = GetTaskQueue(0);
692 msgQueue = (MESSAGEQUEUE *)GlobalLock16( hQueue );
693 if (!msgQueue) return FALSE;
694 msgQueue->changeBits = 0;
696 /* First handle a message put by SendMessage() */
698 while (msgQueue->wakeBits & QS_SENDMESSAGE)
699 QUEUE_ReceiveMessage( msgQueue );
701 /* Now handle a WM_QUIT message */
703 if (msgQueue->wPostQMsg &&
704 (!first || WM_QUIT >= first) &&
705 (!last || WM_QUIT <= last) )
707 msg->hwnd = hwnd;
708 msg->message = WM_QUIT;
709 msg->wParam = msgQueue->wExitCode;
710 msg->lParam = 0;
711 if (flags & PM_REMOVE) msgQueue->wPostQMsg = 0;
712 break;
715 /* Now find a normal message */
717 if (((msgQueue->wakeBits & mask) & QS_POSTMESSAGE) &&
718 ((pos = QUEUE_FindMsg( msgQueue, hwnd, first, last )) != -1))
720 QMSG *qmsg = &msgQueue->messages[pos];
721 *msg = qmsg->msg;
722 msgQueue->GetMessageTimeVal = msg->time;
723 msgQueue->GetMessagePosVal = *(DWORD *)&msg->pt;
724 msgQueue->GetMessageExtraInfoVal = qmsg->extraInfo;
726 if (flags & PM_REMOVE) QUEUE_RemoveMsg( msgQueue, pos );
727 break;
730 msgQueue->changeBits |= MSG_JournalPlayBackMsg();
732 /* Now find a hardware event */
734 if (((msgQueue->wakeBits & mask) & (QS_MOUSE | QS_KEY)) &&
735 MSG_PeekHardwareMsg( msg, hwnd, MAKELONG(first,last), flags & PM_REMOVE ))
737 /* Got one */
738 msgQueue->GetMessageTimeVal = msg->time;
739 msgQueue->GetMessagePosVal = *(DWORD *)&msg->pt;
740 msgQueue->GetMessageExtraInfoVal = 0; /* Always 0 for now */
741 break;
744 /* Check again for SendMessage */
746 while (msgQueue->wakeBits & QS_SENDMESSAGE)
747 QUEUE_ReceiveMessage( msgQueue );
749 /* Now find a WM_PAINT message */
751 if ((msgQueue->wakeBits & mask) & QS_PAINT)
753 WND* wndPtr;
754 msg->hwnd = WIN_FindWinToRepaint( hwnd , hQueue );
755 msg->message = WM_PAINT;
756 msg->wParam = 0;
757 msg->lParam = 0;
759 if ((wndPtr = WIN_FindWndPtr(msg->hwnd)))
761 if( wndPtr->dwStyle & WS_MINIMIZE &&
762 wndPtr->class->hIcon )
764 msg->message = WM_PAINTICON;
765 msg->wParam = 1;
768 if( !hwnd || msg->hwnd == hwnd || IsChild16(hwnd,msg->hwnd) )
770 if( wndPtr->flags & WIN_INTERNAL_PAINT && !wndPtr->hrgnUpdate)
772 wndPtr->flags &= ~WIN_INTERNAL_PAINT;
773 QUEUE_DecPaintCount( hQueue );
775 break;
780 /* Check for timer messages, but yield first */
782 if (!(flags & PM_NOYIELD))
784 UserYield();
785 while (msgQueue->wakeBits & QS_SENDMESSAGE)
786 QUEUE_ReceiveMessage( msgQueue );
788 if ((msgQueue->wakeBits & mask) & QS_TIMER)
790 if (TIMER_GetTimerMsg(msg, hwnd, hQueue, flags & PM_REMOVE)) break;
793 if (peek)
795 if (!(flags & PM_NOYIELD)) UserYield();
796 return FALSE;
798 msgQueue->wakeMask = mask;
799 QUEUE_WaitBits( mask );
802 /* We got a message */
803 if (flags & PM_REMOVE)
805 WORD message = msg->message;
807 if (message == WM_KEYDOWN || message == WM_SYSKEYDOWN)
809 BYTE *p = &QueueKeyStateTable[msg->wParam & 0xff];
811 if (!(*p & 0x80))
812 *p ^= 0x01;
813 *p |= 0x80;
815 else if (message == WM_KEYUP || message == WM_SYSKEYUP)
816 QueueKeyStateTable[msg->wParam & 0xff] &= ~0x80;
818 if (peek) return TRUE;
819 else return (msg->message != WM_QUIT);
823 /***********************************************************************
824 * MSG_InternalGetMessage
826 * GetMessage() function for internal use. Behave like GetMessage(),
827 * but also call message filters and optionally send WM_ENTERIDLE messages.
828 * 'hwnd' must be the handle of the dialog or menu window.
829 * 'code' is the message filter value (MSGF_??? codes).
831 BOOL32 MSG_InternalGetMessage( MSG16 *msg, HWND32 hwnd, HWND32 hwndOwner,
832 WPARAM32 code, WORD flags, BOOL32 sendIdle )
834 for (;;)
836 if (sendIdle)
838 if (!MSG_PeekMessage( msg, 0, 0, 0, flags, TRUE ))
840 /* No message present -> send ENTERIDLE and wait */
841 if (IsWindow32(hwndOwner))
842 SendMessage16( hwndOwner, WM_ENTERIDLE,
843 code, (LPARAM)hwnd );
844 MSG_PeekMessage( msg, 0, 0, 0, flags, FALSE );
847 else /* Always wait for a message */
848 MSG_PeekMessage( msg, 0, 0, 0, flags, FALSE );
850 /* Call message filters */
852 if (HOOK_IsHooked( WH_SYSMSGFILTER ) || HOOK_IsHooked( WH_MSGFILTER ))
854 MSG16 *pmsg = SEGPTR_NEW(MSG16);
855 if (pmsg)
857 BOOL32 ret;
858 *pmsg = *msg;
859 ret = ((BOOL16)HOOK_CallHooks16( WH_SYSMSGFILTER, code, 0,
860 (LPARAM)SEGPTR_GET(pmsg) ) ||
861 (BOOL16)HOOK_CallHooks16( WH_MSGFILTER, code, 0,
862 (LPARAM)SEGPTR_GET(pmsg) ));
863 SEGPTR_FREE(pmsg);
864 if (ret)
866 /* Message filtered -> remove it from the queue */
867 /* if it's still there. */
868 if (!(flags & PM_REMOVE))
869 MSG_PeekMessage( msg, 0, 0, 0, PM_REMOVE, TRUE );
870 continue;
875 return (msg->message != WM_QUIT);
880 /***********************************************************************
881 * PeekMessage16 (USER.109)
883 BOOL16 PeekMessage16( LPMSG16 msg, HWND16 hwnd, UINT16 first,
884 UINT16 last, UINT16 flags )
886 return MSG_PeekMessage( msg, hwnd, first, last, flags, TRUE );
890 /***********************************************************************
891 * GetMessage16 (USER.108)
893 BOOL16 GetMessage16( SEGPTR msg, HWND16 hwnd, UINT16 first, UINT16 last )
895 MSG16 *lpmsg = (MSG16 *)PTR_SEG_TO_LIN(msg);
896 MSG_PeekMessage( lpmsg,
897 hwnd, first, last, PM_REMOVE, FALSE );
899 dprintf_msg(stddeb,"message %04x, hwnd %04x, filter(%04x - %04x)\n", lpmsg->message,
900 hwnd, first, last );
901 HOOK_CallHooks16( WH_GETMESSAGE, HC_ACTION, 0, (LPARAM)msg );
902 return (lpmsg->message != WM_QUIT);
906 /***********************************************************************
907 * PostMessage16 (USER.110)
909 BOOL16 PostMessage16( HWND16 hwnd, UINT16 message, WPARAM16 wParam,
910 LPARAM lParam )
912 MSG16 msg;
913 WND *wndPtr;
915 msg.hwnd = hwnd;
916 msg.message = message;
917 msg.wParam = wParam;
918 msg.lParam = lParam;
919 msg.time = GetTickCount();
920 msg.pt.x = 0;
921 msg.pt.y = 0;
923 #ifdef CONFIG_IPC
924 if (DDE_PostMessage(&msg))
925 return TRUE;
926 #endif /* CONFIG_IPC */
928 if (hwnd == HWND_BROADCAST)
930 dprintf_msg(stddeb,"PostMessage // HWND_BROADCAST !\n");
931 for (wndPtr = WIN_GetDesktop()->child; wndPtr; wndPtr = wndPtr->next)
933 if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION)
935 dprintf_msg(stddeb,"BROADCAST Message to hWnd=%04x m=%04X w=%04X l=%08lX !\n",
936 wndPtr->hwndSelf, message, wParam, lParam);
937 PostMessage16( wndPtr->hwndSelf, message, wParam, lParam );
940 dprintf_msg(stddeb,"PostMessage // End of HWND_BROADCAST !\n");
941 return TRUE;
944 wndPtr = WIN_FindWndPtr( hwnd );
945 if (!wndPtr || !wndPtr->hmemTaskQ) return FALSE;
947 return QUEUE_AddMsg( wndPtr->hmemTaskQ, &msg, 0 );
951 /***********************************************************************
952 * PostMessage32A (USER32.418)
954 BOOL32 PostMessage32A( HWND32 hwnd, UINT32 message, WPARAM32 wParam,
955 LPARAM lParam )
957 /* FIXME */
958 return PostMessage16( hwnd, message, wParam, lParam );
962 /***********************************************************************
963 * PostMessage32W (USER32.419)
965 BOOL32 PostMessage32W( HWND32 hwnd, UINT32 message, WPARAM32 wParam,
966 LPARAM lParam )
968 /* FIXME */
969 return PostMessage16( hwnd, message, wParam, lParam );
973 /***********************************************************************
974 * PostAppMessage16 (USER.116)
976 BOOL16 PostAppMessage16( HTASK16 hTask, UINT16 message, WPARAM16 wParam,
977 LPARAM lParam )
979 MSG16 msg;
981 if (GetTaskQueue(hTask) == 0) return FALSE;
982 msg.hwnd = 0;
983 msg.message = message;
984 msg.wParam = wParam;
985 msg.lParam = lParam;
986 msg.time = GetTickCount();
987 msg.pt.x = 0;
988 msg.pt.y = 0;
990 return QUEUE_AddMsg( GetTaskQueue(hTask), &msg, 0 );
994 /***********************************************************************
995 * SendMessage16 (USER.111)
997 LRESULT SendMessage16( HWND16 hwnd, UINT16 msg, WPARAM16 wParam, LPARAM lParam)
999 WND * wndPtr;
1000 WND **list, **ppWnd;
1001 LRESULT ret;
1003 #ifdef CONFIG_IPC
1004 MSG16 DDE_msg = { hwnd, msg, wParam, lParam };
1005 if (DDE_SendMessage(&DDE_msg)) return TRUE;
1006 #endif /* CONFIG_IPC */
1008 if (hwnd == HWND_BROADCAST)
1010 dprintf_msg(stddeb,"SendMessage // HWND_BROADCAST !\n");
1011 list = WIN_BuildWinArray( WIN_GetDesktop() );
1012 for (ppWnd = list; *ppWnd; ppWnd++)
1014 wndPtr = *ppWnd;
1015 if (!IsWindow32(wndPtr->hwndSelf)) continue;
1016 if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION)
1018 dprintf_msg(stddeb,"BROADCAST Message to hWnd=%04x m=%04X w=%04lX l=%08lX !\n",
1019 wndPtr->hwndSelf, msg, (DWORD)wParam, lParam);
1020 SendMessage16( wndPtr->hwndSelf, msg, wParam, lParam );
1023 HeapFree( SystemHeap, 0, list );
1024 dprintf_msg(stddeb,"SendMessage // End of HWND_BROADCAST !\n");
1025 return TRUE;
1028 if (HOOK_IsHooked( WH_CALLWNDPROC ))
1030 LPCWPSTRUCT16 pmsg;
1032 if ((pmsg = SEGPTR_NEW(CWPSTRUCT16)))
1034 pmsg->hwnd = hwnd;
1035 pmsg->message= msg;
1036 pmsg->wParam = wParam;
1037 pmsg->lParam = lParam;
1038 HOOK_CallHooks16( WH_CALLWNDPROC, HC_ACTION, 1,
1039 (LPARAM)SEGPTR_GET(pmsg) );
1040 hwnd = pmsg->hwnd;
1041 msg = pmsg->message;
1042 wParam = pmsg->wParam;
1043 lParam = pmsg->lParam;
1044 SEGPTR_FREE( pmsg );
1048 if (!(wndPtr = WIN_FindWndPtr( hwnd )))
1050 fprintf( stderr, "SendMessage16: invalid hwnd %04x\n", hwnd );
1051 return 0;
1053 if (QUEUE_IsDoomedQueue(wndPtr->hmemTaskQ))
1054 return 0; /* Don't send anything if the task is dying */
1055 if (wndPtr->hmemTaskQ != GetTaskQueue(0))
1056 return MSG_SendMessage( wndPtr->hmemTaskQ, hwnd, msg, wParam, lParam );
1058 SPY_EnterMessage( SPY_SENDMESSAGE16, hwnd, msg, wParam, lParam );
1059 ret = CallWindowProc16( (WNDPROC16)wndPtr->winproc,
1060 hwnd, msg, wParam, lParam );
1061 SPY_ExitMessage( SPY_RESULT_OK16, hwnd, msg, ret );
1062 return ret;
1065 /************************************************************************
1066 * MSG_CallWndProcHook32
1068 static void MSG_CallWndProcHook32( LPMSG32 pmsg, BOOL32 bUnicode )
1070 CWPSTRUCT32 cwp;
1072 cwp.lParam = pmsg->lParam;
1073 cwp.wParam = pmsg->wParam;
1074 cwp.message = pmsg->message;
1075 cwp.hwnd = pmsg->hwnd;
1077 if (bUnicode) HOOK_CallHooks32W(WH_CALLWNDPROC, HC_ACTION, 1, (LPARAM)&cwp);
1078 else HOOK_CallHooks32A( WH_CALLWNDPROC, HC_ACTION, 1, (LPARAM)&cwp );
1080 pmsg->lParam = cwp.lParam;
1081 pmsg->wParam = cwp.wParam;
1082 pmsg->message = cwp.message;
1083 pmsg->hwnd = cwp.hwnd;
1086 /***********************************************************************
1087 * SendMessage32A (USER32.453)
1089 LRESULT SendMessage32A(HWND32 hwnd, UINT32 msg, WPARAM32 wParam, LPARAM lParam)
1091 WND * wndPtr;
1092 WND **list, **ppWnd;
1093 LRESULT ret;
1095 if (hwnd == HWND_BROADCAST)
1097 list = WIN_BuildWinArray( WIN_GetDesktop() );
1098 for (ppWnd = list; *ppWnd; ppWnd++)
1100 wndPtr = *ppWnd;
1101 if (!IsWindow32(wndPtr->hwndSelf)) continue;
1102 if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION)
1103 SendMessage32A( wndPtr->hwndSelf, msg, wParam, lParam );
1105 HeapFree( SystemHeap, 0, list );
1106 return TRUE;
1109 if (HOOK_IsHooked( WH_CALLWNDPROC ))
1110 MSG_CallWndProcHook32( (LPMSG32)&hwnd, FALSE);
1112 if (!(wndPtr = WIN_FindWndPtr( hwnd )))
1114 fprintf( stderr, "SendMessage32A: invalid hwnd %08x\n", hwnd );
1115 return 0;
1118 if (QUEUE_IsDoomedQueue(wndPtr->hmemTaskQ))
1119 return 0; /* Don't send anything if the task is dying */
1121 if (wndPtr->hmemTaskQ != GetTaskQueue(0))
1123 fprintf( stderr, "SendMessage32A: intertask message [%04x] not supported\n", msg );
1124 return 0;
1127 SPY_EnterMessage( SPY_SENDMESSAGE32, hwnd, msg, wParam, lParam );
1128 ret = CallWindowProc32A( (WNDPROC32)wndPtr->winproc,
1129 hwnd, msg, wParam, lParam );
1130 SPY_ExitMessage( SPY_RESULT_OK32, hwnd, msg, ret );
1131 return ret;
1135 /***********************************************************************
1136 * SendMessage32W (USER32.458)
1138 LRESULT SendMessage32W(HWND32 hwnd, UINT32 msg, WPARAM32 wParam, LPARAM lParam)
1140 WND * wndPtr;
1141 WND **list, **ppWnd;
1142 LRESULT ret;
1144 if (hwnd == HWND_BROADCAST)
1146 list = WIN_BuildWinArray( WIN_GetDesktop() );
1147 for (ppWnd = list; *ppWnd; ppWnd++)
1149 wndPtr = *ppWnd;
1150 if (!IsWindow32(wndPtr->hwndSelf)) continue;
1151 if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION)
1152 SendMessage32W( wndPtr->hwndSelf, msg, wParam, lParam );
1154 HeapFree( SystemHeap, 0, list );
1155 return TRUE;
1158 if (HOOK_IsHooked( WH_CALLWNDPROC ))
1159 MSG_CallWndProcHook32( (LPMSG32)&hwnd, TRUE);
1161 if (!(wndPtr = WIN_FindWndPtr( hwnd )))
1163 fprintf( stderr, "SendMessage32W: invalid hwnd %08x\n", hwnd );
1164 return 0;
1166 if (QUEUE_IsDoomedQueue(wndPtr->hmemTaskQ))
1167 return 0; /* Don't send anything if the task is dying */
1168 if (wndPtr->hmemTaskQ != GetTaskQueue(0))
1170 fprintf( stderr, "SendMessage32W: intertask message not supported\n" );
1171 return 0;
1174 SPY_EnterMessage( SPY_SENDMESSAGE32, hwnd, msg, wParam, lParam );
1175 ret = CallWindowProc32W( (WNDPROC32)wndPtr->winproc,
1176 hwnd, msg, wParam, lParam );
1177 SPY_ExitMessage( SPY_RESULT_OK32, hwnd, msg, ret );
1178 return ret;
1182 /***********************************************************************
1183 * WaitMessage (USER.112) (USER32.577)
1185 void WaitMessage( void )
1187 QUEUE_WaitBits( QS_ALLINPUT );
1191 struct accent_char
1193 BYTE ac_accent;
1194 BYTE ac_char;
1195 BYTE ac_result;
1198 static const struct accent_char accent_chars[] =
1200 /* A good idea should be to read /usr/X11/lib/X11/locale/iso8859-x/Compose */
1201 {'`', 'A', '\300'}, {'`', 'a', '\340'},
1202 {'\'', 'A', '\301'}, {'\'', 'a', '\341'},
1203 {'^', 'A', '\302'}, {'^', 'a', '\342'},
1204 {'~', 'A', '\303'}, {'~', 'a', '\343'},
1205 {'"', 'A', '\304'}, {'"', 'a', '\344'},
1206 {'O', 'A', '\305'}, {'o', 'a', '\345'},
1207 {'0', 'A', '\305'}, {'0', 'a', '\345'},
1208 {'A', 'A', '\305'}, {'a', 'a', '\345'},
1209 {'A', 'E', '\306'}, {'a', 'e', '\346'},
1210 {',', 'C', '\307'}, {',', 'c', '\347'},
1211 {'`', 'E', '\310'}, {'`', 'e', '\350'},
1212 {'\'', 'E', '\311'}, {'\'', 'e', '\351'},
1213 {'^', 'E', '\312'}, {'^', 'e', '\352'},
1214 {'"', 'E', '\313'}, {'"', 'e', '\353'},
1215 {'`', 'I', '\314'}, {'`', 'i', '\354'},
1216 {'\'', 'I', '\315'}, {'\'', 'i', '\355'},
1217 {'^', 'I', '\316'}, {'^', 'i', '\356'},
1218 {'"', 'I', '\317'}, {'"', 'i', '\357'},
1219 {'-', 'D', '\320'}, {'-', 'd', '\360'},
1220 {'~', 'N', '\321'}, {'~', 'n', '\361'},
1221 {'`', 'O', '\322'}, {'`', 'o', '\362'},
1222 {'\'', 'O', '\323'}, {'\'', 'o', '\363'},
1223 {'^', 'O', '\324'}, {'^', 'o', '\364'},
1224 {'~', 'O', '\325'}, {'~', 'o', '\365'},
1225 {'"', 'O', '\326'}, {'"', 'o', '\366'},
1226 {'/', 'O', '\330'}, {'/', 'o', '\370'},
1227 {'`', 'U', '\331'}, {'`', 'u', '\371'},
1228 {'\'', 'U', '\332'}, {'\'', 'u', '\372'},
1229 {'^', 'U', '\333'}, {'^', 'u', '\373'},
1230 {'"', 'U', '\334'}, {'"', 'u', '\374'},
1231 {'\'', 'Y', '\335'}, {'\'', 'y', '\375'},
1232 {'T', 'H', '\336'}, {'t', 'h', '\376'},
1233 {'s', 's', '\337'}, {'"', 'y', '\377'},
1234 {'s', 'z', '\337'}, {'i', 'j', '\377'},
1235 /* iso-8859-2 uses this */
1236 {'<', 'L', '\245'}, {'<', 'l', '\265'}, /* caron */
1237 {'<', 'S', '\251'}, {'<', 's', '\271'},
1238 {'<', 'T', '\253'}, {'<', 't', '\273'},
1239 {'<', 'Z', '\256'}, {'<', 'z', '\276'},
1240 {'<', 'C', '\310'}, {'<', 'c', '\350'},
1241 {'<', 'E', '\314'}, {'<', 'e', '\354'},
1242 {'<', 'D', '\317'}, {'<', 'd', '\357'},
1243 {'<', 'N', '\322'}, {'<', 'n', '\362'},
1244 {'<', 'R', '\330'}, {'<', 'r', '\370'},
1245 {';', 'A', '\241'}, {';', 'a', '\261'}, /* ogonek */
1246 {';', 'E', '\312'}, {';', 'e', '\332'},
1247 {'\'', 'Z', '\254'}, {'\'', 'z', '\274'}, /* acute */
1248 {'\'', 'R', '\300'}, {'\'', 'r', '\340'},
1249 {'\'', 'L', '\305'}, {'\'', 'l', '\345'},
1250 {'\'', 'C', '\306'}, {'\'', 'c', '\346'},
1251 {'\'', 'N', '\321'}, {'\'', 'n', '\361'},
1252 /* collision whith S, from iso-8859-9 !!! */
1253 {',', 'S', '\252'}, {',', 's', '\272'}, /* cedilla */
1254 {',', 'T', '\336'}, {',', 't', '\376'},
1255 {'.', 'Z', '\257'}, {'.', 'z', '\277'}, /* dot above */
1256 {'/', 'L', '\243'}, {'/', 'l', '\263'}, /* slash */
1257 {'/', 'D', '\320'}, {'/', 'd', '\360'},
1258 {'(', 'A', '\303'}, {'(', 'a', '\343'}, /* breve */
1259 {'\275', 'O', '\325'}, {'\275', 'o', '\365'}, /* double acute */
1260 {'\275', 'U', '\334'}, {'\275', 'u', '\374'},
1261 {'0', 'U', '\332'}, {'0', 'u', '\372'}, /* ring above */
1262 /* iso-8859-3 uses this */
1263 {'/', 'H', '\241'}, {'/', 'h', '\261'}, /* slash */
1264 {'>', 'H', '\246'}, {'>', 'h', '\266'}, /* circumflex */
1265 {'>', 'J', '\254'}, {'>', 'j', '\274'},
1266 {'>', 'C', '\306'}, {'>', 'c', '\346'},
1267 {'>', 'G', '\330'}, {'>', 'g', '\370'},
1268 {'>', 'S', '\336'}, {'>', 's', '\376'},
1269 /* collision whith G( from iso-8859-9 !!! */
1270 {'(', 'G', '\253'}, {'(', 'g', '\273'}, /* breve */
1271 {'(', 'U', '\335'}, {'(', 'u', '\375'},
1272 /* collision whith I. from iso-8859-3 !!! */
1273 {'.', 'I', '\251'}, {'.', 'i', '\271'}, /* dot above */
1274 {'.', 'C', '\305'}, {'.', 'c', '\345'},
1275 {'.', 'G', '\325'}, {'.', 'g', '\365'},
1276 /* iso-8859-4 uses this */
1277 {',', 'R', '\243'}, {',', 'r', '\263'}, /* cedilla */
1278 {',', 'L', '\246'}, {',', 'l', '\266'},
1279 {',', 'G', '\253'}, {',', 'g', '\273'},
1280 {',', 'N', '\321'}, {',', 'n', '\361'},
1281 {',', 'K', '\323'}, {',', 'k', '\363'},
1282 {'~', 'I', '\245'}, {'~', 'i', '\265'}, /* tilde */
1283 {'-', 'E', '\252'}, {'-', 'e', '\272'}, /* macron */
1284 {'-', 'A', '\300'}, {'-', 'a', '\340'},
1285 {'-', 'I', '\317'}, {'-', 'i', '\357'},
1286 {'-', 'O', '\322'}, {'-', 'o', '\362'},
1287 {'-', 'U', '\336'}, {'-', 'u', '\376'},
1288 {'/', 'T', '\254'}, {'/', 't', '\274'}, /* slash */
1289 {'.', 'E', '\314'}, {'.', 'e', '\344'}, /* dot above */
1290 {';', 'I', '\307'}, {';', 'i', '\347'}, /* ogonek */
1291 {';', 'U', '\331'}, {';', 'u', '\371'},
1292 /* iso-8859-9 uses this */
1293 /* iso-8859-9 has really bad choosen G( S, and I. as they collide
1294 * whith the same letters on other iso-8859-x (that is they are on
1295 * different places :-( ), if you use turkish uncomment these and
1296 * comment out the lines in iso-8859-2 and iso-8859-3 sections
1297 * FIXME: should be dynamic according to chosen language
1298 * if/when Wine has turkish support.
1300 /* collision whith G( from iso-8859-3 !!! */
1301 /* {'(', 'G', '\320'}, {'(', 'g', '\360'}, */ /* breve */
1302 /* collision whith S, from iso-8859-2 !!! */
1303 /* {',', 'S', '\336'}, {',', 's', '\376'}, */ /* cedilla */
1304 /* collision whith I. from iso-8859-3 !!! */
1305 /* {'.', 'I', '\335'}, {'.', 'i', '\375'}, */ /* dot above */
1309 /***********************************************************************
1310 * MSG_DoTranslateMessage
1312 * Implementation of TranslateMessage.
1314 * TranslateMessage translates virtual-key messages into character-messages,
1315 * as follows :
1316 * WM_KEYDOWN/WM_KEYUP combinations produce a WM_CHAR or WM_DEADCHAR message.
1317 * ditto replacing WM_* with WM_SYS*
1318 * This produces WM_CHAR messages only for keys mapped to ASCII characters
1319 * by the keyboard driver.
1321 static BOOL32 MSG_DoTranslateMessage( UINT32 message, HWND32 hwnd,
1322 WPARAM32 wParam, LPARAM lParam )
1324 static int dead_char;
1325 BYTE wp[2];
1327 if ((debugging_msg && message != WM_MOUSEMOVE && message != WM_TIMER)
1328 || (debugging_key
1329 && message >= WM_KEYFIRST && message <= WM_KEYLAST))
1330 fprintf(stddeb, "TranslateMessage(%s, %04X, %08lX)\n",
1331 SPY_GetMsgName(message), wParam, lParam );
1333 if ((message != WM_KEYDOWN) && (message != WM_SYSKEYDOWN)) return FALSE;
1335 dprintf_key( stddeb, "Translating key %04X, scancode %04X\n",
1336 wParam, HIWORD(lParam) );
1338 /* FIXME : should handle ToAscii yielding 2 */
1339 switch (ToAscii32(wParam, HIWORD(lParam),
1340 QueueKeyStateTable,(LPWORD)wp, 0))
1342 case 1 :
1343 message = (message == WM_KEYDOWN) ? WM_CHAR : WM_SYSCHAR;
1344 /* Should dead chars handling go in ToAscii ? */
1345 if (dead_char)
1347 int i;
1349 if (wp[0] == ' ') wp[0] = dead_char;
1350 if (dead_char == 0xa2) dead_char = '(';
1351 else if (dead_char == 0xa8) dead_char = '"';
1352 else if (dead_char == 0xb2) dead_char = ';';
1353 else if (dead_char == 0xb4) dead_char = '\'';
1354 else if (dead_char == 0xb7) dead_char = '<';
1355 else if (dead_char == 0xb8) dead_char = ',';
1356 else if (dead_char == 0xff) dead_char = '.';
1357 for (i = 0; i < sizeof(accent_chars)/sizeof(accent_chars[0]); i++)
1358 if ((accent_chars[i].ac_accent == dead_char) &&
1359 (accent_chars[i].ac_char == wp[0]))
1361 wp[0] = accent_chars[i].ac_result;
1362 break;
1364 dead_char = 0;
1366 dprintf_key(stddeb, "1 -> PostMessage(%s)\n", SPY_GetMsgName(message));
1367 PostMessage16( hwnd, message, wp[0], lParam );
1368 return TRUE;
1370 case -1 :
1371 message = (message == WM_KEYDOWN) ? WM_DEADCHAR : WM_SYSDEADCHAR;
1372 dead_char = wp[0];
1373 dprintf_key( stddeb, "-1 -> PostMessage(%s)\n",
1374 SPY_GetMsgName(message));
1375 PostMessage16( hwnd, message, wp[0], lParam );
1376 return TRUE;
1378 return FALSE;
1382 /***********************************************************************
1383 * TranslateMessage16 (USER.113)
1385 BOOL16 TranslateMessage16( const MSG16 *msg )
1387 return MSG_DoTranslateMessage( msg->message, msg->hwnd,
1388 msg->wParam, msg->lParam );
1392 /***********************************************************************
1393 * TranslateMessage32 (USER32.555)
1395 BOOL32 TranslateMessage32( const MSG32 *msg )
1397 return MSG_DoTranslateMessage( msg->message, msg->hwnd,
1398 msg->wParam, msg->lParam );
1402 /***********************************************************************
1403 * DispatchMessage16 (USER.114)
1405 LONG DispatchMessage16( const MSG16* msg )
1407 WND * wndPtr;
1408 LONG retval;
1409 int painting;
1411 /* Process timer messages */
1412 if ((msg->message == WM_TIMER) || (msg->message == WM_SYSTIMER))
1414 if (msg->lParam)
1416 return CallWindowProc16( (WNDPROC16)msg->lParam, msg->hwnd,
1417 msg->message, msg->wParam, GetTickCount() );
1421 if (!msg->hwnd) return 0;
1422 if (!(wndPtr = WIN_FindWndPtr( msg->hwnd ))) return 0;
1423 if (!wndPtr->winproc) return 0;
1424 painting = (msg->message == WM_PAINT);
1425 if (painting) wndPtr->flags |= WIN_NEEDS_BEGINPAINT;
1427 SPY_EnterMessage( SPY_DISPATCHMESSAGE16, msg->hwnd, msg->message,
1428 msg->wParam, msg->lParam );
1429 retval = CallWindowProc16( (WNDPROC16)wndPtr->winproc,
1430 msg->hwnd, msg->message,
1431 msg->wParam, msg->lParam );
1432 SPY_ExitMessage( SPY_RESULT_OK16, msg->hwnd, msg->message, retval );
1434 if (painting && (wndPtr = WIN_FindWndPtr( msg->hwnd )) &&
1435 (wndPtr->flags & WIN_NEEDS_BEGINPAINT) && wndPtr->hrgnUpdate)
1437 fprintf(stderr, "BeginPaint not called on WM_PAINT for hwnd %04x!\n",
1438 msg->hwnd);
1439 wndPtr->flags &= ~WIN_NEEDS_BEGINPAINT;
1440 /* Validate the update region to avoid infinite WM_PAINT loop */
1441 ValidateRect32( msg->hwnd, NULL );
1443 return retval;
1447 /***********************************************************************
1448 * DispatchMessage32A (USER32.140)
1450 LONG DispatchMessage32A( const MSG32* msg )
1452 WND * wndPtr;
1453 LONG retval;
1454 int painting;
1456 /* Process timer messages */
1457 if ((msg->message == WM_TIMER) || (msg->message == WM_SYSTIMER))
1459 if (msg->lParam)
1461 /* HOOK_CallHooks32A( WH_CALLWNDPROC, HC_ACTION, 0, FIXME ); */
1462 return CallWindowProc32A( (WNDPROC32)msg->lParam, msg->hwnd,
1463 msg->message, msg->wParam, GetTickCount() );
1467 if (!msg->hwnd) return 0;
1468 if (!(wndPtr = WIN_FindWndPtr( msg->hwnd ))) return 0;
1469 if (!wndPtr->winproc) return 0;
1470 painting = (msg->message == WM_PAINT);
1471 if (painting) wndPtr->flags |= WIN_NEEDS_BEGINPAINT;
1472 /* HOOK_CallHooks32A( WH_CALLWNDPROC, HC_ACTION, 0, FIXME ); */
1474 SPY_EnterMessage( SPY_DISPATCHMESSAGE32, msg->hwnd, msg->message,
1475 msg->wParam, msg->lParam );
1476 retval = CallWindowProc32A( (WNDPROC32)wndPtr->winproc,
1477 msg->hwnd, msg->message,
1478 msg->wParam, msg->lParam );
1479 SPY_ExitMessage( SPY_RESULT_OK32, msg->hwnd, msg->message, retval );
1481 if (painting && (wndPtr = WIN_FindWndPtr( msg->hwnd )) &&
1482 (wndPtr->flags & WIN_NEEDS_BEGINPAINT) && wndPtr->hrgnUpdate)
1484 fprintf(stderr, "BeginPaint not called on WM_PAINT for hwnd %04x!\n",
1485 msg->hwnd);
1486 wndPtr->flags &= ~WIN_NEEDS_BEGINPAINT;
1487 /* Validate the update region to avoid infinite WM_PAINT loop */
1488 ValidateRect32( msg->hwnd, NULL );
1490 return retval;
1494 /***********************************************************************
1495 * DispatchMessage32W (USER32.141)
1497 LONG DispatchMessage32W( const MSG32* msg )
1499 WND * wndPtr;
1500 LONG retval;
1501 int painting;
1503 /* Process timer messages */
1504 if ((msg->message == WM_TIMER) || (msg->message == WM_SYSTIMER))
1506 if (msg->lParam)
1508 /* HOOK_CallHooks32W( WH_CALLWNDPROC, HC_ACTION, 0, FIXME ); */
1509 return CallWindowProc32W( (WNDPROC32)msg->lParam, msg->hwnd,
1510 msg->message, msg->wParam, GetTickCount() );
1514 if (!msg->hwnd) return 0;
1515 if (!(wndPtr = WIN_FindWndPtr( msg->hwnd ))) return 0;
1516 if (!wndPtr->winproc) return 0;
1517 painting = (msg->message == WM_PAINT);
1518 if (painting) wndPtr->flags |= WIN_NEEDS_BEGINPAINT;
1519 /* HOOK_CallHooks32W( WH_CALLWNDPROC, HC_ACTION, 0, FIXME ); */
1521 SPY_EnterMessage( SPY_DISPATCHMESSAGE32, msg->hwnd, msg->message,
1522 msg->wParam, msg->lParam );
1523 retval = CallWindowProc32W( (WNDPROC32)wndPtr->winproc,
1524 msg->hwnd, msg->message,
1525 msg->wParam, msg->lParam );
1526 SPY_ExitMessage( SPY_RESULT_OK32, msg->hwnd, msg->message, retval );
1528 if (painting && (wndPtr = WIN_FindWndPtr( msg->hwnd )) &&
1529 (wndPtr->flags & WIN_NEEDS_BEGINPAINT) && wndPtr->hrgnUpdate)
1531 fprintf(stderr, "BeginPaint not called on WM_PAINT for hwnd %04x!\n",
1532 msg->hwnd);
1533 wndPtr->flags &= ~WIN_NEEDS_BEGINPAINT;
1534 /* Validate the update region to avoid infinite WM_PAINT loop */
1535 ValidateRect32( msg->hwnd, NULL );
1537 return retval;
1541 /***********************************************************************
1542 * RegisterWindowMessage16 (USER.118)
1544 WORD RegisterWindowMessage16( SEGPTR str )
1546 dprintf_msg(stddeb, "RegisterWindowMessage16: %08lx\n", (DWORD)str );
1547 return GlobalAddAtom16( str );
1551 /***********************************************************************
1552 * RegisterWindowMessage32A (USER32.436)
1554 WORD RegisterWindowMessage32A( LPCSTR str )
1556 dprintf_msg(stddeb, "RegisterWindowMessage32A: %s\n", str );
1557 return GlobalAddAtom32A( str );
1561 /***********************************************************************
1562 * RegisterWindowMessage32W (USER32.437)
1564 WORD RegisterWindowMessage32W( LPCWSTR str )
1566 dprintf_msg(stddeb, "RegisterWindowMessage32W: %p\n", str );
1567 return GlobalAddAtom32W( str );
1571 /***********************************************************************
1572 * GetTickCount (USER.13) (KERNEL32.299)
1574 DWORD GetTickCount(void)
1576 struct timeval t;
1577 gettimeofday( &t, NULL );
1578 return ((t.tv_sec * 1000) + (t.tv_usec / 1000)) - MSG_WineStartTicks;
1582 /***********************************************************************
1583 * GetCurrentTime16 (USER.15)
1585 * (effectively identical to GetTickCount)
1587 DWORD GetCurrentTime16(void)
1589 return GetTickCount();
1593 /***********************************************************************
1594 * InSendMessage16 (USER.192)
1596 BOOL16 InSendMessage16(void)
1598 return InSendMessage32();
1602 /***********************************************************************
1603 * InSendMessage32 (USER32.319)
1605 BOOL32 InSendMessage32(void)
1607 MESSAGEQUEUE *queue;
1609 if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(0) )))
1610 return 0;
1611 return (BOOL32)queue->InSendMessageHandle;