diff options
Diffstat (limited to 'vcl/osx')
-rw-r--r-- | vcl/osx/salframeview.mm | 157 |
1 files changed, 149 insertions, 8 deletions
diff --git a/vcl/osx/salframeview.mm b/vcl/osx/salframeview.mm index 546c2a85d24e..355fc84a76b4 100644 --- a/vcl/osx/salframeview.mm +++ b/vcl/osx/salframeview.mm @@ -512,6 +512,7 @@ static AquaSalFrame* getMouseContainerFrame() mbInEndExtTextInput = NO; mbInCommitMarkedText = NO; mpLastMarkedText = nil; + mbTextInputWantsNonRepeatKeyDown = NO; } return self; @@ -998,8 +999,52 @@ static AquaSalFrame* getMouseContainerFrame() if( ! [self handleKeyDownException: pEvent] ) { + sal_uInt16 nKeyCode = ImplMapKeyCode( [pEvent keyCode] ); + if ( nKeyCode == KEY_DELETE && mbTextInputWantsNonRepeatKeyDown ) + { + // tdf#42437 Enable press-and-hold special character input method + // Emulate the press-and-hold behavior of the TextEdit + // application by deleting the marked text when only the + // Delete key is pressed and keep the marked text when the + // Backspace key or Fn-Delete keys are pressed. + if ( [pEvent keyCode] == 51 ) + { + [self deleteTextInputWantsNonRepeatKeyDown]; + } + else + { + [self unmarkText]; + mbKeyHandled = true; + mbInKeyInput = false; + } + + [self endExtTextInput]; + return; + } + NSArray* pArray = [NSArray arrayWithObject: pEvent]; [self interpretKeyEvents: pArray]; + + // Handle repeat key events by explicitly inserting the text if + // -[NSResponder interpretKeyEvents:] does not insert or mark any + // text. Note: do not do this step if there is uncommitted text. + if ( !mpLastMarkedText && mpLastEvent && [mpLastEvent type] == NSEventTypeKeyDown && [mpLastEvent isARepeat] ) + { + NSString *pChars = [mpLastEvent characters]; + [self insertText:pChars replacementRange:NSMakeRange( 0, [pChars length] )]; + } + // tdf#42437 Enable press-and-hold special character input method + // Emulate the press-and-hold behavior of the TextEdit application + // by committing an empty string for key down events dispatched + // while the special character input method popup is displayed. + else if ( mpLastMarkedText && mbTextInputWantsNonRepeatKeyDown && mpLastEvent && [mpLastEvent type] == NSEventTypeKeyDown && ![mpLastEvent isARepeat] ) + { + // If the escape or return key is pressed, unmark the text to + // skip deletion of marked text + if ( nKeyCode == KEY_ESCAPE || nKeyCode == KEY_RETURN ) + [self unmarkText]; + [self insertText:[NSString string] replacementRange:NSMakeRange( NSNotFound, 0 )]; + } } mbInKeyInput = false; @@ -1044,6 +1089,8 @@ static AquaSalFrame* getMouseContainerFrame() SolarMutexGuard aGuard; + [self deleteTextInputWantsNonRepeatKeyDown]; + // Ignore duplicate events that are sometimes posted during cancellation // of the native input method session. This usually happens when // [self endExtTextInput] is called from [self windowDidBecomeKey:] and, @@ -1617,7 +1664,12 @@ static AquaSalFrame* getMouseContainerFrame() - (NSRange)selectedRange { - return mSelectedRange; + // tdf#42437 Enable press-and-hold special character input method + // Always return a valid range location. If the range location is + // NSNotFound, -[NSResponder interpretKeyEvents:] will not call + // [self firstRectForCharacterRange:actualRange:] and will not display the + // special character input method popup. + return ( mSelectedRange.location == NSNotFound ? NSMakeRange( 0, 0 ) : mSelectedRange ); } - (void)setMarkedText:(id)aString selectedRange:(NSRange)selRange replacementRange:(NSRange)replacementRange @@ -1626,6 +1678,8 @@ static AquaSalFrame* getMouseContainerFrame() SolarMutexGuard aGuard; + [self deleteTextInputWantsNonRepeatKeyDown]; + if( ![aString isKindOfClass:[NSAttributedString class]] ) aString = [[[NSAttributedString alloc] initWithString:aString] autorelease]; @@ -1695,6 +1749,7 @@ static AquaSalFrame* getMouseContainerFrame() aInputEvent.maText = aInsertString; aInputEvent.mnCursorPos = nSelectionStart; + aInputEvent.mnCursorFlags = 0; aInputEvent.mpTextAttr = aInputFlags.data(); mpFrame->CallCallback( SalEvent::ExtTextInput, static_cast<void *>(&aInputEvent) ); } else { @@ -1770,6 +1825,8 @@ static AquaSalFrame* getMouseContainerFrame() [mpLastMarkedText release]; mpLastMarkedText = nil; } + + mbTextInputWantsNonRepeatKeyDown = NO; } - (NSRect)firstRectForCharacterRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange @@ -1780,17 +1837,66 @@ static AquaSalFrame* getMouseContainerFrame() SolarMutexGuard aGuard; + // tdf#42437 Enable press-and-hold special character input method + // Some text entry controls, such as Writer comments or the cell editor in + // Calc's Formula Bar, need to have an input method session open or else + // the returned position won't be anywhere near the text cursor. So, + // dispatch an empty SalEvent::ExtTextInput event, fetch the position, + // and then dispatch a SalEvent::EndExtTextInput event. + BOOL bNeedsExtTextInput = ( mbInKeyInput && !mpLastMarkedText && mpLastEvent && [mpLastEvent type] == NSEventTypeKeyDown && [mpLastEvent isARepeat] ); + if ( bNeedsExtTextInput ) + { + SalExtTextInputEvent aInputEvent; + aInputEvent.maText.clear(); + aInputEvent.mnCursorPos = 0; + aInputEvent.mnCursorFlags = 0; + aInputEvent.mpTextAttr = nullptr; + if ( mpFrame && AquaSalFrame::isAlive( mpFrame ) ) + mpFrame->CallCallback( SalEvent::ExtTextInput, static_cast<void *>(&aInputEvent) ); + } + SalExtTextInputPosEvent aPosEvent; - mpFrame->CallCallback( SalEvent::ExtTextInputPos, static_cast<void *>(&aPosEvent) ); + if ( mpFrame && AquaSalFrame::isAlive( mpFrame ) ) + mpFrame->CallCallback( SalEvent::ExtTextInputPos, static_cast<void *>(&aPosEvent) ); + + if ( bNeedsExtTextInput ) + { + if ( mpFrame && AquaSalFrame::isAlive( mpFrame ) ) + mpFrame->CallCallback( SalEvent::EndExtTextInput, nullptr ); + + // tdf#42437 Enable press-and-hold special character input method + // Emulate the press-and-hold behavior of the TextEdit application by + // setting the marked text to the last key down event's characters. The + // characters will already have been committed by the special character + // input method so set the mbTextInputWantsNonRepeatKeyDown flag to + // indicate that the characters need to be deleted if the input method + // replaces the committed characters. + NSString *pChars = [mpLastEvent characters]; + if ( pChars ) + { + [self unmarkText]; + mpLastMarkedText = [[NSAttributedString alloc] initWithString:pChars]; + mSelectedRange = mMarkedRange = NSMakeRange( 0, [mpLastMarkedText length] ); + mbTextInputWantsNonRepeatKeyDown = YES; + } + } NSRect rect; - rect.origin.x = aPosEvent.mnX + mpFrame->maGeometry.x(); - rect.origin.y = aPosEvent.mnY + mpFrame->maGeometry.y() + 4; // add some space for underlines - rect.size.width = aPosEvent.mnWidth; - rect.size.height = aPosEvent.mnHeight; + if ( mpFrame && AquaSalFrame::isAlive( mpFrame ) ) + { + rect.origin.x = aPosEvent.mnX + mpFrame->maGeometry.x(); + rect.origin.y = aPosEvent.mnY + mpFrame->maGeometry.y() + 4; // add some space for underlines + rect.size.width = aPosEvent.mnWidth; + rect.size.height = aPosEvent.mnHeight; + + mpFrame->VCLToCocoa( rect ); + } + else + { + rect = NSMakeRect( aPosEvent.mnX, aPosEvent.mnY, aPosEvent.mnWidth, aPosEvent.mnHeight ); + } - mpFrame->VCLToCocoa( rect ); return rect; } @@ -1903,9 +2009,17 @@ static AquaSalFrame* getMouseContainerFrame() // to be visible. mbInCommitMarkedText = YES; if (nFlags & EndExtTextInputFlags::Complete) - [self insertText:mpLastMarkedText replacementRange:NSMakeRange(0, [mpLastMarkedText length])]; + { + // Retain the last marked text as it will be releasd in + // [self insertText:replacementText:] + NSAttributedString *pText = [mpLastMarkedText retain]; + [self insertText:pText replacementRange:NSMakeRange(0, [mpLastMarkedText length])]; + [pText release]; + } else + { [self insertText:[NSString string] replacementRange:NSMakeRange(0, 0)]; + } mbInCommitMarkedText = NO; } @@ -1927,6 +2041,33 @@ static AquaSalFrame* getMouseContainerFrame() mbInEndExtTextInput = NO; } +-(void)deleteTextInputWantsNonRepeatKeyDown +{ + SolarMutexGuard aGuard; + + // tdf#42437 Enable press-and-hold special character input method + // Emulate the press-and-hold behavior of the TextEdit application by + // dispatching backspace events to delete any marked characters. The + // special character input method commits the marked characters so we must + // delete the marked characters before the input method calls + // [self insertText:replacementRange:]. + if (mbTextInputWantsNonRepeatKeyDown) + { + if ( mpLastMarkedText ) + { + NSString *pChars = [mpLastMarkedText string]; + if ( pChars ) + { + NSUInteger nLength = [pChars length]; + for ( NSUInteger i = 0; i < nLength; i++ ) + [self deleteBackward:self]; + } + } + + [self unmarkText]; + } +} + @end /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |