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
This commit is contained in:
Pierre Ossman 2014-09-15 09:44:35 +00:00
parent 5101a8ea1c
commit 1c7409e0a1
4 changed files with 207 additions and 14 deletions

11
FL/Fl.H
View File

@ -757,6 +757,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*);

View File

@ -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) {

View File

@ -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;
}

View File

@ -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