Browse Source

Mac OS text input: a single FL_KEYBOARD event is now sent when processing dead keys.

git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3@9812 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
pull/49/head
Manolo Gouy 13 years ago
parent
commit
b22744aac0
  1. 1
      FL/mac.H
  2. 3
      src/Fl.cxx
  3. 54
      src/Fl_cocoa.mm

1
FL/mac.H

@ -133,7 +133,6 @@ public:
static void screen_work_area(int &X, int &Y, int &W, int &H, int n); // compute work area of a given screen static void screen_work_area(int &X, int &Y, int &W, int &H, int n); // compute work area of a given screen
static int next_marked_length; // next length of marked text after current marked text will have been replaced static int next_marked_length; // next length of marked text after current marked text will have been replaced
static int insertion_point_location(int *px, int *py, int *pheight); // computes window coordinates & height of insertion point static int insertion_point_location(int *px, int *py, int *pheight); // computes window coordinates & height of insertion point
static int shortcut_events_since_keyDown; // to limit to one FL_SHORTCUT event per keyDown event.
private: private:
static void relink(Fl_Window*, Fl_Window*); static void relink(Fl_Window*, Fl_Window*);
bool subwindow; bool subwindow;

3
src/Fl.cxx

@ -1280,9 +1280,6 @@ int Fl::handle_(int e, Fl_Window* window)
e_number = e = FL_SHORTCUT; e_number = e = FL_SHORTCUT;
case FL_SHORTCUT: case FL_SHORTCUT:
#ifdef __APPLE__
if (Fl_X::shortcut_events_since_keyDown++ > 0) return 0;
#endif
if (grab()) {wi = grab(); break;} // send it to grab window if (grab()) {wi = grab(); break;} // send it to grab window
// Try it as shortcut, sending to mouse widget and all parents: // Try it as shortcut, sending to mouse widget and all parents:

54
src/Fl_cocoa.mm

