From 48ef54d59b7abbc06d660dbfe431708b10d8e3dc Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 19 Aug 2014 14:08:04 +0200 Subject: [PATCH] Disable input methods when the viewport is focused Input methods are way too complex for us to map them to the VNC protocol in any sane manner. Best just to disable them and rely on simple keyboard behaviour when the viewport is active. --- contrib/fltk/13-fltk-1.3.2-im.patch | 466 ++++++++++++++++++++++++++++ vncviewer/Viewport.cxx | 2 + 2 files changed, 468 insertions(+) create mode 100644 contrib/fltk/13-fltk-1.3.2-im.patch diff --git a/contrib/fltk/13-fltk-1.3.2-im.patch b/contrib/fltk/13-fltk-1.3.2-im.patch new file mode 100644 index 00000000..fbdcd785 --- /dev/null +++ b/contrib/fltk/13-fltk-1.3.2-im.patch @@ -0,0 +1,466 @@ +diff -up fltk-1.3.2/FL/Fl.H.im fltk-1.3.2/FL/Fl.H +--- fltk-1.3.2/FL/Fl.H.im 2014-07-25 14:28:52.771417210 +0200 ++++ fltk-1.3.2/FL/Fl.H 2014-07-25 14:28:52.774417261 +0200 +@@ -699,6 +699,17 @@ public: + static int event_inside(const Fl_Widget*); + static int test_shortcut(Fl_Shortcut); + ++ /** ++ Enables the system input methods facilities. This is the default. ++ \see disable_im() ++ */ ++ static void enable_im(); ++ /** ++ Disables the system input methods facilities. ++ \see enable_im() ++ */ ++ static void disable_im(); ++ + // event destinations: + static int handle(int, Fl_Window*); + static int handle_(int, Fl_Window*); +diff -up fltk-1.3.2/FL/win32.H.im fltk-1.3.2/FL/win32.H +--- fltk-1.3.2/FL/win32.H.im 2014-07-25 14:28:52.765417109 +0200 ++++ fltk-1.3.2/FL/win32.H 2014-07-25 14:28:52.774417261 +0200 +@@ -102,6 +102,8 @@ extern FL_EXPORT void fl_save_dc( HWND w + + inline Window fl_xid(const Fl_Window* w) { Fl_X *temp = Fl_X::i(w); return temp ? temp->xid : 0; } + ++extern FL_EXPORT void fl_open_display(); ++ + #else + FL_EXPORT Window fl_xid_(const Fl_Window* w); + #define fl_xid(w) fl_xid_(w) +diff -up fltk-1.3.2/src/Fl_cocoa.mm.im fltk-1.3.2/src/Fl_cocoa.mm +--- fltk-1.3.2/src/Fl_cocoa.mm.im 2014-07-25 14:37:30.656153283 +0200 ++++ fltk-1.3.2/src/Fl_cocoa.mm 2014-07-25 14:38:03.540708006 +0200 +@@ -53,6 +53,7 @@ extern "C" { + #include + + #import ++#import + + #ifndef NSINTEGER_DEFINED // appears with 10.5 in NSObjCRuntime.h + #if defined(__LP64__) && __LP64__ +@@ -1391,6 +1392,35 @@ void fl_close_display() { + } + + ++// Undocumented voodoo. Taken from Mozilla. ++#define ENABLE_ROMAN_KYBDS_ONLY -23 ++ ++void Fl::enable_im() { ++#if (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5) ++ TSMRemoveDocumentProperty(TSMGetActiveDocument(), ++ kTSMDocumentEnabledInputSourcesPropertyTag); ++#else ++ KeyScript(smKeyEnableKybds); ++#endif ++} ++ ++void Fl::disable_im() { ++ // Force a "Roman" or "ASCII" keyboard, which both the Mozilla and ++ // Safari people seem to think implies turning off advanced IME stuff ++ // (see nsTSMManager::SyncKeyScript in Mozilla and enableSecureTextInput ++ // in Safari/Webcore). Should be good enough for us then... ++#if (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5) ++ CFArrayRef inputSources = TISCreateASCIICapableInputSourceList(); ++ TSMSetDocumentProperty(TSMGetActiveDocument(), ++ kTSMDocumentEnabledInputSourcesPropertyTag, ++ sizeof(CFArrayRef), &inputSources); ++ CFRelease(inputSources); ++#else ++ KeyScript(ENABLE_ROMAN_KYBDS_ONLY); ++#endif ++} ++ ++ + // Gets the border sizes and the titlebar size + static void get_window_frame_sizes(int &bx, int &by, int &bt) { + static bool first = true; +diff -up fltk-1.3.2/src/Fl.cxx.im fltk-1.3.2/src/Fl.cxx +--- fltk-1.3.2/src/Fl.cxx.im 2014-07-25 14:28:52.772417227 +0200 ++++ fltk-1.3.2/src/Fl.cxx 2014-07-25 14:28:52.774417261 +0200 +@@ -593,45 +593,6 @@ int Fl::run() { + return 0; + } + +-#ifdef WIN32 +- +-// Function to initialize COM/OLE for usage. This must be done only once. +-// We define a flag to register whether we called it: +-static char oleInitialized = 0; +- +-// This calls the Windows function OleInitialize() exactly once. +-void fl_OleInitialize() { +- if (!oleInitialized) { +- OleInitialize(0L); +- oleInitialized = 1; +- } +-} +- +-// This calls the Windows function OleUninitialize() only, if +-// OleInitialize has been called before. +-void fl_OleUninitialize() { +- if (oleInitialized) { +- OleUninitialize(); +- oleInitialized = 0; +- } +-} +- +-class Fl_Win32_At_Exit { +-public: +- Fl_Win32_At_Exit() { } +- ~Fl_Win32_At_Exit() { +- fl_free_fonts(); // do some WIN32 cleanup +- fl_cleanup_pens(); +- fl_OleUninitialize(); +- fl_brush_action(1); +- fl_cleanup_dc_list(); +- } +-}; +-static Fl_Win32_At_Exit win32_at_exit; +-#endif +- +- +- + /** + Waits until "something happens" and then returns. Call this + repeatedly to "run" your program. You can also check what happened +diff -up fltk-1.3.2/src/Fl_Native_File_Chooser_WIN32.cxx.im fltk-1.3.2/src/Fl_Native_File_Chooser_WIN32.cxx +--- fltk-1.3.2/src/Fl_Native_File_Chooser_WIN32.cxx.im 2012-06-26 09:03:46.000000000 +0200 ++++ fltk-1.3.2/src/Fl_Native_File_Chooser_WIN32.cxx 2014-07-25 14:28:52.774417261 +0200 +@@ -34,6 +34,7 @@ LPCWSTR utf8towchar(const char *in); //M + char *wchartoutf8(LPCWSTR in); //MG + + #include ++#include + + #define LCURLY_CHR '{' + #define RCURLY_CHR '}' +@@ -41,8 +42,6 @@ char *wchartoutf8(LPCWSTR in); //MG + #define RBRACKET_CHR ']' + #define MAXFILTERS 80 + +-void fl_OleInitialize(); // in Fl.cxx (Windows only) +- + // STATIC: PRINT WINDOWS 'DOUBLE NULL' STRING (DEBUG) + #ifdef DEBUG + static void dnullprint(char *wp) { +@@ -471,7 +470,7 @@ int CALLBACK Fl_Native_File_Chooser::Dir + // SHOW DIRECTORY BROWSER + int Fl_Native_File_Chooser::showdir() { + // initialize OLE only once +- fl_OleInitialize(); // init needed by BIF_USENEWUI ++ fl_open_display(); // init needed by BIF_USENEWUI + ClearBINF(); + clear_pathnames(); + // PARENT WINDOW +diff -up fltk-1.3.2/src/Fl_win32.cxx.im fltk-1.3.2/src/Fl_win32.cxx +--- fltk-1.3.2/src/Fl_win32.cxx.im 2014-07-25 14:28:52.772417227 +0200 ++++ fltk-1.3.2/src/Fl_win32.cxx 2014-07-25 14:28:52.775417277 +0200 +@@ -60,8 +60,6 @@ + #include + #include + +-#include "aimm.h" +- + // + // USE_ASYNC_SELECT - define it if you have WSAAsyncSelect()... + // USE_ASYNC_SELECT is OBSOLETED in 1.3 for the following reasons: +@@ -121,27 +119,24 @@ static HMODULE get_wsock_mod() { + * 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); + static flTypeImmSetCompositionWindow flImmSetCompositionWindow = 0; + typedef BOOL (WINAPI* flTypeImmReleaseContext)(HWND, HIMC); + static flTypeImmReleaseContext flImmReleaseContext = 0; +-typedef BOOL (WINAPI* flTypeImmIsIME)(HKL); +-static flTypeImmIsIME flImmIsIME = 0; + +-static HMODULE get_imm_module() { +- if (!s_imm_module) { +- s_imm_module = LoadLibrary("IMM32.DLL"); +- if (!s_imm_module) +- Fl::fatal("FLTK Lib Error: IMM32.DLL file not found!\n\n" +- "Please check your input method manager library accessibility."); +- flImmGetContext = (flTypeImmGetContext)GetProcAddress(s_imm_module, "ImmGetContext"); +- flImmSetCompositionWindow = (flTypeImmSetCompositionWindow)GetProcAddress(s_imm_module, "ImmSetCompositionWindow"); +- flImmReleaseContext = (flTypeImmReleaseContext)GetProcAddress(s_imm_module, "ImmReleaseContext"); +- flImmIsIME = (flTypeImmIsIME)GetProcAddress(s_imm_module, "ImmIsIME"); +- } +- return s_imm_module; ++static void get_imm_module() { ++ s_imm_module = LoadLibrary("IMM32.DLL"); ++ 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"); + } + + // USE_TRACK_MOUSE - define NO_TRACK_MOUSE if you don't have +@@ -259,7 +254,9 @@ void fl_set_spot(int font, int size, int + Fl_Window* tw = win; + while (tw->parent()) tw = tw->window(); // find top level window + +- get_imm_module(); ++ if (!tw->shown()) ++ return; ++ + HIMC himc = flImmGetContext(fl_xid(tw)); + + if (himc) { +@@ -338,7 +335,6 @@ void* Fl::thread_message() { + + extern bool fl_send_xhandlers(void *e); + +-IActiveIMMApp *fl_aimm = NULL; + MSG fl_msg; + + // This is never called with time_to_wait < 0.0. +@@ -441,6 +437,58 @@ int fl_ready() { + return get_wsock_mod() ? s_wsock_select(0,&fdt[0],&fdt[1],&fdt[2],&t) : 0; + } + ++void fl_open_display() { ++ static char beenHereDoneThat = 0; ++ ++ if (beenHereDoneThat) ++ return; ++ ++ beenHereDoneThat = 1; ++ ++ OleInitialize(0L); ++ ++ get_imm_module(); ++} ++ ++class Fl_Win32_At_Exit { ++public: ++ Fl_Win32_At_Exit() { } ++ ~Fl_Win32_At_Exit() { ++ fl_free_fonts(); // do some WIN32 cleanup ++ fl_cleanup_pens(); ++ OleUninitialize(); ++ fl_brush_action(1); ++ fl_cleanup_dc_list(); ++ } ++}; ++static Fl_Win32_At_Exit win32_at_exit; ++ ++static char im_enabled = 1; ++ ++void Fl::enable_im() { ++ fl_open_display(); ++ ++ Fl_X* i = Fl_X::first; ++ while (i) { ++ flImmAssociateContextEx(i->xid, 0, IACE_DEFAULT); ++ i = i->next; ++ } ++ ++ im_enabled = 1; ++} ++ ++void Fl::disable_im() { ++ fl_open_display(); ++ ++ Fl_X* i = Fl_X::first; ++ while (i) { ++ flImmAssociateContextEx(i->xid, 0, 0); ++ i = i->next; ++ } ++ ++ im_enabled = 0; ++} ++ + //////////////////////////////////////////////////////////////// + + int Fl::x() +@@ -683,7 +731,6 @@ void fl_clipboard_notify_untarget(HWND w + } + + //////////////////////////////////////////////////////////////// +-char fl_is_ime = 0; + void fl_get_codepage() + { + HKL hkl = GetKeyboardLayout(0); +@@ -691,14 +738,8 @@ void fl_get_codepage() + + GetLocaleInfo (LOWORD(hkl), LOCALE_IDEFAULTANSICODEPAGE, ld, 6); + DWORD ccp = atol(ld); +- fl_is_ime = 0; + + fl_codepage = ccp; +- if (fl_aimm) { +- fl_aimm->GetCodePageA(GetKeyboardLayout(0), &fl_codepage); +- } else if (get_imm_module() && flImmIsIME(hkl)) { +- fl_is_ime = 1; +- } + } + + HWND fl_capture; +@@ -1564,6 +1605,8 @@ int fl_disable_transient_for; // secret + Fl_X* Fl_X::make(Fl_Window* w) { + Fl_Group::current(0); // get rid of very common user bug: forgot end() + ++ fl_open_display(); ++ + // if the window is a subwindow and our parent is not mapped yet, we + // mark this window visible, so that mapping the parent at a later + // point in time will call this function again to finally map the subwindow. +@@ -1767,16 +1810,10 @@ Fl_X* Fl_X::make(Fl_Window* w) { + (Fl::grab() || (styleEx & WS_EX_TOOLWINDOW)) ? SW_SHOWNOACTIVATE : SW_SHOWNORMAL); + + // Register all windows for potential drag'n'drop operations +- fl_OleInitialize(); + RegisterDragDrop(x->xid, flIDropTarget); + +- if (!fl_aimm) { +- CoCreateInstance(CLSID_CActiveIMM, NULL, CLSCTX_INPROC_SERVER, +- IID_IActiveIMMApp, (void**) &fl_aimm); +- if (fl_aimm) { +- fl_aimm->Activate(TRUE); +- } +- } ++ if (!im_enabled) ++ flImmAssociateContextEx(x->xid, 0, 0); + + return x; + } +diff -up fltk-1.3.2/src/Fl_x.cxx.im fltk-1.3.2/src/Fl_x.cxx +--- fltk-1.3.2/src/Fl_x.cxx.im 2014-07-25 14:28:52.773417244 +0200 ++++ fltk-1.3.2/src/Fl_x.cxx 2014-07-25 14:28:52.775417277 +0200 +@@ -313,6 +313,7 @@ XVisualInfo *fl_visual; + Colormap fl_colormap; + XIM fl_xim_im = 0; + XIC fl_xim_ic = 0; ++Window fl_xim_win = 0; + char fl_is_over_the_spot = 0; + static XRectangle status_area; + +@@ -603,6 +604,55 @@ void fl_init_xim() { + if(xim_styles) XFree(xim_styles); + } + ++void fl_xim_deactivate(void); ++ ++void fl_xim_activate(Window xid) { ++ if (!fl_xim_im) ++ return; ++ ++ // If the focused window has changed, then use the brute force method ++ // of completely recreating the input context. ++ if (fl_xim_win != xid) { ++ fl_xim_deactivate(); ++ ++ fl_new_ic(); ++ fl_xim_win = xid; ++ ++ XSetICValues(fl_xim_ic, ++ XNFocusWindow, fl_xim_win, ++ XNClientWindow, fl_xim_win, ++ NULL); ++ } ++ ++ fl_set_spot(spotf, spots, spot.x, spot.y, spot.width, spot.height); ++} ++ ++void fl_xim_deactivate(void) { ++ if (!fl_xim_ic) ++ return; ++ ++ XDestroyIC(fl_xim_ic); ++ fl_xim_ic = NULL; ++ ++ fl_xim_win = 0; ++} ++ ++void Fl::enable_im() { ++ Fl_Window *win; ++ ++ win = Fl::first_window(); ++ if (win && win->shown()) { ++ fl_xim_activate(fl_xid(win)); ++ XSetICFocus(fl_xim_ic); ++ } else { ++ fl_new_ic(); ++ } ++} ++ ++void Fl::disable_im() { ++ fl_xim_deactivate(); ++} ++ + void fl_open_display() { + if (fl_display) return; + +@@ -1053,10 +1103,9 @@ int fl_handle(const XEvent& thisevent) + XEvent xevent = thisevent; + fl_xevent = &thisevent; + Window xid = xevent.xany.window; +- static Window xim_win = 0; + + if (fl_xim_ic && xevent.type == DestroyNotify && +- xid != xim_win && !fl_find(xid)) ++ xid != fl_xim_win && !fl_find(xid)) + { + XIM xim_im; + xim_im = XOpenIM(fl_display, NULL, NULL, NULL); +@@ -1072,46 +1121,9 @@ int fl_handle(const XEvent& thisevent) + } + + if (fl_xim_ic && (xevent.type == FocusIn)) +- { +-#define POOR_XIM +-#ifdef POOR_XIM +- if (xim_win != xid) +- { +- xim_win = xid; +- XDestroyIC(fl_xim_ic); +- fl_xim_ic = NULL; +- fl_new_ic(); +- XSetICValues(fl_xim_ic, +- XNFocusWindow, xevent.xclient.window, +- XNClientWindow, xid, +- NULL); +- } +- fl_set_spot(spotf, spots, spot.x, spot.y, spot.width, spot.height); +-#else +- if (Fl::first_window() && Fl::first_window()->modal()) { +- Window x = fl_xid(Fl::first_window()); +- if (x != xim_win) { +- xim_win = x; +- XSetICValues(fl_xim_ic, +- XNFocusWindow, xim_win, +- XNClientWindow, xim_win, +- NULL); +- fl_set_spot(spotf, spots, spot.x, spot.y, spot.width, spot.height); +- } +- } else if (xim_win != xid && xid) { +- xim_win = xid; +- XSetICValues(fl_xim_ic, +- XNFocusWindow, xevent.xclient.window, +- XNClientWindow, xid, +- //XNFocusWindow, xim_win, +- //XNClientWindow, xim_win, +- NULL); +- fl_set_spot(spotf, spots, spot.x, spot.y, spot.width, spot.height); +- } +-#endif +- } ++ fl_xim_activate(xid); + +- if ( XFilterEvent((XEvent *)&xevent, 0) ) ++ if (fl_xim_ic && XFilterEvent((XEvent *)&xevent, 0)) + return(1); + + #if USE_XRANDR diff --git a/vncviewer/Viewport.cxx b/vncviewer/Viewport.cxx index 917a9817..81dc7ac0 100644 --- a/vncviewer/Viewport.cxx +++ b/vncviewer/Viewport.cxx @@ -410,6 +410,7 @@ int Viewport::handle(int event) return 1; case FL_FOCUS: + Fl::disable_im(); // Yes, we would like some focus please! return 1; @@ -418,6 +419,7 @@ int Viewport::handle(int event) // sense (e.g. Alt+Tab where we only see the Alt press) while (!downKeySym.empty()) handleKeyRelease(downKeySym.begin()->first); + Fl::enable_im(); return 1; case FL_KEYDOWN: -- 2.39.5