зеркало из https://github.com/mozilla/gecko-dev.git
Bug 610015: Implement updated Cocoa NPAPI text input spec. Part of this patch written by Steven Michaud. r=josh r=smichaud a=blocking2.0betaN+
This commit is contained in:
Родитель
0c4ef98e51
Коммит
187207cb32
|
@ -410,6 +410,11 @@ PluginInstanceChild::NPN_GetValue(NPNVariable aVar,
|
|||
return NPERR_NO_ERROR;
|
||||
}
|
||||
|
||||
case NPNVsupportsUpdatedCocoaTextInputBool: {
|
||||
*static_cast<NPBool*>(aValue) = true;
|
||||
return NPERR_NO_ERROR;
|
||||
}
|
||||
|
||||
#ifndef NP_NO_QUICKDRAW
|
||||
case NPNVsupportsQuickDrawBool: {
|
||||
*((NPBool*)aValue) = false;
|
||||
|
|
|
@ -2234,6 +2234,11 @@ _getvalue(NPP npp, NPNVariable variable, void *result)
|
|||
|
||||
return NPERR_NO_ERROR;
|
||||
}
|
||||
|
||||
case NPNVsupportsUpdatedCocoaTextInputBool: {
|
||||
*(NPBool*)result = true;
|
||||
return NPERR_NO_ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
// we no longer hand out any XPCOM objects, except on WINCE,
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
- (NSTextInputContext*)inputContext;
|
||||
- (BOOL)interpretKeyEvent:(NSEvent*)event string:(NSString**)string;
|
||||
- (void)cancelComposition;
|
||||
- (BOOL)inComposition;
|
||||
|
||||
@end
|
||||
|
||||
|
|
|
@ -124,4 +124,9 @@
|
|||
[self orderOut:nil];
|
||||
}
|
||||
|
||||
- (BOOL)inComposition
|
||||
{
|
||||
return [mInputTextView hasMarkedText];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -174,9 +174,13 @@ extern "C" long TSMProcessRawKeyEvent(EventRef carbonEvent);
|
|||
// Cocoa TSM documents (those created and managed by the NSTSMInputContext
|
||||
// class) -- for some reason TSMProcessRawKeyEvent() doesn't work with them.
|
||||
TSMDocumentID mPluginTSMDoc;
|
||||
BOOL mPluginTSMInComposition;
|
||||
#endif
|
||||
BOOL mPluginComplexTextInputRequested;
|
||||
|
||||
// When this is YES the next key up event (keyUp:) will be ignored.
|
||||
BOOL mIgnoreNextKeyUpEvent;
|
||||
|
||||
NSOpenGLContext *mGLContext;
|
||||
|
||||
// Simple gestures support
|
||||
|
|
|
@ -182,6 +182,10 @@ PRUint32 nsChildView::sLastInputEventCount = 0;
|
|||
- (NPEventModel)pluginEventModel;
|
||||
- (NPDrawingModel)pluginDrawingModel;
|
||||
|
||||
#ifndef NP_NO_CARBON
|
||||
- (void)setPluginTSMInComposition:(BOOL)inComposition;
|
||||
#endif
|
||||
|
||||
- (BOOL)isRectObscuredBySubview:(NSRect)inRect;
|
||||
|
||||
- (void)processPendingRedraws;
|
||||
|
@ -541,6 +545,15 @@ nsresult nsChildView::Create(nsIWidget *aParent,
|
|||
if (!gChildViewMethodsSwizzled) {
|
||||
nsToolkit::SwizzleMethods([NSView class], @selector(mouseDownCanMoveWindow),
|
||||
@selector(nsChildView_NSView_mouseDownCanMoveWindow));
|
||||
#ifndef NP_NO_CARBON
|
||||
Class IMKInputSessionClass = ::NSClassFromString(@"IMKInputSession");
|
||||
nsToolkit::SwizzleMethods(IMKInputSessionClass, @selector(handleEvent:),
|
||||
@selector(nsChildView_IMKInputSession_handleEvent:));
|
||||
nsToolkit::SwizzleMethods(IMKInputSessionClass, @selector(commitComposition),
|
||||
@selector(nsChildView_IMKInputSession_commitComposition));
|
||||
nsToolkit::SwizzleMethods(IMKInputSessionClass, @selector(finishSession),
|
||||
@selector(nsChildView_IMKInputSession_finishSession));
|
||||
#endif
|
||||
gChildViewMethodsSwizzled = PR_TRUE;
|
||||
}
|
||||
|
||||
|
@ -2226,9 +2239,12 @@ NSEvent* gLastDragMouseDownEvent = nil;
|
|||
|
||||
#ifndef NP_NO_CARBON
|
||||
mPluginTSMDoc = nil;
|
||||
mPluginTSMInComposition = NO;
|
||||
#endif
|
||||
mPluginComplexTextInputRequested = NO;
|
||||
|
||||
mIgnoreNextKeyUpEvent = NO;
|
||||
|
||||
mGestureState = eGestureState_None;
|
||||
mCumulativeMagnification = 0.0;
|
||||
mCumulativeRotation = 0.0;
|
||||
|
@ -2505,16 +2521,23 @@ NSEvent* gLastDragMouseDownEvent = nil;
|
|||
mPluginDrawingModel = drawingModel;
|
||||
}
|
||||
|
||||
- (NPEventModel)pluginEventModel;
|
||||
- (NPEventModel)pluginEventModel
|
||||
{
|
||||
return mPluginEventModel;
|
||||
}
|
||||
|
||||
- (NPDrawingModel)pluginDrawingModel;
|
||||
- (NPDrawingModel)pluginDrawingModel
|
||||
{
|
||||
return mPluginDrawingModel;
|
||||
}
|
||||
|
||||
#ifndef NP_NO_CARBON
|
||||
- (void)setPluginTSMInComposition:(BOOL)inComposition
|
||||
{
|
||||
mPluginTSMInComposition = inComposition;
|
||||
}
|
||||
#endif
|
||||
|
||||
- (void)sendFocusEvent:(PRUint32)eventType
|
||||
{
|
||||
if (!mGeckoChild)
|
||||
|
@ -5347,60 +5370,117 @@ static const char* ToEscapedString(NSString* aString, nsCAutoString& aBuf)
|
|||
return YES;
|
||||
}
|
||||
|
||||
- (void)keyDown:(NSEvent*)theEvent
|
||||
- (BOOL)inCocoaPluginComposition
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
||||
|
||||
if (mGeckoChild && mIsPluginView) {
|
||||
// If a plugin has the focus, we need to use an alternate method for
|
||||
// handling NSKeyDown and NSKeyUp events (otherwise Carbon-based IME won't
|
||||
// work in plugins like the Flash plugin). The same strategy is used by the
|
||||
// WebKit. See PluginKeyEventsHandler() and [ChildView processPluginKeyEvent:]
|
||||
// for more info.
|
||||
if (mPluginEventModel == NPEventModelCocoa) {
|
||||
// Reset complex text input request.
|
||||
mPluginComplexTextInputRequested = NO;
|
||||
|
||||
// Send key down event.
|
||||
nsGUIEvent pluginEvent(PR_TRUE, NS_NON_RETARGETED_PLUGIN_EVENT, mGeckoChild);
|
||||
NPCocoaEvent cocoaEvent;
|
||||
ConvertCocoaKeyEventToNPCocoaEvent(theEvent, cocoaEvent);
|
||||
pluginEvent.pluginEvent = &cocoaEvent;
|
||||
mGeckoChild->DispatchWindowEvent(pluginEvent);
|
||||
if (!mGeckoChild)
|
||||
return;
|
||||
|
||||
if (!mPluginComplexTextInputRequested) {
|
||||
#ifdef NP_NO_CARBON
|
||||
[[ComplexTextInputPanel sharedComplexTextInputPanel] cancelComposition];
|
||||
return [[ComplexTextInputPanel sharedComplexTextInputPanel] inComposition];
|
||||
#else
|
||||
if (mPluginTSMDoc) {
|
||||
::FixTSMDocument(mPluginTSMDoc);
|
||||
}
|
||||
return mPluginTSMInComposition;
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef NP_NO_CARBON
|
||||
ComplexTextInputPanel* ctInputPanel = [ComplexTextInputPanel sharedComplexTextInputPanel];
|
||||
NSString* textString = nil;
|
||||
[ctInputPanel interpretKeyEvent:theEvent string:&textString];
|
||||
if (textString) {
|
||||
- (void)sendCocoaNPAPITextEvent:(NSString*)string
|
||||
{
|
||||
NPCocoaEvent cocoaTextEvent;
|
||||
InitNPCocoaEvent(&cocoaTextEvent);
|
||||
cocoaTextEvent.type = NPCocoaEventTextInput;
|
||||
cocoaTextEvent.data.text.text = (NPNSString*)textString;
|
||||
cocoaTextEvent.data.text.text = (NPNSString*)string;
|
||||
|
||||
nsGUIEvent pluginTextEvent(PR_TRUE, NS_NON_RETARGETED_PLUGIN_EVENT, mGeckoChild);
|
||||
pluginTextEvent.time = PR_IntervalNow();
|
||||
pluginTextEvent.pluginEvent = (void*)&cocoaTextEvent;
|
||||
mGeckoChild->DispatchWindowEvent(pluginTextEvent);
|
||||
}
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)keyDown:(NSEvent*)theEvent
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
||||
|
||||
if (mGeckoChild && mIsPluginView) {
|
||||
#ifdef NP_NO_CARBON
|
||||
if (mPluginEventModel == NPEventModelCocoa) {
|
||||
ComplexTextInputPanel* ctiPanel = [ComplexTextInputPanel sharedComplexTextInputPanel];
|
||||
|
||||
// If a composition is in progress then simply let the input panel continue it.
|
||||
if ([self inCocoaPluginComposition]) {
|
||||
// Don't send key up events for key downs associated with compositions.
|
||||
mIgnoreNextKeyUpEvent = YES;
|
||||
|
||||
NSString* textString = nil;
|
||||
[ctiPanel interpretKeyEvent:theEvent string:&textString];
|
||||
if (textString) {
|
||||
[self sendCocoaNPAPITextEvent:textString];
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Reset complex text input request flag.
|
||||
mPluginComplexTextInputRequested = NO;
|
||||
|
||||
// Send key down event to the plugin.
|
||||
nsGUIEvent pluginEvent(PR_TRUE, NS_NON_RETARGETED_PLUGIN_EVENT, mGeckoChild);
|
||||
NPCocoaEvent cocoaEvent;
|
||||
ConvertCocoaKeyEventToNPCocoaEvent(theEvent, cocoaEvent);
|
||||
pluginEvent.pluginEvent = &cocoaEvent;
|
||||
mGeckoChild->DispatchWindowEvent(pluginEvent);
|
||||
if (!mGeckoChild) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Start complex text composition if requested.
|
||||
if (mPluginComplexTextInputRequested) {
|
||||
// Don't send key up events for key downs associated with compositions.
|
||||
mIgnoreNextKeyUpEvent = YES;
|
||||
|
||||
NSString* textString = nil;
|
||||
[ctiPanel interpretKeyEvent:theEvent string:&textString];
|
||||
if (textString) {
|
||||
[self sendCocoaNPAPITextEvent:textString];
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Nothing else to do for Cocoa NPAPI plugins.
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef NP_NO_CARBON
|
||||
BOOL wasInComposition = NO;
|
||||
if (mPluginEventModel == NPEventModelCocoa) {
|
||||
if ([self inCocoaPluginComposition]) {
|
||||
wasInComposition = YES;
|
||||
|
||||
// Don't send key up events for key downs associated with compositions.
|
||||
mIgnoreNextKeyUpEvent = YES;
|
||||
}
|
||||
else {
|
||||
// Reset complex text input request flag.
|
||||
mPluginComplexTextInputRequested = NO;
|
||||
|
||||
// Send key down event to the plugin.
|
||||
nsGUIEvent pluginEvent(PR_TRUE, NS_NON_RETARGETED_PLUGIN_EVENT, mGeckoChild);
|
||||
NPCocoaEvent cocoaEvent;
|
||||
ConvertCocoaKeyEventToNPCocoaEvent(theEvent, cocoaEvent);
|
||||
pluginEvent.pluginEvent = &cocoaEvent;
|
||||
mGeckoChild->DispatchWindowEvent(pluginEvent);
|
||||
if (!mGeckoChild) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Only continue if plugin wants complex text input.
|
||||
if (mPluginComplexTextInputRequested) {
|
||||
// Don't send key up events for key downs associated with compositions.
|
||||
mIgnoreNextKeyUpEvent = YES;
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This will take care of all Carbon plugin events and also send Cocoa plugin
|
||||
// text events when NSInputContext is not available (ifndef NP_NO_CARBON).
|
||||
[self activatePluginTSMDoc];
|
||||
|
@ -5413,6 +5493,7 @@ static const char* ToEscapedString(NSString* aString, nsCAutoString& aBuf)
|
|||
sizeof(ChildView *), &self);
|
||||
::TSMProcessRawKeyEvent([theEvent _eventRef]);
|
||||
::TSMRemoveDocumentProperty(mPluginTSMDoc, kFocusedChildViewTSMDocPropertyTag);
|
||||
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
@ -5446,10 +5527,20 @@ static const char* ToEscapedString(NSString* aString, nsCAutoString& aBuf)
|
|||
if (!mGeckoChild)
|
||||
return;
|
||||
|
||||
if (mIgnoreNextKeyUpEvent) {
|
||||
mIgnoreNextKeyUpEvent = NO;
|
||||
return;
|
||||
}
|
||||
|
||||
nsAutoRetainCocoaObject kungFuDeathGrip(self);
|
||||
|
||||
if (mIsPluginView) {
|
||||
if (mPluginEventModel == NPEventModelCocoa) {
|
||||
// Don't send key up events to Cocoa plugins during composition.
|
||||
if ([self inCocoaPluginComposition]) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsKeyEvent keyUpEvent(PR_TRUE, NS_KEY_UP, nsnull);
|
||||
[self convertCocoaKeyEvent:theEvent toGeckoEvent:&keyUpEvent];
|
||||
NPCocoaEvent pluginEvent;
|
||||
|
@ -6595,6 +6686,72 @@ void NS_RemovePluginKeyEventsHandler()
|
|||
gPluginKeyEventsHandler = NULL;
|
||||
}
|
||||
|
||||
// IMKInputSession is an undocumented class in the HIToolbox framework. It's
|
||||
// present on both Leopard and SnowLeopard, and is used at a low level to
|
||||
// process IME input regardless of which high-level API is used (Text Services
|
||||
// Manager or Cocoa). It works the same way in both 32-bit and 64-bit code.
|
||||
@interface NSObject (IMKInputSessionMethodSwizzling)
|
||||
- (BOOL)nsChildView_IMKInputSession_handleEvent:(EventRef)theEvent;
|
||||
- (void)nsChildView_IMKInputSession_commitComposition;
|
||||
- (void)nsChildView_IMKInputSession_finishSession;
|
||||
@end
|
||||
|
||||
@implementation NSObject (IMKInputSessionMethodSwizzling)
|
||||
|
||||
- (BOOL)nsChildView_IMKInputSession_handleEvent:(EventRef)theEvent
|
||||
{
|
||||
[self retain];
|
||||
BOOL retval = [self nsChildView_IMKInputSession_handleEvent:theEvent];
|
||||
NSUInteger retainCount = [self retainCount];
|
||||
[self release];
|
||||
// Return without doing anything if we've been deleted.
|
||||
if (retainCount == 1) {
|
||||
return retval;
|
||||
}
|
||||
|
||||
NSWindow *mainWindow = [NSApp mainWindow];
|
||||
NSResponder *firstResponder = [mainWindow firstResponder];
|
||||
if (![firstResponder isKindOfClass:[ChildView class]]) {
|
||||
return retval;
|
||||
}
|
||||
|
||||
// 'charactersEntered' is the length (in bytes) of currently "marked text"
|
||||
// -- text that's been entered in IME but not yet committed. If it's
|
||||
// non-zero we're composing text in an IME session; if it's zero we're
|
||||
// not in an IME session.
|
||||
NSInteger charactersEntered = 0;
|
||||
object_getInstanceVariable(self, "charactersEntered", (void **) &charactersEntered);
|
||||
[(ChildView*)firstResponder setPluginTSMInComposition:(charactersEntered != 0)];
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
// This method is called whenever IME input is committed as a result of an
|
||||
// "abnormal" termination -- for example when changing the keyboard focus from
|
||||
// one input field to another.
|
||||
- (void)nsChildView_IMKInputSession_commitComposition
|
||||
{
|
||||
NSWindow *mainWindow = [NSApp mainWindow];
|
||||
NSResponder *firstResponder = [mainWindow firstResponder];
|
||||
if ([firstResponder isKindOfClass:[ChildView class]]) {
|
||||
[(ChildView*)firstResponder setPluginTSMInComposition:NO];
|
||||
}
|
||||
[self nsChildView_IMKInputSession_commitComposition];
|
||||
}
|
||||
|
||||
// This method is called just before we're deallocated.
|
||||
- (void)nsChildView_IMKInputSession_finishSession
|
||||
{
|
||||
NSWindow *mainWindow = [NSApp mainWindow];
|
||||
NSResponder *firstResponder = [mainWindow firstResponder];
|
||||
if ([firstResponder isKindOfClass:[ChildView class]]) {
|
||||
[(ChildView*)firstResponder setPluginTSMInComposition:NO];
|
||||
}
|
||||
[self nsChildView_IMKInputSession_finishSession];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif // NP_NO_CARBON
|
||||
|
||||
@interface NSView (MethodSwizzling)
|
||||
|
|
Загрузка…
Ссылка в новой задаче