Brian P. Hinz 4a11567
diff -ur fltk-1.3.0r9293.org/src/Fl_win32.cxx fltk-1.3.0r9293/src/Fl_win32.cxx
Brian P. Hinz 4a11567
--- fltk-1.3.0r9293.org/src/Fl_win32.cxx	2012-06-18 09:07:56.522314557 +0200
Brian P. Hinz 4a11567
+++ fltk-1.3.0r9293/src/Fl_win32.cxx	2012-06-18 09:08:07.392836285 +0200
Brian P. Hinz 4a11567
@@ -87,6 +87,8 @@
Brian P. Hinz 4a11567
 static Fl_Display_Device fl_gdi_display(&fl_gdi_driver);
Brian P. Hinz 4a11567
 Fl_Display_Device *Fl_Display_Device::_display = &fl_gdi_display; // the platform display
Brian P. Hinz 4a11567
 
Brian P. Hinz 4a11567
+bool use_simple_keyboard = false;
Brian P. Hinz 4a11567
+
Brian P. Hinz 4a11567
 // dynamic wsock dll handling api:
Brian P. Hinz 4a11567
 #if defined(__CYGWIN__) && !defined(SOCKET)
Brian P. Hinz 4a11567
 # define SOCKET int
Brian P. Hinz 4a11567
@@ -120,6 +122,8 @@
Brian P. Hinz 4a11567
  * size and link dependencies.
Brian P. Hinz 4a11567
  */
Brian P. Hinz 4a11567
 static HMODULE s_imm_module = 0;
Brian P. Hinz 4a11567
+typedef BOOL (WINAPI* flTypeImmAssociateContextEx)(HWND, HIMC, DWORD);
Brian P. Hinz 4a11567
+static flTypeImmAssociateContextEx flImmAssociateContextEx = 0;
Brian P. Hinz 4a11567
 typedef HIMC (WINAPI* flTypeImmGetContext)(HWND);
Brian P. Hinz 4a11567
 static flTypeImmGetContext flImmGetContext = 0;
Brian P. Hinz 4a11567
 typedef BOOL (WINAPI* flTypeImmSetCompositionWindow)(HIMC, LPCOMPOSITIONFORM);
Brian P. Hinz 4a11567
@@ -135,6 +139,7 @@
Brian P. Hinz 4a11567
     if (!s_imm_module)
Brian P. Hinz 4a11567
       Fl::fatal("FLTK Lib Error: IMM32.DLL file not found!\n\n"
Brian P. Hinz 4a11567
         "Please check your input method manager library accessibility.");
Brian P. Hinz 4a11567
+    flImmAssociateContextEx = (flTypeImmAssociateContextEx)GetProcAddress(s_imm_module, "ImmAssociateContextEx");
Brian P. Hinz 4a11567
     flImmGetContext = (flTypeImmGetContext)GetProcAddress(s_imm_module, "ImmGetContext");
Brian P. Hinz 4a11567
     flImmSetCompositionWindow = (flTypeImmSetCompositionWindow)GetProcAddress(s_imm_module, "ImmSetCompositionWindow");
Brian P. Hinz 4a11567
     flImmReleaseContext = (flTypeImmReleaseContext)GetProcAddress(s_imm_module, "ImmReleaseContext");
Brian P. Hinz 4a11567
@@ -413,7 +418,12 @@
Brian P. Hinz 4a11567
         }
Brian P. Hinz 4a11567
       }
Brian P. Hinz 4a11567
 
Brian P. Hinz 4a11567
-      TranslateMessage(&fl_msg);
Brian P. Hinz 4a11567
+      // Don't bother with key to character translation as we do
Brian P. Hinz 4a11567
+      // it manually for simpley keyboard widgets. In fact, calling
Brian P. Hinz 4a11567
+      // TranslateMessage() just makes it more difficult as it sets
Brian P. Hinz 4a11567
+      // a bunch of internal state.
Brian P. Hinz 4a11567
+      if (!use_simple_keyboard)
Brian P. Hinz 4a11567
+        TranslateMessage(&fl_msg);
Brian P. Hinz 4a11567
       DispatchMessageW(&fl_msg);
