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>
19 #include "mozilla/EventForwards.h"
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
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
55 static TISInputSourceWrapper
& CurrentInputSource();
57 TISInputSourceWrapper()
59 mInputSourceList
= nullptr;
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
);
87 * InitByLayoutID() initializes the keyboard layout by the layout ID.
89 * @param aLayoutID An ID of keyboard layout.
94 * 4: Dvorak-Qwerty Cmd
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,
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();
131 bool IsKeyboardLayout();
133 bool IsASCIICapable()
135 NS_ENSURE_TRUE(mInputSource
, false);
136 return GetBoolProperty(kTISPropertyInputSourceIsASCIICapable
);
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();
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
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
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
,
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
);
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,
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
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
,
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
;
315 bool mOverrideKeyboard
;
319 * TextInputHandlerBase is a base class of IMEInputHandler and TextInputHandler.
320 * Utility methods should be implemented this level.
323 class TextInputHandlerBase
328 NS_PRECONDITION(int32_t(mRefCnt
) >= 0, "mRefCnt is negative");
330 NS_LOG_ADDREF(this, mRefCnt
, "TextInputHandlerBase", sizeof(*this));
335 NS_PRECONDITION(mRefCnt
!= 0, "mRefCnt is alrady zero");
337 NS_LOG_RELEASE(this, mRefCnt
, "TextInputHandlerBase");
339 mRefCnt
= 1; /* stabilize */
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.
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
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();
444 nsAutoRefCnt mRefCnt
;
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
);
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].
481 // Handling native key event
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)
497 explicit KeyEventState(NSEvent
* aNativeKeyEvent
) : mKeyEvent(nullptr)
500 Set(aNativeKeyEvent
);
503 KeyEventState(const KeyEventState
&aOther
) : mKeyEvent(nullptr)
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
;
520 void Set(NSEvent
* aNativeKeyEvent
)
522 NS_PRECONDITION(aNativeKeyEvent
, "aNativeKeyEvent must not be NULL");
524 mKeyEvent
= [aNativeKeyEvent retain
];
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
556 explicit AutoKeyEventStateCleaner(TextInputHandlerBase
* aHandler
) :
561 ~AutoKeyEventStateCleaner()
563 mHandler
->RemoveCurrentKeyEvent();
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
;
599 keyEvent
= new KeyEventState(aNativeKeyEvent
);
601 return *mCurrentKeyEvents
.AppendElement(keyEvent
);
605 * RemoveCurrentKeyEvent() removes the current key event from
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
) {
622 * GetCurrentKeyEvent() returns current processing key event.
624 KeyEventState
* GetCurrentKeyEvent()
626 if (mCurrentKeyEvents
.Length() == 0) {
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,
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.
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.
661 static bool IsModifierKey(UInt32 aNativeKeyCode
);
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
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
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
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
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(
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
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
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
; }
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
);
835 static CFArrayRef
CreateAllIMEModeList();
836 static void DebugPrintAllIMEModes();
838 // Don't use ::TSMGetActiveDocument() API directly, the document may not
840 static TSMDocumentID
GetCurrentTSMDocumentID();
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
;
848 kNotifyIMEOfFocusChangeInGecko
= 1,
849 kDiscardIMEComposition
= 2,
850 kSyncASCIICapableOnly
= 4
852 uint32_t mPendingMethods
;
854 IMEInputHandler(nsChildView
* aWidget
, NSView
<mozView
> *aNativeView
);
855 virtual ~IMEInputHandler();
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
);
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
;
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
;
893 void KillIMEComposition();
894 void SendCommittedText(NSString
*aString
);
895 void OpenSystemPreferredLanguageIME();
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
,
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
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
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
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
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,
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
;
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.
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
1086 GetModifierKeyForNativeKeyCode(unsigned short aKeyCode
) const;
1089 * GetModifierKeyForDeviceDependentFlags() returns the stored ModifierKey for
1090 * the device dependent flags.
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,
1105 void DispatchKeyEventForFlagsChanged(NSEvent
* aNativeEvent
,
1106 bool aDispatchKeyDown
);
1109 } // namespace widget
1110 } // namespace mozilla
1112 #endif // TextInputHandler_h_