diff options
Diffstat (limited to 'dom/inputmethod/HardwareKeyHandler.h')
-rw-r--r-- | dom/inputmethod/HardwareKeyHandler.h | 224 |
1 files changed, 224 insertions, 0 deletions
diff --git a/dom/inputmethod/HardwareKeyHandler.h b/dom/inputmethod/HardwareKeyHandler.h new file mode 100644 index 000000000..7520c40cd --- /dev/null +++ b/dom/inputmethod/HardwareKeyHandler.h @@ -0,0 +1,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_ |