1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 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/. */
6 
7 #include "ShortcutKeys.h"
8 #include "mozilla/KeyEventHandler.h"
9 #include "nsContentUtils.h"
10 #include "nsAtom.h"
11 #include "mozilla/TextEvents.h"
12 
13 namespace mozilla {
14 
15 NS_IMPL_ISUPPORTS(ShortcutKeys, nsIObserver);
16 
17 StaticRefPtr<ShortcutKeys> ShortcutKeys::sInstance;
18 
ShortcutKeys()19 ShortcutKeys::ShortcutKeys()
20     : mBrowserHandlers(nullptr),
21       mEditorHandlers(nullptr),
22       mInputHandlers(nullptr),
23       mTextAreaHandlers(nullptr) {
24   MOZ_ASSERT(!sInstance, "Attempt to instantiate a second ShortcutKeys.");
25   nsContentUtils::RegisterShutdownObserver(this);
26 }
27 
~ShortcutKeys()28 ShortcutKeys::~ShortcutKeys() {
29   delete mBrowserHandlers;
30   delete mEditorHandlers;
31   delete mInputHandlers;
32   delete mTextAreaHandlers;
33 }
34 
Observe(nsISupports * aSubject,const char * aTopic,const char16_t * aData)35 nsresult ShortcutKeys::Observe(nsISupports* aSubject, const char* aTopic,
36                                const char16_t* aData) {
37   // Clear our strong reference so we can clean up.
38   ShortcutKeys::Shutdown();
39   return NS_OK;
40 }
41 
Shutdown()42 void ShortcutKeys::Shutdown() { sInstance = nullptr; }
43 
44 /* static */
GetHandlers(HandlerType aType)45 KeyEventHandler* ShortcutKeys::GetHandlers(HandlerType aType) {
46   if (!sInstance) {
47     sInstance = new ShortcutKeys();
48   }
49 
50   return sInstance->EnsureHandlers(aType);
51 }
52 
53 /* static */
ConvertEventToDOMEventType(const WidgetKeyboardEvent * aWidgetKeyboardEvent)54 nsAtom* ShortcutKeys::ConvertEventToDOMEventType(
55     const WidgetKeyboardEvent* aWidgetKeyboardEvent) {
56   switch (aWidgetKeyboardEvent->mMessage) {
57     case eKeyDown:
58       return nsGkAtoms::keydown;
59     case eKeyUp:
60       return nsGkAtoms::keyup;
61     // eAccessKeyNotFound event is always created from eKeyPress event and
62     // the original eKeyPress event has stopped its propagation before
63     // dispatched into the DOM tree in this process and not matched with remote
64     // content's access keys.  So, we should treat it as an eKeyPress event and
65     // execute a command if it's registered as a shortcut key.
66     case eKeyPress:
67     case eAccessKeyNotFound:
68       return nsGkAtoms::keypress;
69     default:
70       MOZ_ASSERT_UNREACHABLE(
71           "All event messages relating to shortcut keys should be handled");
72       return nullptr;
73   }
74 }
75 
EnsureHandlers(HandlerType aType)76 KeyEventHandler* ShortcutKeys::EnsureHandlers(HandlerType aType) {
77   ShortcutKeyData* keyData;
78   KeyEventHandler** cache;
79 
80   switch (aType) {
81     case HandlerType::eBrowser:
82       keyData = &sBrowserHandlers[0];
83       cache = &mBrowserHandlers;
84       break;
85     case HandlerType::eEditor:
86       keyData = &sEditorHandlers[0];
87       cache = &mEditorHandlers;
88       break;
89     case HandlerType::eInput:
90       keyData = &sInputHandlers[0];
91       cache = &mInputHandlers;
92       break;
93     case HandlerType::eTextArea:
94       keyData = &sTextAreaHandlers[0];
95       cache = &mTextAreaHandlers;
96       break;
97     default:
98       MOZ_ASSERT(false, "Unknown handler type requested.");
99   }
100 
101   if (*cache) {
102     return *cache;
103   }
104 
105   KeyEventHandler* lastHandler = nullptr;
106   while (keyData->event) {
107     KeyEventHandler* handler = new KeyEventHandler(keyData);
108     if (lastHandler) {
109       lastHandler->SetNextHandler(handler);
110     } else {
111       *cache = handler;
112     }
113     lastHandler = handler;
114     keyData++;
115   }
116 
117   return *cache;
118 }
119 
120 }  // namespace mozilla
121