summaryrefslogtreecommitdiffstats
path: root/contrib/fltk/02-str2599-fltk-1.3.x-keyboard-win32.patch
blob: c29d3b9744c17484f4254b945829dd17cf3505af (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
diff -ur fltk-1.3.0r9293.org/src/Fl_win32.cxx fltk-1.3.0r9293/src/Fl_win32.cxx
--- fltk-1.3.0r9293.org/src/Fl_win32.cxx	2012-06-18 09:07:56.522314557 +0200
+++ fltk-1.3.0r9293/src/Fl_win32.cxx	2012-06-18 09:08:07.392836285 +0200
@@ -87,6 +87,8 @@
 static Fl_Display_Device fl_gdi_display(&fl_gdi_driver);
 Fl_Display_Device *Fl_Display_Device::_display = &fl_gdi_display; // the platform display
 
+bool use_simple_keyboard = false;
+
 // dynamic wsock dll handling api:
 #if defined(__CYGWIN__) && !defined(SOCKET)
 # define SOCKET int
@@ -120,6 +122,8 @@
  * size and link dependencies.
  */
 static HMODULE s_imm_module = 0;
+typedef BOOL (WINAPI* flTypeImmAssociateContextEx)(HWND, HIMC, DWORD);
+static flTypeImmAssociateContextEx flImmAssociateContextEx = 0;
 typedef HIMC (WINAPI* flTypeImmGetContext)(HWND);
 static flTypeImmGetContext flImmGetContext = 0;
 typedef BOOL (WINAPI* flTypeImmSetCompositionWindow)(HIMC, LPCOMPOSITIONFORM);
@@ -135,6 +139,7 @@
     if (!s_imm_module)
       Fl::fatal("FLTK Lib Error: IMM32.DLL file not found!\n\n"
         "Please check your input method manager library accessibility.");
+    flImmAssociateContextEx = (flTypeImmAssociateContextEx)GetProcAddress(s_imm_module, "ImmAssociateContextEx");
     flImmGetContext = (flTypeImmGetContext)GetProcAddress(s_imm_module, "ImmGetContext");
     flImmSetCompositionWindow = (flTypeImmSetCompositionWindow)GetProcAddress(s_imm_module, "ImmSetCompositionWindow");
     flImmReleaseContext = (flTypeImmReleaseContext)GetProcAddress(s_imm_module, "ImmReleaseContext");
@@ -413,7 +418,12 @@
         }
       }
 
-      TranslateMessage(&fl_msg);
+      // Don't bother with key to character translation as we do
+      // it manually for simpley keyboard widgets. In fact, calling
+      // TranslateMessage() just makes it more difficult as it sets
+      // a bunch of internal state.
+      if (!use_simple_keyboard)
+        TranslateMessage(&fl_msg);
       DispatchMessageW(&fl_msg);
       have_message = PeekMessageW(&fl_msg, NULL, 0, 0, PM_REMOVE);
     }
@@ -638,6 +648,49 @@
   }
 }
 
+void fl_update_focus(void)
+{
+  Fl_Widget *focus;
+  Fl_Window *win;
+
+  get_imm_module();
+
+  focus = Fl::grab();
+  if (!focus)
+    focus = Fl::focus();
+  if (!focus)
+    return;
+
+  // Grabs are special in that events are sent to the first
+  // available window
+  if (focus == Fl::grab())
+    win = Fl::first_window();
+  else {
+    win = focus->as_window();
+    if (!win)
+      win = focus->window();
+  }
+
+  if (!win) {
+    Fl::warning("Cannot find window for widget receiving focus");
+    return;
+  }
+
+  // No Win32 window created yet
+  if (!Fl_X::i(win) || !fl_xid(win))
+    return;
+
+  if (focus->simple_keyboard()) {
+    use_simple_keyboard = true;
+    if (flImmGetContext(fl_xid(win)) != 0)
+      flImmAssociateContextEx(fl_xid(win), 0, 0);
+  } else {
+    use_simple_keyboard = false;
+    if (flImmGetContext(fl_xid(win)) == 0)
+      flImmAssociateContextEx(fl_xid(win), 0, IACE_DEFAULT);
+  }
+}
+
 HWND fl_capture;
 
 static int mouse_event(Fl_Window *window, int what, int button,
@@ -785,6 +838,27 @@
   return extended ? extendedlut[vk] : vklut[vk];
 }
 
+static xchar msdead2fltk(xchar in)
+{
+  switch (in) {
+  case 0x0060:      // GRAVE ACCENT
+    return 0x0300;  // COMBINING GRAVE ACCENT
+  case 0x00b4:      // ACUTE ACCENT
+    return 0x0301;  // COMBINING ACUTE ACCENT
+  case 0x005e:      // CIRCUMFLEX ACCENT
+    return 0x0302;  // COMBINING CIRCUMFLEX ACCENT
+  case 0x007e:      // TILDE
+    return 0x0303;  // COMBINING TILDE
+  case 0x00a8:      // DIAERESIS
+    return 0x0308;  // COMBINING DIAERESIS
+  // FIXME: Windows dead key behaviour isn't documented and I don't have
+  //        any more keyboards to test with...
+  }
+
+  // hope that Windows gave us something proper to begin with
+  return in;
+}
+
 #if USE_COLORMAP
 extern HPALETTE fl_select_palette(void); // in fl_color_win32.cxx
 #endif
@@ -846,6 +920,8 @@
   //fl_msg.pt = ???
   //fl_msg.lPrivate = ???
 