@ -107,7 +107,6 @@ Window fl_window;
Fl_Window *Fl_Window::current_; Fl_Window *Fl_Window::current_;
int fl_mac_os_version = calc_mac_os_version(); // the version number of the running Mac OS X (e.g., 100604 for 10.6.4) int fl_mac_os_version = calc_mac_os_version(); // the version number of the running Mac OS X (e.g., 100604 for 10.6.4)
static SEL inputContextSEL = (fl_mac_os_version >= 100600 ? @selector(inputContext) : @selector(FLinputContext)); static SEL inputContextSEL = (fl_mac_os_version >= 100600 ? @selector(inputContext) : @selector(FLinputContext));
int Fl_X::shortcut_events_since_keyDown = INT_MIN;
// forward declarations of variables in this file // forward declarations of variables in this file
static int got_events = 0; static int got_events = 0;
@ -1633,6 +1632,13 @@ static void q_set_window_title(NSWindow *nsw, const char * name, const char *mi
When the character palette is used to enter text, the system sends an insertText: message to myview. The code processes it When the character palette is used to enter text, the system sends an insertText: message to myview. The code processes it
as an FL_PASTE event. The in_key_event field of the FLView class allows to differentiate keyboard from palette inputs. as an FL_PASTE event. The in_key_event field of the FLView class allows to differentiate keyboard from palette inputs.
During processing of the handleEvent message, inserted and marked strings are concatenated in a single string
inserted in a single FL_KEYBOARD event after return from handleEvent. The need_handle member variable of FLView allows
to determine when setMarkedText or insertText strings have been sent during handleEvent processing and must trigger
an FL_KEYBOARD event. Concatenating two insertText operations or an insertText followed by a setMarkedText is possible.
In contrast, setMarkedText followed by insertText or by another setMarkedText isn't correct if concatenated in a single
string. Thus, in such case, the setMarkedText and the next operation produce each an FL_KEYBOARD event.
OS >= 10.7 contains a feature where pressing and holding certain keys opens a menu window that shows a list OS >= 10.7 contains a feature where pressing and holding certain keys opens a menu window that shows a list
of possible accented variants of this key. The selectedRange field of the FLView class and the selectedRange, insertText: of possible accented variants of this key. The selectedRange field of the FLView class and the selectedRange, insertText:
and setMarkedText: methods of the NSTextInputClient protocol are used to support this feature. and setMarkedText: methods of the NSTextInputClient protocol are used to support this feature.
@ -1659,14 +1665,6 @@ static void q_set_window_title(NSWindow *nsw, const char * name, const char *mi
insertText: messages to the FLTextView object that are transmitted unchanged to myview to be processed as with OS >= 10.6. insertText: messages to the FLTextView object that are transmitted unchanged to myview to be processed as with OS >= 10.6.
The system also sends setMarkedText: messages directly to myview. The system also sends setMarkedText: messages directly to myview.
When 2 deadkeys are pressed in succession, the messages sent are [myview setMarkedText:] by the 1st keystroke and
[myview insertText:] [myview setMarkedText:] by the 2nd keystroke. Each of these messages creates an FL_KEYBOARD event,
so there are two FL_KEYBOARD events for the 2nd keystroke. If no widget in the window accepts keyboard input, FL_KEYBOARD
events are re-tried as FL_SHORTCUT events, which makes two FL_SHORTCUT events for a single keystroke. This is a problem
when these keystrokes are used as shortcuts. Such problem occurs, for example, with Alt+e on a US keyboard.
The Fl_X::shortcut_events_since_keyDown variable allows to transform only one FL_KEYBOARD event into an FL_SHORTCUT
event during processing of a keystroke, and thus fixes the double-shortcut problem.
There is furthermore an oddity of dead key processing with OS <= 10.5. It occurs when a dead key followed by a non-accented There is furthermore an oddity of dead key processing with OS <= 10.5. It occurs when a dead key followed by a non-accented
key are pressed. Say, for example, that keys '^' followed by 'p' are pressed on a French or German keyboard. Resulting key are pressed. Say, for example, that keys '^' followed by 'p' are pressed on a French or German keyboard. Resulting
messages are: [myview setMarkedText:@"^"], [myview insertText:@"^"], [myview insertText:@"p"], [FLTextView insertText:@"^p"]. messages are: [myview setMarkedText:@"^"], [myview insertText:@"^"], [myview insertText:@"p"], [FLTextView insertText:@"^p"].
@ -1737,11 +1735,13 @@ static void cocoaKeyboardHandler(NSEvent *theEvent)
, NSTextInputClient , NSTextInputClient
#endif #endif
> { > {
BOOL in_key_event; BOOL in_key_event; // YES means keypress is being processed by handleEvent
BOOL need_handle; // YES means Fl::handle(FL_KEYBOARD,) is needed after handleEvent processing
NSInteger identifier; NSInteger identifier;
NSRange selectedRange; NSRange selectedRange;
} }
+ (void)prepareEtext:(NSString*)aString; + (void)prepareEtext:(NSString*)aString;
+ (void)concatEtext:(NSString*)aString;
- (id)init; - (id)init;
- (void)drawRect:(NSRect)rect; - (void)drawRect:(NSRect)rect;
- (BOOL)acceptsFirstResponder; - (BOOL)acceptsFirstResponder;
@ -1817,7 +1817,9 @@ static void cocoaKeyboardHandler(NSEvent *theEvent)
} }
else { else {
in_key_event = YES; in_key_event = YES;
need_handle = NO;
handled = [[self performSelector:inputContextSEL] handleEvent:theEvent]; handled = [[self performSelector:inputContextSEL] handleEvent:theEvent];
if (need_handle) handled = Fl::handle(FL_KEYBOARD, [(FLWindow*)[theEvent window] getFl_Window]);
in_key_event = NO; in_key_event = NO;
} }
fl_unlock_function(); fl_unlock_function();
@ -1869,9 +1871,9 @@ static void cocoaKeyboardHandler(NSEvent *theEvent)
Fl::first_window(window); Fl::first_window(window);
cocoaKeyboardHandler(theEvent); cocoaKeyboardHandler(theEvent);
in_key_event = YES; in_key_event = YES;
Fl_X::shortcut_events_since_keyDown = 0; need_handle = NO;
[[self performSelector:inputContextSEL] handleEvent:theEvent]; [[self performSelector:inputContextSEL] handleEvent:theEvent];
Fl_X::shortcut_events_since_keyDown = INT_MIN; if (need_handle) Fl::handle(FL_KEYBOARD, window);
in_key_event = NO; in_key_event = NO;
fl_unlock_function(); fl_unlock_function();
} }
@ -2029,6 +2031,12 @@ static void cocoaKeyboardHandler(NSEvent *theEvent)
Fl::e_length = l; Fl::e_length = l;
} }
+ (void)concatEtext:(NSString*)aString {
// extends Fl::e_text with aString
NSString *newstring = [[NSString stringWithUTF8String:Fl::e_text] stringByAppendingString:aString];
[FLView prepareEtext:newstring];
}
- (void)doCommandBySelector:(SEL)aSelector { - (void)doCommandBySelector:(SEL)aSelector {
//NSLog(@"doCommandBySelector:%s",sel_getName(aSelector)); //NSLog(@"doCommandBySelector:%s",sel_getName(aSelector));
[FLView prepareEtext:[[NSApp currentEvent] characters]]; [FLView prepareEtext:[[NSApp currentEvent] characters]];
@ -2057,12 +2065,19 @@ static void cocoaKeyboardHandler(NSEvent *theEvent)
Fl::handle(FL_KEYBOARD, target); Fl::handle(FL_KEYBOARD, target);
Fl::e_keysym = saved_keysym; Fl::e_keysym = saved_keysym;
} }
[FLView prepareEtext:received]; if (in_key_event && Fl_X::next_marked_length && Fl::e_length) {
// if setMarkedText + insertText is sent during handleEvent, text cannot be concatenated in single FL_KEYBOARD event
Fl::handle(FL_KEYBOARD, target);
Fl::e_length = 0;
}
if (in_key_event && Fl::e_length) [FLView concatEtext:received];
else [FLView prepareEtext:received];
// We can get called outside of key events (e.g., from the character palette, from CJK text input). // We can get called outside of key events (e.g., from the character palette, from CJK text input).
// Transform character palette actions to FL_PASTE events. // Transform character palette actions to FL_PASTE events.
Fl_X::next_marked_length = 0; Fl_X::next_marked_length = 0;
int flevent = (in_key_event || Fl::marked_text_length()) ? FL_KEYBOARD : FL_PASTE; int flevent = (in_key_event || Fl::marked_text_length()) ? FL_KEYBOARD : FL_PASTE;
Fl::handle( flevent, target); if (!in_key_event) Fl::handle( flevent, target);
else need_handle = YES;
selectedRange = NSMakeRange(100, 0); // 100 is an arbitrary value selectedRange = NSMakeRange(100, 0); // 100 is an arbitrary value
// for some reason, with the palette, the window does not redraw until the next mouse move or button push // for some reason, with the palette, the window does not redraw until the next mouse move or button push
// sending a 'redraw()' or 'awake()' does not solve the issue! // sending a 'redraw()' or 'awake()' does not solve the issue!
@ -2094,9 +2109,16 @@ static void cocoaKeyboardHandler(NSEvent *theEvent)
Fl::handle(FL_KEYBOARD, target); Fl::handle(FL_KEYBOARD, target);
Fl::e_keysym = 'a'; // pretend a letter key was hit Fl::e_keysym = 'a'; // pretend a letter key was hit
} }
[FLView prepareEtext:received]; if (in_key_event && Fl_X::next_marked_length && Fl::e_length) {
Fl_X::next_marked_length = Fl::e_length; // if setMarkedText + setMarkedText is sent during handleEvent, text cannot be concatenated in single FL_KEYBOARD event
Fl::handle(FL_KEYBOARD, target); Fl::handle(FL_KEYBOARD, target);
Fl::e_length = 0;
}
if (in_key_event && Fl::e_length) [FLView concatEtext:received];
else [FLView prepareEtext:received];
Fl_X::next_marked_length = strlen([received UTF8String]);
if (!in_key_event) Fl::handle( FL_KEYBOARD, target);
else need_handle = YES;
selectedRange = NSMakeRange(100, newSelection.length); selectedRange = NSMakeRange(100, newSelection.length);
fl_unlock_function(); fl_unlock_function();
} }

Loading…
Cancel
Save