1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/widget/cocoa/TextInputHandler.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1245 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=2 sw=2 et tw=80: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#ifndef TextInputHandler_h_ 1.11 +#define TextInputHandler_h_ 1.12 + 1.13 +#include "nsCocoaUtils.h" 1.14 + 1.15 +#import <Carbon/Carbon.h> 1.16 +#import <Cocoa/Cocoa.h> 1.17 +#include "mozView.h" 1.18 +#include "nsString.h" 1.19 +#include "nsCOMPtr.h" 1.20 +#include "nsITimer.h" 1.21 +#include "npapi.h" 1.22 +#include "nsTArray.h" 1.23 +#include "mozilla/EventForwards.h" 1.24 + 1.25 +class nsChildView; 1.26 + 1.27 +namespace mozilla { 1.28 +namespace widget { 1.29 + 1.30 +// Key code constants 1.31 +enum 1.32 +{ 1.33 + kVK_RightCommand = 0x36, // right command key 1.34 + 1.35 + kVK_PC_PrintScreen = kVK_F13, 1.36 + kVK_PC_ScrollLock = kVK_F14, 1.37 + kVK_PC_Pause = kVK_F15, 1.38 + 1.39 + kVK_PC_Insert = kVK_Help, 1.40 + kVK_PC_Backspace = kVK_Delete, 1.41 + kVK_PC_Delete = kVK_ForwardDelete, 1.42 + 1.43 + kVK_PC_ContextMenu = 0x6E, 1.44 + 1.45 + kVK_Powerbook_KeypadEnter = 0x34 // Enter on Powerbook's keyboard is different 1.46 +}; 1.47 + 1.48 +/** 1.49 + * TISInputSourceWrapper is a wrapper for the TISInputSourceRef. If we get the 1.50 + * TISInputSourceRef from InputSourceID, we need to release the CFArray instance 1.51 + * which is returned by TISCreateInputSourceList. However, when we release the 1.52 + * list, we cannot access the TISInputSourceRef. So, it's not usable, and it 1.53 + * may cause the memory leak bugs. nsTISInputSource automatically releases the 1.54 + * list when the instance is destroyed. 1.55 + */ 1.56 +class TISInputSourceWrapper 1.57 +{ 1.58 +public: 1.59 + static TISInputSourceWrapper& CurrentInputSource(); 1.60 + 1.61 + TISInputSourceWrapper() 1.62 + { 1.63 + mInputSourceList = nullptr; 1.64 + Clear(); 1.65 + } 1.66 + 1.67 + TISInputSourceWrapper(const char* aID) 1.68 + { 1.69 + mInputSourceList = nullptr; 1.70 + InitByInputSourceID(aID); 1.71 + } 1.72 + 1.73 + TISInputSourceWrapper(SInt32 aLayoutID) 1.74 + { 1.75 + mInputSourceList = nullptr; 1.76 + InitByLayoutID(aLayoutID); 1.77 + } 1.78 + 1.79 + TISInputSourceWrapper(TISInputSourceRef aInputSource) 1.80 + { 1.81 + mInputSourceList = nullptr; 1.82 + InitByTISInputSourceRef(aInputSource); 1.83 + } 1.84 + 1.85 + ~TISInputSourceWrapper() { Clear(); } 1.86 + 1.87 + void InitByInputSourceID(const char* aID); 1.88 + void InitByInputSourceID(const nsAFlatString &aID); 1.89 + void InitByInputSourceID(const CFStringRef aID); 1.90 + /** 1.91 + * InitByLayoutID() initializes the keyboard layout by the layout ID. 1.92 + * 1.93 + * @param aLayoutID An ID of keyboard layout. 1.94 + * 0: US 1.95 + * 1: Greek 1.96 + * 2: German 1.97 + * 3: Swedish-Pro 1.98 + * 4: Dvorak-Qwerty Cmd 1.99 + * 5: Thai 1.100 + * 6: Arabic 1.101 + * 7: French 1.102 + * 8: Hebrew 1.103 + * 9: Lithuanian 1.104 + * 10: Norwegian 1.105 + * 11: Spanish 1.106 + * @param aOverrideKeyboard When testing set to TRUE, otherwise, set to 1.107 + * FALSE. When TRUE, we use an ANSI keyboard 1.108 + * instead of the actual keyboard. 1.109 + */ 1.110 + void InitByLayoutID(SInt32 aLayoutID, bool aOverrideKeyboard = false); 1.111 + void InitByCurrentInputSource(); 1.112 + void InitByCurrentKeyboardLayout(); 1.113 + void InitByCurrentASCIICapableInputSource(); 1.114 + void InitByCurrentASCIICapableKeyboardLayout(); 1.115 + void InitByCurrentInputMethodKeyboardLayoutOverride(); 1.116 + void InitByTISInputSourceRef(TISInputSourceRef aInputSource); 1.117 + void InitByLanguage(CFStringRef aLanguage); 1.118 + 1.119 + /** 1.120 + * If the instance is initialized with a keyboard layout input source, 1.121 + * returns it. 1.122 + * If the instance is initialized with an IME mode input source, the result 1.123 + * references the keyboard layout for the IME mode. However, this can be 1.124 + * initialized only when the IME mode is actually selected. I.e, if IME mode 1.125 + * input source is initialized with LayoutID or SourceID, this returns null. 1.126 + */ 1.127 + TISInputSourceRef GetKeyboardLayoutInputSource() const 1.128 + { 1.129 + return mKeyboardLayout; 1.130 + } 1.131 + const UCKeyboardLayout* GetUCKeyboardLayout(); 1.132 + 1.133 + bool IsOpenedIMEMode(); 1.134 + bool IsIMEMode(); 1.135 + bool IsKeyboardLayout(); 1.136 + 1.137 + bool IsASCIICapable() 1.138 + { 1.139 + NS_ENSURE_TRUE(mInputSource, false); 1.140 + return GetBoolProperty(kTISPropertyInputSourceIsASCIICapable); 1.141 + } 1.142 + 1.143 + bool IsEnabled() 1.144 + { 1.145 + NS_ENSURE_TRUE(mInputSource, false); 1.146 + return GetBoolProperty(kTISPropertyInputSourceIsEnabled); 1.147 + } 1.148 + 1.149 + bool GetLanguageList(CFArrayRef &aLanguageList); 1.150 + bool GetPrimaryLanguage(CFStringRef &aPrimaryLanguage); 1.151 + bool GetPrimaryLanguage(nsAString &aPrimaryLanguage); 1.152 + 1.153 + bool GetLocalizedName(CFStringRef &aName) 1.154 + { 1.155 + NS_ENSURE_TRUE(mInputSource, false); 1.156 + return GetStringProperty(kTISPropertyLocalizedName, aName); 1.157 + } 1.158 + 1.159 + bool GetLocalizedName(nsAString &aName) 1.160 + { 1.161 + NS_ENSURE_TRUE(mInputSource, false); 1.162 + return GetStringProperty(kTISPropertyLocalizedName, aName); 1.163 + } 1.164 + 1.165 + bool GetInputSourceID(CFStringRef &aID) 1.166 + { 1.167 + NS_ENSURE_TRUE(mInputSource, false); 1.168 + return GetStringProperty(kTISPropertyInputSourceID, aID); 1.169 + } 1.170 + 1.171 + bool GetInputSourceID(nsAString &aID) 1.172 + { 1.173 + NS_ENSURE_TRUE(mInputSource, false); 1.174 + return GetStringProperty(kTISPropertyInputSourceID, aID); 1.175 + } 1.176 + 1.177 + bool GetBundleID(CFStringRef &aBundleID) 1.178 + { 1.179 + NS_ENSURE_TRUE(mInputSource, false); 1.180 + return GetStringProperty(kTISPropertyBundleID, aBundleID); 1.181 + } 1.182 + 1.183 + bool GetBundleID(nsAString &aBundleID) 1.184 + { 1.185 + NS_ENSURE_TRUE(mInputSource, false); 1.186 + return GetStringProperty(kTISPropertyBundleID, aBundleID); 1.187 + } 1.188 + 1.189 + bool GetInputSourceType(CFStringRef &aType) 1.190 + { 1.191 + NS_ENSURE_TRUE(mInputSource, false); 1.192 + return GetStringProperty(kTISPropertyInputSourceType, aType); 1.193 + } 1.194 + 1.195 + bool GetInputSourceType(nsAString &aType) 1.196 + { 1.197 + NS_ENSURE_TRUE(mInputSource, false); 1.198 + return GetStringProperty(kTISPropertyInputSourceType, aType); 1.199 + } 1.200 + 1.201 + bool IsForRTLLanguage(); 1.202 + bool IsInitializedByCurrentInputSource(); 1.203 + 1.204 + enum { 1.205 + // 40 is an actual result of the ::LMGetKbdType() when we connect an 1.206 + // unknown keyboard and set the keyboard type to ANSI manually on the 1.207 + // set up dialog. 1.208 + eKbdType_ANSI = 40 1.209 + }; 1.210 + 1.211 + void Select(); 1.212 + void Clear(); 1.213 + 1.214 + /** 1.215 + * InitKeyEvent() initializes aKeyEvent for aNativeKeyEvent. 1.216 + * 1.217 + * @param aNativeKeyEvent A native key event for which you want to 1.218 + * dispatch a Gecko key event. 1.219 + * @param aKeyEvent The result -- a Gecko key event initialized 1.220 + * from the native key event. 1.221 + * @param aInsertString If caller expects that the event will cause 1.222 + * a character to be input (say in an editor), 1.223 + * the caller should set this. Otherwise, 1.224 + * if caller sets null to this, this method will 1.225 + * compute the character to be input from 1.226 + * characters of aNativeKeyEvent. 1.227 + */ 1.228 + void InitKeyEvent(NSEvent *aNativeKeyEvent, WidgetKeyboardEvent& aKeyEvent, 1.229 + const nsAString *aInsertString = nullptr); 1.230 + 1.231 + /** 1.232 + * ComputeGeckoKeyCode() returns Gecko keycode for aNativeKeyCode on current 1.233 + * keyboard layout. 1.234 + * 1.235 + * @param aNativeKeyCode A native keycode. 1.236 + * @param aKbType A native Keyboard Type value. Typically, 1.237 + * this is a result of ::LMGetKbdType(). 1.238 + * @param aCmdIsPressed TRUE if Cmd key is pressed. Otherwise, FALSE. 1.239 + * @return The computed Gecko keycode. 1.240 + */ 1.241 + uint32_t ComputeGeckoKeyCode(UInt32 aNativeKeyCode, UInt32 aKbType, 1.242 + bool aCmdIsPressed); 1.243 + 1.244 + /** 1.245 + * ComputeGeckoKeyNameIndex() returns Gecko key name index for the key. 1.246 + * 1.247 + * @param aNativeKeyCode A native keycode. 1.248 + */ 1.249 + static KeyNameIndex ComputeGeckoKeyNameIndex(UInt32 aNativeKeyCode); 1.250 + 1.251 +protected: 1.252 + /** 1.253 + * TranslateToString() computes the inputted text from the native keyCode, 1.254 + * modifier flags and keyboard type. 1.255 + * 1.256 + * @param aKeyCode A native keyCode. 1.257 + * @param aModifiers Combination of native modifier flags. 1.258 + * @param aKbType A native Keyboard Type value. Typically, 1.259 + * this is a result of ::LMGetKbdType(). 1.260 + * @param aStr Result, i.e., inputted text. 1.261 + * The result can be two or more characters. 1.262 + * @return If succeeded, TRUE. Otherwise, FALSE. 1.263 + * Even if TRUE, aStr can be empty string. 1.264 + */ 1.265 + bool TranslateToString(UInt32 aKeyCode, UInt32 aModifiers, 1.266 + UInt32 aKbType, nsAString &aStr); 1.267 + 1.268 + /** 1.269 + * TranslateToChar() computes the inputted character from the native keyCode, 1.270 + * modifier flags and keyboard type. If two or more characters would be 1.271 + * input, this returns 0. 1.272 + * 1.273 + * @param aKeyCode A native keyCode. 1.274 + * @param aModifiers Combination of native modifier flags. 1.275 + * @param aKbType A native Keyboard Type value. Typically, 1.276 + * this is a result of ::LMGetKbdType(). 1.277 + * @return If succeeded and the result is one character, 1.278 + * returns the charCode of it. Otherwise, 1.279 + * returns 0. 1.280 + */ 1.281 + uint32_t TranslateToChar(UInt32 aKeyCode, UInt32 aModifiers, UInt32 aKbType); 1.282 + 1.283 + /** 1.284 + * InitKeyPressEvent() initializes aKeyEvent for aNativeKeyEvent. 1.285 + * Don't call this method when aKeyEvent isn't NS_KEY_PRESS. 1.286 + * 1.287 + * @param aNativeKeyEvent A native key event for which you want to 1.288 + * dispatch a Gecko key event. 1.289 + * @param aInsertChar A character to be input in an editor by the 1.290 + * event. 1.291 + * @param aKeyEvent The result -- a Gecko key event initialized 1.292 + * from the native key event. This must be 1.293 + * NS_KEY_PRESS event. 1.294 + * @param aKbType A native Keyboard Type value. Typically, 1.295 + * this is a result of ::LMGetKbdType(). 1.296 + */ 1.297 + void InitKeyPressEvent(NSEvent *aNativeKeyEvent, 1.298 + char16_t aInsertChar, 1.299 + WidgetKeyboardEvent& aKeyEvent, 1.300 + UInt32 aKbType); 1.301 + 1.302 + bool GetBoolProperty(const CFStringRef aKey); 1.303 + bool GetStringProperty(const CFStringRef aKey, CFStringRef &aStr); 1.304 + bool GetStringProperty(const CFStringRef aKey, nsAString &aStr); 1.305 + 1.306 + TISInputSourceRef mInputSource; 1.307 + TISInputSourceRef mKeyboardLayout; 1.308 + CFArrayRef mInputSourceList; 1.309 + const UCKeyboardLayout* mUCKeyboardLayout; 1.310 + int8_t mIsRTL; 1.311 + 1.312 + bool mOverrideKeyboard; 1.313 +}; 1.314 + 1.315 +/** 1.316 + * TextInputHandlerBase is a base class of PluginTextInputHandler, 1.317 + * IMEInputHandler and TextInputHandler. Utility methods should be implemented 1.318 + * this level. 1.319 + */ 1.320 + 1.321 +class TextInputHandlerBase 1.322 +{ 1.323 +public: 1.324 + nsrefcnt AddRef() 1.325 + { 1.326 + NS_PRECONDITION(int32_t(mRefCnt) >= 0, "mRefCnt is negative"); 1.327 + ++mRefCnt; 1.328 + NS_LOG_ADDREF(this, mRefCnt, "TextInputHandlerBase", sizeof(*this)); 1.329 + return mRefCnt; 1.330 + } 1.331 + nsrefcnt Release() 1.332 + { 1.333 + NS_PRECONDITION(mRefCnt != 0, "mRefCnt is alrady zero"); 1.334 + --mRefCnt; 1.335 + NS_LOG_RELEASE(this, mRefCnt, "TextInputHandlerBase"); 1.336 + if (mRefCnt == 0) { 1.337 + mRefCnt = 1; /* stabilize */ 1.338 + delete this; 1.339 + return 0; 1.340 + } 1.341 + return mRefCnt; 1.342 + } 1.343 + 1.344 + /** 1.345 + * DispatchEvent() dispatches aEvent on mWidget. 1.346 + * 1.347 + * @param aEvent An event which you want to dispatch. 1.348 + * @return TRUE if the event is consumed by web contents 1.349 + * or chrome contents. Otherwise, FALSE. 1.350 + */ 1.351 + bool DispatchEvent(WidgetGUIEvent& aEvent); 1.352 + 1.353 + /** 1.354 + * SetSelection() dispatches NS_SELECTION_SET event for the aRange. 1.355 + * 1.356 + * @param aRange The range which will be selected. 1.357 + * @return TRUE if setting selection is succeeded and 1.358 + * the widget hasn't been destroyed. 1.359 + * Otherwise, FALSE. 1.360 + */ 1.361 + bool SetSelection(NSRange& aRange); 1.362 + 1.363 + /** 1.364 + * InitKeyEvent() initializes aKeyEvent for aNativeKeyEvent. 1.365 + * 1.366 + * @param aNativeKeyEvent A native key event for which you want to 1.367 + * dispatch a Gecko key event. 1.368 + * @param aKeyEvent The result -- a Gecko key event initialized 1.369 + * from the native key event. 1.370 + * @param aInsertString If caller expects that the event will cause 1.371 + * a character to be input (say in an editor), 1.372 + * the caller should set this. Otherwise, 1.373 + * if caller sets null to this, this method will 1.374 + * compute the character to be input from 1.375 + * characters of aNativeKeyEvent. 1.376 + */ 1.377 + void InitKeyEvent(NSEvent *aNativeKeyEvent, WidgetKeyboardEvent& aKeyEvent, 1.378 + const nsAString *aInsertString = nullptr); 1.379 + 1.380 + /** 1.381 + * SynthesizeNativeKeyEvent() is an implementation of 1.382 + * nsIWidget::SynthesizeNativeKeyEvent(). See the document in nsIWidget.h 1.383 + * for the detail. 1.384 + */ 1.385 + nsresult SynthesizeNativeKeyEvent(int32_t aNativeKeyboardLayout, 1.386 + int32_t aNativeKeyCode, 1.387 + uint32_t aModifierFlags, 1.388 + const nsAString& aCharacters, 1.389 + const nsAString& aUnmodifiedCharacters); 1.390 + 1.391 + /** 1.392 + * Utility method intended for testing. Attempts to construct a native key 1.393 + * event that would have been generated during an actual key press. This 1.394 + * *does not dispatch* the native event. Instead, it is attached to the 1.395 + * |mNativeKeyEvent| field of the Gecko event that is passed in. 1.396 + * @param aKeyEvent Gecko key event to attach the native event to 1.397 + */ 1.398 + NS_IMETHOD AttachNativeKeyEvent(WidgetKeyboardEvent& aKeyEvent); 1.399 + 1.400 + /** 1.401 + * GetWindowLevel() returns the window level of current focused (in Gecko) 1.402 + * window. E.g., if an <input> element in XUL panel has focus, this returns 1.403 + * the XUL panel's window level. 1.404 + */ 1.405 + NSInteger GetWindowLevel(); 1.406 + 1.407 + /** 1.408 + * IsSpecialGeckoKey() checks whether aNativeKeyCode is mapped to a special 1.409 + * Gecko keyCode. A key is "special" if it isn't used for text input. 1.410 + * 1.411 + * @param aNativeKeyCode A native keycode. 1.412 + * @return If the keycode is mapped to a special key, 1.413 + * TRUE. Otherwise, FALSE. 1.414 + */ 1.415 + static bool IsSpecialGeckoKey(UInt32 aNativeKeyCode); 1.416 + 1.417 + 1.418 + /** 1.419 + * EnableSecureEventInput() and DisableSecureEventInput() wrap the Carbon 1.420 + * Event Manager APIs with the same names. In addition they keep track of 1.421 + * how many times we've called them (in the same process) -- unlike the 1.422 + * Carbon Event Manager APIs, which only keep track of how many times they've 1.423 + * been called from any and all processes. 1.424 + * 1.425 + * The Carbon Event Manager's IsSecureEventInputEnabled() returns whether 1.426 + * secure event input mode is enabled (in any process). This class's 1.427 + * IsSecureEventInputEnabled() returns whether we've made any calls to 1.428 + * EnableSecureEventInput() that are not (yet) offset by the calls we've 1.429 + * made to DisableSecureEventInput(). 1.430 + */ 1.431 + static void EnableSecureEventInput(); 1.432 + static void DisableSecureEventInput(); 1.433 + static bool IsSecureEventInputEnabled(); 1.434 + 1.435 + /** 1.436 + * EnsureSecureEventInputDisabled() calls DisableSecureEventInput() until 1.437 + * our call count becomes 0. 1.438 + */ 1.439 + static void EnsureSecureEventInputDisabled(); 1.440 + 1.441 +protected: 1.442 + nsAutoRefCnt mRefCnt; 1.443 + 1.444 +public: 1.445 + /** 1.446 + * mWidget must not be destroyed without OnDestroyWidget being called. 1.447 + * 1.448 + * @param aDestroyingWidget Destroying widget. This might not be mWidget. 1.449 + * @return This result doesn't have any meaning for 1.450 + * callers. When aDstroyingWidget isn't the same 1.451 + * as mWidget, FALSE. Then, inherited methods in 1.452 + * sub classes should return from this method 1.453 + * without cleaning up. 1.454 + */ 1.455 + virtual bool OnDestroyWidget(nsChildView* aDestroyingWidget); 1.456 + 1.457 +protected: 1.458 + // The creater of this instance and client. 1.459 + // This must not be null after initialized until OnDestroyWidget() is called. 1.460 + nsChildView* mWidget; // [WEAK] 1.461 + 1.462 + // The native view for mWidget. 1.463 + // This view handles the actual text inputting. 1.464 + NSView<mozView>* mView; // [STRONG] 1.465 + 1.466 + TextInputHandlerBase(nsChildView* aWidget, NSView<mozView> *aNativeView); 1.467 + virtual ~TextInputHandlerBase(); 1.468 + 1.469 + bool Destroyed() { return !mWidget; } 1.470 + 1.471 + /** 1.472 + * mCurrentKeyEvent indicates what key event we are handling. While 1.473 + * handling a native keydown event, we need to store the event for insertText, 1.474 + * doCommandBySelector and various action message handlers of NSResponder 1.475 + * such as [NSResponder insertNewline:sender]. 1.476 + */ 1.477 + struct KeyEventState 1.478 + { 1.479 + // Handling native key event 1.480 + NSEvent* mKeyEvent; 1.481 + // Whether keydown event was consumed by web contents or chrome contents. 1.482 + bool mKeyDownHandled; 1.483 + // Whether keypress event was dispatched for mKeyEvent. 1.484 + bool mKeyPressDispatched; 1.485 + // Whether keypress event was consumed by web contents or chrome contents. 1.486 + bool mKeyPressHandled; 1.487 + // Whether the key event causes other key events via IME or something. 1.488 + bool mCausedOtherKeyEvents; 1.489 + 1.490 + KeyEventState() : mKeyEvent(nullptr) 1.491 + { 1.492 + Clear(); 1.493 + } 1.494 + 1.495 + KeyEventState(NSEvent* aNativeKeyEvent) : mKeyEvent(nullptr) 1.496 + { 1.497 + Clear(); 1.498 + Set(aNativeKeyEvent); 1.499 + } 1.500 + 1.501 + KeyEventState(const KeyEventState &aOther) : mKeyEvent(nullptr) 1.502 + { 1.503 + Clear(); 1.504 + if (aOther.mKeyEvent) { 1.505 + mKeyEvent = [aOther.mKeyEvent retain]; 1.506 + } 1.507 + mKeyDownHandled = aOther.mKeyDownHandled; 1.508 + mKeyPressDispatched = aOther.mKeyPressDispatched; 1.509 + mKeyPressHandled = aOther.mKeyPressHandled; 1.510 + mCausedOtherKeyEvents = aOther.mCausedOtherKeyEvents; 1.511 + } 1.512 + 1.513 + ~KeyEventState() 1.514 + { 1.515 + Clear(); 1.516 + } 1.517 + 1.518 + void Set(NSEvent* aNativeKeyEvent) 1.519 + { 1.520 + NS_PRECONDITION(aNativeKeyEvent, "aNativeKeyEvent must not be NULL"); 1.521 + Clear(); 1.522 + mKeyEvent = [aNativeKeyEvent retain]; 1.523 + } 1.524 + 1.525 + void Clear() 1.526 + { 1.527 + if (mKeyEvent) { 1.528 + [mKeyEvent release]; 1.529 + mKeyEvent = nullptr; 1.530 + } 1.531 + mKeyDownHandled = false; 1.532 + mKeyPressDispatched = false; 1.533 + mKeyPressHandled = false; 1.534 + mCausedOtherKeyEvents = false; 1.535 + } 1.536 + 1.537 + bool IsDefaultPrevented() const 1.538 + { 1.539 + return mKeyDownHandled || mKeyPressHandled || mCausedOtherKeyEvents; 1.540 + } 1.541 + 1.542 + bool CanDispatchKeyPressEvent() const 1.543 + { 1.544 + return !mKeyPressDispatched && !IsDefaultPrevented(); 1.545 + } 1.546 + }; 1.547 + 1.548 + /** 1.549 + * Helper class for guaranteeing cleaning mCurrentKeyEvent 1.550 + */ 1.551 + class AutoKeyEventStateCleaner 1.552 + { 1.553 + public: 1.554 + AutoKeyEventStateCleaner(TextInputHandlerBase* aHandler) : 1.555 + mHandler(aHandler) 1.556 + { 1.557 + } 1.558 + 1.559 + ~AutoKeyEventStateCleaner() 1.560 + { 1.561 + mHandler->RemoveCurrentKeyEvent(); 1.562 + } 1.563 + private: 1.564 + nsRefPtr<TextInputHandlerBase> mHandler; 1.565 + }; 1.566 + 1.567 + /** 1.568 + * mCurrentKeyEvents stores all key events which are being processed. 1.569 + * When we call interpretKeyEvents, IME may generate other key events. 1.570 + * mCurrentKeyEvents[0] is the latest key event. 1.571 + */ 1.572 + nsTArray<KeyEventState*> mCurrentKeyEvents; 1.573 + 1.574 + /** 1.575 + * mFirstKeyEvent must be used for first key event. This member prevents 1.576 + * memory fragmentation for most key events. 1.577 + */ 1.578 + KeyEventState mFirstKeyEvent; 1.579 + 1.580 + /** 1.581 + * PushKeyEvent() adds the current key event to mCurrentKeyEvents. 1.582 + */ 1.583 + KeyEventState* PushKeyEvent(NSEvent* aNativeKeyEvent) 1.584 + { 1.585 + uint32_t nestCount = mCurrentKeyEvents.Length(); 1.586 + for (uint32_t i = 0; i < nestCount; i++) { 1.587 + // When the key event is caused by another key event, all key events 1.588 + // which are being handled should be marked as "consumed". 1.589 + mCurrentKeyEvents[i]->mCausedOtherKeyEvents = true; 1.590 + } 1.591 + 1.592 + KeyEventState* keyEvent = nullptr; 1.593 + if (nestCount == 0) { 1.594 + mFirstKeyEvent.Set(aNativeKeyEvent); 1.595 + keyEvent = &mFirstKeyEvent; 1.596 + } else { 1.597 + keyEvent = new KeyEventState(aNativeKeyEvent); 1.598 + } 1.599 + return *mCurrentKeyEvents.AppendElement(keyEvent); 1.600 + } 1.601 + 1.602 + /** 1.603 + * RemoveCurrentKeyEvent() removes the current key event from 1.604 + * mCurrentKeyEvents. 1.605 + */ 1.606 + void RemoveCurrentKeyEvent() 1.607 + { 1.608 + NS_ASSERTION(mCurrentKeyEvents.Length() > 0, 1.609 + "RemoveCurrentKeyEvent() is called unexpectedly"); 1.610 + KeyEventState* keyEvent = GetCurrentKeyEvent(); 1.611 + mCurrentKeyEvents.RemoveElementAt(mCurrentKeyEvents.Length() - 1); 1.612 + if (keyEvent == &mFirstKeyEvent) { 1.613 + keyEvent->Clear(); 1.614 + } else { 1.615 + delete keyEvent; 1.616 + } 1.617 + } 1.618 + 1.619 + /** 1.620 + * GetCurrentKeyEvent() returns current processing key event. 1.621 + */ 1.622 + KeyEventState* GetCurrentKeyEvent() 1.623 + { 1.624 + if (mCurrentKeyEvents.Length() == 0) { 1.625 + return nullptr; 1.626 + } 1.627 + return mCurrentKeyEvents[mCurrentKeyEvents.Length() - 1]; 1.628 + } 1.629 + 1.630 + /** 1.631 + * IsPrintableChar() checks whether the unicode character is 1.632 + * a non-printable ASCII character or not. Note that this returns 1.633 + * TRUE even if aChar is a non-printable UNICODE character. 1.634 + * 1.635 + * @param aChar A unicode character. 1.636 + * @return TRUE if aChar is a printable ASCII character 1.637 + * or a unicode character. Otherwise, i.e, 1.638 + * if aChar is a non-printable ASCII character, 1.639 + * FALSE. 1.640 + */ 1.641 + static bool IsPrintableChar(char16_t aChar); 1.642 + 1.643 + /** 1.644 + * IsNormalCharInputtingEvent() checks whether aKeyEvent causes text input. 1.645 + * 1.646 + * @param aKeyEvent A key event. 1.647 + * @return TRUE if the key event causes text input. 1.648 + * Otherwise, FALSE. 1.649 + */ 1.650 + static bool IsNormalCharInputtingEvent(const WidgetKeyboardEvent& aKeyEvent); 1.651 + 1.652 + /** 1.653 + * IsModifierKey() checks whether the native keyCode is for a modifier key. 1.654 + * 1.655 + * @param aNativeKeyCode A native keyCode. 1.656 + * @return TRUE if aNativeKeyCode is for a modifier key. 1.657 + * Otherwise, FALSE. 1.658 + */ 1.659 + static bool IsModifierKey(UInt32 aNativeKeyCode); 1.660 + 1.661 +private: 1.662 + struct KeyboardLayoutOverride { 1.663 + int32_t mKeyboardLayout; 1.664 + bool mOverrideEnabled; 1.665 + 1.666 + KeyboardLayoutOverride() : 1.667 + mKeyboardLayout(0), mOverrideEnabled(false) 1.668 + { 1.669 + } 1.670 + }; 1.671 + 1.672 + KeyboardLayoutOverride mKeyboardOverride; 1.673 + 1.674 + static int32_t sSecureEventInputCount; 1.675 +}; 1.676 + 1.677 +/** 1.678 + * PluginTextInputHandler handles text input events for plugins. 1.679 + */ 1.680 + 1.681 +class PluginTextInputHandler : public TextInputHandlerBase 1.682 +{ 1.683 +public: 1.684 + 1.685 + /** 1.686 + * When starting complex text input for current event on plugin, this is 1.687 + * called. See also the comment of StartComplexTextInputForCurrentEvent() of 1.688 + * nsIPluginWidget. 1.689 + */ 1.690 + nsresult StartComplexTextInputForCurrentEvent() 1.691 + { 1.692 + mPluginComplexTextInputRequested = true; 1.693 + return NS_OK; 1.694 + } 1.695 + 1.696 + /** 1.697 + * HandleKeyDownEventForPlugin() handles aNativeKeyEvent. 1.698 + * 1.699 + * @param aNativeKeyEvent A native NSKeyDown event. 1.700 + */ 1.701 + void HandleKeyDownEventForPlugin(NSEvent* aNativeKeyEvent); 1.702 + 1.703 + /** 1.704 + * HandleKeyUpEventForPlugin() handles aNativeKeyEvent. 1.705 + * 1.706 + * @param aNativeKeyEvent A native NSKeyUp event. 1.707 + */ 1.708 + void HandleKeyUpEventForPlugin(NSEvent* aNativeKeyEvent); 1.709 + 1.710 + /** 1.711 + * ConvertCocoaKeyEventToNPCocoaEvent() converts aCocoaEvent to NPCocoaEvent. 1.712 + * 1.713 + * @param aCocoaEvent A native key event. 1.714 + * @param aPluginEvent The result. 1.715 + */ 1.716 + static void ConvertCocoaKeyEventToNPCocoaEvent(NSEvent* aCocoaEvent, 1.717 + NPCocoaEvent& aPluginEvent); 1.718 + 1.719 +#ifndef __LP64__ 1.720 + 1.721 + /** 1.722 + * InstallPluginKeyEventsHandler() is called when initializing process. 1.723 + * RemovePluginKeyEventsHandler() is called when finalizing process. 1.724 + * These methods initialize/finalize global resource for handling events for 1.725 + * plugins. 1.726 + */ 1.727 + static void InstallPluginKeyEventsHandler(); 1.728 + static void RemovePluginKeyEventsHandler(); 1.729 + 1.730 + /** 1.731 + * This must be called before first key/IME event for plugins. 1.732 + * This method initializes IMKInputSession methods swizzling. 1.733 + */ 1.734 + static void SwizzleMethods(); 1.735 + 1.736 + /** 1.737 + * When a composition starts or finishes, this is called. 1.738 + */ 1.739 + void SetPluginTSMInComposition(bool aInComposition) 1.740 + { 1.741 + mPluginTSMInComposition = aInComposition; 1.742 + } 1.743 + 1.744 +#endif // #ifndef __LP64__ 1.745 + 1.746 +protected: 1.747 + bool mIgnoreNextKeyUpEvent; 1.748 + 1.749 + PluginTextInputHandler(nsChildView* aWidget, NSView<mozView> *aNativeView); 1.750 + ~PluginTextInputHandler(); 1.751 + 1.752 +private: 1.753 + 1.754 +#ifndef __LP64__ 1.755 + TSMDocumentID mPluginTSMDoc; 1.756 + 1.757 + bool mPluginTSMInComposition; 1.758 +#endif // #ifndef __LP64__ 1.759 + 1.760 + bool mPluginComplexTextInputRequested; 1.761 + 1.762 + /** 1.763 + * DispatchCocoaNPAPITextEvent() dispatches a text event for Cocoa plugin. 1.764 + * 1.765 + * @param aString A string inputted by the dispatching event. 1.766 + * @return TRUE if the dispatched event was consumed. 1.767 + * Otherwise, FALSE. 1.768 + */ 1.769 + bool DispatchCocoaNPAPITextEvent(NSString* aString); 1.770 + 1.771 + /** 1.772 + * Whether the plugin is in composition or not. 1.773 + * On 32bit build, this returns the state of mPluginTSMInComposition. 1.774 + * On 64bit build, this returns ComplexTextInputPanel's state. 1.775 + * 1.776 + * @return TRUE if plugin is in composition. Otherwise, 1.777 + * FALSE. 1.778 + */ 1.779 + bool IsInPluginComposition(); 1.780 + 1.781 +#ifndef __LP64__ 1.782 + 1.783 + /** 1.784 + * Create a TSM document for use with plugins, so that we can support IME in 1.785 + * them. Once it's created, if need be (re)activate it. Some plugins (e.g. 1.786 + * the Flash plugin running in Camino) don't create their own TSM document -- 1.787 + * without which IME can't work. Others (e.g. the Flash plugin running in 1.788 + * Firefox) create a TSM document that (somehow) makes the input window behave 1.789 + * badly when it contains more than one kind of input (say Hiragana and 1.790 + * Romaji). (We can't just use the per-NSView TSM documents that Cocoa 1.791 + * provides (those created and managed by the NSTSMInputContext class) -- for 1.792 + * some reason TSMProcessRawKeyEvent() doesn't work with them.) 1.793 + */ 1.794 + void ActivatePluginTSMDocument(); 1.795 + 1.796 + /** 1.797 + * HandleCarbonPluginKeyEvent() handles the aKeyEvent. This is called by 1.798 + * PluginKeyEventsHandler(). 1.799 + * 1.800 + * @param aKeyEvent A native Carbon event. 1.801 + */ 1.802 + void HandleCarbonPluginKeyEvent(EventRef aKeyEvent); 1.803 + 1.804 + /** 1.805 + * Target for text services events sent as the result of calls made to 1.806 + * TSMProcessRawKeyEvent() in HandleKeyDownEventForPlugin() when a plugin has 1.807 + * the focus. The calls to TSMProcessRawKeyEvent() short-circuit Cocoa-based 1.808 + * IME (which would otherwise interfere with our efforts) and allow Carbon- 1.809 + * based IME to work in plugins (via the NPAPI). This strategy doesn't cause 1.810 + * trouble for plugins that (like the Java Embedding Plugin) bypass the NPAPI 1.811 + * to get their keyboard events and do their own Cocoa-based IME. 1.812 + */ 1.813 + static OSStatus PluginKeyEventsHandler(EventHandlerCallRef aHandlerRef, 1.814 + EventRef aEvent, 1.815 + void *aUserData); 1.816 + 1.817 + static EventHandlerRef sPluginKeyEventsHandler; 1.818 + 1.819 +#endif // #ifndef __LP64__ 1.820 +}; 1.821 + 1.822 +/** 1.823 + * IMEInputHandler manages: 1.824 + * 1. The IME/keyboard layout statement of nsChildView. 1.825 + * 2. The IME composition statement of nsChildView. 1.826 + * And also provides the methods which controls the current IME transaction of 1.827 + * the instance. 1.828 + * 1.829 + * Note that an nsChildView handles one or more NSView's events. E.g., even if 1.830 + * a text editor on XUL panel element, the input events handled on the parent 1.831 + * (or its ancestor) widget handles it (the native focus is set to it). The 1.832 + * actual focused view is notified by OnFocusChangeInGecko. 1.833 + */ 1.834 + 1.835 +class IMEInputHandler : public PluginTextInputHandler 1.836 +{ 1.837 +public: 1.838 + virtual bool OnDestroyWidget(nsChildView* aDestroyingWidget); 1.839 + 1.840 + virtual void OnFocusChangeInGecko(bool aFocus); 1.841 + 1.842 + void OnSelectionChange() { mSelectedRange.location = NSNotFound; } 1.843 + 1.844 + /** 1.845 + * DispatchTextEvent() dispatches a text event on mWidget. 1.846 + * 1.847 + * @param aText User text input. 1.848 + * @param aAttrString An NSAttributedString instance which indicates 1.849 + * current composition string. 1.850 + * @param aSelectedRange Current selected range (or caret position). 1.851 + * @param aDoCommit TRUE if the composition string should be 1.852 + * committed. Otherwise, FALSE. 1.853 + */ 1.854 + bool DispatchTextEvent(const nsString& aText, 1.855 + NSAttributedString* aAttrString, 1.856 + NSRange& aSelectedRange, 1.857 + bool aDoCommit); 1.858 + 1.859 + /** 1.860 + * SetMarkedText() is a handler of setMarkedText of NSTextInput. 1.861 + * 1.862 + * @param aAttrString This mut be an instance of NSAttributedString. 1.863 + * If the aString parameter to 1.864 + * [ChildView setMarkedText:setSelectedRange:] 1.865 + * isn't an instance of NSAttributedString, 1.866 + * create an NSAttributedString from it and pass 1.867 + * that instead. 1.868 + * @param aSelectedRange Current selected range (or caret position). 1.869 + * @param aReplacementRange The range which will be replaced with the 1.870 + * aAttrString instead of current marked range. 1.871 + */ 1.872 + void SetMarkedText(NSAttributedString* aAttrString, 1.873 + NSRange& aSelectedRange, 1.874 + NSRange* aReplacementRange = nullptr); 1.875 + 1.876 + /** 1.877 + * ConversationIdentifier() returns an ID for the current editor. The ID is 1.878 + * guaranteed to be unique among currently existing editors. But it might be 1.879 + * the same as the ID of an editor that has already been destroyed. 1.880 + * 1.881 + * @return An identifier of current focused editor. 1.882 + */ 1.883 + NSInteger ConversationIdentifier(); 1.884 + 1.885 + /** 1.886 + * GetAttributedSubstringFromRange() returns an NSAttributedString instance 1.887 + * which is allocated as autorelease for aRange. 1.888 + * 1.889 + * @param aRange The range of string which you want. 1.890 + * @param aActualRange The actual range of the result. 1.891 + * @return The string in aRange. If the string is empty, 1.892 + * this returns nil. If succeeded, this returns 1.893 + * an instance which is allocated as autorelease. 1.894 + * If this has some troubles, returns nil. 1.895 + */ 1.896 + NSAttributedString* GetAttributedSubstringFromRange( 1.897 + NSRange& aRange, 1.898 + NSRange* aActualRange = nullptr); 1.899 + 1.900 + /** 1.901 + * SelectedRange() returns current selected range. 1.902 + * 1.903 + * @return If an editor has focus, this returns selection 1.904 + * range in the editor. Otherwise, this returns 1.905 + * selection range in the focused document. 1.906 + */ 1.907 + NSRange SelectedRange(); 1.908 + 1.909 + /** 1.910 + * FirstRectForCharacterRange() returns first *character* rect in the range. 1.911 + * Cocoa needs the first line rect in the range, but we cannot compute it 1.912 + * on current implementation. 1.913 + * 1.914 + * @param aRange A range of text to examine. Its position is 1.915 + * an offset from the beginning of the focused 1.916 + * editor or document. 1.917 + * @param aActualRange If this is not null, this returns the actual 1.918 + * range used for computing the result. 1.919 + * @return An NSRect containing the first character in 1.920 + * aRange, in screen coordinates. 1.921 + * If the length of aRange is 0, the width will 1.922 + * be 0. 1.923 + */ 1.924 + NSRect FirstRectForCharacterRange(NSRange& aRange, 1.925 + NSRange* aActualRange = nullptr); 1.926 + 1.927 + /** 1.928 + * CharacterIndexForPoint() returns an offset of a character at aPoint. 1.929 + * XXX This isn't implemented, always returns 0. 1.930 + * 1.931 + * @param The point in screen coordinates. 1.932 + * @return The offset of the character at aPoint from 1.933 + * the beginning of the focused editor or 1.934 + * document. 1.935 + */ 1.936 + NSUInteger CharacterIndexForPoint(NSPoint& aPoint); 1.937 + 1.938 + /** 1.939 + * GetValidAttributesForMarkedText() returns attributes which we support. 1.940 + * 1.941 + * @return Always empty array for now. 1.942 + */ 1.943 + NSArray* GetValidAttributesForMarkedText(); 1.944 + 1.945 + bool HasMarkedText(); 1.946 + NSRange MarkedRange(); 1.947 + 1.948 + bool IsIMEComposing() { return mIsIMEComposing; } 1.949 + bool IsIMEOpened(); 1.950 + bool IsIMEEnabled() { return mIsIMEEnabled; } 1.951 + bool IsASCIICapableOnly() { return mIsASCIICapableOnly; } 1.952 + bool IgnoreIMECommit() { return mIgnoreIMECommit; } 1.953 + 1.954 + bool IgnoreIMEComposition() 1.955 + { 1.956 + // Ignore the IME composition events when we're pending to discard the 1.957 + // composition and we are not to handle the IME composition now. 1.958 + return (mPendingMethods & kDiscardIMEComposition) && 1.959 + (mIsInFocusProcessing || !IsFocused()); 1.960 + } 1.961 + 1.962 + void CommitIMEComposition(); 1.963 + void CancelIMEComposition(); 1.964 + 1.965 + void EnableIME(bool aEnableIME); 1.966 + void SetIMEOpenState(bool aOpen); 1.967 + void SetASCIICapableOnly(bool aASCIICapableOnly); 1.968 + 1.969 + bool IsFocused(); 1.970 + 1.971 + static CFArrayRef CreateAllIMEModeList(); 1.972 + static void DebugPrintAllIMEModes(); 1.973 + 1.974 + // Don't use ::TSMGetActiveDocument() API directly, the document may not 1.975 + // be what you want. 1.976 + static TSMDocumentID GetCurrentTSMDocumentID(); 1.977 + 1.978 +protected: 1.979 + // We cannot do some jobs in the given stack by some reasons. 1.980 + // Following flags and the timer provide the execution pending mechanism, 1.981 + // See the comment in nsCocoaTextInputHandler.mm. 1.982 + nsCOMPtr<nsITimer> mTimer; 1.983 + enum { 1.984 + kNotifyIMEOfFocusChangeInGecko = 1, 1.985 + kDiscardIMEComposition = 2, 1.986 + kSyncASCIICapableOnly = 4 1.987 + }; 1.988 + uint32_t mPendingMethods; 1.989 + 1.990 + IMEInputHandler(nsChildView* aWidget, NSView<mozView> *aNativeView); 1.991 + virtual ~IMEInputHandler(); 1.992 + 1.993 + void ResetTimer(); 1.994 + 1.995 + virtual void ExecutePendingMethods(); 1.996 + 1.997 + /** 1.998 + * InsertTextAsCommittingComposition() commits current composition. If there 1.999 + * is no composition, this starts a composition and commits it immediately. 1.1000 + * 1.1001 + * @param aAttrString A string which is committed. 1.1002 + * @param aReplacementRange The range which will be replaced with the 1.1003 + * aAttrString instead of current selection. 1.1004 + */ 1.1005 + void InsertTextAsCommittingComposition(NSAttributedString* aAttrString, 1.1006 + NSRange* aReplacementRange); 1.1007 + 1.1008 +private: 1.1009 + // If mIsIMEComposing is true, the composition string is stored here. 1.1010 + NSString* mIMECompositionString; 1.1011 + // mLastDispatchedCompositionString stores the lastest dispatched composition 1.1012 + // string by compositionupdate event. 1.1013 + nsString mLastDispatchedCompositionString; 1.1014 + 1.1015 + NSRange mMarkedRange; 1.1016 + NSRange mSelectedRange; 1.1017 + 1.1018 + bool mIsIMEComposing; 1.1019 + bool mIsIMEEnabled; 1.1020 + bool mIsASCIICapableOnly; 1.1021 + bool mIgnoreIMECommit; 1.1022 + // This flag is enabled by OnFocusChangeInGecko, and will be cleared by 1.1023 + // ExecutePendingMethods. When this is true, IsFocus() returns TRUE. At 1.1024 + // that time, the focus processing in Gecko might not be finished yet. So, 1.1025 + // you cannot use WidgetQueryContentEvent or something. 1.1026 + bool mIsInFocusProcessing; 1.1027 + bool mIMEHasFocus; 1.1028 + 1.1029 + void KillIMEComposition(); 1.1030 + void SendCommittedText(NSString *aString); 1.1031 + void OpenSystemPreferredLanguageIME(); 1.1032 + 1.1033 + // Pending methods 1.1034 + void NotifyIMEOfFocusChangeInGecko(); 1.1035 + void DiscardIMEComposition(); 1.1036 + void SyncASCIICapableOnly(); 1.1037 + 1.1038 + static bool sStaticMembersInitialized; 1.1039 + static CFStringRef sLatestIMEOpenedModeInputSourceID; 1.1040 + static void InitStaticMembers(); 1.1041 + static void OnCurrentTextInputSourceChange(CFNotificationCenterRef aCenter, 1.1042 + void* aObserver, 1.1043 + CFStringRef aName, 1.1044 + const void* aObject, 1.1045 + CFDictionaryRef aUserInfo); 1.1046 + 1.1047 + static void FlushPendingMethods(nsITimer* aTimer, void* aClosure); 1.1048 + 1.1049 + /** 1.1050 + * ConvertToTextRangeStyle converts the given native underline style to 1.1051 + * our defined text range type. 1.1052 + * 1.1053 + * @param aUnderlineStyle NSUnderlineStyleSingle or 1.1054 + * NSUnderlineStyleThick. 1.1055 + * @param aSelectedRange Current selected range (or caret position). 1.1056 + * @return NS_TEXTRANGE_*. 1.1057 + */ 1.1058 + uint32_t ConvertToTextRangeType(uint32_t aUnderlineStyle, 1.1059 + NSRange& aSelectedRange); 1.1060 + 1.1061 + /** 1.1062 + * GetRangeCount() computes the range count of aAttrString. 1.1063 + * 1.1064 + * @param aAttrString An NSAttributedString instance whose number of 1.1065 + * NSUnderlineStyleAttributeName ranges you with 1.1066 + * to know. 1.1067 + * @return The count of NSUnderlineStyleAttributeName 1.1068 + * ranges in aAttrString. 1.1069 + */ 1.1070 + uint32_t GetRangeCount(NSAttributedString *aString); 1.1071 + 1.1072 + /** 1.1073 + * CreateTextRangeArray() returns text ranges for clauses and/or caret. 1.1074 + * 1.1075 + * @param aAttrString An NSAttributedString instance which indicates 1.1076 + * current composition string. 1.1077 + * @param aSelectedRange Current selected range (or caret position). 1.1078 + * @return The result is set to the 1.1079 + * NSUnderlineStyleAttributeName ranges in 1.1080 + * aAttrString. 1.1081 + */ 1.1082 + already_AddRefed<mozilla::TextRangeArray> 1.1083 + CreateTextRangeArray(NSAttributedString *aAttrString, 1.1084 + NSRange& aSelectedRange); 1.1085 + 1.1086 + /** 1.1087 + * InitCompositionEvent() initializes aCompositionEvent. 1.1088 + * 1.1089 + * @param aCompositionEvent A composition event which you want to 1.1090 + * initialize. 1.1091 + */ 1.1092 + void InitCompositionEvent(WidgetCompositionEvent& aCompositionEvent); 1.1093 + 1.1094 + /** 1.1095 + * When a composition starts, OnStartIMEComposition() is called. 1.1096 + */ 1.1097 + void OnStartIMEComposition(); 1.1098 + 1.1099 + /** 1.1100 + * When a composition is updated, OnUpdateIMEComposition() is called. 1.1101 + */ 1.1102 + void OnUpdateIMEComposition(NSString* aIMECompositionString); 1.1103 + 1.1104 + /** 1.1105 + * When a composition is finished, OnEndIMEComposition() is called. 1.1106 + */ 1.1107 + void OnEndIMEComposition(); 1.1108 + 1.1109 + // The focused IME handler. Please note that the handler might lost the 1.1110 + // actual focus by deactivating the application. If we are active, this 1.1111 + // must have the actual focused handle. 1.1112 + // We cannot access to the NSInputManager during we aren't active, so, the 1.1113 + // focused handler can have an IME transaction even if we are deactive. 1.1114 + static IMEInputHandler* sFocusedIMEHandler; 1.1115 +}; 1.1116 + 1.1117 +/** 1.1118 + * TextInputHandler implements the NSTextInput protocol. 1.1119 + */ 1.1120 +class TextInputHandler : public IMEInputHandler 1.1121 +{ 1.1122 +public: 1.1123 + static NSUInteger sLastModifierState; 1.1124 + 1.1125 + static CFArrayRef CreateAllKeyboardLayoutList(); 1.1126 + static void DebugPrintAllKeyboardLayouts(); 1.1127 + 1.1128 + TextInputHandler(nsChildView* aWidget, NSView<mozView> *aNativeView); 1.1129 + virtual ~TextInputHandler(); 1.1130 + 1.1131 + /** 1.1132 + * KeyDown event handler. 1.1133 + * 1.1134 + * @param aNativeEvent A native NSKeyDown event. 1.1135 + * @return TRUE if the event is consumed by web contents 1.1136 + * or chrome contents. Otherwise, FALSE. 1.1137 + */ 1.1138 + bool HandleKeyDownEvent(NSEvent* aNativeEvent); 1.1139 + 1.1140 + /** 1.1141 + * KeyUp event handler. 1.1142 + * 1.1143 + * @param aNativeEvent A native NSKeyUp event. 1.1144 + */ 1.1145 + void HandleKeyUpEvent(NSEvent* aNativeEvent); 1.1146 + 1.1147 + /** 1.1148 + * FlagsChanged event handler. 1.1149 + * 1.1150 + * @param aNativeEvent A native NSFlagsChanged event. 1.1151 + */ 1.1152 + void HandleFlagsChanged(NSEvent* aNativeEvent); 1.1153 + 1.1154 + /** 1.1155 + * Insert the string to content. I.e., this is a text input event handler. 1.1156 + * If this is called during keydown event handling, this may dispatch a 1.1157 + * NS_KEY_PRESS event. If this is called during composition, this commits 1.1158 + * the composition by the aAttrString. 1.1159 + * 1.1160 + * @param aAttrString An inserted string. 1.1161 + * @param aReplacementRange The range which will be replaced with the 1.1162 + * aAttrString instead of current selection. 1.1163 + */ 1.1164 + void InsertText(NSAttributedString *aAttrString, 1.1165 + NSRange* aReplacementRange = nullptr); 1.1166 + 1.1167 + /** 1.1168 + * doCommandBySelector event handler. 1.1169 + * 1.1170 + * @param aSelector A selector of the command. 1.1171 + * @return TRUE if the command is consumed. Otherwise, 1.1172 + * FALSE. 1.1173 + */ 1.1174 + bool DoCommandBySelector(const char* aSelector); 1.1175 + 1.1176 + /** 1.1177 + * KeyPressWasHandled() checks whether keypress event was handled or not. 1.1178 + * 1.1179 + * @return TRUE if keypress event for latest native key 1.1180 + * event was handled. Otherwise, FALSE. 1.1181 + * If this handler isn't handling any key events, 1.1182 + * always returns FALSE. 1.1183 + */ 1.1184 + bool KeyPressWasHandled() 1.1185 + { 1.1186 + KeyEventState* currentKeyEvent = GetCurrentKeyEvent(); 1.1187 + return currentKeyEvent && currentKeyEvent->mKeyPressHandled; 1.1188 + } 1.1189 + 1.1190 +protected: 1.1191 + // Stores the association of device dependent modifier flags with a modifier 1.1192 + // keyCode. Being device dependent, this association may differ from one kind 1.1193 + // of hardware to the next. 1.1194 + struct ModifierKey 1.1195 + { 1.1196 + NSUInteger flags; 1.1197 + unsigned short keyCode; 1.1198 + 1.1199 + ModifierKey(NSUInteger aFlags, unsigned short aKeyCode) : 1.1200 + flags(aFlags), keyCode(aKeyCode) 1.1201 + { 1.1202 + } 1.1203 + 1.1204 + NSUInteger GetDeviceDependentFlags() const 1.1205 + { 1.1206 + return (flags & ~NSDeviceIndependentModifierFlagsMask); 1.1207 + } 1.1208 + 1.1209 + NSUInteger GetDeviceIndependentFlags() const 1.1210 + { 1.1211 + return (flags & NSDeviceIndependentModifierFlagsMask); 1.1212 + } 1.1213 + }; 1.1214 + typedef nsTArray<ModifierKey> ModifierKeyArray; 1.1215 + ModifierKeyArray mModifierKeys; 1.1216 + 1.1217 + /** 1.1218 + * GetModifierKeyForNativeKeyCode() returns the stored ModifierKey for 1.1219 + * the key. 1.1220 + */ 1.1221 + const ModifierKey* 1.1222 + GetModifierKeyForNativeKeyCode(unsigned short aKeyCode) const; 1.1223 + 1.1224 + /** 1.1225 + * GetModifierKeyForDeviceDependentFlags() returns the stored ModifierKey for 1.1226 + * the device dependent flags. 1.1227 + */ 1.1228 + const ModifierKey* 1.1229 + GetModifierKeyForDeviceDependentFlags(NSUInteger aFlags) const; 1.1230 + 1.1231 + /** 1.1232 + * DispatchKeyEventForFlagsChanged() dispatches keydown event or keyup event 1.1233 + * for the aNativeEvent. 1.1234 + * 1.1235 + * @param aNativeEvent A native flagschanged event which you want to 1.1236 + * dispatch our key event for. 1.1237 + * @param aDispatchKeyDown TRUE if you want to dispatch a keydown event. 1.1238 + * Otherwise, i.e., to dispatch keyup event, 1.1239 + * FALSE. 1.1240 + */ 1.1241 + void DispatchKeyEventForFlagsChanged(NSEvent* aNativeEvent, 1.1242 + bool aDispatchKeyDown); 1.1243 +}; 1.1244 + 1.1245 +} // namespace widget 1.1246 +} // namespace mozilla 1.1247 + 1.1248 +#endif // TextInputHandler_h_