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 #if !defined(MAC_OS_X_VERSION_10_12) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_12
32 kVK_RightCommand
= 0x36, // right command key
35 kVK_PC_PrintScreen
= kVK_F13
,
36 kVK_PC_ScrollLock
= kVK_F14
,
37 kVK_PC_Pause
= kVK_F15
,
39 kVK_PC_Insert
= kVK_Help
,
40 kVK_PC_Backspace
= kVK_Delete
,
41 kVK_PC_Delete
= kVK_ForwardDelete
,
43 kVK_PC_ContextMenu
= 0x6E,
45 kVK_Powerbook_KeypadEnter
= 0x34 // Enter on Powerbook's keyboard is different
49 * TISInputSourceWrapper is a wrapper for the TISInputSourceRef. If we get the
50 * TISInputSourceRef from InputSourceID, we need to release the CFArray instance
51 * which is returned by TISCreateInputSourceList. However, when we release the
52 * list, we cannot access the TISInputSourceRef. So, it's not usable, and it
53 * may cause the memory leak bugs. nsTISInputSource automatically releases the
54 * list when the instance is destroyed.
56 class TISInputSourceWrapper
{
58 static TISInputSourceWrapper
& CurrentInputSource();
60 * Shutdown() should be called when nobody doesn't need to use this class.
62 static void Shutdown();
64 TISInputSourceWrapper()
65 : mInputSource
{nullptr},
66 mKeyboardLayout
{nullptr},
67 mUCKeyboardLayout
{nullptr},
69 mOverrideKeyboard
{false} {
70 mInputSourceList
= nullptr;
74 explicit TISInputSourceWrapper(const char* aID
)
75 : mInputSource
{nullptr},
76 mKeyboardLayout
{nullptr},
77 mUCKeyboardLayout
{nullptr},
79 mOverrideKeyboard
{false} {
80 mInputSourceList
= nullptr;
81 InitByInputSourceID(aID
);
84 explicit TISInputSourceWrapper(SInt32 aLayoutID
)
85 : mInputSource
{nullptr},
86 mKeyboardLayout
{nullptr},
87 mUCKeyboardLayout
{nullptr},
89 mOverrideKeyboard
{false} {
90 mInputSourceList
= nullptr;
91 InitByLayoutID(aLayoutID
);
94 explicit TISInputSourceWrapper(TISInputSourceRef aInputSource
)
95 : mInputSource
{nullptr},
96 mKeyboardLayout
{nullptr},
97 mUCKeyboardLayout
{nullptr},
99 mOverrideKeyboard
{false} {
100 mInputSourceList
= nullptr;
101 InitByTISInputSourceRef(aInputSource
);
104 ~TISInputSourceWrapper() { Clear(); }
106 void InitByInputSourceID(const char* aID
);
107 void InitByInputSourceID(const nsString
& aID
);
108 void InitByInputSourceID(const CFStringRef aID
);
110 * InitByLayoutID() initializes the keyboard layout by the layout ID.
112 * @param aLayoutID An ID of keyboard layout.
117 * 4: Dvorak-Qwerty Cmd
125 * @param aOverrideKeyboard When testing set to TRUE, otherwise, set to
126 * FALSE. When TRUE, we use an ANSI keyboard
127 * instead of the actual keyboard.
129 void InitByLayoutID(SInt32 aLayoutID
, bool aOverrideKeyboard
= false);
130 void InitByCurrentInputSource();
131 void InitByCurrentKeyboardLayout();
132 void InitByCurrentASCIICapableInputSource();
133 void InitByCurrentASCIICapableKeyboardLayout();
134 void InitByCurrentInputMethodKeyboardLayoutOverride();
135 void InitByTISInputSourceRef(TISInputSourceRef aInputSource
);
136 void InitByLanguage(CFStringRef aLanguage
);
139 * If the instance is initialized with a keyboard layout input source,
141 * If the instance is initialized with an IME mode input source, the result
142 * references the keyboard layout for the IME mode. However, this can be
143 * initialized only when the IME mode is actually selected. I.e, if IME mode
144 * input source is initialized with LayoutID or SourceID, this returns null.
146 TISInputSourceRef
GetKeyboardLayoutInputSource() const { return mKeyboardLayout
; }
147 const UCKeyboardLayout
* GetUCKeyboardLayout();
149 bool IsOpenedIMEMode();
151 bool IsKeyboardLayout();
153 bool IsASCIICapable() {
154 NS_ENSURE_TRUE(mInputSource
, false);
155 return GetBoolProperty(kTISPropertyInputSourceIsASCIICapable
);
159 NS_ENSURE_TRUE(mInputSource
, false);
160 return GetBoolProperty(kTISPropertyInputSourceIsEnabled
);
163 bool GetLanguageList(CFArrayRef
& aLanguageList
);
164 bool GetPrimaryLanguage(CFStringRef
& aPrimaryLanguage
);
165 bool GetPrimaryLanguage(nsAString
& aPrimaryLanguage
);
167 bool GetLocalizedName(CFStringRef
& aName
) {
168 NS_ENSURE_TRUE(mInputSource
, false);
169 return GetStringProperty(kTISPropertyLocalizedName
, aName
);
172 bool GetLocalizedName(nsAString
& aName
) {
173 NS_ENSURE_TRUE(mInputSource
, false);
174 return GetStringProperty(kTISPropertyLocalizedName
, aName
);
177 bool GetInputSourceID(CFStringRef
& aID
) {
178 NS_ENSURE_TRUE(mInputSource
, false);
179 return GetStringProperty(kTISPropertyInputSourceID
, aID
);
182 bool GetInputSourceID(nsAString
& aID
) {
183 NS_ENSURE_TRUE(mInputSource
, false);
184 return GetStringProperty(kTISPropertyInputSourceID
, aID
);
187 bool GetBundleID(CFStringRef
& aBundleID
) {
188 NS_ENSURE_TRUE(mInputSource
, false);
189 return GetStringProperty(kTISPropertyBundleID
, aBundleID
);
192 bool GetBundleID(nsAString
& aBundleID
) {
193 NS_ENSURE_TRUE(mInputSource
, false);
194 return GetStringProperty(kTISPropertyBundleID
, aBundleID
);
197 bool GetInputSourceType(CFStringRef
& aType
) {
198 NS_ENSURE_TRUE(mInputSource
, false);
199 return GetStringProperty(kTISPropertyInputSourceType
, aType
);
202 bool GetInputSourceType(nsAString
& aType
) {
203 NS_ENSURE_TRUE(mInputSource
, false);
204 return GetStringProperty(kTISPropertyInputSourceType
, aType
);
207 bool IsForRTLLanguage();
208 bool IsForJapaneseLanguage();
209 bool IsInitializedByCurrentInputSource();
212 // 40 is an actual result of the ::LMGetKbdType() when we connect an
213 // unknown keyboard and set the keyboard type to ANSI manually on the
222 * InitKeyEvent() initializes aKeyEvent for aNativeKeyEvent.
224 * @param aNativeKeyEvent A native key event for which you want to
225 * dispatch a Gecko key event.
226 * @param aKeyEvent The result -- a Gecko key event initialized
227 * from the native key event.
228 * @param aIsProcessedByIME true if aNativeKeyEvent has been handled
229 * by IME (but except if the composition was
230 * started with dead key).
231 * @param aInsertString If caller expects that the event will cause
232 * a character to be input (say in an editor),
233 * the caller should set this. Otherwise,
234 * if caller sets null to this, this method will
235 * compute the character to be input from
236 * characters of aNativeKeyEvent.
238 void InitKeyEvent(NSEvent
* aNativeKeyEvent
, WidgetKeyboardEvent
& aKeyEvent
,
239 bool aIsProcessedByIME
, const nsAString
* aInsertString
= nullptr);
242 * WillDispatchKeyboardEvent() computes aKeyEvent.mAlternativeCharCodes and
243 * recompute aKeyEvent.mCharCode if it's necessary.
245 * @param aNativeKeyEvent A native key event for which you want to
246 * dispatch a Gecko key event.
247 * @param aInsertString If caller expects that the event will cause
248 * a character to be input (say in an editor),
249 * the caller should set this. Otherwise,
250 * if caller sets null to this, this method will
251 * compute the character to be input from
252 * characters of aNativeKeyEvent.
253 * @param aIndexOfKeypress Index of the eKeyPress event. If a key
254 * inputs 2 or more characters, eKeyPress events
255 * are dispatched for each character. This is
256 * 0 for the first eKeyPress event.
257 * @param aKeyEvent The result -- a Gecko key event initialized
258 * from the native key event. This must be
261 void WillDispatchKeyboardEvent(NSEvent
* aNativeKeyEvent
, const nsAString
* aInsertString
,
262 uint32_t aIndexOfKeypress
, WidgetKeyboardEvent
& aKeyEvent
);
265 * ComputeGeckoKeyCode() returns Gecko keycode for aNativeKeyCode on current
268 * @param aNativeKeyCode A native keycode.
269 * @param aKbType A native Keyboard Type value. Typically,
270 * this is a result of ::LMGetKbdType().
271 * @param aCmdIsPressed TRUE if Cmd key is pressed. Otherwise, FALSE.
272 * @return The computed Gecko keycode.
274 uint32_t ComputeGeckoKeyCode(UInt32 aNativeKeyCode
, UInt32 aKbType
, bool aCmdIsPressed
);
277 * ComputeGeckoKeyNameIndex() returns Gecko key name index for the key.
279 * @param aNativeKeyCode A native keycode.
281 static KeyNameIndex
ComputeGeckoKeyNameIndex(UInt32 aNativeKeyCode
);
284 * ComputeGeckoCodeNameIndex() returns Gecko code name index for the key.
286 * @param aNativeKeyCode A native keycode.
287 * @param aKbType A native Keyboard Type value. Typically,
288 * this is a result of ::LMGetKbdType().
290 static CodeNameIndex
ComputeGeckoCodeNameIndex(UInt32 aNativeKeyCode
, UInt32 aKbType
);
293 * TranslateToChar() checks if aNativeKeyEvent is a dead key.
295 * @param aNativeKeyEvent A native key event.
296 * @return Returns true if the key event is a dead key
297 * event. Otherwise, false.
299 bool IsDeadKey(NSEvent
* aNativeKeyEvent
);
303 * TranslateToString() computes the inputted text from the native keyCode,
304 * modifier flags and keyboard type.
306 * @param aKeyCode A native keyCode.
307 * @param aModifiers Combination of native modifier flags.
308 * @param aKbType A native Keyboard Type value. Typically,
309 * this is a result of ::LMGetKbdType().
310 * @param aStr Result, i.e., inputted text.
311 * The result can be two or more characters.
312 * @return If succeeded, TRUE. Otherwise, FALSE.
313 * Even if TRUE, aStr can be empty string.
315 bool TranslateToString(UInt32 aKeyCode
, UInt32 aModifiers
, UInt32 aKbType
, nsAString
& aStr
);
318 * TranslateToChar() computes the inputted character from the native keyCode,
319 * modifier flags and keyboard type. If two or more characters would be
320 * input, this returns 0.
322 * @param aKeyCode A native keyCode.
323 * @param aModifiers Combination of native modifier flags.
324 * @param aKbType A native Keyboard Type value. Typically,
325 * this is a result of ::LMGetKbdType().
326 * @return If succeeded and the result is one character,
327 * returns the charCode of it. Otherwise,
330 uint32_t TranslateToChar(UInt32 aKeyCode
, UInt32 aModifiers
, UInt32 aKbType
);
333 * TranslateToChar() checks if aKeyCode with aModifiers is a dead key.
335 * @param aKeyCode A native keyCode.
336 * @param aModifiers Combination of native modifier flags.
337 * @param aKbType A native Keyboard Type value. Typically,
338 * this is a result of ::LMGetKbdType().
339 * @return Returns true if the key with specified
340 * modifier state is a dead key. Otherwise,
343 bool IsDeadKey(UInt32 aKeyCode
, UInt32 aModifiers
, UInt32 aKbType
);
346 * ComputeInsertString() computes string to be inserted with the key event.
348 * @param aNativeKeyEvent The native key event which causes our keyboard
350 * @param aKeyEvent A Gecko key event which was partially
351 * initialized with aNativeKeyEvent.
352 * @param aInsertString The string to be inputting by aNativeKeyEvent.
353 * This should be specified by InsertText().
354 * In other words, if the key event doesn't cause
355 * a call of InsertText(), this can be nullptr.
356 * @param aResult The string which should be set to charCode of
359 void ComputeInsertStringForCharCode(NSEvent
* aNativeKeyEvent
,
360 const WidgetKeyboardEvent
& aKeyEvent
,
361 const nsAString
* aInsertString
, nsAString
& aResult
);
364 * IsPrintableKeyEvent() returns true if aNativeKeyEvent is caused by
365 * a printable key. Otherwise, returns false.
367 bool IsPrintableKeyEvent(NSEvent
* aNativeKeyEvent
) const;
370 * GetKbdType() returns physical keyboard type.
372 UInt32
GetKbdType() const;
374 bool GetBoolProperty(const CFStringRef aKey
);
375 bool GetStringProperty(const CFStringRef aKey
, CFStringRef
& aStr
);
376 bool GetStringProperty(const CFStringRef aKey
, nsAString
& aStr
);
378 TISInputSourceRef mInputSource
;
379 TISInputSourceRef mKeyboardLayout
;
380 CFArrayRef mInputSourceList
;
381 const UCKeyboardLayout
* mUCKeyboardLayout
;
384 bool mOverrideKeyboard
;
386 static TISInputSourceWrapper
* sCurrentInputSource
;
390 * TextInputHandlerBase is a base class of IMEInputHandler and TextInputHandler.
391 * Utility methods should be implemented this level.
394 class TextInputHandlerBase
: public TextEventDispatcherListener
{
397 * Other TextEventDispatcherListener methods should be implemented in
403 * DispatchEvent() dispatches aEvent on mWidget.
405 * @param aEvent An event which you want to dispatch.
406 * @return TRUE if the event is consumed by web contents
407 * or chrome contents. Otherwise, FALSE.
409 bool DispatchEvent(WidgetGUIEvent
& aEvent
);
412 * SetSelection() dispatches eSetSelection event for the aRange.
414 * @param aRange The range which will be selected.
415 * @return TRUE if setting selection is succeeded and
416 * the widget hasn't been destroyed.
419 bool SetSelection(NSRange
& aRange
);
422 * InitKeyEvent() initializes aKeyEvent for aNativeKeyEvent.
424 * @param aNativeKeyEvent A native key event for which you want to
425 * dispatch a Gecko key event.
426 * @param aKeyEvent The result -- a Gecko key event initialized
427 * from the native key event.
428 * @param aIsProcessedByIME true if aNativeKeyEvent has been handled
429 * by IME (but except if the composition was
430 * started with dead key).
431 * @param aInsertString If caller expects that the event will cause
432 * a character to be input (say in an editor),
433 * the caller should set this. Otherwise,
434 * if caller sets null to this, this method will
435 * compute the character to be input from
436 * characters of aNativeKeyEvent.
438 void InitKeyEvent(NSEvent
* aNativeKeyEvent
, WidgetKeyboardEvent
& aKeyEvent
,
439 bool aIsProcessedByIME
, const nsAString
* aInsertString
= nullptr);
442 * SynthesizeNativeKeyEvent() is an implementation of
443 * nsIWidget::SynthesizeNativeKeyEvent(). See the document in nsIWidget.h
446 nsresult
SynthesizeNativeKeyEvent(int32_t aNativeKeyboardLayout
, int32_t aNativeKeyCode
,
447 uint32_t aModifierFlags
, const nsAString
& aCharacters
,
448 const nsAString
& aUnmodifiedCharacters
);
451 * Utility method intended for testing. Attempts to construct a native key
452 * event that would have been generated during an actual key press. This
453 * *does not dispatch* the native event. Instead, it is attached to the
454 * |mNativeKeyEvent| field of the Gecko event that is passed in.
455 * @param aKeyEvent Gecko key event to attach the native event to
457 NS_IMETHOD
AttachNativeKeyEvent(WidgetKeyboardEvent
& aKeyEvent
);
460 * GetWindowLevel() returns the window level of current focused (in Gecko)
461 * window. E.g., if an <input> element in XUL panel has focus, this returns
462 * the XUL panel's window level.
464 NSInteger
GetWindowLevel();
467 * IsSpecialGeckoKey() checks whether aNativeKeyCode is mapped to a special
468 * Gecko keyCode. A key is "special" if it isn't used for text input.
470 * @param aNativeKeyCode A native keycode.
471 * @return If the keycode is mapped to a special key,
472 * TRUE. Otherwise, FALSE.
474 static bool IsSpecialGeckoKey(UInt32 aNativeKeyCode
);
477 * EnableSecureEventInput() and DisableSecureEventInput() wrap the Carbon
478 * Event Manager APIs with the same names. In addition they keep track of
479 * how many times we've called them (in the same process) -- unlike the
480 * Carbon Event Manager APIs, which only keep track of how many times they've
481 * been called from any and all processes.
483 * The Carbon Event Manager's IsSecureEventInputEnabled() returns whether
484 * secure event input mode is enabled (in any process). This class's
485 * IsSecureEventInputEnabled() returns whether we've made any calls to
486 * EnableSecureEventInput() that are not (yet) offset by the calls we've
487 * made to DisableSecureEventInput().
489 static void EnableSecureEventInput();
490 static void DisableSecureEventInput();
491 static bool IsSecureEventInputEnabled();
494 * EnsureSecureEventInputDisabled() calls DisableSecureEventInput() until
495 * our call count becomes 0.
497 static void EnsureSecureEventInputDisabled();
501 * mWidget must not be destroyed without OnDestroyWidget being called.
503 * @param aDestroyingWidget Destroying widget. This might not be mWidget.
504 * @return This result doesn't have any meaning for
505 * callers. When aDstroyingWidget isn't the same
506 * as mWidget, FALSE. Then, inherited methods in
507 * sub classes should return from this method
508 * without cleaning up.
510 virtual bool OnDestroyWidget(nsChildView
* aDestroyingWidget
);
513 // The creator of this instance, client and its text event dispatcher.
514 // These members must not be nullptr after initialized until
515 // OnDestroyWidget() is called.
516 nsChildView
* mWidget
; // [WEAK]
517 RefPtr
<TextEventDispatcher
> mDispatcher
;
519 // The native view for mWidget.
520 // This view handles the actual text inputting.
521 NSView
<mozView
>* mView
; // [STRONG]
523 TextInputHandlerBase(nsChildView
* aWidget
, NSView
<mozView
>* aNativeView
);
524 virtual ~TextInputHandlerBase();
526 bool Destroyed() { return !mWidget
; }
529 * mCurrentKeyEvent indicates what key event we are handling. While
530 * handling a native keydown event, we need to store the event for insertText,
531 * doCommandBySelector and various action message handlers of NSResponder
532 * such as [NSResponder insertNewline:sender].
534 struct KeyEventState
{
535 // Handling native key event
537 // String specified by InsertText(). This is not null only during a
538 // call of InsertText().
539 nsAString
* mInsertString
;
540 // String which are included in [mKeyEvent characters] and already handled
541 // by InsertText() call(s).
542 nsString mInsertedString
;
543 // Unique id associated with a keydown / keypress event. It's ok if this
544 // wraps over long periods.
546 // Whether keydown event was dispatched for mKeyEvent.
547 bool mKeyDownDispatched
;
548 // Whether keydown event was consumed by web contents or chrome contents.
549 bool mKeyDownHandled
;
550 // Whether keypress event was dispatched for mKeyEvent.
551 bool mKeyPressDispatched
;
552 // Whether keypress event was consumed by web contents or chrome contents.
553 bool mKeyPressHandled
;
554 // Whether the key event causes other key events via IME or something.
555 bool mCausedOtherKeyEvents
;
556 // Whether the key event causes composition change or committing
557 // composition. So, even if InsertText() is called, this may be false
558 // if it dispatches keypress event.
559 bool mCompositionDispatched
;
561 KeyEventState() : mKeyEvent(nullptr), mUniqueId(0) { Clear(); }
563 explicit KeyEventState(NSEvent
* aNativeKeyEvent
, uint32_t aUniqueId
= 0)
564 : mKeyEvent(nullptr), mUniqueId(0) {
566 Set(aNativeKeyEvent
, aUniqueId
);
569 KeyEventState(const KeyEventState
& aOther
) = delete;
571 ~KeyEventState() { Clear(); }
573 void Set(NSEvent
* aNativeKeyEvent
, uint32_t aUniqueId
= 0) {
574 MOZ_ASSERT(aNativeKeyEvent
, "aNativeKeyEvent must not be NULL");
576 mKeyEvent
= [aNativeKeyEvent retain
];
577 mUniqueId
= aUniqueId
;
586 mInsertString
= nullptr;
587 mInsertedString
.Truncate();
588 mKeyDownDispatched
= false;
589 mKeyDownHandled
= false;
590 mKeyPressDispatched
= false;
591 mKeyPressHandled
= false;
592 mCausedOtherKeyEvents
= false;
593 mCompositionDispatched
= false;
596 bool IsDefaultPrevented() const {
597 return mKeyDownHandled
|| mKeyPressHandled
|| mCausedOtherKeyEvents
|| mCompositionDispatched
;
600 bool CanDispatchKeyDownEvent() const { return !mKeyDownDispatched
; }
602 bool CanDispatchKeyPressEvent() const { return !mKeyPressDispatched
&& !IsDefaultPrevented(); }
604 bool CanHandleCommand() const { return !mKeyDownHandled
&& !mKeyPressHandled
; }
606 bool IsProperKeyEvent(Command aCommand
) const {
607 if (NS_WARN_IF(!mKeyEvent
)) {
610 KeyNameIndex keyNameIndex
=
611 TISInputSourceWrapper::ComputeGeckoKeyNameIndex([mKeyEvent keyCode
]);
612 Modifiers modifiers
= nsCocoaUtils::ModifiersForEvent(mKeyEvent
) &
613 (MODIFIER_SHIFT
| MODIFIER_CONTROL
| MODIFIER_ALT
| MODIFIER_META
);
615 case Command::InsertLineBreak
:
616 return keyNameIndex
== KEY_NAME_INDEX_Enter
&& modifiers
== MODIFIER_CONTROL
;
617 case Command::InsertParagraph
:
618 return keyNameIndex
== KEY_NAME_INDEX_Enter
&& modifiers
== MODIFIER_NONE
;
619 case Command::DeleteCharBackward
:
620 return keyNameIndex
== KEY_NAME_INDEX_Backspace
&& modifiers
== MODIFIER_NONE
;
621 case Command::DeleteToBeginningOfLine
:
622 return keyNameIndex
== KEY_NAME_INDEX_Backspace
&& modifiers
== MODIFIER_META
;
623 case Command::DeleteWordBackward
:
624 return keyNameIndex
== KEY_NAME_INDEX_Backspace
&& modifiers
== MODIFIER_ALT
;
625 case Command::DeleteCharForward
:
626 return keyNameIndex
== KEY_NAME_INDEX_Delete
&& modifiers
== MODIFIER_NONE
;
627 case Command::DeleteWordForward
:
628 return keyNameIndex
== KEY_NAME_INDEX_Delete
&& modifiers
== MODIFIER_ALT
;
629 case Command::InsertTab
:
630 return keyNameIndex
== KEY_NAME_INDEX_Tab
&& modifiers
== MODIFIER_NONE
;
631 case Command::InsertBacktab
:
632 return keyNameIndex
== KEY_NAME_INDEX_Tab
&& modifiers
== MODIFIER_SHIFT
;
633 case Command::CharNext
:
634 return keyNameIndex
== KEY_NAME_INDEX_ArrowRight
&& modifiers
== MODIFIER_NONE
;
635 case Command::SelectCharNext
:
636 return keyNameIndex
== KEY_NAME_INDEX_ArrowRight
&& modifiers
== MODIFIER_SHIFT
;
637 case Command::WordNext
:
638 return keyNameIndex
== KEY_NAME_INDEX_ArrowRight
&& modifiers
== MODIFIER_ALT
;
639 case Command::SelectWordNext
:
640 return keyNameIndex
== KEY_NAME_INDEX_ArrowRight
&&
641 modifiers
== (MODIFIER_ALT
| MODIFIER_SHIFT
);
642 case Command::EndLine
:
643 return keyNameIndex
== KEY_NAME_INDEX_ArrowRight
&& modifiers
== MODIFIER_META
;
644 case Command::SelectEndLine
:
645 return keyNameIndex
== KEY_NAME_INDEX_ArrowRight
&&
646 modifiers
== (MODIFIER_META
| MODIFIER_SHIFT
);
647 case Command::CharPrevious
:
648 return keyNameIndex
== KEY_NAME_INDEX_ArrowLeft
&& modifiers
== MODIFIER_NONE
;
649 case Command::SelectCharPrevious
:
650 return keyNameIndex
== KEY_NAME_INDEX_ArrowLeft
&& modifiers
== MODIFIER_SHIFT
;
651 case Command::WordPrevious
:
652 return keyNameIndex
== KEY_NAME_INDEX_ArrowLeft
&& modifiers
== MODIFIER_ALT
;
653 case Command::SelectWordPrevious
:
654 return keyNameIndex
== KEY_NAME_INDEX_ArrowLeft
&&
655 modifiers
== (MODIFIER_ALT
| MODIFIER_SHIFT
);
656 case Command::BeginLine
:
657 return keyNameIndex
== KEY_NAME_INDEX_ArrowLeft
&& modifiers
== MODIFIER_META
;
658 case Command::SelectBeginLine
:
659 return keyNameIndex
== KEY_NAME_INDEX_ArrowLeft
&&
660 modifiers
== (MODIFIER_META
| MODIFIER_SHIFT
);
661 case Command::LinePrevious
:
662 return keyNameIndex
== KEY_NAME_INDEX_ArrowUp
&& modifiers
== MODIFIER_NONE
;
663 case Command::SelectLinePrevious
:
664 return keyNameIndex
== KEY_NAME_INDEX_ArrowUp
&& modifiers
== MODIFIER_SHIFT
;
665 case Command::MoveTop
:
666 return keyNameIndex
== KEY_NAME_INDEX_ArrowUp
&& modifiers
== MODIFIER_META
;
667 case Command::SelectTop
:
668 return (keyNameIndex
== KEY_NAME_INDEX_ArrowUp
&&
669 modifiers
== (MODIFIER_META
| MODIFIER_SHIFT
)) ||
670 (keyNameIndex
== KEY_NAME_INDEX_Home
&& modifiers
== MODIFIER_SHIFT
);
671 case Command::LineNext
:
672 return keyNameIndex
== KEY_NAME_INDEX_ArrowDown
&& modifiers
== MODIFIER_NONE
;
673 case Command::SelectLineNext
:
674 return keyNameIndex
== KEY_NAME_INDEX_ArrowDown
&& modifiers
== MODIFIER_SHIFT
;
675 case Command::MoveBottom
:
676 return keyNameIndex
== KEY_NAME_INDEX_ArrowDown
&& modifiers
== MODIFIER_META
;
677 case Command::SelectBottom
:
678 return (keyNameIndex
== KEY_NAME_INDEX_ArrowDown
&&
679 modifiers
== (MODIFIER_META
| MODIFIER_SHIFT
)) ||
680 (keyNameIndex
== KEY_NAME_INDEX_End
&& modifiers
== MODIFIER_SHIFT
);
681 case Command::ScrollPageUp
:
682 return keyNameIndex
== KEY_NAME_INDEX_PageUp
&& modifiers
== MODIFIER_NONE
;
683 case Command::SelectPageUp
:
684 return keyNameIndex
== KEY_NAME_INDEX_PageUp
&& modifiers
== MODIFIER_SHIFT
;
685 case Command::ScrollPageDown
:
686 return keyNameIndex
== KEY_NAME_INDEX_PageDown
&& modifiers
== MODIFIER_NONE
;
687 case Command::SelectPageDown
:
688 return keyNameIndex
== KEY_NAME_INDEX_PageDown
&& modifiers
== MODIFIER_SHIFT
;
689 case Command::ScrollBottom
:
690 return keyNameIndex
== KEY_NAME_INDEX_End
&& modifiers
== MODIFIER_NONE
;
691 case Command::ScrollTop
:
692 return keyNameIndex
== KEY_NAME_INDEX_Home
&& modifiers
== MODIFIER_NONE
;
693 case Command::CancelOperation
:
694 return (keyNameIndex
== KEY_NAME_INDEX_Escape
&&
695 (modifiers
== MODIFIER_NONE
|| modifiers
== MODIFIER_SHIFT
)) ||
696 ([mKeyEvent keyCode
] == kVK_ANSI_Period
&& modifiers
== MODIFIER_META
);
697 case Command::Complete
:
698 return keyNameIndex
== KEY_NAME_INDEX_Escape
&&
699 (modifiers
== MODIFIER_ALT
|| modifiers
== (MODIFIER_ALT
| MODIFIER_SHIFT
));
705 void InitKeyEvent(TextInputHandlerBase
* aHandler
, WidgetKeyboardEvent
& aKeyEvent
,
706 bool aIsProcessedByIME
);
709 * GetUnhandledString() returns characters of the event which have not been
710 * handled with InsertText() yet. For example, if there is a composition
711 * caused by a dead key press like '`' and it's committed by some key
712 * combinations like |Cmd+v|, then, the |v|'s KeyDown event's |characters|
713 * is |`v|. Then, after |`| is committed with a call of InsertString(),
714 * this returns only 'v'.
716 void GetUnhandledString(nsAString
& aUnhandledString
) const;
720 * Helper classes for guaranteeing cleaning mCurrentKeyEvent
722 class AutoKeyEventStateCleaner
{
724 explicit AutoKeyEventStateCleaner(TextInputHandlerBase
* aHandler
) : mHandler(aHandler
) {}
726 ~AutoKeyEventStateCleaner() { mHandler
->RemoveCurrentKeyEvent(); }
729 RefPtr
<TextInputHandlerBase
> mHandler
;
732 class MOZ_STACK_CLASS AutoInsertStringClearer
{
734 explicit AutoInsertStringClearer(KeyEventState
* aState
) : mState(aState
) {}
735 ~AutoInsertStringClearer();
738 KeyEventState
* mState
;
742 * mCurrentKeyEvents stores all key events which are being processed.
743 * When we call interpretKeyEvents, IME may generate other key events.
744 * mCurrentKeyEvents[0] is the latest key event.
746 nsTArray
<KeyEventState
*> mCurrentKeyEvents
;
749 * mFirstKeyEvent must be used for first key event. This member prevents
750 * memory fragmentation for most key events.
752 KeyEventState mFirstKeyEvent
;
755 * PushKeyEvent() adds the current key event to mCurrentKeyEvents.
757 KeyEventState
* PushKeyEvent(NSEvent
* aNativeKeyEvent
, uint32_t aUniqueId
= 0) {
758 uint32_t nestCount
= mCurrentKeyEvents
.Length();
759 for (uint32_t i
= 0; i
< nestCount
; i
++) {
760 // When the key event is caused by another key event, all key events
761 // which are being handled should be marked as "consumed".
762 mCurrentKeyEvents
[i
]->mCausedOtherKeyEvents
= true;
765 KeyEventState
* keyEvent
= nullptr;
766 if (nestCount
== 0) {
767 mFirstKeyEvent
.Set(aNativeKeyEvent
, aUniqueId
);
768 keyEvent
= &mFirstKeyEvent
;
770 keyEvent
= new KeyEventState(aNativeKeyEvent
, aUniqueId
);
772 return *mCurrentKeyEvents
.AppendElement(keyEvent
);
776 * RemoveCurrentKeyEvent() removes the current key event from
779 void RemoveCurrentKeyEvent() {
780 NS_ASSERTION(mCurrentKeyEvents
.Length() > 0, "RemoveCurrentKeyEvent() is called unexpectedly");
781 KeyEventState
* keyEvent
= mCurrentKeyEvents
.PopLastElement();
782 if (keyEvent
== &mFirstKeyEvent
) {
790 * GetCurrentKeyEvent() returns current processing key event.
792 KeyEventState
* GetCurrentKeyEvent() {
793 if (mCurrentKeyEvents
.Length() == 0) {
796 return mCurrentKeyEvents
[mCurrentKeyEvents
.Length() - 1];
799 struct KeyboardLayoutOverride final
{
800 int32_t mKeyboardLayout
;
801 bool mOverrideEnabled
;
803 KeyboardLayoutOverride() : mKeyboardLayout(0), mOverrideEnabled(false) {}
806 const KeyboardLayoutOverride
& KeyboardLayoutOverrideRef() const { return mKeyboardOverride
; }
809 * IsPrintableChar() checks whether the unicode character is
810 * a non-printable ASCII character or not. Note that this returns
811 * TRUE even if aChar is a non-printable UNICODE character.
813 * @param aChar A unicode character.
814 * @return TRUE if aChar is a printable ASCII character
815 * or a unicode character. Otherwise, i.e,
816 * if aChar is a non-printable ASCII character,
819 static bool IsPrintableChar(char16_t aChar
);
822 * IsNormalCharInputtingEvent() checks whether aKeyEvent causes text input.
824 * @param aKeyEvent A key event.
825 * @return TRUE if the key event causes text input.
828 static bool IsNormalCharInputtingEvent(const WidgetKeyboardEvent
& aKeyEvent
);
831 * IsModifierKey() checks whether the native keyCode is for a modifier key.
833 * @param aNativeKeyCode A native keyCode.
834 * @return TRUE if aNativeKeyCode is for a modifier key.
837 static bool IsModifierKey(UInt32 aNativeKeyCode
);
840 KeyboardLayoutOverride mKeyboardOverride
;
842 static int32_t sSecureEventInputCount
;
846 * IMEInputHandler manages:
847 * 1. The IME/keyboard layout statement of nsChildView.
848 * 2. The IME composition statement of nsChildView.
849 * And also provides the methods which controls the current IME transaction of
852 * Note that an nsChildView handles one or more NSView's events. E.g., even if
853 * a text editor on XUL panel element, the input events handled on the parent
854 * (or its ancestor) widget handles it (the native focus is set to it). The
855 * actual focused view is notified by OnFocusChangeInGecko.
858 class IMEInputHandler
: public TextInputHandlerBase
{
860 // TextEventDispatcherListener methods
861 NS_IMETHOD
NotifyIME(TextEventDispatcher
* aTextEventDispatcher
,
862 const IMENotification
& aNotification
) override
;
863 NS_IMETHOD_(IMENotificationRequests
) GetIMENotificationRequests() override
;
864 NS_IMETHOD_(void) OnRemovedFrom(TextEventDispatcher
* aTextEventDispatcher
) override
;
866 WillDispatchKeyboardEvent(TextEventDispatcher
* aTextEventDispatcher
,
867 WidgetKeyboardEvent
& aKeyboardEvent
, uint32_t aIndexOfKeypress
,
868 void* aData
) override
;
871 virtual bool OnDestroyWidget(nsChildView
* aDestroyingWidget
) override
;
873 virtual void OnFocusChangeInGecko(bool aFocus
);
875 void OnSelectionChange(const IMENotification
& aIMENotification
);
876 void OnLayoutChange();
879 * Call [NSTextInputContext handleEvent] for mouse event support of IME
881 bool OnHandleEvent(NSEvent
* aEvent
);
884 * SetMarkedText() is a handler of setMarkedText of NSTextInput.
886 * @param aAttrString This mut be an instance of NSAttributedString.
887 * If the aString parameter to
888 * [ChildView setMarkedText:setSelectedRange:]
889 * isn't an instance of NSAttributedString,
890 * create an NSAttributedString from it and pass
892 * @param aSelectedRange Current selected range (or caret position).
893 * @param aReplacementRange The range which will be replaced with the
894 * aAttrString instead of current marked range.
896 void SetMarkedText(NSAttributedString
* aAttrString
, NSRange
& aSelectedRange
,
897 NSRange
* aReplacementRange
= nullptr);
900 * GetAttributedSubstringFromRange() returns an NSAttributedString instance
901 * which is allocated as autorelease for aRange.
903 * @param aRange The range of string which you want.
904 * @param aActualRange The actual range of the result.
905 * @return The string in aRange. If the string is empty,
906 * this returns nil. If succeeded, this returns
907 * an instance which is allocated as autorelease.
908 * If this has some troubles, returns nil.
910 NSAttributedString
* GetAttributedSubstringFromRange(NSRange
& aRange
,
911 NSRange
* aActualRange
= nullptr);
914 * SelectedRange() returns current selected range.
916 * @return If an editor has focus, this returns selection
917 * range in the editor. Otherwise, this returns
918 * selection range in the focused document.
920 NSRange
SelectedRange();
923 * DrawsVerticallyForCharacterAtIndex() returns whether the character at
924 * the given index is being rendered vertically.
926 * @param aCharIndex The character offset to query.
928 * @return True if writing-mode is vertical at the given
929 * character offset; otherwise false.
931 bool DrawsVerticallyForCharacterAtIndex(uint32_t aCharIndex
);
934 * FirstRectForCharacterRange() returns first *character* rect in the range.
935 * Cocoa needs the first line rect in the range, but we cannot compute it
936 * on current implementation.
938 * @param aRange A range of text to examine. Its position is
939 * an offset from the beginning of the focused
940 * editor or document.
941 * @param aActualRange If this is not null, this returns the actual
942 * range used for computing the result.
943 * @return An NSRect containing the first character in
944 * aRange, in screen coordinates.
945 * If the length of aRange is 0, the width will
948 NSRect
FirstRectForCharacterRange(NSRange
& aRange
, NSRange
* aActualRange
= nullptr);
951 * CharacterIndexForPoint() returns an offset of a character at aPoint.
952 * XXX This isn't implemented, always returns 0.
954 * @param The point in screen coordinates.
955 * @return The offset of the character at aPoint from
956 * the beginning of the focused editor or
959 NSUInteger
CharacterIndexForPoint(NSPoint
& aPoint
);
962 * GetValidAttributesForMarkedText() returns attributes which we support.
964 * @return Always empty array for now.
966 NSArray
* GetValidAttributesForMarkedText();
968 bool HasMarkedText();
969 NSRange
MarkedRange();
971 bool IsIMEComposing() { return mIsIMEComposing
; }
972 bool IsDeadKeyComposing() { return mIsDeadKeyComposing
; }
974 bool IsIMEEnabled() { return mIsIMEEnabled
; }
975 bool IsASCIICapableOnly() { return mIsASCIICapableOnly
; }
976 bool IsEditableContent() const { return mIsIMEEnabled
|| mIsASCIICapableOnly
; }
977 bool IgnoreIMECommit() { return mIgnoreIMECommit
; }
979 void CommitIMEComposition();
980 void CancelIMEComposition();
982 void EnableIME(bool aEnableIME
);
983 void SetIMEOpenState(bool aOpen
);
984 void SetASCIICapableOnly(bool aASCIICapableOnly
);
987 * True if OSX believes that our view has keyboard focus.
991 static CFArrayRef
CreateAllIMEModeList();
992 static void DebugPrintAllIMEModes();
994 // Don't use ::TSMGetActiveDocument() API directly, the document may not
996 static TSMDocumentID
GetCurrentTSMDocumentID();
999 // We cannot do some jobs in the given stack by some reasons.
1000 // Following flags and the timer provide the execution pending mechanism,
1001 // See the comment in nsCocoaTextInputHandler.mm.
1002 nsCOMPtr
<nsITimer
> mTimer
;
1003 enum { kNotifyIMEOfFocusChangeInGecko
= 1, kSyncASCIICapableOnly
= 2 };
1004 uint32_t mPendingMethods
;
1006 IMEInputHandler(nsChildView
* aWidget
, NSView
<mozView
>* aNativeView
);
1007 virtual ~IMEInputHandler();
1011 virtual void ExecutePendingMethods();
1014 * InsertTextAsCommittingComposition() commits current composition. If there
1015 * is no composition, this starts a composition and commits it immediately.
1017 * @param aAttrString A string which is committed.
1018 * @param aReplacementRange The range which will be replaced with the
1019 * aAttrString instead of current selection.
1021 void InsertTextAsCommittingComposition(NSAttributedString
* aAttrString
,
1022 NSRange
* aReplacementRange
);
1025 * MaybeDispatchCurrentKeydownEvent() dispatches eKeyDown event for current
1026 * key event. If eKeyDown for current key event has already been dispatched,
1027 * this does nothing.
1029 * @param aIsProcessedByIME true if current key event is handled by IME.
1030 * @return true if the caller can continue to handle
1031 * current key event. Otherwise, false. E.g.,
1032 * focus is moved, the widget has been destroyed
1035 bool MaybeDispatchCurrentKeydownEvent(bool aIsProcessedByIME
);
1038 // If mIsIMEComposing is true, the composition string is stored here.
1039 NSString
* mIMECompositionString
;
1040 // If mIsIMEComposing is true, the start offset of the composition string.
1041 uint32_t mIMECompositionStart
;
1043 NSRange mMarkedRange
;
1044 NSRange mSelectedRange
;
1046 NSRange mRangeForWritingMode
; // range within which mWritingMode applies
1047 mozilla::WritingMode mWritingMode
;
1049 bool mIsIMEComposing
;
1050 // If the composition started with dead key, mIsDeadKeyComposing is set to
1052 bool mIsDeadKeyComposing
;
1054 bool mIsASCIICapableOnly
;
1055 bool mIgnoreIMECommit
;
1058 void KillIMEComposition();
1059 void SendCommittedText(NSString
* aString
);
1060 void OpenSystemPreferredLanguageIME();
1063 void NotifyIMEOfFocusChangeInGecko();
1064 void SyncASCIICapableOnly();
1066 static bool sStaticMembersInitialized
;
1067 static CFStringRef sLatestIMEOpenedModeInputSourceID
;
1068 static void InitStaticMembers();
1069 static void OnCurrentTextInputSourceChange(CFNotificationCenterRef aCenter
, void* aObserver
,
1070 CFStringRef aName
, const void* aObject
,
1071 CFDictionaryRef aUserInfo
);
1073 static void FlushPendingMethods(nsITimer
* aTimer
, void* aClosure
);
1076 * ConvertToTextRangeStyle converts the given native underline style to
1077 * our defined text range type.
1079 * @param aUnderlineStyle NSUnderlineStyleSingle or
1080 * NSUnderlineStyleThick.
1081 * @param aSelectedRange Current selected range (or caret position).
1082 * @return NS_TEXTRANGE_*.
1084 TextRangeType
ConvertToTextRangeType(uint32_t aUnderlineStyle
, NSRange
& aSelectedRange
);
1087 * GetRangeCount() computes the range count of aAttrString.
1089 * @param aAttrString An NSAttributedString instance whose number of
1090 * NSUnderlineStyleAttributeName ranges you with
1092 * @return The count of NSUnderlineStyleAttributeName
1093 * ranges in aAttrString.
1095 uint32_t GetRangeCount(NSAttributedString
* aString
);
1098 * CreateTextRangeArray() returns text ranges for clauses and/or caret.
1100 * @param aAttrString An NSAttributedString instance which indicates
1101 * current composition string.
1102 * @param aSelectedRange Current selected range (or caret position).
1103 * @return The result is set to the
1104 * NSUnderlineStyleAttributeName ranges in
1107 already_AddRefed
<mozilla::TextRangeArray
> CreateTextRangeArray(NSAttributedString
* aAttrString
,
1108 NSRange
& aSelectedRange
);
1111 * DispatchCompositionStartEvent() dispatches a compositionstart event and
1112 * initializes the members indicating composition state.
1114 * @return true if it can continues handling composition.
1115 * Otherwise, e.g., canceled by the web page,
1116 * this returns false.
1118 bool DispatchCompositionStartEvent();
1121 * DispatchCompositionChangeEvent() dispatches a compositionchange event on
1122 * mWidget and modifies the members indicating composition state.
1124 * @param aText User text input.
1125 * @param aAttrString An NSAttributedString instance which indicates
1126 * current composition string.
1127 * @param aSelectedRange Current selected range (or caret position).
1129 * @return true if it can continues handling composition.
1130 * Otherwise, e.g., canceled by the web page,
1131 * this returns false.
1133 bool DispatchCompositionChangeEvent(const nsString
& aText
, NSAttributedString
* aAttrString
,
1134 NSRange
& aSelectedRange
);
1137 * DispatchCompositionCommitEvent() dispatches a compositioncommit event or
1138 * compositioncommitasis event. If aCommitString is null, dispatches
1139 * compositioncommitasis event. I.e., if aCommitString is null, this
1140 * commits the composition with the last data. Otherwise, commits the
1141 * composition with aCommitString value.
1143 * @return true if the widget isn't destroyed.
1146 bool DispatchCompositionCommitEvent(const nsAString
* aCommitString
= nullptr);
1148 // The focused IME handler. Please note that the handler might lost the
1149 // actual focus by deactivating the application. If we are active, this
1150 // must have the actual focused handle.
1151 // We cannot access to the NSInputManager during we aren't active, so, the
1152 // focused handler can have an IME transaction even if we are deactive.
1153 static IMEInputHandler
* sFocusedIMEHandler
;
1155 static bool sCachedIsForRTLLangage
;
1159 * TextInputHandler implements the NSTextInput protocol.
1161 class TextInputHandler
: public IMEInputHandler
{
1163 static NSUInteger sLastModifierState
;
1165 static CFArrayRef
CreateAllKeyboardLayoutList();
1166 static void DebugPrintAllKeyboardLayouts();
1168 TextInputHandler(nsChildView
* aWidget
, NSView
<mozView
>* aNativeView
);
1169 virtual ~TextInputHandler();
1172 * KeyDown event handler.
1174 * @param aNativeEvent A native NSKeyDown event.
1175 * @param aUniqueId A unique ID for the event.
1176 * @return TRUE if the event is dispatched to web
1177 * contents or chrome contents. Otherwise, FALSE.
1179 bool HandleKeyDownEvent(NSEvent
* aNativeEvent
, uint32_t aUniqueId
);
1182 * KeyUp event handler.
1184 * @param aNativeEvent A native NSKeyUp event.
1186 void HandleKeyUpEvent(NSEvent
* aNativeEvent
);
1189 * FlagsChanged event handler.
1191 * @param aNativeEvent A native NSFlagsChanged event.
1193 void HandleFlagsChanged(NSEvent
* aNativeEvent
);
1196 * Insert the string to content. I.e., this is a text input event handler.
1197 * If this is called during keydown event handling, this may dispatch a
1198 * eKeyPress event. If this is called during composition, this commits
1199 * the composition by the aAttrString.
1201 * @param aAttrString An inserted string.
1202 * @param aReplacementRange The range which will be replaced with the
1203 * aAttrString instead of current selection.
1205 void InsertText(NSAttributedString
* aAttrString
, NSRange
* aReplacementRange
= nullptr);
1208 * Handles aCommand. This may cause dispatching an eKeyPress event.
1210 * @param aCommand The command which receives from Cocoa.
1211 * @return true if this handles the command even if it does
1212 * nothing actually. Otherwise, false.
1214 bool HandleCommand(Command aCommand
);
1217 * doCommandBySelector event handler.
1219 * @param aSelector A selector of the command.
1220 * @return TRUE if the command is consumed. Otherwise,
1223 bool DoCommandBySelector(const char* aSelector
);
1226 * KeyPressWasHandled() checks whether keypress event was handled or not.
1228 * @return TRUE if keypress event for latest native key
1229 * event was handled. Otherwise, FALSE.
1230 * If this handler isn't handling any key events,
1231 * always returns FALSE.
1233 bool KeyPressWasHandled() {
1234 KeyEventState
* currentKeyEvent
= GetCurrentKeyEvent();
1235 return currentKeyEvent
&& currentKeyEvent
->mKeyPressHandled
;
1239 // Stores the association of device dependent modifier flags with a modifier
1240 // keyCode. Being device dependent, this association may differ from one kind
1241 // of hardware to the next.
1242 struct ModifierKey
{
1244 unsigned short keyCode
;
1246 ModifierKey(NSUInteger aFlags
, unsigned short aKeyCode
) : flags(aFlags
), keyCode(aKeyCode
) {}
1248 NSUInteger
GetDeviceDependentFlags() const {
1249 return (flags
& ~NSDeviceIndependentModifierFlagsMask
);
1252 NSUInteger
GetDeviceIndependentFlags() const {
1253 return (flags
& NSDeviceIndependentModifierFlagsMask
);
1256 typedef nsTArray
<ModifierKey
> ModifierKeyArray
;
1257 ModifierKeyArray mModifierKeys
;
1260 * GetModifierKeyForNativeKeyCode() returns the stored ModifierKey for
1263 const ModifierKey
* GetModifierKeyForNativeKeyCode(unsigned short aKeyCode
) const;
1266 * GetModifierKeyForDeviceDependentFlags() returns the stored ModifierKey for
1267 * the device dependent flags.
1269 const ModifierKey
* GetModifierKeyForDeviceDependentFlags(NSUInteger aFlags
) const;
1272 * DispatchKeyEventForFlagsChanged() dispatches keydown event or keyup event
1273 * for the aNativeEvent.
1275 * @param aNativeEvent A native flagschanged event which you want to
1276 * dispatch our key event for.
1277 * @param aDispatchKeyDown TRUE if you want to dispatch a keydown event.
1278 * Otherwise, i.e., to dispatch keyup event,
1281 void DispatchKeyEventForFlagsChanged(NSEvent
* aNativeEvent
, bool aDispatchKeyDown
);
1284 } // namespace widget
1285 } // namespace mozilla
1287 #endif // TextInputHandler_h_