diff options
| author | Pierre Ossman <ossman@cendio.se> | 2014-09-15 09:44:35 +0000 |
|---|---|---|
| committer | Pierre Ossman <ossman@cendio.se> | 2014-09-15 09:44:35 +0000 |
| commit | 1c7409e0a12765282a121779ac59168c94de6ef5 (patch) | |
| tree | 7d3a5327dfef685e61f720c63ae2612ed5ab0b29 /src | |
| parent | 5101a8ea1c74729d6416278f043ec0de877706fe (diff) | |
Add methods to enable and disable the system's input methods.
This needs to be done from FLTK as it affects the window interaction,
which FLTK is largely responsible for.
git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3@10314 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
Diffstat (limited to 'src')
| -rw-r--r-- | src/Fl_cocoa.mm | 111 | ||||
| -rw-r--r-- | src/Fl_win32.cxx | 32 | ||||
| -rw-r--r-- | src/Fl_x.cxx | 67 |
3 files changed, 196 insertions, 14 deletions
diff --git a/src/Fl_cocoa.mm b/src/Fl_cocoa.mm index 9756c35dc..6b8e20ed6 100644 --- a/src/Fl_cocoa.mm +++ b/src/Fl_cocoa.mm @@ -92,6 +92,7 @@ static void cocoaMouseHandler(NSEvent *theEvent); static int calc_mac_os_version(); static void clipboard_check(void); static NSString *calc_utf8_format(void); +static void im_update(void); static unsigned make_current_counts = 0; // if > 0, then Fl_Window::make_current() can be called only once static Fl_X *fl_x_to_redraw = NULL; // set by Fl_X::flush() to the Fl_X object of the window to be redrawn @@ -116,6 +117,7 @@ static int main_screen_height; // height of menubar-containing screen used to co // through_drawRect = YES means the drawRect: message was sent to the view, // thus the graphics context was prepared by the system static BOOL through_drawRect = NO; +static int im_enabled = -1; #if CONSOLIDATE_MOTION static Fl_Window* send_motion; @@ -124,6 +126,29 @@ extern Fl_Window* fl_xmousewin; enum { FLTKTimerEvent = 1, FLTKDataReadyEvent }; +// Carbon functions and definitions + +typedef void *TSMDocumentID; + +extern "C" enum { + kTSMDocumentEnabledInputSourcesPropertyTag = 'enis' // from Carbon/TextServices.h +}; + +// Undocumented voodoo. Taken from Mozilla. +static const int smEnableRomanKybdsOnly = -23; + +typedef TSMDocumentID (*TSMGetActiveDocument_type)(void); +static TSMGetActiveDocument_type TSMGetActiveDocument; +typedef OSStatus (*TSMSetDocumentProperty_type)(TSMDocumentID, OSType, UInt32, void*); +static TSMSetDocumentProperty_type TSMSetDocumentProperty; +typedef OSStatus (*TSMRemoveDocumentProperty_type)(TSMDocumentID, OSType); +static TSMRemoveDocumentProperty_type TSMRemoveDocumentProperty; +typedef CFArrayRef (*TISCreateASCIICapableInputSourceList_type)(void); +static TISCreateASCIICapableInputSourceList_type TISCreateASCIICapableInputSourceList; + +typedef void (*KeyScript_type)(short); +static KeyScript_type KeyScript; + /* fltk-utf8 placekeepers */ void fl_reset_spot() @@ -1222,10 +1247,12 @@ static void cocoaMouseHandler(NSEvent *theEvent) #endif { void (*open_cb)(const char*); + TSMDocumentID currentDoc; } - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication*)sender; - (void)applicationDidBecomeActive:(NSNotification *)notify; - (void)applicationDidChangeScreenParameters:(NSNotification *)aNotification; +- (void)applicationDidUpdate:(NSNotification *)aNotification; - (void)applicationWillResignActive:(NSNotification *)notify; - (void)applicationWillHide:(NSNotification *)notify; - (void)applicationWillUnhide:(NSNotification *)notify; @@ -1283,6 +1310,23 @@ static void cocoaMouseHandler(NSEvent *theEvent) Fl::handle(FL_SCREEN_CONFIGURATION_CHANGED, NULL); fl_unlock_function(); } +- (void)applicationDidUpdate:(NSNotification *)aNotification +{ + if ((fl_mac_os_version >= 100500) && (im_enabled != -1) && + (TSMGetActiveDocument != NULL)) { + TSMDocumentID newDoc; + // It is extremely unclear when Cocoa decides to create/update + // the input context, but debugging reveals that it is done + // by NSApplication:updateWindows. So check if the input context + // has shifted after each such run so that we can update our + // input methods status. + newDoc = TSMGetActiveDocument(); + if (newDoc != currentDoc) { + im_update(); + currentDoc = newDoc; + } + } +} - (void)applicationWillResignActive:(NSNotification *)notify { fl_lock_function(); @@ -1420,6 +1464,13 @@ void fl_open_display() { static char beenHereDoneThat = 0; if ( !beenHereDoneThat ) { beenHereDoneThat = 1; + + TSMGetActiveDocument = (TSMGetActiveDocument_type)Fl_X::get_carbon_function("TSMGetActiveDocument"); + TSMSetDocumentProperty = (TSMSetDocumentProperty_type)Fl_X::get_carbon_function("TSMSetDocumentProperty"); + TSMRemoveDocumentProperty = (TSMRemoveDocumentProperty_type)Fl_X::get_carbon_function("TSMRemoveDocumentProperty"); + TISCreateASCIICapableInputSourceList = (TISCreateASCIICapableInputSourceList_type)Fl_X::get_carbon_function("TISCreateASCIICapableInputSourceList"); + + KeyScript = (KeyScript_type)Fl_X::get_carbon_function("KeyScript"); BOOL need_new_nsapp = (NSApp == nil); if (need_new_nsapp) [NSApplication sharedApplication]; @@ -1494,6 +1545,66 @@ void fl_open_display() { void fl_close_display() { } +// 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... + +static void im_update(void) { + if (fl_mac_os_version >= 100500) { + TSMDocumentID doc; + + if ((TSMGetActiveDocument == NULL) || + (TSMSetDocumentProperty == NULL) || + (TSMRemoveDocumentProperty == NULL) || + (TISCreateASCIICapableInputSourceList == NULL)) + return; + + doc = TSMGetActiveDocument(); + + if (im_enabled) + TSMRemoveDocumentProperty(doc, kTSMDocumentEnabledInputSourcesPropertyTag); + else { + CFArrayRef inputSources; + + inputSources = TISCreateASCIICapableInputSourceList(); + TSMSetDocumentProperty(doc, kTSMDocumentEnabledInputSourcesPropertyTag, + sizeof(CFArrayRef), &inputSources); + CFRelease(inputSources); + } + } else { + if (KeyScript == NULL) + return; + + if (im_enabled) + KeyScript(smKeyEnableKybds); + else + KeyScript(smEnableRomanKybdsOnly); + } +} + +void Fl::enable_im() { + fl_open_display(); + + im_enabled = 1; + + if (fl_mac_os_version >= 100500) + [NSApp updateWindows]; + else + im_update(); +} + +void Fl::disable_im() { + fl_open_display(); + + im_enabled = 0; + + if (fl_mac_os_version >= 100500) + [NSApp updateWindows]; + else + im_update(); +} + // Gets the border sizes and the titlebar size static void get_window_frame_sizes(int &bx, int &by, int &bt) { diff --git a/src/Fl_win32.cxx b/src/Fl_win32.cxx index 776bce1c0..ff6da442d 100644 --- a/src/Fl_win32.cxx +++ b/src/Fl_win32.cxx @@ -119,6 +119,8 @@ 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); @@ -131,6 +133,7 @@ static void get_imm_module() { 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"); @@ -460,6 +463,32 @@ public: }; 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() @@ -1878,6 +1907,9 @@ Fl_X* Fl_X::make(Fl_Window* w) { // Register all windows for potential drag'n'drop operations RegisterDragDrop(x->xid, flIDropTarget); + if (!im_enabled) + flImmAssociateContextEx(x->xid, 0, 0); + return x; } diff --git a/src/Fl_x.cxx b/src/Fl_x.cxx index 20041dfec..982369758 100644 --- a/src/Fl_x.cxx +++ b/src/Fl_x.cxx @@ -319,6 +319,7 @@ XVisualInfo *fl_visual; Colormap fl_colormap; static XIM fl_xim_im = 0; XIC fl_xim_ic = 0; +static Window fl_xim_win = 0; static char fl_is_over_the_spot = 0; static XRectangle status_area; @@ -614,6 +615,55 @@ static 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; @@ -1259,10 +1309,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); @@ -1278,19 +1327,9 @@ int fl_handle(const XEvent& thisevent) } if (fl_xim_ic && (xevent.type == FocusIn)) - { - 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); - } + fl_xim_activate(xid); - if ( XFilterEvent((XEvent *)&xevent, 0) ) + if (fl_xim_ic && XFilterEvent((XEvent *)&xevent, 0)) return(1); #if USE_XRANDR |
