summaryrefslogtreecommitdiffstats
path: root/dom/inputmethod/HardwareKeyHandler.h
blob: 7520c40cd6d11dcc9524740733d2075fab073bd8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef mozilla_HardwareKeyHandler_h_
#define mozilla_HardwareKeyHandler_h_

#include "mozilla/EventForwards.h"          // for nsEventStatus
#include "mozilla/StaticPtr.h"
#include "mozilla/TextEvents.h"
#include "nsCOMPtr.h"
#include "nsDeque.h"
#include "nsIHardwareKeyHandler.h"
#include "nsIWeakReferenceUtils.h"          // for nsWeakPtr

class nsIContent;
class nsINode;
class nsIPresShell;
class nsPIDOMWindowOuter;
class nsPresContext;

namespace mozilla {

// This module will copy the events' data into its event queue for reuse
// after receiving input-method-app's reply, so we use the following struct
// for storing these information.
// RefCounted<T> is a helper class for adding reference counting mechanism.
struct KeyboardInfo : public RefCounted<KeyboardInfo>
{
  MOZ_DECLARE_REFCOUNTED_TYPENAME(KeyboardInfo)

  nsINode* mTarget;
  WidgetKeyboardEvent mEvent;
  nsEventStatus mStatus;

  KeyboardInfo(nsINode* aTarget,
               WidgetKeyboardEvent& aEvent,
               nsEventStatus aStatus)
    : mTarget(aTarget)
    , mEvent(aEvent)
    , mStatus(aStatus)
  {
  }
};

// The following is the type-safe wrapper around nsDeque
// for storing events' data.
// The T must be one class that supports reference counting mechanism.
// The EventQueueDeallocator will be called in nsDeque::~nsDeque() or
// nsDeque::Erase() to deallocate the objects. nsDeque::Erase() will remove
// and delete all items in the queue. See more from nsDeque.h.
template <class T>
class EventQueueDeallocator : public nsDequeFunctor
{
  virtual void* operator() (void* aObject)
  {
    RefPtr<T> releaseMe = dont_AddRef(static_cast<T*>(aObject));
    return nullptr;
  }
};

// The type-safe queue to be used to store the KeyboardInfo data
template <class T>
class EventQueue : private nsDeque
{
public:
  EventQueue()
    : nsDeque(new EventQueueDeallocator<T>())
  {
  };

  ~EventQueue()
  {
    Clear();
  }

  inline size_t GetSize()
  {
    return nsDeque::GetSize();
  }

  bool IsEmpty()
  {
    return !nsDeque::GetSize();
  }

  inline bool Push(T* aItem)
  {
    MOZ_ASSERT(aItem);
    NS_ADDREF(aItem);
    size_t sizeBefore = GetSize();
    nsDeque::Push(aItem);
    if (GetSize() != sizeBefore + 1) {
      NS_RELEASE(aItem);
      return false;
    }
    return true;
  }

  inline already_AddRefed<T> PopFront()
  {
    RefPtr<T> rv = dont_AddRef(static_cast<T*>(nsDeque::PopFront()));
    return rv.forget();
  }

  inline void RemoveFront()
  {
    RefPtr<T> releaseMe = PopFront();
  }

  inline T* PeekFront()
  {
    return static_cast<T*>(nsDeque::PeekFront());
  }

  void Clear()
  {
    while (GetSize() > 0) {
      RemoveFront();
    }
  }
};

class HardwareKeyHandler : public nsIHardwareKeyHandler
{
public:
  HardwareKeyHandler();

  NS_DECL_ISUPPORTS
  NS_DECL_NSIHARDWAREKEYHANDLER

  static already_AddRefed<HardwareKeyHandler> GetInstance();

  virtual bool ForwardKeyToInputMethodApp(nsINode* aTarget,
                                          WidgetKeyboardEvent* aEvent,
                                          nsEventStatus* aEventStatus) override;

private:
  virtual ~HardwareKeyHandler();

  // Return true if the keypress is successfully dispatched.
  // Otherwise, return false.
  bool DispatchKeyPress(nsINode* aTarget,
                        WidgetKeyboardEvent& aEvent,
                        nsEventStatus& aStatus);

  void DispatchAfterKeyEvent(nsINode* aTarget, WidgetKeyboardEvent& aEvent);

  void DispatchToCurrentProcess(nsIPresShell* aPresShell,
                                nsIContent* aTarget,
                                WidgetKeyboardEvent& aEvent,
                                nsEventStatus& aStatus);

  bool DispatchToCrossProcess(nsINode* aTarget, WidgetKeyboardEvent& aEvent);

  // This method will dispatch not only key* event to its event target,
  // no mather it's in the current process or in its child process,
  // but also mozbrowserafterkey* to the corresponding target if it needs.
  // Return true if the key is successfully dispatched.
  // Otherwise, return false.
  bool DispatchToTargetApp(nsINode* aTarget,
                           WidgetKeyboardEvent& aEvent,
                           nsEventStatus& aStatus);

  // This method will be called after dispatching keypress to its target,
  // if the input-method-app doesn't handle the key.
  // In normal dispatching path, EventStateManager::PostHandleKeyboardEvent
  // will be called when event is keypress.
  // However, the ::PostHandleKeyboardEvent mentioned above will be aborted
  // when we try to forward key event to the input-method-app.
  // If the input-method-app consumes the key, then we don't need to do anything
  // because the input-method-app will generate a new key event by itself.
  // On the other hand, if the input-method-app doesn't consume the key,
  // then we need to dispatch the key event by ourselves
  // and call ::PostHandleKeyboardEvent again after the event is forwarded.
  // Note that the EventStateManager::PreHandleEvent is already called before
  // forwarding, so we don't need to call it in this module.
  void PostHandleKeyboardEvent(nsINode* aTarget,
                               WidgetKeyboardEvent& aEvent,
                               nsEventStatus& aStatus);

  void SetDefaultPrevented(WidgetKeyboardEvent& aEvent,
                           uint16_t aDefaultPrevented);

  // Check whether the event is valid to be fired.
  // This method should be called every time before dispatching next event.
  bool CanDispatchEvent(nsINode* aTarget,
                        WidgetKeyboardEvent& aEvent);

  already_AddRefed<nsPIDOMWindowOuter> GetRootWindow(nsINode* aNode);

  already_AddRefed<nsIContent> GetCurrentTarget();

  nsPresContext* GetPresContext(nsINode* aNode);

  already_AddRefed<nsIPresShell> GetPresShell(nsINode* aNode);

  static StaticRefPtr<HardwareKeyHandler> sInstance;

  // The event queue is used to store the forwarded keyboard events.
  // Those stored events will be dispatched if input-method-app doesn't
  // consume them.
  EventQueue<KeyboardInfo> mEventQueue;

  // Hold the pointer to the latest keydown's data
  RefPtr<KeyboardInfo> mLatestKeyDownInfo;

  // input-method-app needs to register a listener by
  // |nsIHardwareKeyHandler.registerListener| to receive
  // the hardware keyboard event, and |nsIHardwareKeyHandler.registerListener|
  // will set an nsIHardwareKeyEventListener to mHardwareKeyEventListener.
  // Then, mHardwareKeyEventListener is used to forward the event
  // to the input-method-app.
  nsWeakPtr mHardwareKeyEventListener;

  // To keep tracking the input-method-app is active or disabled.
  bool mInputMethodAppConnected;
};

} // namespace mozilla

#endif // #ifndef mozilla_HardwareKeyHandler_h_