+  MSG fl_orig_msg = fl_msg;
+
   Fl_Window *window = fl_find(hWnd);
 
   if (window) switch (uMsg) {
@@ -1025,23 +1101,82 @@
     if (GetKeyState(VK_SCROLL)) state |= FL_SCROLL_LOCK;
     Fl::e_state = state;
     static char buffer[1024];
-    if (uMsg == WM_CHAR || uMsg == WM_SYSCHAR) {
 
+    if (use_simple_keyboard) {
+      BYTE keystate[256];
+      WCHAR wbuf[8];
+      int ret;
+
+      // I'm not sure if we ever get WM_CHAR (& friends) without an initial
+      // WM_KEYDOWN (& friends), but if we do then we should not send such
+      // side band events to simple keyboard widgets.
+      if ((fl_orig_msg.message != WM_KEYDOWN) &&
+          (fl_orig_msg.message != WM_SYSKEYDOWN) &&
+          (fl_orig_msg.message != WM_KEYUP) &&
+          (fl_orig_msg.message != WM_SYSKEYUP))
+        break;
+
+      GetKeyboardState(keystate);
+
+      // Pressing Ctrl wreaks havoc with the symbol lookup, so turn that off.
+      // But AltGr shows up as Ctrl+Alt in Windows, so keep Ctrl if Alt is
+      // active.
+      if (!(keystate[VK_MENU] & 0x80))
+        keystate[VK_CONTROL] = keystate[VK_LCONTROL] = keystate[VK_RCONTROL] = 0;
+
+      // We cannot inspect or modify Windows' internal state of the keyboard
+      // so we have to try to infer information from ToUnicode() and wedge
+      // things into a known state.
+      for (int i = 0;i < 2;i++) {
+        ret = ToUnicode(fl_orig_msg.wParam, 0, keystate, wbuf,
+                        sizeof(wbuf)/sizeof(wbuf[0]), 0);
+
+        // No symbol for this key (or unexpected length)
+        if ((ret == 0) || (ret < -1)) {
+          buffer[0] = 0;
+          Fl::e_length = 0;
+          break;
+        }
+
+        // A dead key. Convert this to a Unicode combining character so
+        // that the application can tell the difference between dead and
+        // normal keys.
+        if (ret == -1) {
+          xchar u = (xchar) msdead2fltk(wbuf[0]);
+          Fl::e_length = fl_utf8fromwc(buffer, 1024, &u, 1);
+          buffer[Fl::e_length] = 0;
+          break;
+        }
+
+        // If we have two characters (or more) from ToUnicode(), that's
+        // an invalid sequence. One character chould mean a proper symbol,
+        // or it could mean a composed one. In both cases we need to call
+        // ToUnicode() again to get something sane.
+        if (i == 0)
+          continue;
+
+        // We should now have something sane. Give whatever we have to the
+        // application.
+        Fl::e_length = fl_utf8fromwc(buffer, 1024, wbuf, ret);
+        buffer[Fl::e_length] = 0;
+      }
+    } else if (uMsg == WM_CHAR || uMsg == WM_SYSCHAR) {
       xchar u = (xchar) wParam;
 //    Fl::e_length = fl_unicode2utf(&u, 1, buffer);
       Fl::e_length = fl_utf8fromwc(buffer, 1024, &u, 1);
       buffer[Fl::e_length] = 0;
+    } else {
+      buffer[0] = 0;
+      Fl::e_length = 0;
+    }
 
-
-    } else if (Fl::e_keysym >= FL_KP && Fl::e_keysym <= FL_KP_Last) {
-      if (state & FL_NUM_LOCK) {
-        // Convert to regular keypress...
-	buffer[0] = Fl::e_keysym-FL_KP;
-	Fl::e_length = 1;
-      } else {
-        // Convert to special keypress...
-	buffer[0] = 0;
-	Fl::e_length = 0;
+    // The keypad area is a bit odd in that we need to change the keysym
+    // to properly indicate what the user meant, unlike other keys where
+    // we normally change the text and keep keysym stable.
+    if (Fl::e_keysym >= FL_KP && Fl::e_keysym <= FL_KP_Last) {
+      // The initial mapping tables give us a keysym that corresponds to
+      // numlock being on, so we only do something when it is off.
+      if (!(state & FL_NUM_LOCK)) {
 	switch (Fl::e_keysym) {
 	  case FL_KP + '0' :
 	    Fl::e_keysym = FL_Insert;
@@ -1073,30 +1208,10 @@
 	  case FL_KP + '.' :
 	    Fl::e_keysym = FL_Delete;
 	    break;
-	  case FL_KP + '/' :
-	  case FL_KP + '*' :
-	  case FL_KP + '-' :
-	  case FL_KP + '+' :
-	    buffer[0] = Fl::e_keysym-FL_KP;
-	    Fl::e_length = 1;
-	    break;
 	}
       }
-    } else if ((lParam & (1<<31))==0) {
-#ifdef FLTK_PREVIEW_DEAD_KEYS
-      if ((lParam & (1<<24))==0) { // clear if dead key (always?)
-        xchar u = (xchar) wParam;
-        Fl::e_length = fl_utf8fromwc(buffer, 1024, &u, 1);
-        buffer[Fl::e_length] = 0;
-      } else { // set if "extended key" (never printable?)
-        buffer[0] = 0;
-        Fl::e_length = 0;
-      }
-#else
-      buffer[0] = 0;
-      Fl::e_length = 0;
-#endif
     }
+
     Fl::e_text = buffer;
     if (lParam & (1<<31)) { // key up events.
       if (Fl::handle(FL_KEYUP, window)) return 0;