Bumping manifests a=b2g-bump
[gecko.git] / widget / cocoa / TextInputHandler.h
blob3fa5b9f538ba842c89b83a560cc9c943c148e6b8
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 "nsTArray.h"
19 #include "mozilla/EventForwards.h"
21 class nsChildView;
23 namespace mozilla {
24 namespace widget {
26 // Key code constants
27 enum
29 kVK_RightCommand = 0x36, // right command key
31 kVK_PC_PrintScreen = kVK_F13,
32 kVK_PC_ScrollLock = kVK_F14,
33 kVK_PC_Pause = kVK_F15,
35 kVK_PC_Insert = kVK_Help,
36 kVK_PC_Backspace = kVK_Delete,
37 kVK_PC_Delete = kVK_ForwardDelete,
39 kVK_PC_ContextMenu = 0x6E,
41 kVK_Powerbook_KeypadEnter = 0x34 // Enter on Powerbook's keyboard is different
44 /**
45 * TISInputSourceWrapper is a wrapper for the TISInputSourceRef. If we get the
46 * TISInputSourceRef from InputSourceID, we need to release the CFArray instance
47 * which is returned by TISCreateInputSourceList. However, when we release the
48 * list, we cannot access the TISInputSourceRef. So, it's not usable, and it
49 * may cause the memory leak bugs. nsTISInputSource automatically releases the
50 * list when the instance is destroyed.
52 class TISInputSourceWrapper
54 public:
55 static TISInputSourceWrapper& CurrentInputSource();
57 TISInputSourceWrapper()
59 mInputSourceList = nullptr;
60 Clear();
63 explicit TISInputSourceWrapper(const char* aID)
65 mInputSourceList = nullptr;
66 InitByInputSourceID(aID);
69 explicit TISInputSourceWrapper(SInt32 aLayoutID)
71 mInputSourceList = nullptr;
72 InitByLayoutID(aLayoutID);
75 explicit TISInputSourceWrapper(TISInputSourceRef aInputSource)
77 mInputSourceList = nullptr;
78 InitByTISInputSourceRef(aInputSource);
81 ~TISInputSourceWrapper() { Clear(); }
83 void InitByInputSourceID(const char* aID);
84 void InitByInputSourceID(const nsAFlatString &aID);
85 void InitByInputSourceID(const CFStringRef aID);
86 /**
87 * InitByLayoutID() initializes the keyboard layout by the layout ID.
89 * @param aLayoutID An ID of keyboard layout.
90 * 0: US
91 * 1: Greek
92 * 2: German
93 * 3: Swedish-Pro
94 * 4: Dvorak-Qwerty Cmd
95 * 5: Thai
96 * 6: Arabic
97 * 7: French
98 * 8: Hebrew
99 * 9: Lithuanian
100 * 10: Norwegian
101 * 11: Spanish
102 * @param aOverrideKeyboard When testing set to TRUE, otherwise, set to
103 * FALSE. When TRUE, we use an ANSI keyboard
104 * instead of the actual keyboard.
106 void InitByLayoutID(SInt32 aLayoutID, bool aOverrideKeyboard = false);
107 void InitByCurrentInputSource();
108 void InitByCurrentKeyboardLayout();
109 void InitByCurrentASCIICapableInputSource();
110 void InitByCurrentASCIICapableKeyboardLayout();
111 void InitByCurrentInputMethodKeyboardLayoutOverride();
112 void InitByTISInputSourceRef(TISInputSourceRef aInputSource);
113 void InitByLanguage(CFStringRef aLanguage);
116 * If the instance is initialized with a keyboard layout input source,
117 * returns it.
118 * If the instance is initialized with an IME mode input source, the result
119 * references the keyboard layout for the IME mode. However, this can be
120 * initialized only when the IME mode is actually selected. I.e, if IME mode
121 * input source is initialized with LayoutID or SourceID, this returns null.
123 TISInputSourceRef GetKeyboardLayoutInputSource() const
125 return mKeyboardLayout;
127 const UCKeyboardLayout* GetUCKeyboardLayout();
129 bool IsOpenedIMEMode();
130 bool IsIMEMode();
131 bool IsKeyboardLayout();
133 bool IsASCIICapable()
135 NS_ENSURE_TRUE(mInputSource, false);
136 return GetBoolProperty(kTISPropertyInputSourceIsASCIICapable);
139 bool IsEnabled()
141 NS_ENSURE_TRUE(mInputSource, false);
142 return GetBoolProperty(kTISPropertyInputSourceIsEnabled);
145 bool GetLanguageList(CFArrayRef &aLanguageList);
146 bool GetPrimaryLanguage(CFStringRef &aPrimaryLanguage);
147 bool GetPrimaryLanguage(nsAString &aPrimaryLanguage);
149 bool GetLocalizedName(CFStringRef &aName)
151 NS_ENSURE_TRUE(mInputSource, false);
152 return GetStringProperty(kTISPropertyLocalizedName, aName);
155 bool GetLocalizedName(nsAString &aName)
157 NS_ENSURE_TRUE(mInputSource, false);
158 return GetStringProperty(kTISPropertyLocalizedName, aName);
161 bool GetInputSourceID(CFStringRef &aID)
163 NS_ENSURE_TRUE(mInputSource, false);
164 return GetStringProperty(kTISPropertyInputSourceID, aID);
167 bool GetInputSourceID(nsAString &aID)
169 NS_ENSURE_TRUE(mInputSource, false);
170 return GetStringProperty(kTISPropertyInputSourceID, aID);
173 bool GetBundleID(CFStringRef &aBundleID)
175 NS_ENSURE_TRUE(mInputSource, false);
176 return GetStringProperty(kTISPropertyBundleID, aBundleID);
179 bool GetBundleID(nsAString &aBundleID)
181 NS_ENSURE_TRUE(mInputSource, false);
182 return GetStringProperty(kTISPropertyBundleID, aBundleID);
185 bool GetInputSourceType(CFStringRef &aType)
187 NS_ENSURE_TRUE(mInputSource, false);
188 return GetStringProperty(kTISPropertyInputSourceType, aType);
191 bool GetInputSourceType(nsAString &aType)
193 NS_ENSURE_TRUE(mInputSource, false);
194 return GetStringProperty(kTISPropertyInputSourceType, aType);
197 bool IsForRTLLanguage();
198 bool IsInitializedByCurrentInputSource();
200 enum {
201 // 40 is an actual result of the ::LMGetKbdType() when we connect an
202 // unknown keyboard and set the keyboard type to ANSI manually on the
203 // set up dialog.
204 eKbdType_ANSI = 40
207 void Select();
208 void Clear();
211 * InitKeyEvent() initializes aKeyEvent for aNativeKeyEvent.
213 * @param aNativeKeyEvent A native key event for which you want to
214 * dispatch a Gecko key event.
215 * @param aKeyEvent The result -- a Gecko key event initialized
216 * from the native key event.
217 * @param aInsertString If caller expects that the event will cause
218 * a character to be input (say in an editor),
219 * the caller should set this. Otherwise,
220 * if caller sets null to this, this method will
221 * compute the character to be input from
222 * characters of aNativeKeyEvent.
224 void InitKeyEvent(NSEvent *aNativeKeyEvent, WidgetKeyboardEvent& aKeyEvent,
225 const nsAString *aInsertString = nullptr);
228 * ComputeGeckoKeyCode() returns Gecko keycode for aNativeKeyCode on current
229 * keyboard layout.
231 * @param aNativeKeyCode A native keycode.
232 * @param aKbType A native Keyboard Type value. Typically,
233 * this is a result of ::LMGetKbdType().
234 * @param aCmdIsPressed TRUE if Cmd key is pressed. Otherwise, FALSE.
235 * @return The computed Gecko keycode.
237 uint32_t ComputeGeckoKeyCode(UInt32 aNativeKeyCode, UInt32 aKbType,
238 bool aCmdIsPressed);
241 * ComputeGeckoKeyNameIndex() returns Gecko key name index for the key.
243 * @param aNativeKeyCode A native keycode.
245 static KeyNameIndex ComputeGeckoKeyNameIndex(UInt32 aNativeKeyCode);
248 * ComputeGeckoCodeNameIndex() returns Gecko code name index for the key.
250 * @param aNativeKeyCode A native keycode.
252 static CodeNameIndex ComputeGeckoCodeNameIndex(UInt32 aNativeKeyCode);
254 protected:
256 * TranslateToString() computes the inputted text from the native keyCode,
257 * modifier flags and keyboard type.
259 * @param aKeyCode A native keyCode.
260 * @param aModifiers Combination of native modifier flags.
261 * @param aKbType A native Keyboard Type value. Typically,
262 * this is a result of ::LMGetKbdType().
263 * @param aStr Result, i.e., inputted text.
264 * The result can be two or more characters.
265 * @return If succeeded, TRUE. Otherwise, FALSE.
266 * Even if TRUE, aStr can be empty string.
268 bool TranslateToString(UInt32 aKeyCode, UInt32 aModifiers,
269 UInt32 aKbType, nsAString &aStr);
272 * TranslateToChar() computes the inputted character from the native keyCode,
273 * modifier flags and keyboard type. If two or more characters would be
274 * input, this returns 0.
276 * @param aKeyCode A native keyCode.
277 * @param aModifiers Combination of native modifier flags.
278 * @param aKbType A native Keyboard Type value. Typically,
279 * this is a result of ::LMGetKbdType().
280 * @return If succeeded and the result is one character,
281 * returns the charCode of it. Otherwise,
282 * returns 0.
284 uint32_t TranslateToChar(UInt32 aKeyCode, UInt32 aModifiers, UInt32 aKbType);
287 * InitKeyPressEvent() initializes aKeyEvent for aNativeKeyEvent.
288 * Don't call this method when aKeyEvent isn't NS_KEY_PRESS.
290 * @param aNativeKeyEvent A native key event for which you want to
291 * dispatch a Gecko key event.
292 * @param aInsertChar A character to be input in an editor by the
293 * event.
294 * @param aKeyEvent The result -- a Gecko key event initialized
295 * from the native key event. This must be
296 * NS_KEY_PRESS event.
297 * @param aKbType A native Keyboard Type value. Typically,
298 * this is a result of ::LMGetKbdType().
300 void InitKeyPressEvent(NSEvent *aNativeKeyEvent,
301 char16_t aInsertChar,
302 WidgetKeyboardEvent& aKeyEvent,
303 UInt32 aKbType);
305 bool GetBoolProperty(const CFStringRef aKey);
306 bool GetStringProperty(const CFStringRef aKey, CFStringRef &aStr);
307 bool GetStringProperty(const CFStringRef aKey, nsAString &aStr);
309 TISInputSourceRef mInputSource;
310 TISInputSourceRef mKeyboardLayout;
311 CFArrayRef mInputSourceList;
312 const UCKeyboardLayout* mUCKeyboardLayout;
313 int8_t mIsRTL;
315 bool mOverrideKeyboard;
319 * TextInputHandlerBase is a base class of IMEInputHandler and TextInputHandler.
320 * Utility methods should be implemented this level.
323 class TextInputHandlerBase
325 public:
326 nsrefcnt AddRef()
328 NS_PRECONDITION(int32_t(mRefCnt) >= 0, "mRefCnt is negative");
329 ++mRefCnt;
330 NS_LOG_ADDREF(this, mRefCnt, "TextInputHandlerBase", sizeof(*this));
331 return mRefCnt;
333 nsrefcnt Release()
335 NS_PRECONDITION(mRefCnt != 0, "mRefCnt is alrady zero");
336 --mRefCnt;
337 NS_LOG_RELEASE(this, mRefCnt, "TextInputHandlerBase");
338 if (mRefCnt == 0) {
339 mRefCnt = 1; /* stabilize */
340 delete this;
341 return 0;
343 return mRefCnt;
347 * DispatchEvent() dispatches aEvent on mWidget.
349 * @param aEvent An event which you want to dispatch.
350 * @return TRUE if the event is consumed by web contents
351 * or chrome contents. Otherwise, FALSE.
353 bool DispatchEvent(WidgetGUIEvent& aEvent);
356 * SetSelection() dispatches NS_SELECTION_SET event for the aRange.
358 * @param aRange The range which will be selected.
359 * @return TRUE if setting selection is succeeded and
360 * the widget hasn't been destroyed.
361 * Otherwise, FALSE.
363 bool SetSelection(NSRange& aRange);
366 * InitKeyEvent() initializes aKeyEvent for aNativeKeyEvent.
368 * @param aNativeKeyEvent A native key event for which you want to
369 * dispatch a Gecko key event.
370 * @param aKeyEvent The result -- a Gecko key event initialized
371 * from the native key event.
372 * @param aInsertString If caller expects that the event will cause
373 * a character to be input (say in an editor),
374 * the caller should set this. Otherwise,
375 * if caller sets null to this, this method will
376 * compute the character to be input from
377 * characters of aNativeKeyEvent.
379 void InitKeyEvent(NSEvent *aNativeKeyEvent, WidgetKeyboardEvent& aKeyEvent,
380 const nsAString *aInsertString = nullptr);
383 * SynthesizeNativeKeyEvent() is an implementation of
384 * nsIWidget::SynthesizeNativeKeyEvent(). See the document in nsIWidget.h
385 * for the detail.
387 nsresult SynthesizeNativeKeyEvent(int32_t aNativeKeyboardLayout,
388 int32_t aNativeKeyCode,
389 uint32_t aModifierFlags,
390 const nsAString& aCharacters,
391 const nsAString& aUnmodifiedCharacters);
394 * Utility method intended for testing. Attempts to construct a native key
395 * event that would have been generated during an actual key press. This
396 * *does not dispatch* the native event. Instead, it is attached to the
397 * |mNativeKeyEvent| field of the Gecko event that is passed in.
398 * @param aKeyEvent Gecko key event to attach the native event to
400 NS_IMETHOD AttachNativeKeyEvent(WidgetKeyboardEvent& aKeyEvent);
403 * GetWindowLevel() returns the window level of current focused (in Gecko)
404 * window. E.g., if an <input> element in XUL panel has focus, this returns
405 * the XUL panel's window level.
407 NSInteger GetWindowLevel();
410 * IsSpecialGeckoKey() checks whether aNativeKeyCode is mapped to a special
411 * Gecko keyCode. A key is "special" if it isn't used for text input.
413 * @param aNativeKeyCode A native keycode.
414 * @return If the keycode is mapped to a special key,
415 * TRUE. Otherwise, FALSE.
417 static bool IsSpecialGeckoKey(UInt32 aNativeKeyCode);
421 * EnableSecureEventInput() and DisableSecureEventInput() wrap the Carbon
422 * Event Manager APIs with the same names. In addition they keep track of
423 * how many times we've called them (in the same process) -- unlike the
424 * Carbon Event Manager APIs, which only keep track of how many times they've
425 * been called from any and all processes.
427 * The Carbon Event Manager's IsSecureEventInputEnabled() returns whether
428 * secure event input mode is enabled (in any process). This class's
429 * IsSecureEventInputEnabled() returns whether we've made any calls to
430 * EnableSecureEventInput() that are not (yet) offset by the calls we've
431 * made to DisableSecureEventInput().
433 static void EnableSecureEventInput();
434 static void DisableSecureEventInput();
435 static bool IsSecureEventInputEnabled();
438 * EnsureSecureEventInputDisabled() calls DisableSecureEventInput() until
439 * our call count becomes 0.
441 static void EnsureSecureEventInputDisabled();
443 protected:
444 nsAutoRefCnt mRefCnt;
446 public:
448 * mWidget must not be destroyed without OnDestroyWidget being called.
450 * @param aDestroyingWidget Destroying widget. This might not be mWidget.
451 * @return This result doesn't have any meaning for
452 * callers. When aDstroyingWidget isn't the same
453 * as mWidget, FALSE. Then, inherited methods in
454 * sub classes should return from this method
455 * without cleaning up.
457 virtual bool OnDestroyWidget(nsChildView* aDestroyingWidget);
459 protected:
460 // The creater of this instance and client.
461 // This must not be null after initialized until OnDestroyWidget() is called.
462 nsChildView* mWidget; // [WEAK]
464 // The native view for mWidget.
465 // This view handles the actual text inputting.
466 NSView<mozView>* mView; // [STRONG]
468 TextInputHandlerBase(nsChildView* aWidget, NSView<mozView> *aNativeView);
469 virtual ~TextInputHandlerBase();
471 bool Destroyed() { return !mWidget; }
474 * mCurrentKeyEvent indicates what key event we are handling. While
475 * handling a native keydown event, we need to store the event for insertText,
476 * doCommandBySelector and various action message handlers of NSResponder
477 * such as [NSResponder insertNewline:sender].
479 struct KeyEventState
481 // Handling native key event
482 NSEvent* mKeyEvent;
483 // Whether keydown event was consumed by web contents or chrome contents.
484 bool mKeyDownHandled;
485 // Whether keypress event was dispatched for mKeyEvent.
486 bool mKeyPressDispatched;
487 // Whether keypress event was consumed by web contents or chrome contents.
488 bool mKeyPressHandled;
489 // Whether the key event causes other key events via IME or something.
490 bool mCausedOtherKeyEvents;
492 KeyEventState() : mKeyEvent(nullptr)
494 Clear();
497 explicit KeyEventState(NSEvent* aNativeKeyEvent) : mKeyEvent(nullptr)
499 Clear();
500 Set(aNativeKeyEvent);
503 KeyEventState(const KeyEventState &aOther) : mKeyEvent(nullptr)
505 Clear();
506 if (aOther.mKeyEvent) {
507 mKeyEvent = [aOther.mKeyEvent retain];
509 mKeyDownHandled = aOther.mKeyDownHandled;
510 mKeyPressDispatched = aOther.mKeyPressDispatched;
511 mKeyPressHandled = aOther.mKeyPressHandled;
512 mCausedOtherKeyEvents = aOther.mCausedOtherKeyEvents;
515 ~KeyEventState()
517 Clear();
520 void Set(NSEvent* aNativeKeyEvent)
522 NS_PRECONDITION(aNativeKeyEvent, "aNativeKeyEvent must not be NULL");
523 Clear();
524 mKeyEvent = [aNativeKeyEvent retain];
527 void Clear()
529 if (mKeyEvent) {
530 [mKeyEvent release];
531 mKeyEvent = nullptr;
533 mKeyDownHandled = false;
534 mKeyPressDispatched = false;
535 mKeyPressHandled = false;
536 mCausedOtherKeyEvents = false;
539 bool IsDefaultPrevented() const
541 return mKeyDownHandled || mKeyPressHandled || mCausedOtherKeyEvents;
544 bool CanDispatchKeyPressEvent() const
546 return !mKeyPressDispatched && !IsDefaultPrevented();
551 * Helper class for guaranteeing cleaning mCurrentKeyEvent
553 class AutoKeyEventStateCleaner
555 public:
556 explicit AutoKeyEventStateCleaner(TextInputHandlerBase* aHandler) :
557 mHandler(aHandler)
561 ~AutoKeyEventStateCleaner()
563 mHandler->RemoveCurrentKeyEvent();
565 private:
566 nsRefPtr<TextInputHandlerBase> mHandler;
570 * mCurrentKeyEvents stores all key events which are being processed.
571 * When we call interpretKeyEvents, IME may generate other key events.
572 * mCurrentKeyEvents[0] is the latest key event.
574 nsTArray<KeyEventState*> mCurrentKeyEvents;
577 * mFirstKeyEvent must be used for first key event. This member prevents
578 * memory fragmentation for most key events.
580 KeyEventState mFirstKeyEvent;
583 * PushKeyEvent() adds the current key event to mCurrentKeyEvents.
585 KeyEventState* PushKeyEvent(NSEvent* aNativeKeyEvent)
587 uint32_t nestCount = mCurrentKeyEvents.Length();
588 for (uint32_t i = 0; i < nestCount; i++) {
589 // When the key event is caused by another key event, all key events
590 // which are being handled should be marked as "consumed".
591 mCurrentKeyEvents[i]->mCausedOtherKeyEvents = true;
594 KeyEventState* keyEvent = nullptr;
595 if (nestCount == 0) {
596 mFirstKeyEvent.Set(aNativeKeyEvent);
597 keyEvent = &mFirstKeyEvent;
598 } else {
599 keyEvent = new KeyEventState(aNativeKeyEvent);
601 return *mCurrentKeyEvents.AppendElement(keyEvent);
605 * RemoveCurrentKeyEvent() removes the current key event from
606 * mCurrentKeyEvents.
608 void RemoveCurrentKeyEvent()
610 NS_ASSERTION(mCurrentKeyEvents.Length() > 0,
611 "RemoveCurrentKeyEvent() is called unexpectedly");
612 KeyEventState* keyEvent = GetCurrentKeyEvent();
613 mCurrentKeyEvents.RemoveElementAt(mCurrentKeyEvents.Length() - 1);
614 if (keyEvent == &mFirstKeyEvent) {
615 keyEvent->Clear();
616 } else {
617 delete keyEvent;
622 * GetCurrentKeyEvent() returns current processing key event.
624 KeyEventState* GetCurrentKeyEvent()
626 if (mCurrentKeyEvents.Length() == 0) {
627 return nullptr;
629 return mCurrentKeyEvents[mCurrentKeyEvents.Length() - 1];
633 * IsPrintableChar() checks whether the unicode character is
634 * a non-printable ASCII character or not. Note that this returns
635 * TRUE even if aChar is a non-printable UNICODE character.
637 * @param aChar A unicode character.
638 * @return TRUE if aChar is a printable ASCII character
639 * or a unicode character. Otherwise, i.e,
640 * if aChar is a non-printable ASCII character,
641 * FALSE.
643 static bool IsPrintableChar(char16_t aChar);
646 * IsNormalCharInputtingEvent() checks whether aKeyEvent causes text input.
648 * @param aKeyEvent A key event.
649 * @return TRUE if the key event causes text input.
650 * Otherwise, FALSE.
652 static bool IsNormalCharInputtingEvent(const WidgetKeyboardEvent& aKeyEvent);
655 * IsModifierKey() checks whether the native keyCode is for a modifier key.
657 * @param aNativeKeyCode A native keyCode.
658 * @return TRUE if aNativeKeyCode is for a modifier key.
659 * Otherwise, FALSE.
661 static bool IsModifierKey(UInt32 aNativeKeyCode);
663 private:
664 struct KeyboardLayoutOverride {
665 int32_t mKeyboardLayout;
666 bool mOverrideEnabled;
668 KeyboardLayoutOverride() :
669 mKeyboardLayout(0), mOverrideEnabled(false)
674 KeyboardLayoutOverride mKeyboardOverride;
676 static int32_t sSecureEventInputCount;
680 * IMEInputHandler manages:
681 * 1. The IME/keyboard layout statement of nsChildView.
682 * 2. The IME composition statement of nsChildView.
683 * And also provides the methods which controls the current IME transaction of
684 * the instance.
686 * Note that an nsChildView handles one or more NSView's events. E.g., even if
687 * a text editor on XUL panel element, the input events handled on the parent
688 * (or its ancestor) widget handles it (the native focus is set to it). The
689 * actual focused view is notified by OnFocusChangeInGecko.
692 class IMEInputHandler : public TextInputHandlerBase
694 public:
695 virtual bool OnDestroyWidget(nsChildView* aDestroyingWidget);
697 virtual void OnFocusChangeInGecko(bool aFocus);
699 void OnSelectionChange() { mSelectedRange.location = NSNotFound; }
702 * DispatchCompositionChangeEvent() dispatches a compositionchange event on
703 * mWidget.
705 * @param aText User text input.
706 * @param aAttrString An NSAttributedString instance which indicates
707 * current composition string.
708 * @param aSelectedRange Current selected range (or caret position).
710 bool DispatchCompositionChangeEvent(const nsString& aText,
711 NSAttributedString* aAttrString,
712 NSRange& aSelectedRange);
715 * DispatchCompositionCommitEvent() dispatches a compositioncommit event or
716 * compositioncommitasis event. If aCommitString is null, dispatches
717 * compositioncommitasis event. I.e., if aCommitString is null, this
718 * commits the composition with the last data. Otherwise, commits the
719 * composition with aCommitString value.
721 bool DispatchCompositionCommitEvent(const nsAString* aCommitString = nullptr);
724 * SetMarkedText() is a handler of setMarkedText of NSTextInput.
726 * @param aAttrString This mut be an instance of NSAttributedString.
727 * If the aString parameter to
728 * [ChildView setMarkedText:setSelectedRange:]
729 * isn't an instance of NSAttributedString,
730 * create an NSAttributedString from it and pass
731 * that instead.
732 * @param aSelectedRange Current selected range (or caret position).
733 * @param aReplacementRange The range which will be replaced with the
734 * aAttrString instead of current marked range.
736 void SetMarkedText(NSAttributedString* aAttrString,
737 NSRange& aSelectedRange,
738 NSRange* aReplacementRange = nullptr);
741 * ConversationIdentifier() returns an ID for the current editor. The ID is
742 * guaranteed to be unique among currently existing editors. But it might be
743 * the same as the ID of an editor that has already been destroyed.
745 * @return An identifier of current focused editor.
747 NSInteger ConversationIdentifier();
750 * GetAttributedSubstringFromRange() returns an NSAttributedString instance
751 * which is allocated as autorelease for aRange.
753 * @param aRange The range of string which you want.
754 * @param aActualRange The actual range of the result.
755 * @return The string in aRange. If the string is empty,
756 * this returns nil. If succeeded, this returns
757 * an instance which is allocated as autorelease.
758 * If this has some troubles, returns nil.
760 NSAttributedString* GetAttributedSubstringFromRange(
761 NSRange& aRange,
762 NSRange* aActualRange = nullptr);
765 * SelectedRange() returns current selected range.
767 * @return If an editor has focus, this returns selection
768 * range in the editor. Otherwise, this returns
769 * selection range in the focused document.
771 NSRange SelectedRange();
774 * FirstRectForCharacterRange() returns first *character* rect in the range.
775 * Cocoa needs the first line rect in the range, but we cannot compute it
776 * on current implementation.
778 * @param aRange A range of text to examine. Its position is
779 * an offset from the beginning of the focused
780 * editor or document.
781 * @param aActualRange If this is not null, this returns the actual
782 * range used for computing the result.
783 * @return An NSRect containing the first character in
784 * aRange, in screen coordinates.
785 * If the length of aRange is 0, the width will
786 * be 0.
788 NSRect FirstRectForCharacterRange(NSRange& aRange,
789 NSRange* aActualRange = nullptr);
792 * CharacterIndexForPoint() returns an offset of a character at aPoint.
793 * XXX This isn't implemented, always returns 0.
795 * @param The point in screen coordinates.
796 * @return The offset of the character at aPoint from
797 * the beginning of the focused editor or
798 * document.
800 NSUInteger CharacterIndexForPoint(NSPoint& aPoint);
803 * GetValidAttributesForMarkedText() returns attributes which we support.
805 * @return Always empty array for now.
807 NSArray* GetValidAttributesForMarkedText();
809 bool HasMarkedText();
810 NSRange MarkedRange();
812 bool IsIMEComposing() { return mIsIMEComposing; }
813 bool IsIMEOpened();
814 bool IsIMEEnabled() { return mIsIMEEnabled; }
815 bool IsASCIICapableOnly() { return mIsASCIICapableOnly; }
816 bool IgnoreIMECommit() { return mIgnoreIMECommit; }
818 bool IgnoreIMEComposition()
820 // Ignore the IME composition events when we're pending to discard the
821 // composition and we are not to handle the IME composition now.
822 return (mPendingMethods & kDiscardIMEComposition) &&
823 (mIsInFocusProcessing || !IsFocused());
826 void CommitIMEComposition();
827 void CancelIMEComposition();
829 void EnableIME(bool aEnableIME);
830 void SetIMEOpenState(bool aOpen);
831 void SetASCIICapableOnly(bool aASCIICapableOnly);
833 bool IsFocused();
835 static CFArrayRef CreateAllIMEModeList();
836 static void DebugPrintAllIMEModes();
838 // Don't use ::TSMGetActiveDocument() API directly, the document may not
839 // be what you want.
840 static TSMDocumentID GetCurrentTSMDocumentID();
842 protected:
843 // We cannot do some jobs in the given stack by some reasons.
844 // Following flags and the timer provide the execution pending mechanism,
845 // See the comment in nsCocoaTextInputHandler.mm.
846 nsCOMPtr<nsITimer> mTimer;
847 enum {
848 kNotifyIMEOfFocusChangeInGecko = 1,
849 kDiscardIMEComposition = 2,
850 kSyncASCIICapableOnly = 4
852 uint32_t mPendingMethods;
854 IMEInputHandler(nsChildView* aWidget, NSView<mozView> *aNativeView);
855 virtual ~IMEInputHandler();
857 void ResetTimer();
859 virtual void ExecutePendingMethods();
862 * InsertTextAsCommittingComposition() commits current composition. If there
863 * is no composition, this starts a composition and commits it immediately.
865 * @param aAttrString A string which is committed.
866 * @param aReplacementRange The range which will be replaced with the
867 * aAttrString instead of current selection.
869 void InsertTextAsCommittingComposition(NSAttributedString* aAttrString,
870 NSRange* aReplacementRange);
872 private:
873 // If mIsIMEComposing is true, the composition string is stored here.
874 NSString* mIMECompositionString;
875 // mLastDispatchedCompositionString stores the lastest dispatched composition
876 // string by compositionupdate event.
877 nsString mLastDispatchedCompositionString;
879 NSRange mMarkedRange;
880 NSRange mSelectedRange;
882 bool mIsIMEComposing;
883 bool mIsIMEEnabled;
884 bool mIsASCIICapableOnly;
885 bool mIgnoreIMECommit;
886 // This flag is enabled by OnFocusChangeInGecko, and will be cleared by
887 // ExecutePendingMethods. When this is true, IsFocus() returns TRUE. At
888 // that time, the focus processing in Gecko might not be finished yet. So,
889 // you cannot use WidgetQueryContentEvent or something.
890 bool mIsInFocusProcessing;
891 bool mIMEHasFocus;
893 void KillIMEComposition();
894 void SendCommittedText(NSString *aString);
895 void OpenSystemPreferredLanguageIME();
897 // Pending methods
898 void NotifyIMEOfFocusChangeInGecko();
899 void DiscardIMEComposition();
900 void SyncASCIICapableOnly();
902 static bool sStaticMembersInitialized;
903 static CFStringRef sLatestIMEOpenedModeInputSourceID;
904 static void InitStaticMembers();
905 static void OnCurrentTextInputSourceChange(CFNotificationCenterRef aCenter,
906 void* aObserver,
907 CFStringRef aName,
908 const void* aObject,
909 CFDictionaryRef aUserInfo);
911 static void FlushPendingMethods(nsITimer* aTimer, void* aClosure);
914 * ConvertToTextRangeStyle converts the given native underline style to
915 * our defined text range type.
917 * @param aUnderlineStyle NSUnderlineStyleSingle or
918 * NSUnderlineStyleThick.
919 * @param aSelectedRange Current selected range (or caret position).
920 * @return NS_TEXTRANGE_*.
922 uint32_t ConvertToTextRangeType(uint32_t aUnderlineStyle,
923 NSRange& aSelectedRange);
926 * GetRangeCount() computes the range count of aAttrString.
928 * @param aAttrString An NSAttributedString instance whose number of
929 * NSUnderlineStyleAttributeName ranges you with
930 * to know.
931 * @return The count of NSUnderlineStyleAttributeName
932 * ranges in aAttrString.
934 uint32_t GetRangeCount(NSAttributedString *aString);
937 * CreateTextRangeArray() returns text ranges for clauses and/or caret.
939 * @param aAttrString An NSAttributedString instance which indicates
940 * current composition string.
941 * @param aSelectedRange Current selected range (or caret position).
942 * @return The result is set to the
943 * NSUnderlineStyleAttributeName ranges in
944 * aAttrString.
946 already_AddRefed<mozilla::TextRangeArray>
947 CreateTextRangeArray(NSAttributedString *aAttrString,
948 NSRange& aSelectedRange);
951 * InitCompositionEvent() initializes aCompositionEvent.
953 * @param aCompositionEvent A composition event which you want to
954 * initialize.
956 void InitCompositionEvent(WidgetCompositionEvent& aCompositionEvent);
959 * When a composition starts, OnStartIMEComposition() is called.
961 void OnStartIMEComposition();
964 * When a composition is updated, OnUpdateIMEComposition() is called.
966 void OnUpdateIMEComposition(NSString* aIMECompositionString);
969 * When a composition is finished, OnEndIMEComposition() is called.
971 void OnEndIMEComposition();
973 // The focused IME handler. Please note that the handler might lost the
974 // actual focus by deactivating the application. If we are active, this
975 // must have the actual focused handle.
976 // We cannot access to the NSInputManager during we aren't active, so, the
977 // focused handler can have an IME transaction even if we are deactive.
978 static IMEInputHandler* sFocusedIMEHandler;
982 * TextInputHandler implements the NSTextInput protocol.
984 class TextInputHandler : public IMEInputHandler
986 public:
987 static NSUInteger sLastModifierState;
989 static CFArrayRef CreateAllKeyboardLayoutList();
990 static void DebugPrintAllKeyboardLayouts();
992 TextInputHandler(nsChildView* aWidget, NSView<mozView> *aNativeView);
993 virtual ~TextInputHandler();
996 * KeyDown event handler.
998 * @param aNativeEvent A native NSKeyDown event.
999 * @return TRUE if the event is consumed by web contents
1000 * or chrome contents. Otherwise, FALSE.
1002 bool HandleKeyDownEvent(NSEvent* aNativeEvent);
1005 * KeyUp event handler.
1007 * @param aNativeEvent A native NSKeyUp event.
1009 void HandleKeyUpEvent(NSEvent* aNativeEvent);
1012 * FlagsChanged event handler.
1014 * @param aNativeEvent A native NSFlagsChanged event.
1016 void HandleFlagsChanged(NSEvent* aNativeEvent);
1019 * Insert the string to content. I.e., this is a text input event handler.
1020 * If this is called during keydown event handling, this may dispatch a
1021 * NS_KEY_PRESS event. If this is called during composition, this commits
1022 * the composition by the aAttrString.
1024 * @param aAttrString An inserted string.
1025 * @param aReplacementRange The range which will be replaced with the
1026 * aAttrString instead of current selection.
1028 void InsertText(NSAttributedString *aAttrString,
1029 NSRange* aReplacementRange = nullptr);
1032 * doCommandBySelector event handler.
1034 * @param aSelector A selector of the command.
1035 * @return TRUE if the command is consumed. Otherwise,
1036 * FALSE.
1038 bool DoCommandBySelector(const char* aSelector);
1041 * KeyPressWasHandled() checks whether keypress event was handled or not.
1043 * @return TRUE if keypress event for latest native key
1044 * event was handled. Otherwise, FALSE.
1045 * If this handler isn't handling any key events,
1046 * always returns FALSE.
1048 bool KeyPressWasHandled()
1050 KeyEventState* currentKeyEvent = GetCurrentKeyEvent();
1051 return currentKeyEvent && currentKeyEvent->mKeyPressHandled;
1054 protected:
1055 // Stores the association of device dependent modifier flags with a modifier
1056 // keyCode. Being device dependent, this association may differ from one kind
1057 // of hardware to the next.
1058 struct ModifierKey
1060 NSUInteger flags;
1061 unsigned short keyCode;
1063 ModifierKey(NSUInteger aFlags, unsigned short aKeyCode) :
1064 flags(aFlags), keyCode(aKeyCode)
1068 NSUInteger GetDeviceDependentFlags() const
1070 return (flags & ~NSDeviceIndependentModifierFlagsMask);
1073 NSUInteger GetDeviceIndependentFlags() const
1075 return (flags & NSDeviceIndependentModifierFlagsMask);
1078 typedef nsTArray<ModifierKey> ModifierKeyArray;
1079 ModifierKeyArray mModifierKeys;
1082 * GetModifierKeyForNativeKeyCode() returns the stored ModifierKey for
1083 * the key.
1085 const ModifierKey*
1086 GetModifierKeyForNativeKeyCode(unsigned short aKeyCode) const;
1089 * GetModifierKeyForDeviceDependentFlags() returns the stored ModifierKey for
1090 * the device dependent flags.
1092 const ModifierKey*
1093 GetModifierKeyForDeviceDependentFlags(NSUInteger aFlags) const;
1096 * DispatchKeyEventForFlagsChanged() dispatches keydown event or keyup event
1097 * for the aNativeEvent.
1099 * @param aNativeEvent A native flagschanged event which you want to
1100 * dispatch our key event for.
1101 * @param aDispatchKeyDown TRUE if you want to dispatch a keydown event.
1102 * Otherwise, i.e., to dispatch keyup event,
1103 * FALSE.
1105 void DispatchKeyEventForFlagsChanged(NSEvent* aNativeEvent,
1106 bool aDispatchKeyDown);
1109 } // namespace widget
1110 } // namespace mozilla
1112 #endif // TextInputHandler_h_