diff options
| author | Manolo Gouy <Manolo> | 2011-04-27 11:21:57 +0000 |
|---|---|---|
| committer | Manolo Gouy <Manolo> | 2011-04-27 11:21:57 +0000 |
| commit | 73a6f06c3425f2e77282a1e6ee38d23620b859dc (patch) | |
| tree | 8b9f910af440f04fdd6e344301adbefb7a63dd73 | |
| parent | 0f5ea9a2e23328203e7e8d8142b6919f88ccac8d (diff) | |
Reorganized keyboard input-handling code.
git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3@8626 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
| -rw-r--r-- | src/Fl_cocoa.mm | 298 | ||||
| -rw-r--r-- | src/Fl_compose.cxx | 3 |
2 files changed, 160 insertions, 141 deletions
diff --git a/src/Fl_cocoa.mm b/src/Fl_cocoa.mm index 7ed48cc7c..9d05181a1 100644 --- a/src/Fl_cocoa.mm +++ b/src/Fl_cocoa.mm @@ -167,9 +167,9 @@ static unsigned short macKeyLookUp[128] = FL_KP+'6', FL_KP+'7', 0, FL_KP+'8', FL_KP+'9', 0, 0, 0, FL_F+5, FL_F+6, FL_F+7, FL_F+3, FL_F+8, FL_F+9, 0, FL_F+11, - 0, 0/*FL_F+13*/, FL_Print, FL_Scroll_Lock, 0, FL_F+10, FL_Menu, FL_F+12, + 0, FL_F+13, FL_F+16, FL_F+14, 0, FL_F+10, FL_Menu, FL_F+12, - 0, FL_Pause, FL_Help, FL_Home, FL_Page_Up, FL_Delete, FL_F+4, FL_End, + 0, FL_F+15, FL_Help, FL_Home, FL_Page_Up, FL_Delete, FL_F+4, FL_End, FL_F+2, FL_Page_Down, FL_F+1, FL_Left, FL_Right, FL_Down, FL_Up, 0/*FL_Power*/, }; @@ -191,23 +191,6 @@ static unsigned int mods_to_e_state( NSUInteger mods ) return ret; } - -/* - * convert the current key chord into the FLTK keysym - */ - - /*static void mods_to_e_keysym( NSUInteger mods ) - { - if ( mods & NSCommandKeyMask ) Fl::e_keysym = FL_Meta_L; - else if ( mods & NSNumericPadKeyMask ) Fl::e_keysym = FL_Num_Lock; - else if ( mods & NSAlternateKeyMask ) Fl::e_keysym = FL_Alt_L; - else if ( mods & NSControlKeyMask ) Fl::e_keysym = FL_Control_L; - else if ( mods & NSShiftKeyMask ) Fl::e_keysym = FL_Shift_L; - else if ( mods & NSAlphaShiftKeyMask ) Fl::e_keysym = FL_Caps_Lock; - else Fl::e_keysym = 0; - //printf( "to sym 0x%08x (%04x)\n", Fl::e_keysym, mods ); - }*/ - // these pointers are set by the Fl::lock() function: static void nothing() {} void (*fl_lock_function)() = nothing; @@ -590,9 +573,7 @@ static void do_timer(CFRunLoopTimerRef timer, void* data) } - (FLWindow*)initWithFl_W:(Fl_Window *)flw contentRect:(NSRect)rect - styleMask:(NSUInteger)windowStyle - backing:(NSBackingStoreType)bufferingType - defer:(BOOL)deferCreation; + styleMask:(NSUInteger)windowStyle; - (Fl_Window *)getFl_Window; - (BOOL)windowShouldClose:(FLWindow *)w; - (BOOL)containsGLsubwindow; @@ -603,10 +584,8 @@ static void do_timer(CFRunLoopTimerRef timer, void* data) - (FLWindow*)initWithFl_W:(Fl_Window *)flw contentRect:(NSRect)rect styleMask:(NSUInteger)windowStyle - backing:(NSBackingStoreType)bufferingType - defer:(BOOL)deferCreation { - self = [super initWithContentRect:rect styleMask:windowStyle backing:bufferingType defer:deferCreation]; + self = [super initWithContentRect:rect styleMask:windowStyle backing:NSBackingStoreBuffered defer:NO]; if (self) { w = flw; containsGLsubwindow = NO; @@ -848,35 +827,6 @@ static void cocoaMouseHandler(NSEvent *theEvent) return; } - -static void calc_e_text(CFStringRef s, char *buffer, size_t len, unsigned sym) -{ - int i, no_text_key = false; - static unsigned notext[] = { // keys that don't emit text - FL_BackSpace, FL_Print, FL_Scroll_Lock, FL_Pause, - FL_Insert, FL_Home, FL_Page_Up, FL_Delete, FL_End, FL_Page_Down, - FL_Left, FL_Up, FL_Right, FL_Down, - FL_Menu, FL_Num_Lock, FL_Help - }; - int count = sizeof(notext)/sizeof(int); - - if (sym > FL_F && sym <= FL_F_Last) no_text_key = true; - else for (i=0; i < count; i++) { - if (notext[i] == sym) { - no_text_key = true; - break; - } - } - - if (no_text_key) { - buffer[0] = 0; - } else { - CFStringGetCString(s, buffer, len, kCFStringEncodingUTF8); - } -} - -static int cocoaKeyboardHandler(NSEvent *theEvent); - @interface FLTextView : NSTextView // this subclass is needed under OS X <= 10.4 but not under >= 10.5 where the base class is enough { @@ -885,11 +835,11 @@ static int cocoaKeyboardHandler(NSEvent *theEvent); @implementation FLTextView - (void)insertText:(id)aString { - cocoaKeyboardHandler([NSApp currentEvent]); + [[[NSApp keyWindow] contentView] insertText:aString]; } - (void)doCommandBySelector:(SEL)aSelector { - cocoaKeyboardHandler([NSApp currentEvent]); + [[[NSApp keyWindow] contentView] doCommandBySelector:aSelector]; } @end @@ -897,20 +847,14 @@ static int cocoaKeyboardHandler(NSEvent *theEvent); Handle cocoa keyboard events Events during a character composition sequence: - keydown with deadkey -> [[theEvent characters] length] is 0 - - keyup -> [theEvent characters] contains the deadkey: display it temporarily - - keydown with next key -> [theEvent characters] contains the composed character: - replace the temporary character by this one + - keyup -> [theEvent characters] contains the deadkey + - keydown with next key -> [theEvent characters] contains the composed character - keyup -> [theEvent characters] contains the standard character */ -static int cocoaKeyboardHandler(NSEvent *theEvent) +static void cocoaKeyboardHandler(NSEvent *theEvent) { - static char buffer[32]; - int sendEvent = 0, retval = 0; - Fl_Window *window = (Fl_Window*)[(FLWindow*)[theEvent window] getFl_Window]; - Fl::first_window(window); NSUInteger mods; - fl_lock_function(); // get the modifiers mods = [theEvent modifierFlags]; // get the key code @@ -926,40 +870,30 @@ static int cocoaKeyboardHandler(NSEvent *theEvent) // In this mode, there seem to be no key-down codes // printf("%08x %08x %08x\n", keyCode, mods, key); maskedKeyCode = keyCode & 0x7f; - switch([theEvent type]) { - case NSKeyDown: - sendEvent = FL_KEYBOARD; - // fall through - case NSKeyUp: - if ( !sendEvent ) { - sendEvent = FL_KEYUP; - Fl::e_state &= 0xbfffffff; // clear the deadkey flag - } - mods_to_e_state( mods ); // process modifier keys - sym = macKeyLookUp[maskedKeyCode]; - if (sym < 0xff00) { // a "simple" key - // find the result of this key without modifier - NSString *sim = [theEvent charactersIgnoringModifiers]; - UniChar one; - CFStringGetCharacters((CFStringRef)sim, CFRangeMake(0, 1), &one); - // charactersIgnoringModifiers doesn't ignore shift, remove it when it's on - if(one >= 'A' && one <= 'Z') one += 32; - if (one > 0 && one <= 0x7f && (sym<'0' || sym>'9') ) sym = one; - } - Fl::e_keysym = Fl::e_original_keysym = sym; - // Handle FL_KP_Enter on regular keyboards and on Powerbooks - if ( maskedKeyCode==0x4c || maskedKeyCode==0x34) s = @"\r"; - calc_e_text((CFStringRef)s, buffer, sizeof(buffer), sym); - Fl::e_length = strlen(buffer); - Fl::e_text = buffer; - default: // prevent 'not handled in switch' warnings - break; + + if ([theEvent type] == NSKeyUp) { + Fl::e_state &= 0xbfffffff; // clear the deadkey flag } - if (sendEvent) { - retval = Fl::handle(sendEvent,window); + + mods_to_e_state( mods ); // process modifier keys + sym = macKeyLookUp[maskedKeyCode]; + if (sym < 0xff00) { // a "simple" key + // find the result of this key without modifier + NSString *sim = [theEvent charactersIgnoringModifiers]; + UniChar one; + CFStringGetCharacters((CFStringRef)sim, CFRangeMake(0, 1), &one); + // charactersIgnoringModifiers doesn't ignore shift, remove it when it's on + if(one >= 'A' && one <= 'Z') one += 32; + if (one > 0 && one <= 0x7f && (sym<'0' || sym>'9') ) sym = one; } - fl_unlock_function(); - return retval; + Fl::e_keysym = Fl::e_original_keysym = sym; + + //NSLog(@"cocoaKeyboardHandler: keycode=%08x keysym=%08x mods=%08x symbol=%@ (%@)", + // keyCode, sym, mods, [theEvent characters], [theEvent charactersIgnoringModifiers]); + + // If there is text associated with this key, it will be filled in later. + Fl::e_length = 0; + Fl::e_text = (char*)""; } @@ -1637,7 +1571,11 @@ static void q_set_window_title(NSWindow *nsw, const char * name ) { @interface FLView : NSView <NSTextInput> { + int next_compose_length; + bool in_key_event; } ++ (void)prepareEtext:(NSString*)aString; +- (id)init; - (void)drawRect:(NSRect)rect; - (BOOL)acceptsFirstResponder; - (BOOL)acceptsFirstMouse:(NSEvent*)theEvent; @@ -1653,6 +1591,7 @@ static void q_set_window_title(NSWindow *nsw, const char * name ) { - (void)rightMouseDragged:(NSEvent *)theEvent; - (void)otherMouseDragged:(NSEvent *)theEvent; - (void)scrollWheel:(NSEvent *)theEvent; +- (BOOL)handleKeyDown:(NSEvent *)theEvent; - (void)keyDown:(NSEvent *)theEvent; - (void)keyUp:(NSEvent *)theEvent; - (void)flagsChanged:(NSEvent *)theEvent; @@ -1664,6 +1603,15 @@ static void q_set_window_title(NSWindow *nsw, const char * name ) { @end @implementation FLView +- (id)init +{ + self = [super init]; + if (self) { + next_compose_length = -1; + in_key_event = false; + } + return self; +} - (void)drawRect:(NSRect)rect { fl_lock_function(); @@ -1679,8 +1627,8 @@ static void q_set_window_title(NSWindow *nsw, const char * name ) { } - (BOOL)performKeyEquivalent:(NSEvent*)theEvent { - int retval = cocoaKeyboardHandler(theEvent); - return (retval ? YES : NO); + //NSLog(@"performKeyEquivalent:"); + return [self handleKeyDown:theEvent]; } - (BOOL)acceptsFirstMouse:(NSEvent*)theEvent { @@ -1721,14 +1669,65 @@ static void q_set_window_title(NSWindow *nsw, const char * name ) { - (void)scrollWheel:(NSEvent *)theEvent { cocoaMouseWheelHandler(theEvent); } +- (BOOL)handleKeyDown:(NSEvent *)theEvent { + //NSLog(@"handleKeyDown"); + fl_lock_function(); + + Fl_Window *window = (Fl_Window*)[(FLWindow*)[theEvent window] getFl_Window]; + Fl::first_window(window); + + next_compose_length = -1; + // First let's process the raw key press + cocoaKeyboardHandler(theEvent); + + int no_text_key = false; + static const int notext[] = { // keys that don't emit text + FL_BackSpace, FL_Print, FL_Scroll_Lock, FL_Pause, + FL_Insert, FL_Home, FL_Page_Up, FL_Delete, FL_End, FL_Page_Down, + FL_Left, FL_Up, FL_Right, FL_Down, + FL_Menu, FL_Num_Lock, FL_Help + }; + static const int count = sizeof(notext)/sizeof(int); + if (Fl::e_keysym > FL_F && Fl::e_keysym <= FL_F_Last) no_text_key = true; + else for (int i=0; i < count; i++) { + if (notext[i] == Fl::e_keysym) { + no_text_key = true; + break; + } + } + if (!no_text_key) { + // Then we can let the OS have a stab at it and see if it thinks it + // should result in some text + NSText *edit = [[theEvent window] fieldEditor:YES forObject:nil]; + in_key_event = true; + [edit interpretKeyEvents:[NSArray arrayWithObject:theEvent]]; + in_key_event = false; + } + //NSLog(@"to text=%@ l=%d", [NSString stringWithUTF8String:Fl::e_text], Fl::e_length); + int handled = Fl::handle(FL_KEYDOWN, window); + // We have to update this after Fl::handle as it says what to do on the + // _next_ input + if (next_compose_length != -1) + Fl::compose_state = next_compose_length; + + fl_unlock_function(); + return (handled ? YES : NO); +} - (void)keyDown:(NSEvent *)theEvent { - NSText *edit = [[theEvent window] fieldEditor:YES forObject:nil]; - [edit interpretKeyEvents:[NSArray arrayWithObject:theEvent]]; + //NSLog(@"keyDown: "); + [self handleKeyDown:theEvent]; } - (void)keyUp:(NSEvent *)theEvent { + //NSLog(@"keyUp: "); + fl_lock_function(); + Fl_Window *window = (Fl_Window*)[(FLWindow*)[theEvent window] getFl_Window]; + Fl::first_window(window); cocoaKeyboardHandler(theEvent); + Fl::handle(FL_KEYUP,window); + fl_unlock_function(); } - (void)flagsChanged:(NSEvent *)theEvent { + //NSLog(@"flagsChanged: "); fl_lock_function(); static UInt32 prevMods = 0; NSUInteger mods = [theEvent modifierFlags]; @@ -1737,7 +1736,6 @@ static void q_set_window_title(NSWindow *nsw, const char * name ) { int sendEvent = 0; if ( tMods ) { - //mods_to_e_keysym( tMods ); unsigned short keycode = [theEvent keyCode]; Fl::e_keysym = macKeyLookUp[keycode & 0x7f]; if ( Fl::e_keysym ) @@ -1836,6 +1834,27 @@ static void q_set_window_title(NSWindow *nsw, const char * name ) { return NSDragOperationGeneric; } ++ (void)prepareEtext:(NSString*)aString { + // fills Fl::e_text with UTF-8 encoded aString using an adequate memory allocation + static char *received_utf8 = NULL; + static int lreceived = 0; + char *p = (char*)[aString UTF8String]; + int l = strlen(p); + if (l > 0) { + if (lreceived == 0) { + received_utf8 = (char*)malloc(l + 1); + lreceived = l; + } + else if (l > lreceived) { + received_utf8 = (char*)realloc(received_utf8, l + 1); + lreceived = l; + } + strcpy(received_utf8, p); + Fl::e_text = received_utf8; + } + Fl::e_length = l; +} + // These functions implement text input. // Only two-stroke character composition works at this point. // Needs much elaboration to fully support CJK text input, @@ -1844,48 +1863,51 @@ static void q_set_window_title(NSWindow *nsw, const char * name ) { } - (void)insertText:(id)aString { - NSEvent *event = [NSApp currentEvent]; - NSEventType type = [event type]; - NSString *str = @""; NSString *received; if ([aString isKindOfClass:[NSAttributedString class]]) { received = [(NSAttributedString*)aString string]; } else { received = (NSString*)aString; } - if (type == NSKeyDown ) { - str = [event characters]; - } - if ([received isEqualToString:@"\b"] || [str isEqualToString:received]) { - if (type == NSKeyDown ) cocoaKeyboardHandler(event); - } else { - fl_lock_function(); - Fl_Window *window = [(FLWindow*)[NSApp keyWindow] getFl_Window]; - Fl::e_text = (char*)[received UTF8String]; - Fl::e_length = strlen(Fl::e_text); - if (type == NSKeyDown ) { - Fl::e_keysym = macKeyLookUp[ [event keyCode] & 0x7f] ; - Fl::handle(FL_KEYBOARD, window); - } - else { - Fl::handle(FL_PASTE, window); - // for some reason, the window does not redraw until the next mouse move or button push - // sending a 'redraw()' or 'awake()' does not solve the issue! - Fl::flush(); - } - fl_unlock_function(); + //NSLog(@"insertText: received=%@",received); + + if (!in_key_event) fl_lock_function(); + [FLView prepareEtext:received]; + // We can get called outside of key events (e.g. from the character + // palette). Transform such actions to FL_PASTE events. + if (!in_key_event) { + Fl_Window *target = [(FLWindow*)[self window] getFl_Window]; + Fl::handle(FL_PASTE, target); + // for some reason, the window does not redraw until the next mouse move or button push + // sending a 'redraw()' or 'awake()' does not solve the issue! + Fl::flush(); } + if (!in_key_event) fl_unlock_function(); } - (void)setMarkedText:(id)aString selectedRange:(NSRange)newSelection { - // NSLog(@"setMarkedText: %@ %d %d Fl::compose_state=%d", - // aString,newSelection.location,newSelection.length,newSelection.location); - [self insertText:aString]; - Fl::compose_state = newSelection.location; + NSString *received; + if (newSelection.location == 0) { + [self unmarkText]; + return; + } + if ([aString isKindOfClass:[NSAttributedString class]]) { + received = [(NSAttributedString*)aString string]; + } else { + received = (NSString*)aString; + } + //NSLog(@"setMarkedText: %@ %d %d",received,newSelection.location,newSelection.length); + // This code creates the OS X behaviour of seeing dead keys as things + // are being composed. + next_compose_length = newSelection.location; + [FLView prepareEtext:received]; + //NSLog(@"Fl::e_text=%@ Fl::e_length=%d next_compose_length=%d", received, Fl::e_length, next_compose_length); } - (void)unmarkText { + fl_lock_function(); Fl::compose_state = 0; + fl_unlock_function(); //NSLog(@"unmarkText"); } @@ -1928,8 +1950,8 @@ static void q_set_window_title(NSWindow *nsw, const char * name ) { glyphRect.origin.y = (CGFloat)y + current->textsize(); glyphRect.size.height = current->textsize(); } else { - glyphRect.origin.x = (CGFloat)Fl::event_x(); - glyphRect.origin.y = (CGFloat)Fl::event_y() + 12; + glyphRect.origin.x = focus->x(); + glyphRect.origin.y = focus->y() + focus->h(); glyphRect.size.height = 12; } // Convert the rect to screen coordinates @@ -2077,9 +2099,7 @@ void Fl_X::make(Fl_Window* w) crect.size.height=w->h(); FLWindow *cw = [[FLWindow alloc] initWithFl_W:w contentRect:crect - styleMask:winstyle - backing:NSBackingStoreBuffered - defer:NO]; + styleMask:winstyle]; [cw setHasShadow:YES]; [cw setAcceptsMouseMovedEvents:YES]; x->xid = cw; @@ -2108,10 +2128,10 @@ void Fl_X::make(Fl_Window* w) // Install DnD handlers [myview registerForDraggedTypes:[NSArray arrayWithObjects: NSStringPboardType, NSFilenamesPboardType, nil]]; - if ( ! Fl_X::first->next ) { // if this is the first window, we need to bring the application to the front - ProcessSerialNumber psn; - OSErr err = GetCurrentProcess( &psn ); - if ( err==noErr ) SetFrontProcess( &psn ); + if ( ! Fl_X::first->next ) { + // if this is the first window, we need to bring the application to the front + ProcessSerialNumber psn = { 0, kCurrentProcess }; + SetFrontProcess( &psn ); } if (w->size_range_set) w->size_range_(); diff --git a/src/Fl_compose.cxx b/src/Fl_compose.cxx index f6b05f3a2..4c8235157 100644 --- a/src/Fl_compose.cxx +++ b/src/Fl_compose.cxx @@ -29,7 +29,6 @@ #include <FL/x.H> #ifndef FL_DOXYGEN -// at present, this is effectively used by Mac OS X only int Fl::compose_state = 0; #endif @@ -74,8 +73,8 @@ int Fl::compose(int& del) { if(Fl::compose_state) { del = Fl::compose_state; Fl::compose_state = 0; - } else { #ifndef __APPLE__ + } else { // Only insert non-control characters: if (! (ascii & ~31 && ascii!=127)) { return 0; } #endif |