Brian P. Hinz 4a11567
       have_message = PeekMessageW(&fl_msg, NULL, 0, 0, PM_REMOVE);
Brian P. Hinz 4a11567
     }
Brian P. Hinz 4a11567
@@ -638,6 +648,49 @@
Brian P. Hinz 4a11567
   }
Brian P. Hinz 4a11567
 }
Brian P. Hinz 4a11567
 
Brian P. Hinz 4a11567
+void fl_update_focus(void)
Brian P. Hinz 4a11567
+{
Brian P. Hinz 4a11567
+  Fl_Widget *focus;
Brian P. Hinz 4a11567
+  Fl_Window *win;
Brian P. Hinz 4a11567
+
Brian P. Hinz 4a11567
+  get_imm_module();
Brian P. Hinz 4a11567
+
Brian P. Hinz 4a11567
+  focus = Fl::grab();
Brian P. Hinz 4a11567
+  if (!focus)
Brian P. Hinz 4a11567
+    focus = Fl::focus();
Brian P. Hinz 4a11567
+  if (!focus)
Brian P. Hinz 4a11567
+    return;
Brian P. Hinz 4a11567
+
Brian P. Hinz 4a11567
+  // Grabs are special in that events are sent to the first
Brian P. Hinz 4a11567
+  // available window
Brian P. Hinz 4a11567
+  if (focus == Fl::grab())
Brian P. Hinz 4a11567
+    win = Fl::first_window();
Brian P. Hinz 4a11567
+  else {
Brian P. Hinz 4a11567
+    win = focus->as_window();
Brian P. Hinz 4a11567
+    if (!win)
Brian P. Hinz 4a11567
+      win = focus->window();
Brian P. Hinz 4a11567
+  }
Brian P. Hinz 4a11567
+
Brian P. Hinz 4a11567
+  if (!win) {
Brian P. Hinz 4a11567
+    Fl::warning("Cannot find window for widget receiving focus");
Brian P. Hinz 4a11567
+    return;
Brian P. Hinz 4a11567
+  }
Brian P. Hinz 4a11567
+
Brian P. Hinz 4a11567
+  // No Win32 window created yet
Brian P. Hinz 4a11567
+  if (!Fl_X::i(win) || !fl_xid(win))
Brian P. Hinz 4a11567
+    return;
Brian P. Hinz 4a11567
+
Brian P. Hinz 4a11567
+  if (focus->simple_keyboard()) {
Brian P. Hinz 4a11567
+    use_simple_keyboard = true;
Brian P. Hinz 4a11567
+    if (flImmGetContext(fl_xid(win)) != 0)
Brian P. Hinz 4a11567
+      flImmAssociateContextEx(fl_xid(win), 0, 0);
Brian P. Hinz 4a11567
+  } else {
Brian P. Hinz 4a11567
+    use_simple_keyboard = false;
Brian P. Hinz 4a11567
+    if (flImmGetContext(fl_xid(win)) == 0)
Brian P. Hinz 4a11567
+      flImmAssociateContextEx(fl_xid(win), 0, IACE_DEFAULT);
Brian P. Hinz 4a11567
+  }
Brian P. Hinz 4a11567
+}
Brian P. Hinz 4a11567
+
Brian P. Hinz 4a11567
 HWND fl_capture;
Brian P. Hinz 4a11567
 
Brian P. Hinz 4a11567
 static int mouse_event(Fl_Window *window, int what, int button,
Brian P. Hinz 4a11567
@@ -785,6 +838,27 @@
Brian P. Hinz 4a11567
   return extended ? extendedlut[vk] : vklut[vk];
Brian P. Hinz 4a11567
 }
Brian P. Hinz 4a11567
 
