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/BasicEvents.h"
20 #include "mozilla/EventForwards.h"
21 #include "mozilla/TextEventDispatcherListener.h"
22 #include "WritingModes.h"
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
{
54 static TISInputSourceWrapper
& CurrentInputSource();
56 * Shutdown() should be called when nobody doesn't need to use this class.
58 static void Shutdown();
60 TISInputSourceWrapper()
61 : mInputSource
{nullptr},
62 mKeyboardLayout
{nullptr},
63 mUCKeyboardLayout
{nullptr},
65 mOverrideKeyboard
{false} {
66 mInputSourceList
= nullptr;
70 explicit TISInputSourceWrapper(const char* aID
)
71 : mInputSource
{nullptr},
72 mKeyboardLayout
{nullptr},
73 mUCKeyboardLayout
{nullptr},
75 mOverrideKeyboard
{false} {
76 mInputSourceList
= nullptr;
77 InitByInputSourceID(aID
);
80 explicit TISInputSourceWrapper(SInt32 aLayoutID
)
81 : mInputSource
{nullptr},
82 mKeyboardLayout
{nullptr},
83 mUCKeyboardLayout
{nullptr},
85 mOverrideKeyboard
{false} {
86 mInputSourceList
= nullptr;
87 InitByLayoutID(aLayoutID
);
90 explicit TISInputSourceWrapper(TISInputSourceRef aInputSource
)
91 : mInputSource
{nullptr},
92 mKeyboardLayout
{nullptr},
93 mUCKeyboardLayout
{nullptr},
95 mOverrideKeyboard
{false} {
96 mInputSourceList
= nullptr;
97 InitByTISInputSourceRef(aInputSource
);
100 ~TISInputSourceWrapper() { Clear(); }
102 void InitByInputSourceID(const char* aID
);
103 void InitByInputSourceID(const nsString
& aID
);
104 void InitByInputSourceID(const CFStringRef aID
);
106 * InitByLayoutID() initializes the keyboard layout by the layout ID.
108 * @param aLayoutID An ID of keyboard layout.
113 * 4: Dvorak-Qwerty Cmd
121 * @param aOverrideKeyboard When testing set to TRUE, otherwise, set to
122 * FALSE. When TRUE, we use an ANSI keyboard
123 * instead of the actual keyboard.
125 void InitByLayoutID(SInt32 aLayoutID
, bool aOverrideKeyboard
= false);
126 void InitByCurrentInputSource();
127 void InitByCurrentKeyboardLayout();
128 void InitByCurrentASCIICapableInputSource();
129 void InitByCurrentASCIICapableKeyboardLayout();
130 void InitByCurrentInputMethodKeyboardLayoutOverride();
131 void InitByTISInputSourceRef(TISInputSourceRef aInputSource
);
132 void InitByLanguage(CFStringRef aLanguage
);
135 * If the instance is initialized with a keyboard layout input source,
137 * If the instance is initialized with an IME mode input source, the result
138 * references the keyboard layout for the IME mode. However, this can be
139 * initialized only when the IME mode is actually selected. I.e, if IME mode
140 * input source is initialized with LayoutID or SourceID, this returns null.
142 TISInputSourceRef
GetKeyboardLayoutInputSource() const { return mKeyboardLayout
; }
143 const UCKeyboardLayout
* GetUCKeyboardLayout();
145 bool IsOpenedIMEMode();
147 bool IsKeyboardLayout();
149 bool IsASCIICapable() {
150 NS_ENSURE_TRUE(mInputSource
, false);
151 return GetBoolProperty(kTISPropertyInputSourceIsASCIICapable
);
155 NS_ENSURE_TRUE(mInputSource
, false);
156 return GetBoolProperty(kTISPropertyInputSourceIsEnabled
);
159 bool GetLanguageList(CFArrayRef
& aLanguageList
);
160 bool GetPrimaryLanguage(CFStringRef
& aPrimaryLanguage
);
161 bool GetPrimaryLanguage(nsAString
& aPrimaryLanguage
);
163 bool GetLocalizedName(CFStringRef
& aName
) {
164 NS_ENSURE_TRUE(mInputSource
, false);
165 return GetStringProperty(kTISPropertyLocalizedName
, aName
);
168 bool GetLocalizedName(nsAString
& aName
) {
169 NS_ENSURE_TRUE(mInputSource
, false);
170 return GetStringProperty(kTISPropertyLocalizedName
, aName
);
173 bool GetInputSourceID(CFStringRef
& aID
) {
174 NS_ENSURE_TRUE(mInputSource
, false);
175 return GetStringProperty(kTISPropertyInputSourceID
, aID
);
178 bool GetInputSourceID(nsAString
& aID
) {
179 NS_ENSURE_TRUE(mInputSource
, false);
180 return GetStringProperty(kTISPropertyInputSourceID
, aID
);
183 bool GetBundleID(CFStringRef
& aBundleID
) {
184 NS_ENSURE_TRUE(mInputSource
, false);
185 return GetStringProperty(kTISPropertyBundleID
, aBundleID
);
188 bool GetBundleID(nsAString
& aBundleID
) {
189 NS_ENSURE_TRUE(mInputSource
, false);
190 return GetStringProperty(kTISPropertyBundleID
, aBundleID
);
193 bool GetInputSourceType(CFStringRef
& aType
) {
194 NS_ENSURE_TRUE(mInputSource
, false);
195 return GetStringProperty(kTISPropertyInputSourceType
, aType
);
198 bool GetInputSourceType(nsAString
& aType
) {
199 NS_ENSURE_TRUE(mInputSource
, false);
200 return GetStringProperty(kTISPropertyInputSourceType
, aType
);
203 bool IsForRTLLanguage();
204 bool IsForJapaneseLanguage();
205 bool IsInitializedByCurrentInputSource();
208 // 40 is an actual result of the ::LMGetKbdType() when we connect an
209 // unknown keyboard and set the keyboard type to ANSI manually on the
218 * InitKeyEvent() initializes aKeyEvent for aNativeKeyEvent.
220 * @param aNativeKeyEvent A native key event for which you want to
221 * dispatch a Gecko key event.
222 * @param aKeyEvent The result -- a Gecko key event initialized
223 * from the native key event.
224 * @param aIsProcessedByIME true if aNativeKeyEvent has been handled
225 * by IME (but except if the composition was
226 * started with dead key).
227 * @param aInsertString If caller expects that the event will cause
228 * a character to be input (say in an editor),
229 * the caller should set this. Otherwise,
230 * if caller sets null to this, this method will
231 * compute the character to be input from
232 * characters of aNativeKeyEvent.
234 void InitKeyEvent(NSEvent
* aNativeKeyEvent
, WidgetKeyboardEvent
& aKeyEvent
,
235 bool aIsProcessedByIME
, const nsAString
* aInsertString
= nullptr);
238 * WillDispatchKeyboardEvent() computes aKeyEvent.mAlternativeCharCodes and
239 * recompute aKeyEvent.mCharCode if it's necessary.
241 * @param aNativeKeyEvent A native key event for which you want to
242 * dispatch a Gecko key event.
243 * @param aInsertString If caller expects that the event will cause
244 * a character to be input (say in an editor),
245 * the caller should set this. Otherwise,
246 * if caller sets null to this, this method will
247 * compute the character to be input from
248 * characters of aNativeKeyEvent.
249 * @param aIndexOfKeypress Index of the eKeyPress event. If a key
250 * inputs 2 or more characters, eKeyPress events
251 * are dispatched for each character. This is
252 * 0 for the first eKeyPress event.
253 * @param aKeyEvent The result -- a Gecko key event initialized
254 * from the native key event. This must be
257 void WillDispatchKeyboardEvent(NSEvent
* aNativeKeyEvent
, const nsAString
* aInsertString
,
258 uint32_t aIndexOfKeypress
, WidgetKeyboardEvent
& aKeyEvent
);
261 * ComputeGeckoKeyCode() returns Gecko keycode for aNativeKeyCode on current
264 * @param aNativeKeyCode A native keycode.
265 * @param aKbType A native Keyboard Type value. Typically,
266 * this is a result of ::LMGetKbdType().
267 * @param aCmdIsPressed TRUE if Cmd key is pressed. Otherwise, FALSE.
268 * @return The computed Gecko keycode.
270 uint32_t ComputeGeckoKeyCode(UInt32 aNativeKeyCode
, UInt32 aKbType
, bool aCmdIsPressed
);
273 * ComputeGeckoKeyNameIndex() returns Gecko key name index for the key.
275 * @param aNativeKeyCode A native keycode.
277 static KeyNameIndex
ComputeGeckoKeyNameIndex(UInt32 aNativeKeyCode
);
280 * ComputeGeckoCodeNameIndex() returns Gecko code name index for the key.
282 * @param aNativeKeyCode A native keycode.
283 * @param aKbType A native Keyboard Type value. Typically,
284 * this is a result of ::LMGetKbdType().
286 static CodeNameIndex
ComputeGeckoCodeNameIndex(UInt32 aNativeKeyCode
, UInt32 aKbType
);
289 * TranslateToChar() checks if aNativeKeyEvent is a dead key.
291 * @param aNativeKeyEvent A native key event.
292 * @return Returns true if the key event is a dead key
293 * event. Otherwise, false.
295 bool IsDeadKey(NSEvent
* aNativeKeyEvent
);
299 * TranslateToString() computes the inputted text from the native keyCode,
300 * modifier flags and keyboard type.
302 * @param aKeyCode A native keyCode.
303 * @param aModifiers Combination of native modifier flags.
304 * @param aKbType A native Keyboard Type value. Typically,
305 * this is a result of ::LMGetKbdType().
306 * @param aStr Result, i.e., inputted text.
307 * The result can be two or more characters.
308 * @return If succeeded, TRUE. Otherwise, FALSE.
309 * Even if TRUE, aStr can be empty string.
311 bool TranslateToString(UInt32 aKeyCode
, UInt32 aModifiers
, UInt32 aKbType
, nsAString
& aStr
);
314 * TranslateToChar() computes the inputted character from the native keyCode,
315 * modifier flags and keyboard type. If two or more characters would be
316 * input, this returns 0.
318 * @param aKeyCode A native keyCode.
319 * @param aModifiers Combination of native modifier flags.
320 * @param aKbType A native Keyboard Type value. Typically,
321 * this is a result of ::LMGetKbdType().
322 * @return If succeeded and the result is one character,
323 * returns the charCode of it. Otherwise,
326 uint32_t TranslateToChar(UInt32 aKeyCode
, UInt32 aModifiers
, UInt32 aKbType
);
329 * TranslateToChar() checks if aKeyCode with aModifiers is a dead key.
331 * @param aKeyCode A native keyCode.
332 * @param aModifiers Combination of native modifier flags.
333 * @param aKbType A native Keyboard Type value. Typically,
334 * this is a result of ::LMGetKbdType().
335 * @return Returns true if the key with specified
336 * modifier state is a dead key. Otherwise,
339 bool IsDeadKey(UInt32 aKeyCode
, UInt32 aModifiers
, UInt32 aKbType
);
342 * ComputeInsertString() computes string to be inserted with the key event.
344 * @param aNativeKeyEvent The native key event which causes our keyboard
346 * @param aKeyEvent A Gecko key event which was partially
347 * initialized with aNativeKeyEvent.
348 * @param aInsertString The string to be inputting by aNativeKeyEvent.
349 * This should be specified by InsertText().
350 * In other words, if the key event doesn't cause
351 * a call of InsertText(), this can be nullptr.
352 * @param aResult The string which should be set to charCode of
355 void ComputeInsertStringForCharCode(NSEvent
* aNativeKeyEvent
,
356 const WidgetKeyboardEvent
& aKeyEvent
,
357 const nsAString
* aInsertString
, nsAString
& aResult
);
360 * IsPrintableKeyEvent() returns true if aNativeKeyEvent is caused by
361 * a printable key. Otherwise, returns false.
363 bool IsPrintableKeyEvent(NSEvent
* aNativeKeyEvent
) const;
366 * GetKbdType() returns physical keyboard type.
368 UInt32
GetKbdType() const;
370 bool GetBoolProperty(const CFStringRef aKey
);
371 bool GetStringProperty(const CFStringRef aKey
, CFStringRef
& aStr
);
372 bool GetStringProperty(const CFStringRef aKey
, nsAString
& aStr
);
374 TISInputSourceRef mInputSource
;
375 TISInputSourceRef mKeyboardLayout
;
376 CFArrayRef mInputSourceList
;
377 const UCKeyboardLayout
* mUCKeyboardLayout
;
380 bool mOverrideKeyboard
;
382 static TISInputSourceWrapper
* sCurrentInputSource
;
386 * TextInputHandlerBase is a base class of IMEInputHandler and TextInputHandler.
387 * Utility methods should be implemented this level.
390 class TextInputHandlerBase
: public TextEventDispatcherListener
{
393 * Other TextEventDispatcherListener methods should be implemented in
399 * DispatchEvent() dispatches aEvent on mWidget.
401 * @param aEvent An event which you want to dispatch.
402 * @return TRUE if the event is consumed by web contents
403 * or chrome contents. Otherwise, FALSE.
405 bool DispatchEvent(WidgetGUIEvent
& aEvent
);
408 * SetSelection() dispatches eSetSelection event for the aRange.
410 * @param aRange The range which will be selected.
411 * @return TRUE if setting selection is succeeded and
412 * the widget hasn't been destroyed.
415 bool SetSelection(NSRange
& aRange
);
418 * InitKeyEvent() initializes aKeyEvent for aNativeKeyEvent.
420 * @param aNativeKeyEvent A native key event for which you want to
421 * dispatch a Gecko key event.
422 * @param aKeyEvent The result -- a Gecko key event initialized
423 * from the native key event.
424 * @param aIsProcessedByIME true if aNativeKeyEvent has been handled
425 * by IME (but except if the composition was
426 * started with dead key).
427 * @param aInsertString If caller expects that the event will cause
428 * a character to be input (say in an editor),
429 * the caller should set this. Otherwise,
430 * if caller sets null to this, this method will
431 * compute the character to be input from
432 * characters of aNativeKeyEvent.
434 void InitKeyEvent(NSEvent
* aNativeKeyEvent
, WidgetKeyboardEvent
& aKeyEvent
,
435 bool aIsProcessedByIME
, const nsAString
* aInsertString
= nullptr);
438 * SynthesizeNativeKeyEvent() is an implementation of
439 * nsIWidget::SynthesizeNativeKeyEvent(). See the document in nsIWidget.h
442 nsresult
SynthesizeNativeKeyEvent(int32_t aNativeKeyboardLayout
, int32_t aNativeKeyCode
,
443 uint32_t aModifierFlags
, const nsAString
& aCharacters
,
444 const nsAString
& aUnmodifiedCharacters
);
447 * Utility method intended for testing. Attempts to construct a native key
448 * event that would have been generated during an actual key press. This
449 * *does not dispatch* the native event. Instead, it is attached to the
450 * |mNativeKeyEvent| field of the Gecko event that is passed in.
451 * @param aKeyEvent Gecko key event to attach the native event to
453 NS_IMETHOD
AttachNativeKeyEvent(WidgetKeyboardEvent
& aKeyEvent
);
456 * GetWindowLevel() returns the window level of current focused (in Gecko)
457 * window. E.g., if an <input> element in XUL panel has focus, this returns
458 * the XUL panel's window level.
460 NSInteger
GetWindowLevel();
463 * IsSpecialGeckoKey() checks whether aNativeKeyCode is mapped to a special
464 * Gecko keyCode. A key is "special" if it isn't used for text input.
466 * @param aNativeKeyCode A native keycode.
467 * @return If the keycode is mapped to a special key,
468 * TRUE. Otherwise, FALSE.
470 static bool IsSpecialGeckoKey(UInt32 aNativeKeyCode
);
473 * EnableSecureEventInput() and DisableSecureEventInput() wrap the Carbon
474 * Event Manager APIs with the same names. In addition they keep track of
475 * how many times we've called them (in the same process) -- unlike the
476 * Carbon Event Manager APIs, which only keep track of how many times they've
477 * been called from any and all processes.
479 * The Carbon Event Manager's IsSecureEventInputEnabled() returns whether
480 * secure event input mode is enabled (in any process). This class's
481 * IsSecureEventInputEnabled() returns whether we've made any calls to
482 * EnableSecureEventInput() that are not (yet) offset by the calls we've
483 * made to DisableSecureEventInput().
485 static void EnableSecureEventInput();
486 static void DisableSecureEventInput();
487 static bool IsSecureEventInputEnabled();
490 * EnsureSecureEventInputDisabled() calls DisableSecureEventInput() until
491 * our call count becomes 0.
493 static void EnsureSecureEventInputDisabled();
497 * mWidget must not be destroyed without OnDestroyWidget being called.
499 * @param aDestroyingWidget Destroying widget. This might not be mWidget.
500 * @return This result doesn't have any meaning for
501 * callers. When aDstroyingWidget isn't the same
502 * as mWidget, FALSE. Then, inherited methods in
503 * sub classes should return from this method
504 * without cleaning up.
506 virtual bool OnDestroyWidget(nsChildView
* aDestroyingWidget
);
509 // The creator of this instance, client and its text event dispatcher.
510 // These members must not be nullptr after initialized until
511 // OnDestroyWidget() is called.
512 nsChildView
* mWidget
; // [WEAK]
513 RefPtr
<TextEventDispatcher
> mDispatcher
;
515 // The native view for mWidget.
516 // This view handles the actual text inputting.
517 NSView
<mozView
>* mView
; // [STRONG]
519 TextInputHandlerBase(nsChildView
* aWidget
, NSView
<mozView
>* aNativeView
);
520 virtual ~TextInputHandlerBase();
522 bool Destroyed() { return !mWidget
; }
525 * mCurrentKeyEvent indicates what key event we are handling. While
526 * handling a native keydown event, we need to store the event for insertText,
527 * doCommandBySelector and various action message handlers of NSResponder
528 * such as [NSResponder insertNewline:sender].
530 struct KeyEventState
{
531 // Handling native key event
533 // String specified by InsertText(). This is not null only during a
534 // call of InsertText().
535 nsAString
* mInsertString
;
536 // String which are included in [mKeyEvent characters] and already handled
537 // by InsertText() call(s).
538 nsString mInsertedString
;
539 // Unique id associated with a keydown / keypress event. It's ok if this
540 // wraps over long periods.
542 // Whether keydown event was dispatched for mKeyEvent.
543 bool mKeyDownDispatched
;
544 // Whether keydown event was consumed by web contents or chrome contents.
545 bool mKeyDownHandled
;
546 // Whether keypress event was dispatched for mKeyEvent.
547 bool mKeyPressDispatched
;
548 // Whether keypress event was consumed by web contents or chrome contents.
549 bool mKeyPressHandled
;
550 // Whether the key event causes other key events via IME or something.
551 bool mCausedOtherKeyEvents
;
552 // Whether the key event causes composition change or committing
553 // composition. So, even if InsertText() is called, this may be false
554 // if it dispatches keypress event.
555 bool mCompositionDispatched
;
557 KeyEventState() : mKeyEvent(nullptr), mUniqueId(0) { Clear(); }
559 explicit KeyEventState(NSEvent
* aNativeKeyEvent
, uint32_t aUniqueId
= 0)
560 : mKeyEvent(nullptr), mUniqueId(0) {
562 Set(aNativeKeyEvent
, aUniqueId
);
565 KeyEventState(const KeyEventState
& aOther
) = delete;
567 ~KeyEventState() { Clear(); }
569 void Set(NSEvent
* aNativeKeyEvent
, uint32_t aUniqueId
= 0) {
570 MOZ_ASSERT(aNativeKeyEvent
, "aNativeKeyEvent must not be NULL");
572 mKeyEvent
= [aNativeKeyEvent retain
];
573 mUniqueId
= aUniqueId
;
582 mInsertString
= nullptr;
583 mInsertedString
.Truncate();
584 mKeyDownDispatched
= false;
585 mKeyDownHandled
= false;
586 mKeyPressDispatched
= false;
587 mKeyPressHandled
= false;
588 mCausedOtherKeyEvents
= false;
589 mCompositionDispatched
= false;
592 bool IsDefaultPrevented() const {
593 return mKeyDownHandled
|| mKeyPressHandled
|| mCausedOtherKeyEvents
|| mCompositionDispatched
;
596 bool CanDispatchKeyDownEvent() const { return !mKeyDownDispatched
; }
598 bool CanDispatchKeyPressEvent() const { return !mKeyPressDispatched
&& !IsDefaultPrevented(); }
600 bool CanHandleCommand() const { return !mKeyDownHandled
&& !mKeyPressHandled
; }
602 bool IsProperKeyEvent(Command aCommand
) const {
603 if (NS_WARN_IF(!mKeyEvent
)) {
606 KeyNameIndex keyNameIndex
=
607 TISInputSourceWrapper::ComputeGeckoKeyNameIndex([mKeyEvent keyCode
]);
608 Modifiers modifiers
= nsCocoaUtils::ModifiersForEvent(mKeyEvent
) &
609 (MODIFIER_SHIFT
| MODIFIER_CONTROL
| MODIFIER_ALT
| MODIFIER_META
);
611 case Command::InsertLineBreak
:
612 return keyNameIndex
== KEY_NAME_INDEX_Enter
&& modifiers
== MODIFIER_CONTROL
;
613 case Command::InsertParagraph
:
614 return keyNameIndex
== KEY_NAME_INDEX_Enter
&& modifiers
== MODIFIER_NONE
;
615 case Command::DeleteCharBackward
:
616 return keyNameIndex
== KEY_NAME_INDEX_Backspace
&& modifiers
== MODIFIER_NONE
;
617 case Command::DeleteToBeginningOfLine
:
618 return keyNameIndex
== KEY_NAME_INDEX_Backspace
&& modifiers
== MODIFIER_META
;
619 case Command::DeleteWordBackward
:
620 return keyNameIndex
== KEY_NAME_INDEX_Backspace
&& modifiers
== MODIFIER_ALT
;
621 case Command::DeleteCharForward
:
622 return keyNameIndex
== KEY_NAME_INDEX_Delete
&& modifiers
== MODIFIER_NONE
;
623 case Command::DeleteWordForward
:
624 return keyNameIndex
== KEY_NAME_INDEX_Delete
&& modifiers
== MODIFIER_ALT
;
625 case Command::InsertTab
:
626 return keyNameIndex
== KEY_NAME_INDEX_Tab
&& modifiers
== MODIFIER_NONE
;
627 case Command::InsertBacktab
:
628 return keyNameIndex
== KEY_NAME_INDEX_Tab
&& modifiers
== MODIFIER_SHIFT
;
629 case Command::CharNext
:
630 return keyNameIndex
== KEY_NAME_INDEX_ArrowRight
&& modifiers
== MODIFIER_NONE
;
631 case Command::SelectCharNext
:
632 return keyNameIndex
== KEY_NAME_INDEX_ArrowRight
&& modifiers
== MODIFIER_SHIFT
;
633 case Command::WordNext
:
634 return keyNameIndex
== KEY_NAME_INDEX_ArrowRight
&& modifiers
== MODIFIER_ALT
;
635 case Command::SelectWordNext
:
636 return keyNameIndex
== KEY_NAME_INDEX_ArrowRight
&&
637 modifiers
== (MODIFIER_ALT
| MODIFIER_SHIFT
);
638 case Command::EndLine
:
639 return keyNameIndex
== KEY_NAME_INDEX_ArrowRight
&& modifiers
== MODIFIER_META
;
640 case Command::SelectEndLine
:
641 return keyNameIndex
== KEY_NAME_INDEX_ArrowRight
&&
642 modifiers
== (MODIFIER_META
| MODIFIER_SHIFT
);
643 case Command::CharPrevious
:
644 return keyNameIndex
== KEY_NAME_INDEX_ArrowLeft
&& modifiers
== MODIFIER_NONE
;
645 case Command::SelectCharPrevious
:
646 return keyNameIndex
== KEY_NAME_INDEX_ArrowLeft
&& modifiers
== MODIFIER_SHIFT
;
647 case Command::WordPrevious
:
648 return keyNameIndex
== KEY_NAME_INDEX_ArrowLeft
&& modifiers
== MODIFIER_ALT
;
649 case Command::SelectWordPrevious
:
650 return keyNameIndex
== KEY_NAME_INDEX_ArrowLeft
&&
651 modifiers
== (MODIFIER_ALT
| MODIFIER_SHIFT
);
652 case Command::BeginLine
:
653 return keyNameIndex
== KEY_NAME_INDEX_ArrowLeft
&& modifiers
== MODIFIER_META
;
654 case Command::SelectBeginLine
:
655 return keyNameIndex
== KEY_NAME_INDEX_ArrowLeft
&&
656 modifiers
== (MODIFIER_META
| MODIFIER_SHIFT
);
657 case Command::LinePrevious
:
658 return keyNameIndex
== KEY_NAME_INDEX_ArrowUp
&& modifiers
== MODIFIER_NONE
;
659 case Command::SelectLinePrevious
:
660 return keyNameIndex
== KEY_NAME_INDEX_ArrowUp
&& modifiers
== MODIFIER_SHIFT
;
661 case Command::MoveTop
:
662 return keyNameIndex
== KEY_NAME_INDEX_ArrowUp
&& modifiers
== MODIFIER_META
;
663 case Command::SelectTop
:
664 return (keyNameIndex
== KEY_NAME_INDEX_ArrowUp
&&
665 modifiers
== (MODIFIER_META
| MODIFIER_SHIFT
)) ||
666 (keyNameIndex
== KEY_NAME_INDEX_Home
&& modifiers
== MODIFIER_SHIFT
);
667 case Command::LineNext
:
668 return keyNameIndex
== KEY_NAME_INDEX_ArrowDown
&& modifiers
== MODIFIER_NONE
;
669 case Command::SelectLineNext
:
670 return keyNameIndex
== KEY_NAME_INDEX_ArrowDown
&& modifiers
== MODIFIER_SHIFT
;
671 case Command::MoveBottom
:
672 return keyNameIndex
== KEY_NAME_INDEX_ArrowDown
&& modifiers
== MODIFIER_META
;
673 case Command::SelectBottom
:
674 return (keyNameIndex
== KEY_NAME_INDEX_ArrowDown
&&
675 modifiers
== (MODIFIER_META
| MODIFIER_SHIFT
)) ||
676 (keyNameIndex
== KEY_NAME_INDEX_End
&& modifiers
== MODIFIER_SHIFT
);
677 case Command::ScrollPageUp
:
678 return keyNameIndex
== KEY_NAME_INDEX_PageUp
&& modifiers
== MODIFIER_NONE
;
679 case Command::SelectPageUp
:
680 return keyNameIndex
== KEY_NAME_INDEX_PageUp
&& modifiers
== MODIFIER_SHIFT
;
681 case Command::ScrollPageDown
:
682 return keyNameIndex
== KEY_NAME_INDEX_PageDown
&& modifiers
== MODIFIER_NONE
;
683 case Command::SelectPageDown
:
684 return keyNameIndex
== KEY_NAME_INDEX_PageDown
&& modifiers
== MODIFIER_SHIFT
;
685 case Command::ScrollBottom
:
686 return keyNameIndex
== KEY_NAME_INDEX_End
&& modifiers
== MODIFIER_NONE
;
687 case Command::ScrollTop
:
688 return keyNameIndex
== KEY_NAME_INDEX_Home
&& modifiers
== MODIFIER_NONE
;
689 case Command::CancelOperation
:
690 return (keyNameIndex
== KEY_NAME_INDEX_Escape
&&
691 (modifiers
== MODIFIER_NONE
|| modifiers
== MODIFIER_SHIFT
)) ||
692 ([mKeyEvent keyCode
] == kVK_ANSI_Period
&& modifiers
== MODIFIER_META
);
693 case Command::Complete
:
694 return keyNameIndex
== KEY_NAME_INDEX_Escape
&&
695 (modifiers
== MODIFIER_ALT
|| modifiers
== (MODIFIER_ALT
| MODIFIER_SHIFT
));
701 void InitKeyEvent(TextInputHandlerBase
* aHandler
, WidgetKeyboardEvent
& aKeyEvent
,
702 bool aIsProcessedByIME
);
705 * GetUnhandledString() returns characters of the event which have not been
706 * handled with InsertText() yet. For example, if there is a composition
707 * caused by a dead key press like '`' and it's committed by some key
708 * combinations like |Cmd+v|, then, the |v|'s KeyDown event's |characters|
709 * is |`v|. Then, after |`| is committed with a call of InsertString(),
710 * this returns only 'v'.
712 void GetUnhandledString(nsAString
& aUnhandledString
) const;
716 * Helper classes for guaranteeing cleaning mCurrentKeyEvent
718 class AutoKeyEventStateCleaner
{
720 explicit AutoKeyEventStateCleaner(TextInputHandlerBase
* aHandler
) : mHandler(aHandler
) {}
722 ~AutoKeyEventStateCleaner() { mHandler
->RemoveCurrentKeyEvent(); }
725 RefPtr
<TextInputHandlerBase
> mHandler
;
728 class MOZ_STACK_CLASS AutoInsertStringClearer
{
730 explicit AutoInsertStringClearer(KeyEventState
* aState
) : mState(aState
) {}
731 ~AutoInsertStringClearer();
734 KeyEventState
* mState
;
738 * mCurrentKeyEvents stores all key events which are being processed.
739 * When we call interpretKeyEvents, IME may generate other key events.
740 * mCurrentKeyEvents[0] is the latest key event.
742 nsTArray
<KeyEventState
*> mCurrentKeyEvents
;
745 * mFirstKeyEvent must be used for first key event. This member prevents
746 * memory fragmentation for most key events.
748 KeyEventState mFirstKeyEvent
;
751 * PushKeyEvent() adds the current key event to mCurrentKeyEvents.
753 KeyEventState
* PushKeyEvent(NSEvent
* aNativeKeyEvent
, uint32_t aUniqueId
= 0) {
754 uint32_t nestCount
= mCurrentKeyEvents
.Length();
755 for (uint32_t i
= 0; i
< nestCount
; i
++) {
756 // When the key event is caused by another key event, all key events
757 // which are being handled should be marked as "consumed".
758 mCurrentKeyEvents
[i
]->mCausedOtherKeyEvents
= true;
761 KeyEventState
* keyEvent
= nullptr;
762 if (nestCount
== 0) {
763 mFirstKeyEvent
.Set(aNativeKeyEvent
, aUniqueId
);
764 keyEvent
= &mFirstKeyEvent
;
766 keyEvent
= new KeyEventState(aNativeKeyEvent
, aUniqueId
);
768 return *mCurrentKeyEvents
.AppendElement(keyEvent
);
772 * RemoveCurrentKeyEvent() removes the current key event from
775 void RemoveCurrentKeyEvent() {
776 NS_ASSERTION(mCurrentKeyEvents
.Length() > 0, "RemoveCurrentKeyEvent() is called unexpectedly");
777 KeyEventState
* keyEvent
= mCurrentKeyEvents
.PopLastElement();
778 if (keyEvent
== &mFirstKeyEvent
) {
786 * GetCurrentKeyEvent() returns current processing key event.
788 KeyEventState
* GetCurrentKeyEvent() {
789 if (mCurrentKeyEvents
.Length() == 0) {
792 return mCurrentKeyEvents
[mCurrentKeyEvents
.Length() - 1];
795 struct KeyboardLayoutOverride final
{
796 int32_t mKeyboardLayout
;
797 bool mOverrideEnabled
;
799 KeyboardLayoutOverride() : mKeyboardLayout(0), mOverrideEnabled(false) {}
802 const KeyboardLayoutOverride
& KeyboardLayoutOverrideRef() const { return mKeyboardOverride
; }
805 * IsPrintableChar() checks whether the unicode character is
806 * a non-printable ASCII character or not. Note that this returns
807 * TRUE even if aChar is a non-printable UNICODE character.
809 * @param aChar A unicode character.
810 * @return TRUE if aChar is a printable ASCII character
811 * or a unicode character. Otherwise, i.e,
812 * if aChar is a non-printable ASCII character,
815 static bool IsPrintableChar(char16_t aChar
);
818 * IsNormalCharInputtingEvent() checks whether aNativeEvent causes text input.
820 * @param aNativeEvent A key event.
821 * @return TRUE if the key event causes text input.
824 static bool IsNormalCharInputtingEvent(NSEvent
* aNativeEvent
);
827 * IsModifierKey() checks whether the native keyCode is for a modifier key.
829 * @param aNativeKeyCode A native keyCode.
830 * @return TRUE if aNativeKeyCode is for a modifier key.
833 static bool IsModifierKey(UInt32 aNativeKeyCode
);
836 KeyboardLayoutOverride mKeyboardOverride
;
838 static int32_t sSecureEventInputCount
;
842 * IMEInputHandler manages:
843 * 1. The IME/keyboard layout statement of nsChildView.
844 * 2. The IME composition statement of nsChildView.
845 * And also provides the methods which controls the current IME transaction of
848 * Note that an nsChildView handles one or more NSView's events. E.g., even if
849 * a text editor on XUL panel element, the input events handled on the parent
850 * (or its ancestor) widget handles it (the native focus is set to it). The
851 * actual focused view is notified by OnFocusChangeInGecko.
854 class IMEInputHandler
: public TextInputHandlerBase
{
856 // TextEventDispatcherListener methods
857 NS_IMETHOD
NotifyIME(TextEventDispatcher
* aTextEventDispatcher
,
858 const IMENotification
& aNotification
) override
;
859 NS_IMETHOD_(IMENotificationRequests
) GetIMENotificationRequests() override
;
860 NS_IMETHOD_(void) OnRemovedFrom(TextEventDispatcher
* aTextEventDispatcher
) override
;
862 WillDispatchKeyboardEvent(TextEventDispatcher
* aTextEventDispatcher
,
863 WidgetKeyboardEvent
& aKeyboardEvent
, uint32_t aIndexOfKeypress
,
864 void* aData
) override
;
867 virtual bool OnDestroyWidget(nsChildView
* aDestroyingWidget
) override
;
869 virtual void OnFocusChangeInGecko(bool aFocus
);
871 void OnSelectionChange(const IMENotification
& aIMENotification
);
872 void OnLayoutChange();
875 * Call [NSTextInputContext handleEvent] for mouse event support of IME
877 bool OnHandleEvent(NSEvent
* aEvent
);
880 * SetMarkedText() is a handler of setMarkedText of NSTextInput.
882 * @param aAttrString This mut be an instance of NSAttributedString.
883 * If the aString parameter to
884 * [ChildView setMarkedText:setSelectedRange:]
885 * isn't an instance of NSAttributedString,
886 * create an NSAttributedString from it and pass
888 * @param aSelectedRange Current selected range (or caret position).
889 * @param aReplacementRange The range which will be replaced with the
890 * aAttrString instead of current marked range.
892 void SetMarkedText(NSAttributedString
* aAttrString
, NSRange
& aSelectedRange
,
893 NSRange
* aReplacementRange
= nullptr);
896 * GetAttributedSubstringFromRange() returns an NSAttributedString instance
897 * which is allocated as autorelease for aRange.
899 * @param aRange The range of string which you want.
900 * @param aActualRange The actual range of the result.
901 * @return The string in aRange. If the string is empty,
902 * this returns nil. If succeeded, this returns
903 * an instance which is allocated as autorelease.
904 * If this has some troubles, returns nil.
906 NSAttributedString
* GetAttributedSubstringFromRange(NSRange
& aRange
,
907 NSRange
* aActualRange
= nullptr);
910 * SelectedRange() returns current selected range.
912 * @return If an editor has focus, this returns selection
913 * range in the editor. Otherwise, this returns
914 * selection range in the focused document.
916 NSRange
SelectedRange();
919 * DrawsVerticallyForCharacterAtIndex() returns whether the character at
920 * the given index is being rendered vertically.
922 * @param aCharIndex The character offset to query.
924 * @return True if writing-mode is vertical at the given
925 * character offset; otherwise false.
927 bool DrawsVerticallyForCharacterAtIndex(uint32_t aCharIndex
);
930 * FirstRectForCharacterRange() returns first *character* rect in the range.
931 * Cocoa needs the first line rect in the range, but we cannot compute it
932 * on current implementation.
934 * @param aRange A range of text to examine. Its position is
935 * an offset from the beginning of the focused
936 * editor or document.
937 * @param aActualRange If this is not null, this returns the actual
938 * range used for computing the result.
939 * @return An NSRect containing the first character in
940 * aRange, in screen coordinates.
941 * If the length of aRange is 0, the width will
944 NSRect
FirstRectForCharacterRange(NSRange
& aRange
, NSRange
* aActualRange
= nullptr);
947 * CharacterIndexForPoint() returns an offset of a character at aPoint.
948 * XXX This isn't implemented, always returns 0.
950 * @param The point in screen coordinates.
951 * @return The offset of the character at aPoint from
952 * the beginning of the focused editor or
955 NSUInteger
CharacterIndexForPoint(NSPoint
& aPoint
);
958 * GetValidAttributesForMarkedText() returns attributes which we support.
960 * @return Always empty array for now.
962 NSArray
* GetValidAttributesForMarkedText();
964 bool HasMarkedText();
965 NSRange
MarkedRange();
967 bool IsIMEComposing() { return mIsIMEComposing
; }
968 bool IsDeadKeyComposing() { return mIsDeadKeyComposing
; }
970 bool IsIMEEnabled() { return mIsIMEEnabled
; }
971 bool IsASCIICapableOnly() { return mIsASCIICapableOnly
; }
972 bool IsEditableContent() const { return mIsIMEEnabled
|| mIsASCIICapableOnly
; }
973 bool IgnoreIMECommit() { return mIgnoreIMECommit
; }
975 void CommitIMEComposition();
976 void CancelIMEComposition();
978 void EnableIME(bool aEnableIME
);
979 void SetIMEOpenState(bool aOpen
);
980 void SetASCIICapableOnly(bool aASCIICapableOnly
);
983 * True if OSX believes that our view has keyboard focus.
987 static CFArrayRef
CreateAllIMEModeList();
988 static void DebugPrintAllIMEModes();
990 // Don't use ::TSMGetActiveDocument() API directly, the document may not
992 static TSMDocumentID
GetCurrentTSMDocumentID();
995 // We cannot do some jobs in the given stack by some reasons.
996 // Following flags and the timer provide the execution pending mechanism,
997 // See the comment in nsCocoaTextInputHandler.mm.
998 nsCOMPtr
<nsITimer
> mTimer
;
999 enum { kNotifyIMEOfFocusChangeInGecko
= 1, kSyncASCIICapableOnly
= 2 };
1000 uint32_t mPendingMethods
;
1002 IMEInputHandler(nsChildView
* aWidget
, NSView
<mozView
>* aNativeView
);
1003 virtual ~IMEInputHandler();
1007 virtual void ExecutePendingMethods();
1010 * InsertTextAsCommittingComposition() commits current composition. If there
1011 * is no composition, this starts a composition and commits it immediately.
1013 * @param aAttrString A string which is committed.
1014 * @param aReplacementRange The range which will be replaced with the
1015 * aAttrString instead of current selection.
1017 void InsertTextAsCommittingComposition(NSAttributedString
* aAttrString
,
1018 NSRange
* aReplacementRange
);
1021 * MaybeDispatchCurrentKeydownEvent() dispatches eKeyDown event for current
1022 * key event. If eKeyDown for current key event has already been dispatched,
1023 * this does nothing.
1025 * @param aIsProcessedByIME true if current key event is handled by IME.
1026 * @return true if the caller can continue to handle
1027 * current key event. Otherwise, false. E.g.,
1028 * focus is moved, the widget has been destroyed
1031 bool MaybeDispatchCurrentKeydownEvent(bool aIsProcessedByIME
);
1034 // If mIsIMEComposing is true, the composition string is stored here.
1035 NSString
* mIMECompositionString
;
1036 // If mIsIMEComposing is true, the start offset of the composition string.
1037 uint32_t mIMECompositionStart
;
1039 NSRange mMarkedRange
;
1040 NSRange mSelectedRange
;
1042 NSRange mRangeForWritingMode
; // range within which mWritingMode applies
1043 mozilla::WritingMode mWritingMode
;
1045 bool mIsIMEComposing
;
1046 // If the composition started with dead key, mIsDeadKeyComposing is set to
1048 bool mIsDeadKeyComposing
;
1050 bool mIsASCIICapableOnly
;
1051 bool mIgnoreIMECommit
;
1054 void KillIMEComposition();
1055 void SendCommittedText(NSString
* aString
);
1056 void OpenSystemPreferredLanguageIME();
1059 void NotifyIMEOfFocusChangeInGecko();
1060 void SyncASCIICapableOnly();
1062 static bool sStaticMembersInitialized
;
1063 static CFStringRef sLatestIMEOpenedModeInputSourceID
;
1064 static void InitStaticMembers();
1065 static void OnCurrentTextInputSourceChange(CFNotificationCenterRef aCenter
, void* aObserver
,
1066 CFStringRef aName
, const void* aObject
,
1067 CFDictionaryRef aUserInfo
);
1069 static void FlushPendingMethods(nsITimer
* aTimer
, void* aClosure
);
1072 * ConvertToTextRangeStyle converts the given native underline style to
1073 * our defined text range type.
1075 * @param aUnderlineStyle NSUnderlineStyleSingle or
1076 * NSUnderlineStyleThick.
1077 * @param aSelectedRange Current selected range (or caret position).
1078 * @return NS_TEXTRANGE_*.
1080 TextRangeType
ConvertToTextRangeType(uint32_t aUnderlineStyle
, NSRange
& aSelectedRange
);
1083 * GetRangeCount() computes the range count of aAttrString.
1085 * @param aAttrString An NSAttributedString instance whose number of
1086 * NSUnderlineStyleAttributeName ranges you with
1088 * @return The count of NSUnderlineStyleAttributeName
1089 * ranges in aAttrString.
1091 uint32_t GetRangeCount(NSAttributedString
* aString
);
1094 * CreateTextRangeArray() returns text ranges for clauses and/or caret.
1096 * @param aAttrString An NSAttributedString instance which indicates
1097 * current composition string.
1098 * @param aSelectedRange Current selected range (or caret position).
1099 * @return The result is set to the
1100 * NSUnderlineStyleAttributeName ranges in
1103 already_AddRefed
<mozilla::TextRangeArray
> CreateTextRangeArray(NSAttributedString
* aAttrString
,
1104 NSRange
& aSelectedRange
);
1107 * DispatchCompositionStartEvent() dispatches a compositionstart event and
1108 * initializes the members indicating composition state.
1110 * @return true if it can continues handling composition.
1111 * Otherwise, e.g., canceled by the web page,
1112 * this returns false.
1114 bool DispatchCompositionStartEvent();
1117 * DispatchCompositionChangeEvent() dispatches a compositionchange event on
1118 * mWidget and modifies the members indicating composition state.
1120 * @param aText User text input.
1121 * @param aAttrString An NSAttributedString instance which indicates
1122 * current composition string.
1123 * @param aSelectedRange Current selected range (or caret position).
1125 * @return true if it can continues handling composition.
1126 * Otherwise, e.g., canceled by the web page,
1127 * this returns false.
1129 bool DispatchCompositionChangeEvent(const nsString
& aText
, NSAttributedString
* aAttrString
,
1130 NSRange
& aSelectedRange
);
1133 * DispatchCompositionCommitEvent() dispatches a compositioncommit event or
1134 * compositioncommitasis event. If aCommitString is null, dispatches
1135 * compositioncommitasis event. I.e., if aCommitString is null, this
1136 * commits the composition with the last data. Otherwise, commits the
1137 * composition with aCommitString value.
1139 * @return true if the widget isn't destroyed.
1142 bool DispatchCompositionCommitEvent(const nsAString
* aCommitString
= nullptr);
1144 // The focused IME handler. Please note that the handler might lost the
1145 // actual focus by deactivating the application. If we are active, this
1146 // must have the actual focused handle.
1147 // We cannot access to the NSInputManager during we aren't active, so, the
1148 // focused handler can have an IME transaction even if we are deactive.
1149 static IMEInputHandler
* sFocusedIMEHandler
;
1151 static bool sCachedIsForRTLLangage
;
1155 * TextInputHandler implements the NSTextInput protocol.
1157 class TextInputHandler
: public IMEInputHandler
{
1159 static NSUInteger sLastModifierState
;
1161 static CFArrayRef
CreateAllKeyboardLayoutList();
1162 static void DebugPrintAllKeyboardLayouts();
1164 TextInputHandler(nsChildView
* aWidget
, NSView
<mozView
>* aNativeView
);
1165 virtual ~TextInputHandler();
1168 * KeyDown event handler.
1170 * @param aNativeEvent A native NSEventTypeKeyDown event.
1171 * @param aUniqueId A unique ID for the event.
1172 * @return TRUE if the event is dispatched to web
1173 * contents or chrome contents. Otherwise, FALSE.
1175 bool HandleKeyDownEvent(NSEvent
* aNativeEvent
, uint32_t aUniqueId
);
1178 * KeyUp event handler.
1180 * @param aNativeEvent A native NSEventTypeKeyUp event.
1182 void HandleKeyUpEvent(NSEvent
* aNativeEvent
);
1185 * FlagsChanged event handler.
1187 * @param aNativeEvent A native NSEventTypeFlagsChanged event.
1189 void HandleFlagsChanged(NSEvent
* aNativeEvent
);
1192 * Insert the string to content. I.e., this is a text input event handler.
1193 * If this is called during keydown event handling, this may dispatch a
1194 * eKeyPress event. If this is called during composition, this commits
1195 * the composition by the aAttrString.
1197 * @param aAttrString An inserted string.
1198 * @param aReplacementRange The range which will be replaced with the
1199 * aAttrString instead of current selection.
1201 void InsertText(NSAttributedString
* aAttrString
, NSRange
* aReplacementRange
= nullptr);
1204 * Handles aCommand. This may cause dispatching an eKeyPress event.
1206 * @param aCommand The command which receives from Cocoa.
1207 * @return true if this handles the command even if it does
1208 * nothing actually. Otherwise, false.
1210 bool HandleCommand(Command aCommand
);
1213 * doCommandBySelector event handler.
1215 * @param aSelector A selector of the command.
1216 * @return TRUE if the command is consumed. Otherwise,
1219 bool DoCommandBySelector(const char* aSelector
);
1222 * KeyPressWasHandled() checks whether keypress event was handled or not.
1224 * @return TRUE if keypress event for latest native key
1225 * event was handled. Otherwise, FALSE.
1226 * If this handler isn't handling any key events,
1227 * always returns FALSE.
1229 bool KeyPressWasHandled() {
1230 KeyEventState
* currentKeyEvent
= GetCurrentKeyEvent();
1231 return currentKeyEvent
&& currentKeyEvent
->mKeyPressHandled
;
1235 // Stores the association of device dependent modifier flags with a modifier
1236 // keyCode. Being device dependent, this association may differ from one kind
1237 // of hardware to the next.
1238 struct ModifierKey
{
1240 unsigned short keyCode
;
1242 ModifierKey(NSUInteger aFlags
, unsigned short aKeyCode
) : flags(aFlags
), keyCode(aKeyCode
) {}
1244 NSUInteger
GetDeviceDependentFlags() const {
1245 return (flags
& ~NSEventModifierFlagDeviceIndependentFlagsMask
);
1248 NSUInteger
GetDeviceIndependentFlags() const {
1249 return (flags
& NSEventModifierFlagDeviceIndependentFlagsMask
);
1252 typedef nsTArray
<ModifierKey
> ModifierKeyArray
;
1253 ModifierKeyArray mModifierKeys
;
1256 * GetModifierKeyForNativeKeyCode() returns the stored ModifierKey for
1259 const ModifierKey
* GetModifierKeyForNativeKeyCode(unsigned short aKeyCode
) const;
1262 * GetModifierKeyForDeviceDependentFlags() returns the stored ModifierKey for
1263 * the device dependent flags.
1265 const ModifierKey
* GetModifierKeyForDeviceDependentFlags(NSUInteger aFlags
) const;
1268 * DispatchKeyEventForFlagsChanged() dispatches keydown event or keyup event
1269 * for the aNativeEvent.
1271 * @param aNativeEvent A native flagschanged event which you want to
1272 * dispatch our key event for.
1273 * @param aDispatchKeyDown TRUE if you want to dispatch a keydown event.
1274 * Otherwise, i.e., to dispatch keyup event,
1277 void DispatchKeyEventForFlagsChanged(NSEvent
* aNativeEvent
, bool aDispatchKeyDown
);
1280 } // namespace widget
1281 } // namespace mozilla
1283 #endif // TextInputHandler_h_