Subject: bug#10299: Emacs doesn't handle Unicode characters in keyboard layout on MS Windows

From: Joakim Hårsman <[email-masked]>
Date: Tue, 24 Jan 2012 21:42:46 +0100

GetMessage is a macro, many Windows API functions are, and switches
between GetMessageA and GetMessageW based on whether UNICODE is
defined. I really should explicitly use GetMessageA, I just missed it.

I switched to Stefan's suggestion, but with explicit use of
GetMessageA. Note that this makes that line longer than 80 chars.

Here's an amended patch that also moves the definition of the
INIT_WINDOW_CLASS macro to just before use, and makes
w32_set_frame_text static.

=== modified file 'src/w32fns.c'
--- src/w32fns.c        2011-12-04 08:02:42 +0000
+++ src/w32fns.c        2012-01-24 20:22:52 +0000
@@ -1641,6 +1641,20 @@

 }

+/* Set text of w32 frame with handle HWND to TEXT.
+
+   We explicitly switch between the Unicode and ANSI version of
+   SetWindowText because Emacs isn't compiled with UNICODE defined to
+   retain compatibility with Windows 95. */
+
+static void
+w32_set_frame_text (HWND hwnd, LPCSTR text)
+{
+  if (os_subtype == OS_NT)
+    SetWindowTextW (hwnd, (LPCWSTR)text);
+  else
+    SetWindowTextA (hwnd, text);
+}

 /* Change the name of frame F to NAME.  If NAME is nil, set F's name to
        w32_id_name.
@@ -1697,10 +1711,10 @@
   if (FRAME_W32_WINDOW (f))
     {
       if (STRING_MULTIBYTE (name))
-       name = ENCODE_SYSTEM (name);
-
+        name = ENCODE_SYSTEM (name);
+
       BLOCK_INPUT;
-      SetWindowText (FRAME_W32_WINDOW (f), SDATA (name));
+      w32_set_frame_text(FRAME_W32_WINDOW (f), SDATA (name));
       UNBLOCK_INPUT;
     }
 }
@@ -1746,7 +1760,7 @@
        name = ENCODE_SYSTEM (name);

       BLOCK_INPUT;
-      SetWindowText (FRAME_W32_WINDOW (f), SDATA (name));
+      w32_set_frame_text(FRAME_W32_WINDOW (f), SDATA (name));
       UNBLOCK_INPUT;
     }
 }
@@ -1782,23 +1796,37 @@

 static LRESULT CALLBACK w32_wnd_proc (HWND, UINT, WPARAM, LPARAM);

+#define INIT_WINDOW_CLASS(wc)                   \
+  wc.style = CS_HREDRAW | CS_VREDRAW;           \
+  wc.lpfnWndProc = (WNDPROC) w32_wnd_proc;      \
+  wc.cbClsExtra = 0;                            \
+  wc.cbWndExtra = WND_EXTRA_BYTES;              \
+  wc.hInstance = hinst;                         \
+  wc.hIcon = LoadIcon (hinst, EMACS_CLASS);     \
+  wc.hCursor = w32_load_cursor (IDC_ARROW);     \
+  wc.hbrBackground = NULL;                      \
+  wc.lpszMenuName = NULL;                       \
+
 static BOOL
 w32_init_class (HINSTANCE hinst)
 {
-  WNDCLASS wc;
-
-  wc.style = CS_HREDRAW | CS_VREDRAW;
-  wc.lpfnWndProc = (WNDPROC) w32_wnd_proc;
-  wc.cbClsExtra = 0;
-  wc.cbWndExtra = WND_EXTRA_BYTES;
-  wc.hInstance = hinst;
-  wc.hIcon = LoadIcon (hinst, EMACS_CLASS);
-  wc.hCursor = w32_load_cursor (IDC_ARROW);
-  wc.hbrBackground = NULL; /* GetStockObject (WHITE_BRUSH);  */
-  wc.lpszMenuName = NULL;
-  wc.lpszClassName = EMACS_CLASS;
-
-  return (RegisterClass (&wc));
+
+  if (os_subtype == OS_NT)
+    {
+      WNDCLASSW  uwc;
+      INIT_WINDOW_CLASS(uwc);
+      uwc.lpszClassName = L"Emacs";
+
+      return (RegisterClassW (&uwc));
+    }
+  else
+    {
+      WNDCLASS  wc;
+      INIT_WINDOW_CLASS(wc);
+      wc.lpszClassName = EMACS_CLASS;
+
+      return (RegisterClassA (&wc));
+    }
 }

 static HWND
@@ -2248,8 +2276,13 @@

   msh_mousewheel = RegisterWindowMessage (MSH_MOUSEWHEEL);

-  while (GetMessage (&msg, NULL, 0, 0))
+  while (1)
     {
+      result = (os_subtype == OS_NT ? GetMessageW : GetMessageA)
(&msg, NULL, 0, 0);
+
+      if (!result)
+        break;
+
       if (msg.hwnd == NULL)
        {
          switch (msg.message)
@@ -2915,8 +2948,21 @@

     case WM_SYSCHAR:
     case WM_CHAR:
-      post_character_message (hwnd, msg, wParam, lParam,
-                             w32_get_key_modifiers (wParam, lParam));
+      if (wParam > 255 )
+        {
+          unsigned short lo = wParam & 0x0000FFFF;
+          unsigned short hi = (wParam & 0xFFFF0000) >> 8;
+          wParam  = hi | lo;
+
+          W32Msg wmsg;
+          wmsg.dwModifiers = w32_get_key_modifiers (wParam, lParam);
+          signal_user_input ();
+          my_post_msg (&wmsg, hwnd, WM_UNICHAR, wParam, lParam);
+
+        }
+      else
+        post_character_message (hwnd, msg, wParam, lParam,
+                                w32_get_key_modifiers (wParam, lParam));
       break;

     case WM_UNICHAR:

On 24 January 2012 13:03, Juanma Barranquero <[email-masked]> wrote:
> On Tue, Jan 24, 2012 at 10:40, Andreas Schwab <[email-masked]> wrote:
>
>>>   result = (os_subtype == OS_NT ? GetMessageW : GetMessage) (&msg, NULL, 0, 0);
>>
>> That can fail if either of the functions is defined only as a
>> function-like macro.
>
> OTOH, if the patch explicitly references W functions, it should be
> using RegisterClassA and GetMessageA for the explicit A versions.
>
>     Juanma