Brian P. Hinz 4a11567
+static xchar msdead2fltk(xchar in)
Brian P. Hinz 4a11567
+{
Brian P. Hinz 4a11567
+  switch (in) {
Brian P. Hinz 4a11567
+  case 0x0060:      // GRAVE ACCENT
Brian P. Hinz 4a11567
+    return 0x0300;  // COMBINING GRAVE ACCENT
Brian P. Hinz 4a11567
+  case 0x00b4:      // ACUTE ACCENT
Brian P. Hinz 4a11567
+    return 0x0301;  // COMBINING ACUTE ACCENT
Brian P. Hinz 4a11567
+  case 0x005e:      // CIRCUMFLEX ACCENT
Brian P. Hinz 4a11567
+    return 0x0302;  // COMBINING CIRCUMFLEX ACCENT
Brian P. Hinz 4a11567
+  case 0x007e:      // TILDE
Brian P. Hinz 4a11567
+    return 0x0303;  // COMBINING TILDE
Brian P. Hinz 4a11567
+  case 0x00a8:      // DIAERESIS
Brian P. Hinz 4a11567
+    return 0x0308;  // COMBINING DIAERESIS
Brian P. Hinz 4a11567
+  // FIXME: Windows dead key behaviour isn't documented and I don't have
Brian P. Hinz 4a11567
+  //        any more keyboards to test with...
Brian P. Hinz 4a11567
+  }
Brian P. Hinz 4a11567
+
Brian P. Hinz 4a11567
+  // hope that Windows gave us something proper to begin with
Brian P. Hinz 4a11567
+  return in;
Brian P. Hinz 4a11567
+}
Brian P. Hinz 4a11567
+
Brian P. Hinz 4a11567
 #if USE_COLORMAP
Brian P. Hinz 4a11567
 extern HPALETTE fl_select_palette(void); // in fl_color_win32.cxx
Brian P. Hinz 4a11567
 #endif
Brian P. Hinz 4a11567
@@ -846,6 +920,8 @@
Brian P. Hinz 4a11567
   //fl_msg.pt = ???
Brian P. Hinz 4a11567
   //fl_msg.lPrivate = ???
Brian P. Hinz 4a11567
 
Brian P. Hinz 4a11567
+  MSG fl_orig_msg = fl_msg;
Brian P. Hinz 4a11567
+
Brian P. Hinz 4a11567
   Fl_Window *window = fl_find(hWnd);
Brian P. Hinz 4a11567
 
