Bug 1673311 [wpt PR 26282] - Fieldset NG: Percentage heights for content elements...
[gecko.git] / widget / cocoa / TextInputHandler.h
blob4d1db1697460cba542d12a5fce1ddb194dbbb597
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 #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
33 #endif
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
48 /**
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 {
57 public:
58 static TISInputSourceWrapper& CurrentInputSource();
59 /**
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},
68 mIsRTL{0},
69 mOverrideKeyboard{false} {
70 mInputSourceList = nullptr;
71 Clear();
74 explicit TISInputSourceWrapper(const char* aID)
75 : mInputSource{nullptr},
76 mKeyboardLayout{nullptr},
77 mUCKeyboardLayout{nullptr},
78 mIsRTL{0},
79 mOverrideKeyboard{false} {
80 mInputSourceList = nullptr;
81 InitByInputSourceID(aID);
84 explicit TISInputSourceWrapper(SInt32 aLayoutID)
85 : mInputSource{nullptr},
86 mKeyboardLayout{nullptr},
87 mUCKeyboardLayout{nullptr},
88 mIsRTL{0},
89 mOverrideKeyboard{false} {
90 mInputSourceList = nullptr;
91 InitByLayoutID(aLayoutID);
94 explicit TISInputSourceWrapper(TISInputSourceRef aInputSource)
95 : mInputSource{nullptr},
96 mKeyboardLayout{nullptr},
97 mUCKeyboardLayout{nullptr},
98 mIsRTL{0},
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.
113 * 0: US
114 * 1: Greek
115 * 2: German
116 * 3: Swedish-Pro
117 * 4: Dvorak-Qwerty Cmd
118 * 5: Thai
119 * 6: Arabic
120 * 7: French
121 * 8: Hebrew
122 * 9: Lithuanian
123 * 10: Norwegian
124 * 11: Spanish
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,
140 * returns it.
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();
150 bool IsIMEMode();
151 bool IsKeyboardLayout();
153 bool IsASCIICapable() {
154 NS_ENSURE_TRUE(mInputSource, false);
155 return GetBoolProperty(kTISPropertyInputSourceIsASCIICapable);
158 bool IsEnabled() {
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();
211 enum {
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
214 // set up dialog.
215 eKbdType_ANSI = 40
218 void Select();
219 void Clear();
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
259 * eKeyPress event.
261 void WillDispatchKeyboardEvent(NSEvent* aNativeKeyEvent, const nsAString* aInsertString,
262 uint32_t aIndexOfKeypress, WidgetKeyboardEvent& aKeyEvent);
265 * ComputeGeckoKeyCode() returns Gecko keycode for aNativeKeyCode on current
266 * keyboard layout.
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);
301 protected:
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,
328 * returns 0.
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,
341 * false.
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
349 * event(s).
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
357 * keypress event(s).
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;
382 int8_t mIsRTL;
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 {
395 public:
397 * Other TextEventDispatcherListener methods should be implemented in
398 * IMEInputHandler.
400 NS_DECL_ISUPPORTS
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.
417 * Otherwise, FALSE.
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
444 * for the detail.
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();
499 public:
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);
512 protected:
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
536 NSEvent* mKeyEvent;
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.
545 uint32_t mUniqueId;
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) {
565 Clear();
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");
575 Clear();
576 mKeyEvent = [aNativeKeyEvent retain];
577 mUniqueId = aUniqueId;
580 void Clear() {
581 if (mKeyEvent) {
582 [mKeyEvent release];
583 mKeyEvent = nullptr;
584 mUniqueId = 0;
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)) {
608 return false;
610 KeyNameIndex keyNameIndex =
611 TISInputSourceWrapper::ComputeGeckoKeyNameIndex([mKeyEvent keyCode]);
612 Modifiers modifiers = nsCocoaUtils::ModifiersForEvent(mKeyEvent) &
613 (MODIFIER_SHIFT | MODIFIER_CONTROL | MODIFIER_ALT | MODIFIER_META);
614 switch (aCommand) {
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));
700 default:
701 return false;
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 {
723 public:
724 explicit AutoKeyEventStateCleaner(TextInputHandlerBase* aHandler) : mHandler(aHandler) {}
726 ~AutoKeyEventStateCleaner() { mHandler->RemoveCurrentKeyEvent(); }
728 private:
729 RefPtr<TextInputHandlerBase> mHandler;
732 class MOZ_STACK_CLASS AutoInsertStringClearer {
733 public:
734 explicit AutoInsertStringClearer(KeyEventState* aState) : mState(aState) {}
735 ~AutoInsertStringClearer();
737 private:
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;
769 } else {
770 keyEvent = new KeyEventState(aNativeKeyEvent, aUniqueId);
772 return *mCurrentKeyEvents.AppendElement(keyEvent);
776 * RemoveCurrentKeyEvent() removes the current key event from
777 * mCurrentKeyEvents.
779 void RemoveCurrentKeyEvent() {
780 NS_ASSERTION(mCurrentKeyEvents.Length() > 0, "RemoveCurrentKeyEvent() is called unexpectedly");
781 KeyEventState* keyEvent = mCurrentKeyEvents.PopLastElement();
782 if (keyEvent == &mFirstKeyEvent) {
783 keyEvent->Clear();
784 } else {
785 delete keyEvent;
790 * GetCurrentKeyEvent() returns current processing key event.
792 KeyEventState* GetCurrentKeyEvent() {
793 if (mCurrentKeyEvents.Length() == 0) {
794 return nullptr;
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,
817 * FALSE.
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.
826 * Otherwise, FALSE.
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.
835 * Otherwise, FALSE.
837 static bool IsModifierKey(UInt32 aNativeKeyCode);
839 private:
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
850 * the instance.
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 {
859 public:
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;
865 NS_IMETHOD_(void)
866 WillDispatchKeyboardEvent(TextEventDispatcher* aTextEventDispatcher,
867 WidgetKeyboardEvent& aKeyboardEvent, uint32_t aIndexOfKeypress,
868 void* aData) override;
870 public:
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
891 * that instead.
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
946 * be 0.
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
957 * document.
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; }
973 bool IsIMEOpened();
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.
989 bool IsFocused();
991 static CFArrayRef CreateAllIMEModeList();
992 static void DebugPrintAllIMEModes();
994 // Don't use ::TSMGetActiveDocument() API directly, the document may not
995 // be what you want.
996 static TSMDocumentID GetCurrentTSMDocumentID();
998 protected:
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();
1009 void ResetTimer();
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
1033 * or something.
1035 bool MaybeDispatchCurrentKeydownEvent(bool aIsProcessedByIME);
1037 private:
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
1051 // true.
1052 bool mIsDeadKeyComposing;
1053 bool mIsIMEEnabled;
1054 bool mIsASCIICapableOnly;
1055 bool mIgnoreIMECommit;
1056 bool mIMEHasFocus;
1058 void KillIMEComposition();
1059 void SendCommittedText(NSString* aString);
1060 void OpenSystemPreferredLanguageIME();
1062 // Pending methods
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
1091 * to know.
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
1105 * aAttrString.
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.
1144 * Otherwise, false.
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 {
1162 public:
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,
1221 * FALSE.
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;
1238 protected:
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 {
1243 NSUInteger flags;
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
1261 * the key.
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,
1279 * FALSE.
1281 void DispatchKeyEventForFlagsChanged(NSEvent* aNativeEvent, bool aDispatchKeyDown);
1284 } // namespace widget
1285 } // namespace mozilla
1287 #endif // TextInputHandler_h_