Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 sw=2 et tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef TextInputHandler_h_
8 #define TextInputHandler_h_
10 #include "nsCocoaUtils.h"
12 #import <Carbon/Carbon.h>
13 #import <Cocoa/Cocoa.h>
14 #include "mozView.h"
15 #include "nsString.h"
16 #include "nsCOMPtr.h"
17 #include "nsITimer.h"
18 #include "npapi.h"
19 #include "nsTArray.h"
20 #include "mozilla/EventForwards.h"
22 class nsChildView;
24 namespace mozilla {
25 namespace widget {
27 // Key code constants
28 enum
29 {
30 kVK_RightCommand = 0x36, // right command key
32 kVK_PC_PrintScreen = kVK_F13,
33 kVK_PC_ScrollLock = kVK_F14,
34 kVK_PC_Pause = kVK_F15,
36 kVK_PC_Insert = kVK_Help,
37 kVK_PC_Backspace = kVK_Delete,
38 kVK_PC_Delete = kVK_ForwardDelete,
40 kVK_PC_ContextMenu = 0x6E,
42 kVK_Powerbook_KeypadEnter = 0x34 // Enter on Powerbook's keyboard is different
43 };
45 /**
46 * TISInputSourceWrapper is a wrapper for the TISInputSourceRef. If we get the
47 * TISInputSourceRef from InputSourceID, we need to release the CFArray instance
48 * which is returned by TISCreateInputSourceList. However, when we release the
49 * list, we cannot access the TISInputSourceRef. So, it's not usable, and it
50 * may cause the memory leak bugs. nsTISInputSource automatically releases the
51 * list when the instance is destroyed.
52 */
53 class TISInputSourceWrapper
54 {
55 public:
56 static TISInputSourceWrapper& CurrentInputSource();
58 TISInputSourceWrapper()
59 {
60 mInputSourceList = nullptr;
61 Clear();
62 }
64 TISInputSourceWrapper(const char* aID)
65 {
66 mInputSourceList = nullptr;
67 InitByInputSourceID(aID);
68 }
70 TISInputSourceWrapper(SInt32 aLayoutID)
71 {
72 mInputSourceList = nullptr;
73 InitByLayoutID(aLayoutID);
74 }
76 TISInputSourceWrapper(TISInputSourceRef aInputSource)
77 {
78 mInputSourceList = nullptr;
79 InitByTISInputSourceRef(aInputSource);
80 }
82 ~TISInputSourceWrapper() { Clear(); }
84 void InitByInputSourceID(const char* aID);
85 void InitByInputSourceID(const nsAFlatString &aID);
86 void InitByInputSourceID(const CFStringRef aID);
87 /**
88 * InitByLayoutID() initializes the keyboard layout by the layout ID.
89 *
90 * @param aLayoutID An ID of keyboard layout.
91 * 0: US
92 * 1: Greek
93 * 2: German
94 * 3: Swedish-Pro
95 * 4: Dvorak-Qwerty Cmd
96 * 5: Thai
97 * 6: Arabic
98 * 7: French
99 * 8: Hebrew
100 * 9: Lithuanian
101 * 10: Norwegian
102 * 11: Spanish
103 * @param aOverrideKeyboard When testing set to TRUE, otherwise, set to
104 * FALSE. When TRUE, we use an ANSI keyboard
105 * instead of the actual keyboard.
106 */
107 void InitByLayoutID(SInt32 aLayoutID, bool aOverrideKeyboard = false);
108 void InitByCurrentInputSource();
109 void InitByCurrentKeyboardLayout();
110 void InitByCurrentASCIICapableInputSource();
111 void InitByCurrentASCIICapableKeyboardLayout();
112 void InitByCurrentInputMethodKeyboardLayoutOverride();
113 void InitByTISInputSourceRef(TISInputSourceRef aInputSource);
114 void InitByLanguage(CFStringRef aLanguage);
116 /**
117 * If the instance is initialized with a keyboard layout input source,
118 * returns it.
119 * If the instance is initialized with an IME mode input source, the result
120 * references the keyboard layout for the IME mode. However, this can be
121 * initialized only when the IME mode is actually selected. I.e, if IME mode
122 * input source is initialized with LayoutID or SourceID, this returns null.
123 */
124 TISInputSourceRef GetKeyboardLayoutInputSource() const
125 {
126 return mKeyboardLayout;
127 }
128 const UCKeyboardLayout* GetUCKeyboardLayout();
130 bool IsOpenedIMEMode();
131 bool IsIMEMode();
132 bool IsKeyboardLayout();
134 bool IsASCIICapable()
135 {
136 NS_ENSURE_TRUE(mInputSource, false);
137 return GetBoolProperty(kTISPropertyInputSourceIsASCIICapable);
138 }
140 bool IsEnabled()
141 {
142 NS_ENSURE_TRUE(mInputSource, false);
143 return GetBoolProperty(kTISPropertyInputSourceIsEnabled);
144 }
146 bool GetLanguageList(CFArrayRef &aLanguageList);
147 bool GetPrimaryLanguage(CFStringRef &aPrimaryLanguage);
148 bool GetPrimaryLanguage(nsAString &aPrimaryLanguage);
150 bool GetLocalizedName(CFStringRef &aName)
151 {
152 NS_ENSURE_TRUE(mInputSource, false);
153 return GetStringProperty(kTISPropertyLocalizedName, aName);
154 }
156 bool GetLocalizedName(nsAString &aName)
157 {
158 NS_ENSURE_TRUE(mInputSource, false);
159 return GetStringProperty(kTISPropertyLocalizedName, aName);
160 }
162 bool GetInputSourceID(CFStringRef &aID)
163 {
164 NS_ENSURE_TRUE(mInputSource, false);
165 return GetStringProperty(kTISPropertyInputSourceID, aID);
166 }
168 bool GetInputSourceID(nsAString &aID)
169 {
170 NS_ENSURE_TRUE(mInputSource, false);
171 return GetStringProperty(kTISPropertyInputSourceID, aID);
172 }
174 bool GetBundleID(CFStringRef &aBundleID)
175 {
176 NS_ENSURE_TRUE(mInputSource, false);
177 return GetStringProperty(kTISPropertyBundleID, aBundleID);
178 }
180 bool GetBundleID(nsAString &aBundleID)
181 {
182 NS_ENSURE_TRUE(mInputSource, false);
183 return GetStringProperty(kTISPropertyBundleID, aBundleID);
184 }
186 bool GetInputSourceType(CFStringRef &aType)
187 {
188 NS_ENSURE_TRUE(mInputSource, false);
189 return GetStringProperty(kTISPropertyInputSourceType, aType);
190 }
192 bool GetInputSourceType(nsAString &aType)
193 {
194 NS_ENSURE_TRUE(mInputSource, false);
195 return GetStringProperty(kTISPropertyInputSourceType, aType);
196 }
198 bool IsForRTLLanguage();
199 bool IsInitializedByCurrentInputSource();
201 enum {
202 // 40 is an actual result of the ::LMGetKbdType() when we connect an
203 // unknown keyboard and set the keyboard type to ANSI manually on the
204 // set up dialog.
205 eKbdType_ANSI = 40
206 };
208 void Select();
209 void Clear();
211 /**
212 * InitKeyEvent() initializes aKeyEvent for aNativeKeyEvent.
213 *
214 * @param aNativeKeyEvent A native key event for which you want to
215 * dispatch a Gecko key event.
216 * @param aKeyEvent The result -- a Gecko key event initialized
217 * from the native key event.
218 * @param aInsertString If caller expects that the event will cause
219 * a character to be input (say in an editor),
220 * the caller should set this. Otherwise,
221 * if caller sets null to this, this method will
222 * compute the character to be input from
223 * characters of aNativeKeyEvent.
224 */
225 void InitKeyEvent(NSEvent *aNativeKeyEvent, WidgetKeyboardEvent& aKeyEvent,
226 const nsAString *aInsertString = nullptr);
228 /**
229 * ComputeGeckoKeyCode() returns Gecko keycode for aNativeKeyCode on current
230 * keyboard layout.
231 *
232 * @param aNativeKeyCode A native keycode.
233 * @param aKbType A native Keyboard Type value. Typically,
234 * this is a result of ::LMGetKbdType().
235 * @param aCmdIsPressed TRUE if Cmd key is pressed. Otherwise, FALSE.
236 * @return The computed Gecko keycode.
237 */
238 uint32_t ComputeGeckoKeyCode(UInt32 aNativeKeyCode, UInt32 aKbType,
239 bool aCmdIsPressed);
241 /**
242 * ComputeGeckoKeyNameIndex() returns Gecko key name index for the key.
243 *
244 * @param aNativeKeyCode A native keycode.
245 */
246 static KeyNameIndex ComputeGeckoKeyNameIndex(UInt32 aNativeKeyCode);
248 protected:
249 /**
250 * TranslateToString() computes the inputted text from the native keyCode,
251 * modifier flags and keyboard type.
252 *
253 * @param aKeyCode A native keyCode.
254 * @param aModifiers Combination of native modifier flags.
255 * @param aKbType A native Keyboard Type value. Typically,
256 * this is a result of ::LMGetKbdType().
257 * @param aStr Result, i.e., inputted text.
258 * The result can be two or more characters.
259 * @return If succeeded, TRUE. Otherwise, FALSE.
260 * Even if TRUE, aStr can be empty string.
261 */
262 bool TranslateToString(UInt32 aKeyCode, UInt32 aModifiers,
263 UInt32 aKbType, nsAString &aStr);
265 /**
266 * TranslateToChar() computes the inputted character from the native keyCode,
267 * modifier flags and keyboard type. If two or more characters would be
268 * input, this returns 0.
269 *
270 * @param aKeyCode A native keyCode.
271 * @param aModifiers Combination of native modifier flags.
272 * @param aKbType A native Keyboard Type value. Typically,
273 * this is a result of ::LMGetKbdType().
274 * @return If succeeded and the result is one character,
275 * returns the charCode of it. Otherwise,
276 * returns 0.
277 */
278 uint32_t TranslateToChar(UInt32 aKeyCode, UInt32 aModifiers, UInt32 aKbType);
280 /**
281 * InitKeyPressEvent() initializes aKeyEvent for aNativeKeyEvent.
282 * Don't call this method when aKeyEvent isn't NS_KEY_PRESS.
283 *
284 * @param aNativeKeyEvent A native key event for which you want to
285 * dispatch a Gecko key event.
286 * @param aInsertChar A character to be input in an editor by the
287 * event.
288 * @param aKeyEvent The result -- a Gecko key event initialized
289 * from the native key event. This must be
290 * NS_KEY_PRESS event.
291 * @param aKbType A native Keyboard Type value. Typically,
292 * this is a result of ::LMGetKbdType().
293 */
294 void InitKeyPressEvent(NSEvent *aNativeKeyEvent,
295 char16_t aInsertChar,
296 WidgetKeyboardEvent& aKeyEvent,
297 UInt32 aKbType);
299 bool GetBoolProperty(const CFStringRef aKey);
300 bool GetStringProperty(const CFStringRef aKey, CFStringRef &aStr);
301 bool GetStringProperty(const CFStringRef aKey, nsAString &aStr);
303 TISInputSourceRef mInputSource;
304 TISInputSourceRef mKeyboardLayout;
305 CFArrayRef mInputSourceList;
306 const UCKeyboardLayout* mUCKeyboardLayout;
307 int8_t mIsRTL;
309 bool mOverrideKeyboard;
310 };
312 /**
313 * TextInputHandlerBase is a base class of PluginTextInputHandler,
314 * IMEInputHandler and TextInputHandler. Utility methods should be implemented
315 * this level.
316 */
318 class TextInputHandlerBase
319 {
320 public:
321 nsrefcnt AddRef()
322 {
323 NS_PRECONDITION(int32_t(mRefCnt) >= 0, "mRefCnt is negative");
324 ++mRefCnt;
325 NS_LOG_ADDREF(this, mRefCnt, "TextInputHandlerBase", sizeof(*this));
326 return mRefCnt;
327 }
328 nsrefcnt Release()
329 {
330 NS_PRECONDITION(mRefCnt != 0, "mRefCnt is alrady zero");
331 --mRefCnt;
332 NS_LOG_RELEASE(this, mRefCnt, "TextInputHandlerBase");
333 if (mRefCnt == 0) {
334 mRefCnt = 1; /* stabilize */
335 delete this;
336 return 0;
337 }
338 return mRefCnt;
339 }
341 /**
342 * DispatchEvent() dispatches aEvent on mWidget.
343 *
344 * @param aEvent An event which you want to dispatch.
345 * @return TRUE if the event is consumed by web contents
346 * or chrome contents. Otherwise, FALSE.
347 */
348 bool DispatchEvent(WidgetGUIEvent& aEvent);
350 /**
351 * SetSelection() dispatches NS_SELECTION_SET event for the aRange.
352 *
353 * @param aRange The range which will be selected.
354 * @return TRUE if setting selection is succeeded and
355 * the widget hasn't been destroyed.
356 * Otherwise, FALSE.
357 */
358 bool SetSelection(NSRange& aRange);
360 /**
361 * InitKeyEvent() initializes aKeyEvent for aNativeKeyEvent.
362 *
363 * @param aNativeKeyEvent A native key event for which you want to
364 * dispatch a Gecko key event.
365 * @param aKeyEvent The result -- a Gecko key event initialized
366 * from the native key event.
367 * @param aInsertString If caller expects that the event will cause
368 * a character to be input (say in an editor),
369 * the caller should set this. Otherwise,
370 * if caller sets null to this, this method will
371 * compute the character to be input from
372 * characters of aNativeKeyEvent.
373 */
374 void InitKeyEvent(NSEvent *aNativeKeyEvent, WidgetKeyboardEvent& aKeyEvent,
375 const nsAString *aInsertString = nullptr);
377 /**
378 * SynthesizeNativeKeyEvent() is an implementation of
379 * nsIWidget::SynthesizeNativeKeyEvent(). See the document in nsIWidget.h
380 * for the detail.
381 */
382 nsresult SynthesizeNativeKeyEvent(int32_t aNativeKeyboardLayout,
383 int32_t aNativeKeyCode,
384 uint32_t aModifierFlags,
385 const nsAString& aCharacters,
386 const nsAString& aUnmodifiedCharacters);
388 /**
389 * Utility method intended for testing. Attempts to construct a native key
390 * event that would have been generated during an actual key press. This
391 * *does not dispatch* the native event. Instead, it is attached to the
392 * |mNativeKeyEvent| field of the Gecko event that is passed in.
393 * @param aKeyEvent Gecko key event to attach the native event to
394 */
395 NS_IMETHOD AttachNativeKeyEvent(WidgetKeyboardEvent& aKeyEvent);
397 /**
398 * GetWindowLevel() returns the window level of current focused (in Gecko)
399 * window. E.g., if an <input> element in XUL panel has focus, this returns
400 * the XUL panel's window level.
401 */
402 NSInteger GetWindowLevel();
404 /**
405 * IsSpecialGeckoKey() checks whether aNativeKeyCode is mapped to a special
406 * Gecko keyCode. A key is "special" if it isn't used for text input.
407 *
408 * @param aNativeKeyCode A native keycode.
409 * @return If the keycode is mapped to a special key,
410 * TRUE. Otherwise, FALSE.
411 */
412 static bool IsSpecialGeckoKey(UInt32 aNativeKeyCode);
415 /**
416 * EnableSecureEventInput() and DisableSecureEventInput() wrap the Carbon
417 * Event Manager APIs with the same names. In addition they keep track of
418 * how many times we've called them (in the same process) -- unlike the
419 * Carbon Event Manager APIs, which only keep track of how many times they've
420 * been called from any and all processes.
421 *
422 * The Carbon Event Manager's IsSecureEventInputEnabled() returns whether
423 * secure event input mode is enabled (in any process). This class's
424 * IsSecureEventInputEnabled() returns whether we've made any calls to
425 * EnableSecureEventInput() that are not (yet) offset by the calls we've
426 * made to DisableSecureEventInput().
427 */
428 static void EnableSecureEventInput();
429 static void DisableSecureEventInput();
430 static bool IsSecureEventInputEnabled();
432 /**
433 * EnsureSecureEventInputDisabled() calls DisableSecureEventInput() until
434 * our call count becomes 0.
435 */
436 static void EnsureSecureEventInputDisabled();
438 protected:
439 nsAutoRefCnt mRefCnt;
441 public:
442 /**
443 * mWidget must not be destroyed without OnDestroyWidget being called.
444 *
445 * @param aDestroyingWidget Destroying widget. This might not be mWidget.
446 * @return This result doesn't have any meaning for
447 * callers. When aDstroyingWidget isn't the same
448 * as mWidget, FALSE. Then, inherited methods in
449 * sub classes should return from this method
450 * without cleaning up.
451 */
452 virtual bool OnDestroyWidget(nsChildView* aDestroyingWidget);
454 protected:
455 // The creater of this instance and client.
456 // This must not be null after initialized until OnDestroyWidget() is called.
457 nsChildView* mWidget; // [WEAK]
459 // The native view for mWidget.
460 // This view handles the actual text inputting.
461 NSView<mozView>* mView; // [STRONG]
463 TextInputHandlerBase(nsChildView* aWidget, NSView<mozView> *aNativeView);
464 virtual ~TextInputHandlerBase();
466 bool Destroyed() { return !mWidget; }
468 /**
469 * mCurrentKeyEvent indicates what key event we are handling. While
470 * handling a native keydown event, we need to store the event for insertText,
471 * doCommandBySelector and various action message handlers of NSResponder
472 * such as [NSResponder insertNewline:sender].
473 */
474 struct KeyEventState
475 {
476 // Handling native key event
477 NSEvent* mKeyEvent;
478 // Whether keydown event was consumed by web contents or chrome contents.
479 bool mKeyDownHandled;
480 // Whether keypress event was dispatched for mKeyEvent.
481 bool mKeyPressDispatched;
482 // Whether keypress event was consumed by web contents or chrome contents.
483 bool mKeyPressHandled;
484 // Whether the key event causes other key events via IME or something.
485 bool mCausedOtherKeyEvents;
487 KeyEventState() : mKeyEvent(nullptr)
488 {
489 Clear();
490 }
492 KeyEventState(NSEvent* aNativeKeyEvent) : mKeyEvent(nullptr)
493 {
494 Clear();
495 Set(aNativeKeyEvent);
496 }
498 KeyEventState(const KeyEventState &aOther) : mKeyEvent(nullptr)
499 {
500 Clear();
501 if (aOther.mKeyEvent) {
502 mKeyEvent = [aOther.mKeyEvent retain];
503 }
504 mKeyDownHandled = aOther.mKeyDownHandled;
505 mKeyPressDispatched = aOther.mKeyPressDispatched;
506 mKeyPressHandled = aOther.mKeyPressHandled;
507 mCausedOtherKeyEvents = aOther.mCausedOtherKeyEvents;
508 }
510 ~KeyEventState()
511 {
512 Clear();
513 }
515 void Set(NSEvent* aNativeKeyEvent)
516 {
517 NS_PRECONDITION(aNativeKeyEvent, "aNativeKeyEvent must not be NULL");
518 Clear();
519 mKeyEvent = [aNativeKeyEvent retain];
520 }
522 void Clear()
523 {
524 if (mKeyEvent) {
525 [mKeyEvent release];
526 mKeyEvent = nullptr;
527 }
528 mKeyDownHandled = false;
529 mKeyPressDispatched = false;
530 mKeyPressHandled = false;
531 mCausedOtherKeyEvents = false;
532 }
534 bool IsDefaultPrevented() const
535 {
536 return mKeyDownHandled || mKeyPressHandled || mCausedOtherKeyEvents;
537 }
539 bool CanDispatchKeyPressEvent() const
540 {
541 return !mKeyPressDispatched && !IsDefaultPrevented();
542 }
543 };
545 /**
546 * Helper class for guaranteeing cleaning mCurrentKeyEvent
547 */
548 class AutoKeyEventStateCleaner
549 {
550 public:
551 AutoKeyEventStateCleaner(TextInputHandlerBase* aHandler) :
552 mHandler(aHandler)
553 {
554 }
556 ~AutoKeyEventStateCleaner()
557 {
558 mHandler->RemoveCurrentKeyEvent();
559 }
560 private:
561 nsRefPtr<TextInputHandlerBase> mHandler;
562 };
564 /**
565 * mCurrentKeyEvents stores all key events which are being processed.
566 * When we call interpretKeyEvents, IME may generate other key events.
567 * mCurrentKeyEvents[0] is the latest key event.
568 */
569 nsTArray<KeyEventState*> mCurrentKeyEvents;
571 /**
572 * mFirstKeyEvent must be used for first key event. This member prevents
573 * memory fragmentation for most key events.
574 */
575 KeyEventState mFirstKeyEvent;
577 /**
578 * PushKeyEvent() adds the current key event to mCurrentKeyEvents.
579 */
580 KeyEventState* PushKeyEvent(NSEvent* aNativeKeyEvent)
581 {
582 uint32_t nestCount = mCurrentKeyEvents.Length();
583 for (uint32_t i = 0; i < nestCount; i++) {
584 // When the key event is caused by another key event, all key events
585 // which are being handled should be marked as "consumed".
586 mCurrentKeyEvents[i]->mCausedOtherKeyEvents = true;
587 }
589 KeyEventState* keyEvent = nullptr;
590 if (nestCount == 0) {
591 mFirstKeyEvent.Set(aNativeKeyEvent);
592 keyEvent = &mFirstKeyEvent;
593 } else {
594 keyEvent = new KeyEventState(aNativeKeyEvent);
595 }
596 return *mCurrentKeyEvents.AppendElement(keyEvent);
597 }
599 /**
600 * RemoveCurrentKeyEvent() removes the current key event from
601 * mCurrentKeyEvents.
602 */
603 void RemoveCurrentKeyEvent()
604 {
605 NS_ASSERTION(mCurrentKeyEvents.Length() > 0,
606 "RemoveCurrentKeyEvent() is called unexpectedly");
607 KeyEventState* keyEvent = GetCurrentKeyEvent();
608 mCurrentKeyEvents.RemoveElementAt(mCurrentKeyEvents.Length() - 1);
609 if (keyEvent == &mFirstKeyEvent) {
610 keyEvent->Clear();
611 } else {
612 delete keyEvent;
613 }
614 }
616 /**
617 * GetCurrentKeyEvent() returns current processing key event.
618 */
619 KeyEventState* GetCurrentKeyEvent()
620 {
621 if (mCurrentKeyEvents.Length() == 0) {
622 return nullptr;
623 }
624 return mCurrentKeyEvents[mCurrentKeyEvents.Length() - 1];
625 }
627 /**
628 * IsPrintableChar() checks whether the unicode character is
629 * a non-printable ASCII character or not. Note that this returns
630 * TRUE even if aChar is a non-printable UNICODE character.
631 *
632 * @param aChar A unicode character.
633 * @return TRUE if aChar is a printable ASCII character
634 * or a unicode character. Otherwise, i.e,
635 * if aChar is a non-printable ASCII character,
636 * FALSE.
637 */
638 static bool IsPrintableChar(char16_t aChar);
640 /**
641 * IsNormalCharInputtingEvent() checks whether aKeyEvent causes text input.
642 *
643 * @param aKeyEvent A key event.
644 * @return TRUE if the key event causes text input.
645 * Otherwise, FALSE.
646 */
647 static bool IsNormalCharInputtingEvent(const WidgetKeyboardEvent& aKeyEvent);
649 /**
650 * IsModifierKey() checks whether the native keyCode is for a modifier key.
651 *
652 * @param aNativeKeyCode A native keyCode.
653 * @return TRUE if aNativeKeyCode is for a modifier key.
654 * Otherwise, FALSE.
655 */
656 static bool IsModifierKey(UInt32 aNativeKeyCode);
658 private:
659 struct KeyboardLayoutOverride {
660 int32_t mKeyboardLayout;
661 bool mOverrideEnabled;
663 KeyboardLayoutOverride() :
664 mKeyboardLayout(0), mOverrideEnabled(false)
665 {
666 }
667 };
669 KeyboardLayoutOverride mKeyboardOverride;
671 static int32_t sSecureEventInputCount;
672 };
674 /**
675 * PluginTextInputHandler handles text input events for plugins.
676 */
678 class PluginTextInputHandler : public TextInputHandlerBase
679 {
680 public:
682 /**
683 * When starting complex text input for current event on plugin, this is
684 * called. See also the comment of StartComplexTextInputForCurrentEvent() of
685 * nsIPluginWidget.
686 */
687 nsresult StartComplexTextInputForCurrentEvent()
688 {
689 mPluginComplexTextInputRequested = true;
690 return NS_OK;
691 }
693 /**
694 * HandleKeyDownEventForPlugin() handles aNativeKeyEvent.
695 *
696 * @param aNativeKeyEvent A native NSKeyDown event.
697 */
698 void HandleKeyDownEventForPlugin(NSEvent* aNativeKeyEvent);
700 /**
701 * HandleKeyUpEventForPlugin() handles aNativeKeyEvent.
702 *
703 * @param aNativeKeyEvent A native NSKeyUp event.
704 */
705 void HandleKeyUpEventForPlugin(NSEvent* aNativeKeyEvent);
707 /**
708 * ConvertCocoaKeyEventToNPCocoaEvent() converts aCocoaEvent to NPCocoaEvent.
709 *
710 * @param aCocoaEvent A native key event.
711 * @param aPluginEvent The result.
712 */
713 static void ConvertCocoaKeyEventToNPCocoaEvent(NSEvent* aCocoaEvent,
714 NPCocoaEvent& aPluginEvent);
716 #ifndef __LP64__
718 /**
719 * InstallPluginKeyEventsHandler() is called when initializing process.
720 * RemovePluginKeyEventsHandler() is called when finalizing process.
721 * These methods initialize/finalize global resource for handling events for
722 * plugins.
723 */
724 static void InstallPluginKeyEventsHandler();
725 static void RemovePluginKeyEventsHandler();
727 /**
728 * This must be called before first key/IME event for plugins.
729 * This method initializes IMKInputSession methods swizzling.
730 */
731 static void SwizzleMethods();
733 /**
734 * When a composition starts or finishes, this is called.
735 */
736 void SetPluginTSMInComposition(bool aInComposition)
737 {
738 mPluginTSMInComposition = aInComposition;
739 }
741 #endif // #ifndef __LP64__
743 protected:
744 bool mIgnoreNextKeyUpEvent;
746 PluginTextInputHandler(nsChildView* aWidget, NSView<mozView> *aNativeView);
747 ~PluginTextInputHandler();
749 private:
751 #ifndef __LP64__
752 TSMDocumentID mPluginTSMDoc;
754 bool mPluginTSMInComposition;
755 #endif // #ifndef __LP64__
757 bool mPluginComplexTextInputRequested;
759 /**
760 * DispatchCocoaNPAPITextEvent() dispatches a text event for Cocoa plugin.
761 *
762 * @param aString A string inputted by the dispatching event.
763 * @return TRUE if the dispatched event was consumed.
764 * Otherwise, FALSE.
765 */
766 bool DispatchCocoaNPAPITextEvent(NSString* aString);
768 /**
769 * Whether the plugin is in composition or not.
770 * On 32bit build, this returns the state of mPluginTSMInComposition.
771 * On 64bit build, this returns ComplexTextInputPanel's state.
772 *
773 * @return TRUE if plugin is in composition. Otherwise,
774 * FALSE.
775 */
776 bool IsInPluginComposition();
778 #ifndef __LP64__
780 /**
781 * Create a TSM document for use with plugins, so that we can support IME in
782 * them. Once it's created, if need be (re)activate it. Some plugins (e.g.
783 * the Flash plugin running in Camino) don't create their own TSM document --
784 * without which IME can't work. Others (e.g. the Flash plugin running in
785 * Firefox) create a TSM document that (somehow) makes the input window behave
786 * badly when it contains more than one kind of input (say Hiragana and
787 * Romaji). (We can't just use the per-NSView TSM documents that Cocoa
788 * provides (those created and managed by the NSTSMInputContext class) -- for
789 * some reason TSMProcessRawKeyEvent() doesn't work with them.)
790 */
791 void ActivatePluginTSMDocument();
793 /**
794 * HandleCarbonPluginKeyEvent() handles the aKeyEvent. This is called by
795 * PluginKeyEventsHandler().
796 *
797 * @param aKeyEvent A native Carbon event.
798 */
799 void HandleCarbonPluginKeyEvent(EventRef aKeyEvent);
801 /**
802 * Target for text services events sent as the result of calls made to
803 * TSMProcessRawKeyEvent() in HandleKeyDownEventForPlugin() when a plugin has
804 * the focus. The calls to TSMProcessRawKeyEvent() short-circuit Cocoa-based
805 * IME (which would otherwise interfere with our efforts) and allow Carbon-
806 * based IME to work in plugins (via the NPAPI). This strategy doesn't cause
807 * trouble for plugins that (like the Java Embedding Plugin) bypass the NPAPI
808 * to get their keyboard events and do their own Cocoa-based IME.
809 */
810 static OSStatus PluginKeyEventsHandler(EventHandlerCallRef aHandlerRef,
811 EventRef aEvent,
812 void *aUserData);
814 static EventHandlerRef sPluginKeyEventsHandler;
816 #endif // #ifndef __LP64__
817 };
819 /**
820 * IMEInputHandler manages:
821 * 1. The IME/keyboard layout statement of nsChildView.
822 * 2. The IME composition statement of nsChildView.
823 * And also provides the methods which controls the current IME transaction of
824 * the instance.
825 *
826 * Note that an nsChildView handles one or more NSView's events. E.g., even if
827 * a text editor on XUL panel element, the input events handled on the parent
828 * (or its ancestor) widget handles it (the native focus is set to it). The
829 * actual focused view is notified by OnFocusChangeInGecko.
830 */
832 class IMEInputHandler : public PluginTextInputHandler
833 {
834 public:
835 virtual bool OnDestroyWidget(nsChildView* aDestroyingWidget);
837 virtual void OnFocusChangeInGecko(bool aFocus);
839 void OnSelectionChange() { mSelectedRange.location = NSNotFound; }
841 /**
842 * DispatchTextEvent() dispatches a text event on mWidget.
843 *
844 * @param aText User text input.
845 * @param aAttrString An NSAttributedString instance which indicates
846 * current composition string.
847 * @param aSelectedRange Current selected range (or caret position).
848 * @param aDoCommit TRUE if the composition string should be
849 * committed. Otherwise, FALSE.
850 */
851 bool DispatchTextEvent(const nsString& aText,
852 NSAttributedString* aAttrString,
853 NSRange& aSelectedRange,
854 bool aDoCommit);
856 /**
857 * SetMarkedText() is a handler of setMarkedText of NSTextInput.
858 *
859 * @param aAttrString This mut be an instance of NSAttributedString.
860 * If the aString parameter to
861 * [ChildView setMarkedText:setSelectedRange:]
862 * isn't an instance of NSAttributedString,
863 * create an NSAttributedString from it and pass
864 * that instead.
865 * @param aSelectedRange Current selected range (or caret position).
866 * @param aReplacementRange The range which will be replaced with the
867 * aAttrString instead of current marked range.
868 */
869 void SetMarkedText(NSAttributedString* aAttrString,
870 NSRange& aSelectedRange,
871 NSRange* aReplacementRange = nullptr);
873 /**
874 * ConversationIdentifier() returns an ID for the current editor. The ID is
875 * guaranteed to be unique among currently existing editors. But it might be
876 * the same as the ID of an editor that has already been destroyed.
877 *
878 * @return An identifier of current focused editor.
879 */
880 NSInteger ConversationIdentifier();
882 /**
883 * GetAttributedSubstringFromRange() returns an NSAttributedString instance
884 * which is allocated as autorelease for aRange.
885 *
886 * @param aRange The range of string which you want.
887 * @param aActualRange The actual range of the result.
888 * @return The string in aRange. If the string is empty,
889 * this returns nil. If succeeded, this returns
890 * an instance which is allocated as autorelease.
891 * If this has some troubles, returns nil.
892 */
893 NSAttributedString* GetAttributedSubstringFromRange(
894 NSRange& aRange,
895 NSRange* aActualRange = nullptr);
897 /**
898 * SelectedRange() returns current selected range.
899 *
900 * @return If an editor has focus, this returns selection
901 * range in the editor. Otherwise, this returns
902 * selection range in the focused document.
903 */
904 NSRange SelectedRange();
906 /**
907 * FirstRectForCharacterRange() returns first *character* rect in the range.
908 * Cocoa needs the first line rect in the range, but we cannot compute it
909 * on current implementation.
910 *
911 * @param aRange A range of text to examine. Its position is
912 * an offset from the beginning of the focused
913 * editor or document.
914 * @param aActualRange If this is not null, this returns the actual
915 * range used for computing the result.
916 * @return An NSRect containing the first character in
917 * aRange, in screen coordinates.
918 * If the length of aRange is 0, the width will
919 * be 0.
920 */
921 NSRect FirstRectForCharacterRange(NSRange& aRange,
922 NSRange* aActualRange = nullptr);
924 /**
925 * CharacterIndexForPoint() returns an offset of a character at aPoint.
926 * XXX This isn't implemented, always returns 0.
927 *
928 * @param The point in screen coordinates.
929 * @return The offset of the character at aPoint from
930 * the beginning of the focused editor or
931 * document.
932 */
933 NSUInteger CharacterIndexForPoint(NSPoint& aPoint);
935 /**
936 * GetValidAttributesForMarkedText() returns attributes which we support.
937 *
938 * @return Always empty array for now.
939 */
940 NSArray* GetValidAttributesForMarkedText();
942 bool HasMarkedText();
943 NSRange MarkedRange();
945 bool IsIMEComposing() { return mIsIMEComposing; }
946 bool IsIMEOpened();
947 bool IsIMEEnabled() { return mIsIMEEnabled; }
948 bool IsASCIICapableOnly() { return mIsASCIICapableOnly; }
949 bool IgnoreIMECommit() { return mIgnoreIMECommit; }
951 bool IgnoreIMEComposition()
952 {
953 // Ignore the IME composition events when we're pending to discard the
954 // composition and we are not to handle the IME composition now.
955 return (mPendingMethods & kDiscardIMEComposition) &&
956 (mIsInFocusProcessing || !IsFocused());
957 }
959 void CommitIMEComposition();
960 void CancelIMEComposition();
962 void EnableIME(bool aEnableIME);
963 void SetIMEOpenState(bool aOpen);
964 void SetASCIICapableOnly(bool aASCIICapableOnly);
966 bool IsFocused();
968 static CFArrayRef CreateAllIMEModeList();
969 static void DebugPrintAllIMEModes();
971 // Don't use ::TSMGetActiveDocument() API directly, the document may not
972 // be what you want.
973 static TSMDocumentID GetCurrentTSMDocumentID();
975 protected:
976 // We cannot do some jobs in the given stack by some reasons.
977 // Following flags and the timer provide the execution pending mechanism,
978 // See the comment in nsCocoaTextInputHandler.mm.
979 nsCOMPtr<nsITimer> mTimer;
980 enum {
981 kNotifyIMEOfFocusChangeInGecko = 1,
982 kDiscardIMEComposition = 2,
983 kSyncASCIICapableOnly = 4
984 };
985 uint32_t mPendingMethods;
987 IMEInputHandler(nsChildView* aWidget, NSView<mozView> *aNativeView);
988 virtual ~IMEInputHandler();
990 void ResetTimer();
992 virtual void ExecutePendingMethods();
994 /**
995 * InsertTextAsCommittingComposition() commits current composition. If there
996 * is no composition, this starts a composition and commits it immediately.
997 *
998 * @param aAttrString A string which is committed.
999 * @param aReplacementRange The range which will be replaced with the
1000 * aAttrString instead of current selection.
1001 */
1002 void InsertTextAsCommittingComposition(NSAttributedString* aAttrString,
1003 NSRange* aReplacementRange);
1005 private:
1006 // If mIsIMEComposing is true, the composition string is stored here.
1007 NSString* mIMECompositionString;
1008 // mLastDispatchedCompositionString stores the lastest dispatched composition
1009 // string by compositionupdate event.
1010 nsString mLastDispatchedCompositionString;
1012 NSRange mMarkedRange;
1013 NSRange mSelectedRange;
1015 bool mIsIMEComposing;
1016 bool mIsIMEEnabled;
1017 bool mIsASCIICapableOnly;
1018 bool mIgnoreIMECommit;
1019 // This flag is enabled by OnFocusChangeInGecko, and will be cleared by
1020 // ExecutePendingMethods. When this is true, IsFocus() returns TRUE. At
1021 // that time, the focus processing in Gecko might not be finished yet. So,
1022 // you cannot use WidgetQueryContentEvent or something.
1023 bool mIsInFocusProcessing;
1024 bool mIMEHasFocus;
1026 void KillIMEComposition();
1027 void SendCommittedText(NSString *aString);
1028 void OpenSystemPreferredLanguageIME();
1030 // Pending methods
1031 void NotifyIMEOfFocusChangeInGecko();
1032 void DiscardIMEComposition();
1033 void SyncASCIICapableOnly();
1035 static bool sStaticMembersInitialized;
1036 static CFStringRef sLatestIMEOpenedModeInputSourceID;
1037 static void InitStaticMembers();
1038 static void OnCurrentTextInputSourceChange(CFNotificationCenterRef aCenter,
1039 void* aObserver,
1040 CFStringRef aName,
1041 const void* aObject,
1042 CFDictionaryRef aUserInfo);
1044 static void FlushPendingMethods(nsITimer* aTimer, void* aClosure);
1046 /**
1047 * ConvertToTextRangeStyle converts the given native underline style to
1048 * our defined text range type.
1049 *
1050 * @param aUnderlineStyle NSUnderlineStyleSingle or
1051 * NSUnderlineStyleThick.
1052 * @param aSelectedRange Current selected range (or caret position).
1053 * @return NS_TEXTRANGE_*.
1054 */
1055 uint32_t ConvertToTextRangeType(uint32_t aUnderlineStyle,
1056 NSRange& aSelectedRange);
1058 /**
1059 * GetRangeCount() computes the range count of aAttrString.
1060 *
1061 * @param aAttrString An NSAttributedString instance whose number of
1062 * NSUnderlineStyleAttributeName ranges you with
1063 * to know.
1064 * @return The count of NSUnderlineStyleAttributeName
1065 * ranges in aAttrString.
1066 */
1067 uint32_t GetRangeCount(NSAttributedString *aString);
1069 /**
1070 * CreateTextRangeArray() returns text ranges for clauses and/or caret.
1071 *
1072 * @param aAttrString An NSAttributedString instance which indicates
1073 * current composition string.
1074 * @param aSelectedRange Current selected range (or caret position).
1075 * @return The result is set to the
1076 * NSUnderlineStyleAttributeName ranges in
1077 * aAttrString.
1078 */
1079 already_AddRefed<mozilla::TextRangeArray>
1080 CreateTextRangeArray(NSAttributedString *aAttrString,
1081 NSRange& aSelectedRange);
1083 /**
1084 * InitCompositionEvent() initializes aCompositionEvent.
1085 *
1086 * @param aCompositionEvent A composition event which you want to
1087 * initialize.
1088 */
1089 void InitCompositionEvent(WidgetCompositionEvent& aCompositionEvent);
1091 /**
1092 * When a composition starts, OnStartIMEComposition() is called.
1093 */
1094 void OnStartIMEComposition();
1096 /**
1097 * When a composition is updated, OnUpdateIMEComposition() is called.
1098 */
1099 void OnUpdateIMEComposition(NSString* aIMECompositionString);
1101 /**
1102 * When a composition is finished, OnEndIMEComposition() is called.
1103 */
1104 void OnEndIMEComposition();
1106 // The focused IME handler. Please note that the handler might lost the
1107 // actual focus by deactivating the application. If we are active, this
1108 // must have the actual focused handle.
1109 // We cannot access to the NSInputManager during we aren't active, so, the
1110 // focused handler can have an IME transaction even if we are deactive.
1111 static IMEInputHandler* sFocusedIMEHandler;
1112 };
1114 /**
1115 * TextInputHandler implements the NSTextInput protocol.
1116 */
1117 class TextInputHandler : public IMEInputHandler
1118 {
1119 public:
1120 static NSUInteger sLastModifierState;
1122 static CFArrayRef CreateAllKeyboardLayoutList();
1123 static void DebugPrintAllKeyboardLayouts();
1125 TextInputHandler(nsChildView* aWidget, NSView<mozView> *aNativeView);
1126 virtual ~TextInputHandler();
1128 /**
1129 * KeyDown event handler.
1130 *
1131 * @param aNativeEvent A native NSKeyDown event.
1132 * @return TRUE if the event is consumed by web contents
1133 * or chrome contents. Otherwise, FALSE.
1134 */
1135 bool HandleKeyDownEvent(NSEvent* aNativeEvent);
1137 /**
1138 * KeyUp event handler.
1139 *
1140 * @param aNativeEvent A native NSKeyUp event.
1141 */
1142 void HandleKeyUpEvent(NSEvent* aNativeEvent);
1144 /**
1145 * FlagsChanged event handler.
1146 *
1147 * @param aNativeEvent A native NSFlagsChanged event.
1148 */
1149 void HandleFlagsChanged(NSEvent* aNativeEvent);
1151 /**
1152 * Insert the string to content. I.e., this is a text input event handler.
1153 * If this is called during keydown event handling, this may dispatch a
1154 * NS_KEY_PRESS event. If this is called during composition, this commits
1155 * the composition by the aAttrString.
1156 *
1157 * @param aAttrString An inserted string.
1158 * @param aReplacementRange The range which will be replaced with the
1159 * aAttrString instead of current selection.
1160 */
1161 void InsertText(NSAttributedString *aAttrString,
1162 NSRange* aReplacementRange = nullptr);
1164 /**
1165 * doCommandBySelector event handler.
1166 *
1167 * @param aSelector A selector of the command.
1168 * @return TRUE if the command is consumed. Otherwise,
1169 * FALSE.
1170 */
1171 bool DoCommandBySelector(const char* aSelector);
1173 /**
1174 * KeyPressWasHandled() checks whether keypress event was handled or not.
1175 *
1176 * @return TRUE if keypress event for latest native key
1177 * event was handled. Otherwise, FALSE.
1178 * If this handler isn't handling any key events,
1179 * always returns FALSE.
1180 */
1181 bool KeyPressWasHandled()
1182 {
1183 KeyEventState* currentKeyEvent = GetCurrentKeyEvent();
1184 return currentKeyEvent && currentKeyEvent->mKeyPressHandled;
1185 }
1187 protected:
1188 // Stores the association of device dependent modifier flags with a modifier
1189 // keyCode. Being device dependent, this association may differ from one kind
1190 // of hardware to the next.
1191 struct ModifierKey
1192 {
1193 NSUInteger flags;
1194 unsigned short keyCode;
1196 ModifierKey(NSUInteger aFlags, unsigned short aKeyCode) :
1197 flags(aFlags), keyCode(aKeyCode)
1198 {
1199 }
1201 NSUInteger GetDeviceDependentFlags() const
1202 {
1203 return (flags & ~NSDeviceIndependentModifierFlagsMask);
1204 }
1206 NSUInteger GetDeviceIndependentFlags() const
1207 {
1208 return (flags & NSDeviceIndependentModifierFlagsMask);
1209 }
1210 };
1211 typedef nsTArray<ModifierKey> ModifierKeyArray;
1212 ModifierKeyArray mModifierKeys;
1214 /**
1215 * GetModifierKeyForNativeKeyCode() returns the stored ModifierKey for
1216 * the key.
1217 */
1218 const ModifierKey*
1219 GetModifierKeyForNativeKeyCode(unsigned short aKeyCode) const;
1221 /**
1222 * GetModifierKeyForDeviceDependentFlags() returns the stored ModifierKey for
1223 * the device dependent flags.
1224 */
1225 const ModifierKey*
1226 GetModifierKeyForDeviceDependentFlags(NSUInteger aFlags) const;
1228 /**
1229 * DispatchKeyEventForFlagsChanged() dispatches keydown event or keyup event
1230 * for the aNativeEvent.
1231 *
1232 * @param aNativeEvent A native flagschanged event which you want to
1233 * dispatch our key event for.
1234 * @param aDispatchKeyDown TRUE if you want to dispatch a keydown event.
1235 * Otherwise, i.e., to dispatch keyup event,
1236 * FALSE.
1237 */
1238 void DispatchKeyEventForFlagsChanged(NSEvent* aNativeEvent,
1239 bool aDispatchKeyDown);
1240 };
1242 } // namespace widget
1243 } // namespace mozilla
1245 #endif // TextInputHandler_h_