Brian P. Hinz 4a11567
   if (window) switch (uMsg) {
Brian P. Hinz 4a11567
@@ -1025,23 +1101,82 @@
Brian P. Hinz 4a11567
     if (GetKeyState(VK_SCROLL)) state |= FL_SCROLL_LOCK;
Brian P. Hinz 4a11567
     Fl::e_state = state;
Brian P. Hinz 4a11567
     static char buffer[1024];
Brian P. Hinz 4a11567
-    if (uMsg == WM_CHAR || uMsg == WM_SYSCHAR) {
Brian P. Hinz 4a11567
 
Brian P. Hinz 4a11567
+    if (use_simple_keyboard) {
Brian P. Hinz 4a11567
+      BYTE keystate[256];
Brian P. Hinz 4a11567
+      WCHAR wbuf[8];
Brian P. Hinz 4a11567
+      int ret;
Brian P. Hinz 4a11567
+
Brian P. Hinz 4a11567
+      // I'm not sure if we ever get WM_CHAR (& friends) without an initial
Brian P. Hinz 4a11567
+      // WM_KEYDOWN (& friends), but if we do then we should not send such
Brian P. Hinz 4a11567
+      // side band events to simple keyboard widgets.
Brian P. Hinz 4a11567
+      if ((fl_orig_msg.message != WM_KEYDOWN) &&
Brian P. Hinz 4a11567
+          (fl_orig_msg.message != WM_SYSKEYDOWN) &&
Brian P. Hinz 4a11567
+          (fl_orig_msg.message != WM_KEYUP) &&
Brian P. Hinz 4a11567
+          (fl_orig_msg.message != WM_SYSKEYUP))
Brian P. Hinz 4a11567
+        break;
Brian P. Hinz 4a11567
+
Brian P. Hinz 4a11567
+      GetKeyboardState(keystate);
Brian P. Hinz 4a11567
+
Brian P. Hinz 4a11567
+      // Pressing Ctrl wreaks havoc with the symbol lookup, so turn that off.
Brian P. Hinz 4a11567
+      // But AltGr shows up as Ctrl+Alt in Windows, so keep Ctrl if Alt is
Brian P. Hinz 4a11567
+      // active.
Brian P. Hinz 4a11567
+      if (!(keystate[VK_MENU] & 0x80))
Brian P. Hinz 4a11567
+        keystate[VK_CONTROL] = keystate[VK_LCONTROL] = keystate[VK_RCONTROL] = 0;
Brian P. Hinz 4a11567
+
Brian P. Hinz 4a11567
+      // We cannot inspect or modify Windows' internal state of the keyboard
Brian P. Hinz 4a11567
+      // so we have to try to infer information from ToUnicode() and wedge
Brian P. Hinz 4a11567
+      // things into a known state.
Brian P. Hinz 4a11567
+      for (int i = 0;i < 2;i++) {
Brian P. Hinz 4a11567
+        ret = ToUnicode(fl_orig_msg.wParam, 0, keystate, wbuf,
Brian P. Hinz 4a11567
+                        sizeof(wbuf)/sizeof(wbuf[0]), 0);
Brian P. Hinz 4a11567
+
Brian P. Hinz 4a11567
+        // No symbol for this key (or unexpected length)
Brian P. Hinz 4a11567
+        if ((ret == 0) || (ret < -1)) {
Brian P. Hinz 4a11567
+          buffer[0] = 0;
Brian P. Hinz 4a11567
+          Fl::e_length = 0;
Brian P. Hinz 4a11567
+          break;
Brian P. Hinz 4a11567
+        }
Brian P. Hinz 4a11567
+
Brian P. Hinz 4a11567
+        // A dead key. Convert this to a Unicode combining character so
Brian P. Hinz 4a11567
+        // that the application can tell the difference between dead and
Brian P. Hinz 4a11567
+        // normal keys.
Brian P. Hinz 4a11567
+        if (ret == -1) {
Brian P. Hinz 4a11567
+          xchar u = (xchar) msdead2fltk(wbuf[0]);
Brian P. Hinz 4a11567
+          Fl::e_length = fl_utf8fromwc(buffer, 1024, &u, 1);
Brian P. Hinz 4a11567
+          buffer[Fl::e_length] = 0;
Brian P. Hinz 4a11567
+          break;
Brian P. Hinz 4a11567
+        }
Brian P. Hinz 4a11567
+
Brian P. Hinz 4a11567
+        // If we have two characters (or more) from ToUnicode(), that's
Brian P. Hinz 4a11567
+        // an invalid sequence. One character chould mean a proper symbol,
Brian P. Hinz 4a11567
+        // or it could mean a composed one. In both cases we need to call
Brian P. Hinz 4a11567
+        // ToUnicode() again to get something sane.
Brian P. Hinz 4a11567
+        if (i == 0)
Brian P. Hinz 4a11567
+          continue;
Brian P. Hinz 4a11567
+
Brian P. Hinz 4a11567
+        // We should now have something sane. Give whatever we have to the
Brian P. Hinz 4a11567
+        // application.
Brian P. Hinz 4a11567
+        Fl::e_length = fl_utf8fromwc(buffer, 1024, wbuf, ret);
Brian P. Hinz 4a11567
+        buffer[Fl::e_length] = 0;
Brian P. Hinz 4a11567
+      }
Brian P. Hinz 4a11567
+    } else if (uMsg == WM_CHAR || uMsg == WM_SYSCHAR) {
Brian P. Hinz 4a11567
       xchar u = (xchar) wParam;
Brian P. Hinz 4a11567
 //    Fl::e_length = fl_unicode2utf(&u, 1, buffer);
Brian P. Hinz 4a11567
       Fl::e_length = fl_utf8fromwc(buffer, 1024, &u, 1);
Brian P. Hinz 4a11567
       buffer[Fl::e_length] = 0;
Brian P. Hinz 4a11567
+    } else {
Brian P. Hinz 4a11567
+      buffer[0] = 0;
Brian P. Hinz 4a11567
+      Fl::e_length = 0;
Brian P. Hinz 4a11567
+    }
Brian P. Hinz 4a11567
 
Brian P. Hinz 4a11567
-
Brian P. Hinz 4a11567
-    } else if (Fl::e_keysym >= FL_KP && Fl::e_keysym <= FL_KP_Last) {
Brian P. Hinz 4a11567
-      if (state & FL_NUM_LOCK) {
Brian P. Hinz 4a11567
-        // Convert to regular keypress...
Brian P. Hinz 4a11567
-	buffer[0] = Fl::e_keysym-FL_KP;
Brian P. Hinz 4a11567
-	Fl::e_length = 1;
Brian P. Hinz 4a11567
-      } else {
Brian P. Hinz 4a11567
-        // Convert to special keypress...
Brian P. Hinz 4a11567
-	buffer[0] = 0;
Brian P. Hinz 4a11567
-	Fl::e_length = 0;
Brian P. Hinz 4a11567
+    // The keypad area is a bit odd in that we need to change the keysym
Brian P. Hinz 4a11567
+    // to properly indicate what the user meant, unlike other keys where
Brian P. Hinz 4a11567
+    // we normally change the text and keep keysym stable.
Brian P. Hinz 4a11567
+    if (Fl::e_keysym >= FL_KP && Fl::e_keysym <= FL_KP_Last) {
Brian P. Hinz 4a11567
+      // The initial mapping tables give us a keysym that corresponds to
Brian P. Hinz 4a11567
+      // numlock being on, so we only do something when it is off.
Brian P. Hinz 4a11567
+      if (!(state & FL_NUM_LOCK)) {
Brian P. Hinz 4a11567
 	switch (Fl::e_keysym) {
Brian P. Hinz 4a11567
 	  case FL_KP + '0' :
Brian P. Hinz 4a11567
 	    Fl::e_keysym = FL_Insert;
Brian P. Hinz 4a11567
@@ -1073,30 +1208,10 @@
Brian P. Hinz 4a11567
 	  case FL_KP + '.' :
Brian P. Hinz 4a11567
 	    Fl::e_keysym = FL_Delete;
Brian P. Hinz 4a11567
 	    break;
Brian P. Hinz 4a11567
-	  case FL_KP + '/' :
Brian P. Hinz 4a11567
-	  case FL_KP + '*' :
Brian P. Hinz 4a11567
-	  case FL_KP + '-' :
Brian P. Hinz 4a11567
-	  case FL_KP + '+' :
Brian P. Hinz 4a11567
-	    buffer[0] = Fl::e_keysym-FL_KP;
Brian P. Hinz 4a11567
-	    Fl::e_length = 1;
Brian P. Hinz 4a11567
-	    break;
Brian P. Hinz 4a11567
 	}
Brian P. Hinz 4a11567
       }
Brian P. Hinz 4a11567
-    } else if ((lParam & (1<<31))==0) {
Brian P. Hinz 4a11567
-#ifdef FLTK_PREVIEW_DEAD_KEYS
Brian P. Hinz 4a11567
-      if ((lParam & (1<<24))==0) { // clear if dead key (always?)
Brian P. Hinz 4a11567
-        xchar u = (xchar) wParam;
Brian P. Hinz 4a11567
-        Fl::e_length = fl_utf8fromwc(buffer, 1024, &u, 1);
Brian P. Hinz 4a11567
-        buffer[Fl::e_length] = 0;
Brian P. Hinz 4a11567
-      } else { // set if "extended key" (never printable?)
Brian P. Hinz 4a11567
-        buffer[0] = 0;
Brian P. Hinz 4a11567
-        Fl::e_length = 0;
Brian P. Hinz 4a11567
-      }
Brian P. Hinz 4a11567
-#else
Brian P. Hinz 4a11567
-      buffer[0] = 0;
Brian P. Hinz 4a11567
-      Fl::e_length = 0;
Brian P. Hinz 4a11567
-#endif
Brian P. Hinz 4a11567
     }
Brian P. Hinz 4a11567
+
Brian P. Hinz 4a11567
     Fl::e_text = buffer;
Brian P. Hinz 4a11567
     if (lParam & (1<<31)) { // key up events.
Brian P. Hinz 4a11567
       if (Fl::handle(FL_KEYUP, window)) return 0;