Alexandre Julliard : user32: Support for the magic WM_CHAR W-> A conversion in Get/PeekMessage.

Alexandre Julliard julliard at wine.codeweavers.com
Thu Aug 9 08:23:00 CDT 2007


Module: wine
Branch: master
Commit: 2ce799c4f6099625aad2f9cb958bb0402bbda648
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=2ce799c4f6099625aad2f9cb958bb0402bbda648

Author: Alexandre Julliard <julliard at winehq.org>
Date:   Wed Aug  8 20:35:24 2007 +0200

user32: Support for the magic WM_CHAR W->A conversion in Get/PeekMessage.

---

 dlls/user32/message.c      |   85 +++++++++++++++++++++++++++++++-------------
 dlls/user32/tests/msg.c    |   68 +++++++++++++++++++++++++++++++++++
 dlls/user32/user_private.h |    1 +
 3 files changed, 129 insertions(+), 25 deletions(-)

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 @@ static inline BOOL check_hwnd_filter( const MSG *msg, HWND hwnd_filter )
     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 @@ BOOL map_wparam_AtoW( UINT message, WPARAM *wparam, enum wm_char_mapping mapping
  *
  * 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 PeekMessageW( MSG *msg_out, HWND hwnd, UINT first, UINT last, UINT f
  */
 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 GetMessageW( MSG *msg, HWND hwnd, UINT first, UINT last )
  */
 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 @@ static void test_dbcs_wm_char(void)
     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 @@ static void test_dbcs_wm_char(void)
     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 @@ enum wm_char_mapping
 struct wm_char_mapping_data
 {
     BYTE lead_byte[WMCHAR_MAP_COUNT];
+    MSG  get_msg;
 };
 
 /* this is the structure stored in TEB->Win32ClientInfo */




More information about the wine-cvs mailing list