From 17b40fcb9d1fc9f45457006027a874e05f9f1ae5 Mon Sep 17 00:00:00 2001 From: Andreas Date: Tue, 22 Jun 2010 16:04:44 +0200 Subject: [PATCH 1/4] Adapt CPTextField to use interpretKeyEvents and actions instead of directly reading from keyDown --- AppKit/CPTextField.j | 86 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 70 insertions(+), 16 deletions(-) diff --git a/AppKit/CPTextField.j b/AppKit/CPTextField.j index e355c926b..660c43e65 100644 --- a/AppKit/CPTextField.j +++ b/AppKit/CPTextField.j @@ -672,25 +672,79 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); - (void)keyDown:(CPEvent)anEvent { - if ([anEvent keyCode] === CPReturnKeyCode) - { - if (_isEditing) - { - _isEditing = NO; - [self textDidEndEditing:[CPNotification notificationWithName:CPControlTextDidEndEditingNotification object:self userInfo:nil]]; - } - - [self sendAction:[self action] to:[self target]]; - [self selectText:nil]; - - [[[self window] platformWindow] _propagateCurrentDOMEvent:NO]; - } - else - [[[self window] platformWindow] _propagateCurrentDOMEvent:YES]; - + if ([anEvent _couldBeKeyEquivalent] && [self performKeyEquivalent:anEvent]) + return; + + // CPTextField uses an HTML input element to take the input so we need to + // propagate the dom event so the element is updated. This has to be done + // before interpretKeyEvents: though so individual commands have a chance + // to override this (tab to go to the next keyView and such). + [[[self window] platformWindow] _propagateCurrentDOMEvent:YES]; + + [self interpretKeyEvents:[anEvent]]; + [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode]; } +/*! + Invoke the action specified by aSelector on the current responder. + + This is implemented by CPResponder and by default it passes any unrecignized + actions on to the next responder but text fields appearently aren't supposed + to do that according to this documentation by Apple: + + http://developer.apple.com/mac/library/documentation/cocoa/reference/NSTextInputClient_Protocol/Reference/Reference.html#//apple_ref/occ/intfm/NSTextInputClient/doCommandBySelector: +*/ +- (void)doCommandBySelector:(SEL)aSelector +{ + if ([self respondsToSelector:aSelector]) + [self performSelector:aSelector]; +} + +- (void)insertNewline:(id)sender +{ + if (_isEditing) + { + _isEditing = NO; + [self textDidEndEditing:[CPNotification notificationWithName:CPControlTextDidEndEditingNotification object:self userInfo:nil]]; + } + + [self sendAction:[self action] to:[self target]]; + [self selectText:nil]; + + [[[self window] platformWindow] _propagateCurrentDOMEvent:NO]; +} + +- (void)selectNextKeyView:(id)sender +{ + [[self window] selectNextKeyView:self]; + + if ([[[self window] firstResponder] respondsToSelector:@selector(selectText:)]) + [[[self window] firstResponder] selectText:self]; + + [[[self window] platformWindow] _propagateCurrentDOMEvent:NO]; +} + +- (void)selectPreviousKeyView:(id)sender +{ + [[self window] selectPreviousKeyView:self]; + + if ([[[self window] firstResponder] respondsToSelector:@selector(selectText:)]) + [[[self window] firstResponder] selectText:self]; + + [[[self window] platformWindow] _propagateCurrentDOMEvent:NO]; +} + +- (void)insertTab:(id)sender +{ + [self selectNextKeyView:sender]; +} + +- (void)insertBacktab:(id)sender +{ + [self selectPreviousKeyView:sender]; +} + - (void)textDidBlur:(CPNotification)note { // this looks to prevent false propagation of notifications for other objects From 9b7f8ec31ee477f4928fa749dd85fe90babbaf3b Mon Sep 17 00:00:00 2001 From: Andreas Date: Mon, 12 Jul 2010 11:19:28 +0200 Subject: [PATCH 2/4] Add -insertTabIgnoringFieldEditor: and -insertNewlineIgnoringFieldEditor: --- AppKit/CPTextField.j | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/AppKit/CPTextField.j b/AppKit/CPTextField.j index 660c43e65..0762c791d 100644 --- a/AppKit/CPTextField.j +++ b/AppKit/CPTextField.j @@ -715,6 +715,25 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); [[[self window] platformWindow] _propagateCurrentDOMEvent:NO]; } +- (void)insertNewlineIgnoringFieldEditor:(id)sender +{ + var oldValue = [self stringValue]; + + [self _inputElement].value += CPNewlineCharacter; + [self _setStringValue:[self _inputElement].value]; + + if (oldValue !== [self stringValue]) + { + if (!_isEditing) + { + _isEditing = YES; + [self textDidBeginEditing:[CPNotification notificationWithName:CPControlTextDidBeginEditingNotification object:self userInfo:nil]]; + } + + [self textDidChange:[CPNotification notificationWithName:CPControlTextDidChangeNotification object:self userInfo:nil]]; + } +} + - (void)selectNextKeyView:(id)sender { [[self window] selectNextKeyView:self]; @@ -740,6 +759,25 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); [self selectNextKeyView:sender]; } +- (void)insertTabIgnoringFieldEditor:(id)sender +{ + var oldValue = [self stringValue]; + + [self _inputElement].value += CPTabCharacter; + [self _setStringValue:[self _inputElement].value]; + + if (oldValue !== [self stringValue]) + { + if (!_isEditing) + { + _isEditing = YES; + [self textDidBeginEditing:[CPNotification notificationWithName:CPControlTextDidBeginEditingNotification object:self userInfo:nil]]; + } + + [self textDidChange:[CPNotification notificationWithName:CPControlTextDidChangeNotification object:self userInfo:nil]]; + } +} + - (void)insertBacktab:(id)sender { [self selectPreviousKeyView:sender]; From bb9e1a830d22bd241b78495af5c296a10ca0cc6d Mon Sep 17 00:00:00 2001 From: Andreas Date: Tue, 22 Jun 2010 16:06:40 +0200 Subject: [PATCH 3/4] Add cancelOperation action to clear text when pressing ESC --- AppKit/CPSearchField.j | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/AppKit/CPSearchField.j b/AppKit/CPSearchField.j index 6494df077..e039948e9 100644 --- a/AppKit/CPSearchField.j +++ b/AppKit/CPSearchField.j @@ -182,7 +182,7 @@ var RECENT_SEARCH_PREFIX = @" "; [_cancelButton setFrame:[self cancelButtonRectForBounds:[self bounds]]]; [_cancelButton setAutoresizingMask:CPViewMinXMargin]; [_cancelButton setTarget:self]; - [_cancelButton setAction:@selector(_searchFieldCancel:)]; + [_cancelButton setAction:@selector(cancelOperation:)]; [self _updateCancelButtonVisibility]; [self addSubview:_cancelButton]; } @@ -210,7 +210,7 @@ var RECENT_SEARCH_PREFIX = @" "; [button setAlternateImage:CPSearchFieldCancelPressedImage]; [button setAutoresizingMask:CPViewMinXMargin]; [button setTarget:self]; - [button setAction:@selector(_searchFieldCancel:)]; + [button setAction:@selector(cancelOperation:)]; } // Custom Layout @@ -684,8 +684,8 @@ var RECENT_SEARCH_PREFIX = @" "; [_partialStringTimer invalidate]; } -- (void)_searchFieldCancel:(id)sender -{ +- (void)cancelOperation:(id)sender +{ [self setObjectValue:@""]; [self _sendPartialString]; [self _updateCancelButtonVisibility]; From a302fdfb8fb061ad43cc7871c3e55c42289d8fd3 Mon Sep 17 00:00:00 2001 From: Andreas Falk Date: Mon, 15 Nov 2010 19:40:07 +0100 Subject: [PATCH 4/4] CPTextField should not bother with handling tab to go to the next key view, CPWindow does that for us. --- AppKit/CPTextField.j | 46 ++++++++------------------------------------ 1 file changed, 8 insertions(+), 38 deletions(-) diff --git a/AppKit/CPTextField.j b/AppKit/CPTextField.j index 0762c791d..15b12f937 100644 --- a/AppKit/CPTextField.j +++ b/AppKit/CPTextField.j @@ -674,15 +674,15 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); { if ([anEvent _couldBeKeyEquivalent] && [self performKeyEquivalent:anEvent]) return; - - // CPTextField uses an HTML input element to take the input so we need to + + // CPTextField uses an HTML input element to take the input so we need to // propagate the dom event so the element is updated. This has to be done // before interpretKeyEvents: though so individual commands have a chance - // to override this (tab to go to the next keyView and such). + // to override this (escape to clear the text in a search field for example). [[[self window] platformWindow] _propagateCurrentDOMEvent:YES]; - + [self interpretKeyEvents:[anEvent]]; - + [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode]; } @@ -711,14 +711,14 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); [self sendAction:[self action] to:[self target]]; [self selectText:nil]; - + [[[self window] platformWindow] _propagateCurrentDOMEvent:NO]; } - (void)insertNewlineIgnoringFieldEditor:(id)sender { var oldValue = [self stringValue]; - + [self _inputElement].value += CPNewlineCharacter; [self _setStringValue:[self _inputElement].value]; @@ -734,35 +734,10 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); } } -- (void)selectNextKeyView:(id)sender -{ - [[self window] selectNextKeyView:self]; - - if ([[[self window] firstResponder] respondsToSelector:@selector(selectText:)]) - [[[self window] firstResponder] selectText:self]; - - [[[self window] platformWindow] _propagateCurrentDOMEvent:NO]; -} - -- (void)selectPreviousKeyView:(id)sender -{ - [[self window] selectPreviousKeyView:self]; - - if ([[[self window] firstResponder] respondsToSelector:@selector(selectText:)]) - [[[self window] firstResponder] selectText:self]; - - [[[self window] platformWindow] _propagateCurrentDOMEvent:NO]; -} - -- (void)insertTab:(id)sender -{ - [self selectNextKeyView:sender]; -} - - (void)insertTabIgnoringFieldEditor:(id)sender { var oldValue = [self stringValue]; - + [self _inputElement].value += CPTabCharacter; [self _setStringValue:[self _inputElement].value]; @@ -778,11 +753,6 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); } } -- (void)insertBacktab:(id)sender -{ - [self selectPreviousKeyView:sender]; -} - - (void)textDidBlur:(CPNotification)note { // this looks to prevent false propagation of notifications for other objects