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;