diff options
author | Patrick Luby <guibmacdev@gmail.com> | 2024-10-03 19:47:25 -0400 |
---|---|---|
committer | Adolfo Jayme Barrientos <fitojb@ubuntu.com> | 2024-10-14 06:05:06 +0200 |
commit | b0ffb1ae420ec7511e5d27a8e95191627428947d (patch) | |
tree | 00ae33258c913499e596867c19c5902e1c83c0f0 /vcl | |
parent | c6a2014aeb60fa14f9ff3bebccd358f2a55ce0be (diff) |
tdf#162843 replace the event's string parameters
When using the Dvorak - QWERTY keyboard, the
event's charactersIgnoringModifiers string causes
pasting to fail so replace both the event's
characters and charactersIgnoringModifiers strings
with this menu item's key equivalent.
Also, fix the following related bugs when using the
Dvorak - QWERTY keyboard:
- When pressing Command-V with a Dvorak - QWERTY
keyboard, that single event passes through the
-[SalNSMainMenu performKeyEquivalent:] selector twice
which causes content to be pasted twice in any text
fields in the Find and Replace dialog.
- When using the Dvorak - QWERTY keyboard and the
Command key is pressed, any key events that match a
disabled menu item are handled in the
-[SalFrameView noop:]. However, the Dvorak - QWERTY
event's charactersIgnoringModifiers string can cause
cutting and copying to fail in the Find toolbar and
the Find and Replace dialog so replace the event's
charactersIgnoringModifiers string with the event's
character string.
Lastly, fix temporarily disabled menu items failing to
be reenabled when a modal dialog closes caused by the
fix for tdf#126638 by returning the last enabled state
set by the LibreOffice code. Apparently whatever is
returned by -[SalNSMenuItem validateMenuItem:] will be
passed to -[NSMenuItem setEnabled:] which can cause
the enabled state to be different than the enabled
state that the LibreOffice code expoects. This results
in menu items failing to be reenabled after being
temporarily disabled such as when a native modal dialog
is closed. So, return the last enabled state set by the
LibreOffice code.
Change-Id: Iae9cc6f1b94484c1529b22ea3a7acdac2009a58b
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/174462
Tested-by: Jenkins
Reviewed-by: Patrick Luby <guibomacdev@gmail.com>
(cherry picked from commit 9240debe362a382389e7601073523162ea0cd80d)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/174673
Reviewed-by: Adolfo Jayme Barrientos <fitojb@ubuntu.com>
Diffstat (limited to 'vcl')
-rw-r--r-- | vcl/inc/osx/salnsmenu.h | 6 | ||||
-rw-r--r-- | vcl/osx/salframeview.mm | 32 | ||||
-rw-r--r-- | vcl/osx/salmenu.cxx | 12 | ||||
-rw-r--r-- | vcl/osx/salnsmenu.mm | 84 |
4 files changed, 116 insertions, 18 deletions
diff --git a/vcl/inc/osx/salnsmenu.h b/vcl/inc/osx/salnsmenu.h index 9e0f9acf68ed..d6b065a7706e 100644 --- a/vcl/inc/osx/salnsmenu.h +++ b/vcl/inc/osx/salnsmenu.h @@ -44,15 +44,21 @@ class AquaSalMenuItem; @interface SalNSMenuItem : NSMenuItem <NSMenuItemValidation> { AquaSalMenuItem* mpMenuItem; + BOOL mbReallyEnabled; } - (id)initWithMenuItem:(AquaSalMenuItem*)pMenuItem; +- (BOOL)isReallyEnabled; - (void)menuItemTriggered:(id)aSender; - (BOOL)validateMenuItem:(NSMenuItem*)pMenuItem; +- (void)setReallyEnabled:(BOOL)bEnabled; @end @interface SalNSMainMenu : NSMenu { + NSEvent* mpLastPerformKeyEquivalentEvent; } +- (id)initWithTitle:(NSString*)pTitle; +- (void)dealloc; - (BOOL)performKeyEquivalent:(NSEvent*)pEvent; @end diff --git a/vcl/osx/salframeview.mm b/vcl/osx/salframeview.mm index eb8ed68add34..a8432aba31b9 100644 --- a/vcl/osx/salframeview.mm +++ b/vcl/osx/salframeview.mm @@ -1748,9 +1748,37 @@ static void updateWinDataInLiveResize(bool bInLiveResize) -(void)noop: (id)aSender { (void)aSender; - if( ! mbKeyHandled ) + if( ! mbKeyHandled && mpLastEvent ) { - if( ! [self sendSingleCharacter:mpLastEvent] ) + // Related tdf#162843: replace the event's string parameter + // When using the Dvorak - QWERTY keyboard and the Command key + // is pressed, any key events that match a disabled menu item + // are handled here. However, the Dvorak - QWERTY event's + // charactersIgnoringModifiers string can cause cutting and + // copying to fail in the Find toolbar and the Find and Replace + // dialog so replace the event's charactersIgnoringModifiers + // string with the event's character string. + NSEvent* pEvent = mpLastEvent; + NSEventModifierFlags nModMask = [mpLastEvent modifierFlags]; + if( nModMask & NSEventModifierFlagCommand ) + { + switch( [mpLastEvent type] ) + { + case NSEventTypeKeyDown: + case NSEventTypeKeyUp: + case NSEventTypeFlagsChanged: + { + NSString* pCharacters = [mpLastEvent characters]; + NSString* pCharactersIgnoringModifiers = ( nModMask & NSEventModifierFlagShift ) ? [pCharacters uppercaseString] : pCharacters; + pEvent = [NSEvent keyEventWithType: [pEvent type] location: [pEvent locationInWindow] modifierFlags: nModMask timestamp: [pEvent timestamp] windowNumber: [pEvent windowNumber] context: nil characters: pCharacters charactersIgnoringModifiers: pCharactersIgnoringModifiers isARepeat: [pEvent isARepeat] keyCode: [pEvent keyCode]]; + break; + } + default: + break; + } + } + + if( ! [self sendSingleCharacter:pEvent] ) { /* prevent recursion */ if( mpLastEvent != mpLastSuperEvent && [NSApp respondsToSelector: @selector(sendSuperEvent:)] ) diff --git a/vcl/osx/salmenu.cxx b/vcl/osx/salmenu.cxx index dcac168f7e53..0410da4e99fd 100644 --- a/vcl/osx/salmenu.cxx +++ b/vcl/osx/salmenu.cxx @@ -412,7 +412,10 @@ void AquaSalMenu::enableMainMenu( bool bEnable ) for( int n = 1; n < nItems; n++ ) { NSMenuItem* pItem = [pMainMenu itemAtIndex: n]; - [pItem setEnabled: bEnable ? YES : NO]; + if( [pItem isKindOfClass: [SalNSMenuItem class]]) + [static_cast<SalNSMenuItem*>(pItem) setReallyEnabled: bEnable]; + else + [pItem setEnabled: bEnable]; } } } @@ -581,7 +584,10 @@ void AquaSalMenu::EnableItem( unsigned nPos, bool bEnable ) if( nPos < maItems.size() ) { NSMenuItem* pItem = maItems[nPos]->mpMenuItem; - [pItem setEnabled: bEnable ? YES : NO]; + if( [pItem isKindOfClass: [SalNSMenuItem class]]) + [static_cast<SalNSMenuItem*>(pItem) setReallyEnabled: bEnable]; + else + [pItem setEnabled: bEnable]; } } @@ -874,7 +880,7 @@ AquaSalMenuItem::AquaSalMenuItem( const SalItemParams* pItemData ) : else { mpMenuItem = [[SalNSMenuItem alloc] initWithMenuItem: this]; - [mpMenuItem setEnabled: YES]; + [static_cast<SalNSMenuItem*>(mpMenuItem) setReallyEnabled: YES]; // peel mnemonics because on mac there are no such things for menu items // Delete CJK-style mnemonics for the dropdown menu of the 'New button' and lower menu of 'File > New' diff --git a/vcl/osx/salnsmenu.mm b/vcl/osx/salnsmenu.mm index 31a2ace83f07..383e0b574a54 100644 --- a/vcl/osx/salnsmenu.mm +++ b/vcl/osx/salnsmenu.mm @@ -142,8 +142,15 @@ action: @selector(menuItemTriggered:) keyEquivalent: [NSString string]]; [ret setTarget: self]; + mbReallyEnabled = [ret isEnabled]; return ret; } + +-(BOOL)isReallyEnabled +{ + return mbReallyEnabled; +} + -(void)menuItemTriggered: (id)aSender { (void)aSender; @@ -187,8 +194,8 @@ [pCharacters isEqualToString: @"a"] || [pCharacters isEqualToString: @"z"] ) ) { - NSEvent* pEvent = [NSApp currentEvent]; NSEvent* pKeyEvent = nil; + NSEvent* pEvent = [NSApp currentEvent]; if( pEvent ) { switch( [pEvent type] ) @@ -196,23 +203,29 @@ case NSEventTypeKeyDown: case NSEventTypeKeyUp: case NSEventTypeFlagsChanged: - pKeyEvent = pEvent; + // tdf#162843 replace the event's string parameters + // When using the Dvorak - QWERTY keyboard, the + // event's charactersIgnoringModifiers string causes + // pasting to fail so replace both the event's + // characters and charactersIgnoringModifiers strings + // with this menu item's key equivalent. + pKeyEvent = [NSEvent keyEventWithType: [pEvent type] location: [pEvent locationInWindow] modifierFlags: nModMask timestamp: [pEvent timestamp] windowNumber: [pEvent windowNumber] context: nil characters: pCharacters charactersIgnoringModifiers: pCharacters isARepeat: [pEvent isARepeat] keyCode: [pEvent keyCode]]; break; default: break; } + } - if( !pKeyEvent ) - { - // Native key events appear to set the location to the - // top left corner of the key window - NSPoint aPoint = NSMakePoint(0, [pKeyWin frame].size.height); - pKeyEvent = [NSEvent keyEventWithType: NSEventTypeKeyDown location: aPoint modifierFlags: nModMask timestamp: [[NSProcessInfo processInfo] systemUptime] windowNumber: [pKeyWin windowNumber] context: nil characters: pCharacters charactersIgnoringModifiers: pCharacters isARepeat: NO keyCode: 0]; - } - - [[pKeyWin contentView] keyDown: pKeyEvent]; - return; + if( !pKeyEvent ) + { + // Native key events appear to set the location to the + // top left corner of the key window + NSPoint aPoint = NSMakePoint(0, [pKeyWin frame].size.height); + pKeyEvent = [NSEvent keyEventWithType: NSEventTypeKeyDown location: aPoint modifierFlags: nModMask timestamp: [[NSProcessInfo processInfo] systemUptime] windowNumber: [pKeyWin windowNumber] context: nil characters: pCharacters charactersIgnoringModifiers: pCharacters isARepeat: NO keyCode: 0]; } + + [[pKeyWin contentView] keyDown: pKeyEvent]; + return; } } @@ -255,6 +268,12 @@ } } +-(void)setReallyEnabled: (BOOL)bEnabled +{ + mbReallyEnabled = bEnabled; + [self setEnabled: mbReallyEnabled]; +} + -(BOOL)validateMenuItem: (NSMenuItem *)pMenuItem { // Related: tdf#126638 disable all menu items when displaying modal windows @@ -265,7 +284,18 @@ if (!pMenuItem || [NSApp modalWindow]) return NO; - return [pMenuItem isEnabled]; + // Related: tdf#126638 return the last enabled state set by the LibreOffice code + // Apparently whatever is returned will be passed to + // -[NSMenuItem setEnabled:] which can cause the enabled state + // to be different than the enabled state that the LibreOffice + // code expoects. This results in menu items failing to be + // reenabled after being temporarily disabled such as when a + // native modal dialog is closed. So, return the last enabled + // state set by the LibreOffice code. + if ([pMenuItem isKindOfClass: [SalNSMenuItem class]]) + return [static_cast<SalNSMenuItem*>(pMenuItem) isReallyEnabled]; + else + return [pMenuItem isEnabled]; } @end @@ -359,8 +389,36 @@ SAL_WNODEPRECATED_DECLARATIONS_POP @implementation SalNSMainMenu +- (id)initWithTitle:(NSString*)pTitle +{ + mpLastPerformKeyEquivalentEvent = nil; + return [super initWithTitle:pTitle]; +} + +- (void)dealloc +{ + if (mpLastPerformKeyEquivalentEvent) + [mpLastPerformKeyEquivalentEvent release]; + + [super dealloc]; +} + - (BOOL)performKeyEquivalent:(NSEvent*)pEvent { + // Related: tdf#162843 prevent dispatch of the same event more than once + // When pressing Command-V with a Dvorak - QWERTY keyboard, + // that single event passes through this selector twice which + // causes content to be pasted twice in any text fields in the + // Find and Replace dialog. + if (pEvent == mpLastPerformKeyEquivalentEvent) + return false; + + if (mpLastPerformKeyEquivalentEvent) + [mpLastPerformKeyEquivalentEvent release]; + mpLastPerformKeyEquivalentEvent = pEvent; + if (mpLastPerformKeyEquivalentEvent) + [mpLastPerformKeyEquivalentEvent retain]; + bool bRet = [super performKeyEquivalent: pEvent]; // tdf#126638 dispatch key shortcut events to modal windows |