Backed out changeset b4a0f8afc02e (bug 1857946) for causing bc failures at browser...
[gecko.git] / widget / cocoa / TextInputHandler.h
blob91ca29a9018411b2c8c718469c2de84339667183
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 sw=2 et tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef TextInputHandler_h_
8 #define TextInputHandler_h_
10 #include "nsCocoaUtils.h"
12 #import <Carbon/Carbon.h>
13 #import <Cocoa/Cocoa.h>
14 #include "mozView.h"
15 #include "nsString.h"
16 #include "nsCOMPtr.h"
17 #include "nsITimer.h"
18 #include "nsTArray.h"
19 #include "mozilla/BasicEvents.h"
20 #include "mozilla/EventForwards.h"
21 #include "mozilla/TextEventDispatcherListener.h"
22 #include "WritingModes.h"
24 class nsChildView;
26 namespace mozilla {
27 namespace widget {
29 // Key code constants
30 enum {
31 kVK_PC_PrintScreen = kVK_F13,
32 kVK_PC_ScrollLock = kVK_F14,
33 kVK_PC_Pause = kVK_F15,
35 kVK_PC_Insert = kVK_Help,
36 kVK_PC_Backspace = kVK_Delete,
37 kVK_PC_Delete = kVK_ForwardDelete,
39 kVK_PC_ContextMenu = 0x6E,
41 kVK_Powerbook_KeypadEnter = 0x34 // Enter on Powerbook's keyboard is different
44 /**
45 * TISInputSourceWrapper is a wrapper for the TISInputSourceRef. If we get the
46 * TISInputSourceRef from InputSourceID, we need to release the CFArray instance
47 * which is returned by TISCreateInputSourceList. However, when we release the
48 * list, we cannot access the TISInputSourceRef. So, it's not usable, and it
49 * may cause the memory leak bugs. nsTISInputSource automatically releases the
50 * list when the instance is destroyed.
52 class TISInputSourceWrapper {
53 public:
54 static TISInputSourceWrapper& CurrentInputSource();
55 /**
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},
64 mIsRTL{0},
65 mOverrideKeyboard{false} {
66 mInputSourceList = nullptr;
67 Clear();
70 explicit TISInputSourceWrapper(const char* aID)
71 : mInputSource{nullptr},
72 mKeyboardLayout{nullptr},
73 mUCKeyboardLayout{nullptr},
74 mIsRTL{0},
75 mOverrideKeyboard{false} {
76 mInputSourceList = nullptr;
77 InitByInputSourceID(aID);
80 explicit TISInputSourceWrapper(SInt32 aLayoutID)
81 : mInputSource{nullptr},
82 mKeyboardLayout{nullptr},
83 mUCKeyboardLayout{nullptr},
84 mIsRTL{0},
85 mOverrideKeyboard{false} {
86 mInputSourceList = nullptr;
87 InitByLayoutID(aLayoutID);
90 explicit TISInputSourceWrapper(TISInputSourceRef aInputSource)
91 : mInputSource{nullptr},
92 mKeyboardLayout{nullptr},
93 mUCKeyboardLayout{nullptr},
94 mIsRTL{0},
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.
109 * 0: US
110 * 1: Greek
111 * 2: German
112 * 3: Swedish-Pro
113 * 4: Dvorak-Qwerty Cmd
114 * 5: Thai
115 * 6: Arabic
116 * 7: French
117 * 8: Hebrew
118 * 9: Lithuanian
119 * 10: Norwegian
120 * 11: Spanish
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,
136 * returns it.
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();
146 bool IsIMEMode();
147 bool IsKeyboardLayout();
149 bool IsASCIICapable() {
150 NS_ENSURE_TRUE(mInputSource, false);
151 return GetBoolProperty(kTISPropertyInputSourceIsASCIICapable);
154 bool IsEnabled() {
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();
207 enum {
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
210 // set up dialog.
211 eKbdType_ANSI = 40
214 void Select();
215 void Clear();
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
255 * eKeyPress event.
257 void WillDispatchKeyboardEvent(NSEvent* aNativeKeyEvent, const nsAString* aInsertString,
258 uint32_t aIndexOfKeypress, WidgetKeyboardEvent& aKeyEvent);
261 * ComputeGeckoKeyCode() returns Gecko keycode for aNativeKeyCode on current
262 * keyboard layout.
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);
297 protected:
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,
324 * returns 0.
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,
337 * false.
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
345 * event(s).
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
353 * keypress event(s).
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;
378 int8_t mIsRTL;
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 {
391 public:
393 * Other TextEventDispatcherListener methods should be implemented in
394 * IMEInputHandler.
396 NS_DECL_ISUPPORTS
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.
413 * Otherwise, FALSE.
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
440 * for the detail.
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();
495 public:
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);
508 protected:
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
532 NSEvent* mKeyEvent;
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.
541 uint32_t mUniqueId;
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) {
561 Clear();
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");
571 Clear();
572 mKeyEvent = [aNativeKeyEvent retain];
573 mUniqueId = aUniqueId;
576 void Clear() {
577 if (mKeyEvent) {
578 [mKeyEvent release];
579 mKeyEvent = nullptr;
580 mUniqueId = 0;
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)) {
604 return false;
606 KeyNameIndex keyNameIndex =
607 TISInputSourceWrapper::ComputeGeckoKeyNameIndex([mKeyEvent keyCode]);
608 Modifiers modifiers = nsCocoaUtils::ModifiersForEvent(mKeyEvent) &
609 (MODIFIER_SHIFT | MODIFIER_CONTROL | MODIFIER_ALT | MODIFIER_META);
610 switch (aCommand) {
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));
696 default:
697 return false;
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 {
719 public:
720 explicit AutoKeyEventStateCleaner(TextInputHandlerBase* aHandler) : mHandler(aHandler) {}
722 ~AutoKeyEventStateCleaner() { mHandler->RemoveCurrentKeyEvent(); }
724 private:
725 RefPtr<TextInputHandlerBase> mHandler;
728 class MOZ_STACK_CLASS AutoInsertStringClearer {
729 public:
730 explicit AutoInsertStringClearer(KeyEventState* aState) : mState(aState) {}
731 ~AutoInsertStringClearer();
733 private:
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;
765 } else {
766 keyEvent = new KeyEventState(aNativeKeyEvent, aUniqueId);
768 return *mCurrentKeyEvents.AppendElement(keyEvent);
772 * RemoveCurrentKeyEvent() removes the current key event from
773 * mCurrentKeyEvents.
775 void RemoveCurrentKeyEvent() {
776 NS_ASSERTION(mCurrentKeyEvents.Length() > 0, "RemoveCurrentKeyEvent() is called unexpectedly");
777 KeyEventState* keyEvent = mCurrentKeyEvents.PopLastElement();
778 if (keyEvent == &mFirstKeyEvent) {
779 keyEvent->Clear();
780 } else {
781 delete keyEvent;
786 * GetCurrentKeyEvent() returns current processing key event.
788 KeyEventState* GetCurrentKeyEvent() {
789 if (mCurrentKeyEvents.Length() == 0) {
790 return nullptr;
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,
813 * FALSE.
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.
822 * Otherwise, FALSE.
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.
831 * Otherwise, FALSE.
833 static bool IsModifierKey(UInt32 aNativeKeyCode);
835 private:
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
846 * the instance.
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 {
855 public:
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;
861 NS_IMETHOD_(void)
862 WillDispatchKeyboardEvent(TextEventDispatcher* aTextEventDispatcher,
863 WidgetKeyboardEvent& aKeyboardEvent, uint32_t aIndexOfKeypress,
864 void* aData) override;
866 public:
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
887 * that instead.
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
942 * be 0.
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
953 * document.
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; }
969 bool IsIMEOpened();
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.
985 bool IsFocused();
987 static CFArrayRef CreateAllIMEModeList();
988 static void DebugPrintAllIMEModes();
990 // Don't use ::TSMGetActiveDocument() API directly, the document may not
991 // be what you want.
992 static TSMDocumentID GetCurrentTSMDocumentID();
994 protected:
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();
1005 void ResetTimer();
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
1029 * or something.
1031 bool MaybeDispatchCurrentKeydownEvent(bool aIsProcessedByIME);
1033 private:
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
1047 // true.
1048 bool mIsDeadKeyComposing;
1049 bool mIsIMEEnabled;
1050 bool mIsASCIICapableOnly;
1051 bool mIgnoreIMECommit;
1052 bool mIMEHasFocus;
1054 void KillIMEComposition();
1055 void SendCommittedText(NSString* aString);
1056 void OpenSystemPreferredLanguageIME();
1058 // Pending methods
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
1087 * to know.
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
1101 * aAttrString.
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.
1140 * Otherwise, false.
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 {
1158 public:
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,
1217 * FALSE.
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;
1234 protected:
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 {
1239 NSUInteger flags;
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
1257 * the key.
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,
1275 * FALSE.
1277 void DispatchKeyEventForFlagsChanged(NSEvent* aNativeEvent, bool aDispatchKeyDown);
1280 } // namespace widget
1281 } // namespace mozilla
1283 #endif // TextInputHandler_h_