user32: Support for the magic WM_CHAR W->A conversion in Get/PeekMessage.
diff --git a/dlls/user32/message.c b/dlls/user32/message.c
index bd6c103..c89a7ff 100644
--- a/dlls/user32/message.c
+++ b/dlls/user32/message.c
@@ -307,6 +307,18 @@
return (msg->hwnd == hwnd_filter || IsChild( hwnd_filter, msg->hwnd ));
}
+/* check for pending WM_CHAR message with DBCS trailing byte */
+static inline BOOL get_pending_wmchar( MSG *msg, UINT first, UINT last, BOOL remove )
+{
+ struct wm_char_mapping_data *data = get_user_thread_info()->wmchar_data;
+
+ if (!data || !data->get_msg.message) return FALSE;
+ if ((first || last) && (first > WM_CHAR || last < WM_CHAR)) return FALSE;
+ if (!msg) return FALSE;
+ *msg = data->get_msg;
+ if (remove) data->get_msg.message = 0;
+ return TRUE;
+}
/***********************************************************************
* broadcast_message_callback
@@ -435,39 +447,60 @@
*
* Convert the wparam of a Unicode message to ASCII.
*/
-static WPARAM map_wparam_WtoA( UINT message, WPARAM wparam )
+static void map_wparam_WtoA( MSG *msg, BOOL remove )
{
- switch(message)
+ BYTE ch[2];
+ WCHAR wch[2];
+ DWORD len;
+
+ switch(msg->message)
{
+ case WM_CHAR:
+ if (!HIWORD(msg->wParam))
+ {
+ wch[0] = LOWORD(msg->wParam);
+ ch[0] = ch[1] = 0;
+ RtlUnicodeToMultiByteN( (LPSTR)ch, 2, &len, wch, sizeof(wch[0]) );
+ if (len == 2) /* DBCS char */
+ {
+ struct wm_char_mapping_data *data = get_user_thread_info()->wmchar_data;
+ if (!data)
+ {
+ if (!(data = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data) ))) return;
+ get_user_thread_info()->wmchar_data = data;
+ }
+ if (remove)
+ {
+ data->get_msg = *msg;
+ data->get_msg.wParam = ch[1];
+ }
+ msg->wParam = ch[0];
+ return;
+ }
+ }
+ /* else fall through */
case WM_CHARTOITEM:
case EM_SETPASSWORDCHAR:
- case WM_CHAR:
case WM_DEADCHAR:
case WM_SYSCHAR:
case WM_SYSDEADCHAR:
case WM_MENUCHAR:
- {
- WCHAR wch[2];
- BYTE ch[2];
- wch[0] = LOWORD(wparam);
- wch[1] = HIWORD(wparam);
- WideCharToMultiByte( CP_ACP, 0, wch, 2, (LPSTR)ch, 2, NULL, NULL );
- wparam = MAKEWPARAM( ch[0] | (ch[1] << 8), 0 );
- }
+ wch[0] = LOWORD(msg->wParam);
+ wch[1] = HIWORD(msg->wParam);
+ ch[0] = ch[1] = 0;
+ RtlUnicodeToMultiByteN( (LPSTR)ch, 2, NULL, wch, sizeof(wch) );
+ msg->wParam = MAKEWPARAM( ch[0] | (ch[1] << 8), 0 );
break;
case WM_IME_CHAR:
- {
- WCHAR wch = LOWORD(wparam);
- BYTE ch[2];
-
- if (WideCharToMultiByte( CP_ACP, 0, &wch, 1, (LPSTR)ch, 2, NULL, NULL ) == 2)
- wparam = MAKEWPARAM( (ch[0] << 8) | ch[1], HIWORD(wparam) );
- else
- wparam = MAKEWPARAM( ch[0], HIWORD(wparam) );
- }
+ wch[0] = LOWORD(msg->wParam);
+ ch[0] = ch[1] = 0;
+ RtlUnicodeToMultiByteN( (LPSTR)ch, 2, &len, wch, sizeof(wch[0]) );
+ if (len == 2)
+ msg->wParam = MAKEWPARAM( (ch[0] << 8) | ch[1], HIWORD(msg->wParam) );
+ else
+ msg->wParam = MAKEWPARAM( ch[0], HIWORD(msg->wParam) );
break;
}
- return wparam;
}
@@ -2876,9 +2909,10 @@
*/
BOOL WINAPI PeekMessageA( MSG *msg, HWND hwnd, UINT first, UINT last, UINT flags )
{
- BOOL ret = PeekMessageW( msg, hwnd, first, last, flags );
- if (ret) msg->wParam = map_wparam_WtoA( msg->message, msg->wParam );
- return ret;
+ if (get_pending_wmchar( msg, first, last, (flags & PM_REMOVE) )) return TRUE;
+ if (!PeekMessageW( msg, hwnd, first, last, flags )) return FALSE;
+ map_wparam_WtoA( msg, (flags & PM_REMOVE) );
+ return TRUE;
}
@@ -2940,8 +2974,9 @@
*/
BOOL WINAPI GetMessageA( MSG *msg, HWND hwnd, UINT first, UINT last )
{
+ if (get_pending_wmchar( msg, first, last, TRUE )) return TRUE;
GetMessageW( msg, hwnd, first, last );
- msg->wParam = map_wparam_WtoA( msg->message, msg->wParam );
+ map_wparam_WtoA( msg, TRUE );
return (msg->message != WM_QUIT);
}
diff --git a/dlls/user32/tests/msg.c b/dlls/user32/tests/msg.c
index d51cf91..336cdce 100644
--- a/dlls/user32/tests/msg.c
+++ b/dlls/user32/tests/msg.c
@@ -9281,6 +9281,8 @@
WCHAR wch, bad_wch;
HWND hwnd, hwnd2;
MSG msg;
+ DWORD time;
+ POINT pt;
DWORD_PTR res;
CPINFOEXA cpinfo;
UINT i, j, k;
@@ -9481,6 +9483,72 @@
ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
+ /* test retrieving messages */
+
+ PostMessageW( hwnd, WM_CHAR, wch, 0 );
+ ok( PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
+ ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
+ ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
+ ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
+ ok( PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
+ ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
+ ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
+ ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
+ ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
+
+ /* message filters */
+ PostMessageW( hwnd, WM_CHAR, wch, 0 );
+ ok( PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
+ ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
+ ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
+ ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
+ /* message id is filtered, hwnd is not */
+ ok( !PeekMessageA( &msg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ), "no message\n" );
+ ok( PeekMessageA( &msg, hwnd2, 0, 0, PM_REMOVE ), "no message\n" );
+ ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
+ ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
+ ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
+ ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
+
+ /* mixing GetMessage and PostMessage */
+ PostMessageW( hwnd, WM_CHAR, wch, 0xbeef );
+ ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
+ ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
+ ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
+ ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
+ ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
+ time = msg.time;
+ pt = msg.pt;
+ ok( time - GetTickCount() <= 100, "bad time %x\n", msg.time );
+ ok( PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "no message\n" );
+ ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
+ ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
+ ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
+ ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
+ ok( msg.time == time, "bad time %x/%x\n", msg.time, time );
+ ok( msg.pt.x == pt.x && msg.pt.y == pt.y, "bad point %u,%u/%u,%u\n", msg.pt.x, msg.pt.y, pt.x, pt.y );
+ ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
+
+ /* without PM_REMOVE */
+ PostMessageW( hwnd, WM_CHAR, wch, 0 );
+ ok( PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "no message\n" );
+ ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
+ ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
+ ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
+ ok( PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "no message\n" );
+ ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
+ ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
+ ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
+ ok( PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "no message\n" );
+ ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
+ ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
+ ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
+ ok( PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "no message\n" );
+ ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
+ ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
+ ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
+ ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
+
DestroyWindow(hwnd);
}
diff --git a/dlls/user32/user_private.h b/dlls/user32/user_private.h
index 85039fd..fd46832 100644
--- a/dlls/user32/user_private.h
+++ b/dlls/user32/user_private.h
@@ -185,6 +185,7 @@
struct wm_char_mapping_data
{
BYTE lead_byte[WMCHAR_MAP_COUNT];
+ MSG get_msg;
};
/* this is the structure stored in TEB->Win32ClientInfo */