Fix various key handling bugs by processing key down events uniformly and making sure we always send down and press events. Fixes key events in dialogs, emacs bindings, various key commands, changing IME input modes. b=358379, also fixes 418226,411304,417108. r=masayuki sr=roc a=beltzner

This commit is contained in:
joshmoz@gmail.com 2008-02-28 21:47:41 -08:00
parent 7821e133e7
commit 782bc77a51
2 changed files with 65 additions and 36 deletions

View File

@ -91,12 +91,21 @@ union nsPluginPort;
// Whether we're a plugin view.
BOOL mIsPluginView;
NSEvent* mCurKeyEvent; // only valid during a keyDown
// The following variables are only valid during key down event processing.
// Their current usage needs to be fixed to avoid problems with nested event
// loops that can confuse them. Once a variable is set during key down event
// processing, if an event spawns a nested event loop the previously set value
// will be wiped out.
NSEvent* mCurKeyEvent;
PRBool mKeyDownHandled;
BOOL mIgnoreDoCommand;
// While we process key down events we need to keep track of whether or not
// we sent a key press event. This helps us make sure we do send one
// eventually.
BOOL mKeyPressSent;
// needed for NSTextInput implementation
NSRange mMarkedRange;
BOOL mIgnoreDoCommand;
BOOL mInHandScroll; // true for as long as we are hand scrolling
// hand scroll locations

View File

@ -1994,13 +1994,16 @@ NSEvent* gLastDragEvent = nil;
mWindow = nil;
mGeckoChild = inChild;
mIsPluginView = NO;
mCurKeyEvent = nil;
mKeyDownHandled = PR_FALSE;
mIgnoreDoCommand = NO;
mKeyPressSent = NO;
// initialization for NSTextInput
mMarkedRange.location = NSNotFound;
mMarkedRange.length = 0;
mIgnoreDoCommand = NO;
mLastMenuForEventEvent = nil;
mDragService = nsnull;
}
@ -3842,7 +3845,7 @@ static PRBool IsSpecialGeckoKey(UInt32 macKeyCode)
outGeckoEvent->isChar = PR_TRUE; // this is not a special key
outGeckoEvent->charCode = 0;
outGeckoEvent->keyCode = 0;
outGeckoEvent->keyCode = 0; // not set for key press events
NSString* unmodifiedChars = [aKeyEvent charactersIgnoringModifiers];
if ([unmodifiedChars length] > 0)
@ -3983,6 +3986,7 @@ static PRBool IsSpecialGeckoKey(UInt32 macKeyCode)
}
mGeckoChild->DispatchWindowEvent(geckoEvent);
mKeyPressSent = YES;
}
else {
if (!nsTSMManager::IsComposing()) {
@ -4339,9 +4343,7 @@ static PRBool IsSpecialGeckoKey(UInt32 macKeyCode)
}
// Handle matching cocoa IME with gecko key events. Sends a key down and key press
// event to gecko.
- (void)keyDown:(NSEvent*)theEvent
- (void)processKeyDownEvent:(NSEvent*)theEvent keyEquiv:(BOOL)isKeyEquiv
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
@ -4351,7 +4353,6 @@ static PRBool IsSpecialGeckoKey(UInt32 macKeyCode)
nsAutoRetainView kungFuDeathGrip(self);
mCurKeyEvent = theEvent;
PRBool dispatchedKeyPress = PR_FALSE;
BOOL nonDeadKeyPress = [[theEvent characters] length] > 0;
if (nonDeadKeyPress) {
if (![theEvent isARepeat]) {
@ -4364,6 +4365,7 @@ static PRBool IsSpecialGeckoKey(UInt32 macKeyCode)
EventRecord macEvent;
ConvertCocoaKeyEventToMacEvent(theEvent, macEvent);
geckoEvent.nativeMsg = &macEvent;
mKeyDownHandled = mGeckoChild->DispatchWindowEvent(geckoEvent);
if (!mGeckoChild)
return;
@ -4380,15 +4382,15 @@ static PRBool IsSpecialGeckoKey(UInt32 macKeyCode)
nsKeyEvent geckoEvent(PR_TRUE, NS_KEY_PRESS, nsnull);
[self convertCocoaKeyEvent:theEvent toGeckoEvent:&geckoEvent];
if (mKeyDownHandled)
geckoEvent.flags |= NS_EVENT_FLAG_NO_DEFAULT;
// if this is a non-letter keypress, or the control key is down,
// dispatch the keydown to gecko, so that we trap delete,
// control-letter combinations etc before Cocoa tries to use
// them for keybindings.
if ((!geckoEvent.isChar || geckoEvent.isControl) &&
!nsTSMManager::IsComposing()) {
if (mKeyDownHandled)
geckoEvent.flags |= NS_EVENT_FLAG_NO_DEFAULT;
// create native EventRecord for use by plugins
EventRecord macEvent;
ConvertCocoaKeyEventToMacEvent(theEvent, macEvent);
@ -4397,24 +4399,39 @@ static PRBool IsSpecialGeckoKey(UInt32 macKeyCode)
mIgnoreDoCommand = mGeckoChild->DispatchWindowEvent(geckoEvent);
if (!mGeckoChild)
return;
dispatchedKeyPress = PR_TRUE;
mKeyPressSent = YES;
}
}
// We should send this event to the superclass if IME is enabled.
// Otherwise, we need to suppress IME composition. We can do it by
// not sending this event to the superclass. But in that case,
// we need to call insertText ourselves.
if (!dispatchedKeyPress) {
if (nsTSMManager::IsIMEEnabled())
[super interpretKeyEvents:[NSArray arrayWithObject:theEvent]];
else if (nonDeadKeyPress)
[self insertText:[theEvent characters]];
// Let Cocoa interpret the key events, caching IsComposing first.
// We don't do it if this came from performKeyEquivalent because
// interpretKeyEvents isn't set up to handle those key combinations.
PRBool wasComposing = nsTSMManager::IsComposing();
if (!isKeyEquiv)
[super interpretKeyEvents:[NSArray arrayWithObject:theEvent]];
if (!mGeckoChild)
return;
if (!mKeyPressSent && nonDeadKeyPress && !wasComposing && !nsTSMManager::IsComposing()) {
nsKeyEvent geckoEvent(PR_TRUE, NS_KEY_PRESS, nsnull);
[self convertCocoaKeyEvent:theEvent toGeckoEvent:&geckoEvent];
if (mKeyDownHandled)
geckoEvent.flags |= NS_EVENT_FLAG_NO_DEFAULT;
// create native EventRecord for use by plugins
EventRecord macEvent;
ConvertCocoaKeyEventToMacEvent(theEvent, macEvent);
geckoEvent.nativeMsg = &macEvent;
mGeckoChild->DispatchWindowEvent(geckoEvent);
}
// Note: mGeckoChild might have become null here. Don't count on it from here on.
// See note about nested event loops where these variables are declared in header.
mIgnoreDoCommand = NO;
mKeyPressSent = NO;
mCurKeyEvent = nil;
mKeyDownHandled = PR_FALSE;
@ -4422,6 +4439,12 @@ static PRBool IsSpecialGeckoKey(UInt32 macKeyCode)
}
- (void)keyDown:(NSEvent*)theEvent
{
[self processKeyDownEvent:theEvent keyEquiv:NO];
}
static BOOL keyUpAlreadySentKeyDown = NO;
- (void)keyUp:(NSEvent*)theEvent
@ -4451,6 +4474,7 @@ static BOOL keyUpAlreadySentKeyDown = NO;
EventRecord macEvent;
ConvertCocoaKeyEventToMacEvent(nativeKeyDownEvent, macEvent);
geckoEvent.nativeMsg = &macEvent;
keyDownHandled = mGeckoChild->DispatchWindowEvent(geckoEvent);
if (!mGeckoChild)
return;
@ -4512,11 +4536,15 @@ static BOOL keyUpAlreadySentKeyDown = NO;
if (modifierFlags & NSCommandKeyMask && [theEvent keyCode] == kTildeKeyCode)
return NO;
// don't bother if we don't have a gecko widget
// don't do anything if we don't have a gecko widget
if (!mGeckoChild)
return YES;
return NO;
// return 'NO' if we are in a transaction of IME.
// if we aren't the first responder, pass the event on
if ([[self window] firstResponder] != self)
return [super performKeyEquivalent:theEvent];
// don't process if we're composing, but don't consume the event
if (nsTSMManager::IsComposing())
return NO;
@ -4551,16 +4579,8 @@ static BOOL keyUpAlreadySentKeyDown = NO;
if ((modifierFlags & NSFunctionKeyMask) || (modifierFlags & NSNumericPadKeyMask))
return NO;
// handle the event ourselves
nsKeyEvent geckoEvent(PR_TRUE, NS_KEY_PRESS, nsnull);
[self convertCocoaKeyEvent:theEvent toGeckoEvent:&geckoEvent];
// create native EventRecord for use by plugins
EventRecord macEvent;
ConvertCocoaKeyEventToMacEvent(theEvent, macEvent);
geckoEvent.nativeMsg = &macEvent;
mGeckoChild->DispatchWindowEvent(geckoEvent);
if ([theEvent type] == NSKeyDown)
[self processKeyDownEvent:theEvent keyEquiv:YES];
return YES;