mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1016232 - Add detection when pen leave hover of digitizer. r=smaug, r=jimm
This commit is contained in:
parent
84f1b7eccf
commit
cf514a707d
223
widget/windows/InkCollector.cpp
Normal file
223
widget/windows/InkCollector.cpp
Normal file
@ -0,0 +1,223 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: set ts=2 sw=2 et tw=78:
|
||||
* 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/.
|
||||
*/
|
||||
|
||||
#include "InkCollector.h"
|
||||
|
||||
// Msinkaut_i.c and Msinkaut.h should both be included
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms695519.aspx
|
||||
#include <msinkaut_i.c>
|
||||
|
||||
StaticRefPtr<InkCollector> InkCollector::sInkCollector;
|
||||
|
||||
InkCollector::InkCollector()
|
||||
{
|
||||
}
|
||||
|
||||
InkCollector::~InkCollector()
|
||||
{
|
||||
Shutdown();
|
||||
MOZ_ASSERT(!mRefCount);
|
||||
}
|
||||
|
||||
void InkCollector::Initialize()
|
||||
{
|
||||
// Possibly, we can use mConnectionPoint for checking,
|
||||
// But if errors exist (perhaps COM object is unavailable),
|
||||
// Initialize() will be called more times.
|
||||
static bool sInkCollectorCreated = false;
|
||||
if (sInkCollectorCreated) {
|
||||
return;
|
||||
}
|
||||
sInkCollectorCreated = true;
|
||||
|
||||
// COM could get uninitialized due to previous initialization.
|
||||
mComInitialized = SUCCEEDED(::CoInitialize(nullptr));
|
||||
|
||||
// Set up a free threaded marshaler.
|
||||
if (FAILED(::CoCreateFreeThreadedMarshaler(this, getter_AddRefs(mMarshaller)))) {
|
||||
return;
|
||||
}
|
||||
// Create the ink collector.
|
||||
if (FAILED(::CoCreateInstance(CLSID_InkCollector, NULL, CLSCTX_INPROC_SERVER,
|
||||
IID_IInkCollector, getter_AddRefs(mInkCollector)))) {
|
||||
return;
|
||||
}
|
||||
NS_ADDREF(mInkCollector);
|
||||
// Set up connection between sink and InkCollector.
|
||||
nsRefPtr<IConnectionPointContainer> connPointContainer;
|
||||
// Get the connection point container.
|
||||
if (SUCCEEDED(mInkCollector->QueryInterface(IID_IConnectionPointContainer,
|
||||
getter_AddRefs(connPointContainer)))) {
|
||||
// Find the connection point for Ink Collector events.
|
||||
if (SUCCEEDED(connPointContainer->FindConnectionPoint(__uuidof(_IInkCollectorEvents),
|
||||
getter_AddRefs(mConnectionPoint)))) {
|
||||
NS_ADDREF(mConnectionPoint);
|
||||
// Hook up sink to connection point.
|
||||
if (SUCCEEDED(mConnectionPoint->Advise(this, &mCookie))) {
|
||||
OnInitialize();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InkCollector::Shutdown()
|
||||
{
|
||||
Enable(false);
|
||||
if (mConnectionPoint) {
|
||||
// Remove the connection of the sink to the Ink Collector.
|
||||
mConnectionPoint->Unadvise(mCookie);
|
||||
NS_RELEASE(mConnectionPoint);
|
||||
}
|
||||
NS_IF_RELEASE(mMarshaller);
|
||||
NS_IF_RELEASE(mInkCollector);
|
||||
|
||||
// Let uninitialization get handled in a place where it got inited.
|
||||
if (mComInitialized) {
|
||||
CoUninitialize();
|
||||
mComInitialized = false;
|
||||
}
|
||||
}
|
||||
|
||||
void InkCollector::OnInitialize()
|
||||
{
|
||||
// Suppress all events to do not allow performance decreasing.
|
||||
// https://msdn.microsoft.com/en-us/library/ms820347.aspx
|
||||
mInkCollector->SetEventInterest(InkCollectorEventInterest::ICEI_AllEvents, VARIANT_FALSE);
|
||||
|
||||
// Sets a value that indicates whether an object or control has interest in a specified event.
|
||||
mInkCollector->SetEventInterest(InkCollectorEventInterest::ICEI_CursorOutOfRange, VARIANT_TRUE);
|
||||
|
||||
// If the MousePointer property is set to IMP_Custom and the MouseIcon property is NULL,
|
||||
// Then the ink collector no longer handles mouse cursor settings.
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms700686.aspx
|
||||
mInkCollector->put_MouseIcon(nullptr);
|
||||
mInkCollector->put_MousePointer(InkMousePointer::IMP_Custom);
|
||||
|
||||
// This mode allows an ink collector to collect ink from any tablet attached to the Tablet PC.
|
||||
// The Boolean value that indicates whether to use the mouse as an input device.
|
||||
// If TRUE, the mouse is used for input.
|
||||
// https://msdn.microsoft.com/en-us/library/ms820346.aspx
|
||||
mInkCollector->SetAllTabletsMode(VARIANT_FALSE);
|
||||
|
||||
// Sets the value that specifies whether ink is rendered as it is drawn.
|
||||
// VARIANT_TRUE to render ink as it is drawn on the display.
|
||||
// VARIANT_FALSE to not have the ink appear on the display as strokes are made.
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/dd314598.aspx
|
||||
mInkCollector->put_DynamicRendering(VARIANT_FALSE);
|
||||
}
|
||||
|
||||
// Sets a value that specifies whether the InkCollector object collects pen input.
|
||||
// This property must be set to FALSE before setting or
|
||||
// calling specific properties and methods of the object.
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms701721.aspx
|
||||
void InkCollector::Enable(bool aNewState)
|
||||
{
|
||||
if (aNewState != mEnabled) {
|
||||
if (mInkCollector) {
|
||||
if (S_OK == mInkCollector->put_Enabled(aNewState ? VARIANT_TRUE : VARIANT_FALSE)) {
|
||||
mEnabled = aNewState;
|
||||
} else {
|
||||
NS_WARNING("InkCollector did not change status successfully");
|
||||
}
|
||||
} else {
|
||||
NS_WARNING("InkCollector should be exist");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InkCollector::SetTarget(HWND aTargetWindow)
|
||||
{
|
||||
NS_ASSERTION(aTargetWindow, "aTargetWindow should be exist");
|
||||
if (aTargetWindow && (aTargetWindow != mTargetWindow)) {
|
||||
Initialize();
|
||||
if (mInkCollector) {
|
||||
Enable(false);
|
||||
if (S_OK == mInkCollector->put_hWnd((LONG_PTR)aTargetWindow)) {
|
||||
mTargetWindow = aTargetWindow;
|
||||
} else {
|
||||
NS_WARNING("InkCollector did not change window property successfully");
|
||||
}
|
||||
Enable(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The display and the digitizer have quite different properties.
|
||||
// The display has CursorMustTouch, the mouse pointer alway touches the display surface.
|
||||
// The digitizer lists Integrated and HardProximity.
|
||||
// When the stylus is in the proximity of the tablet its movements are also detected.
|
||||
// An external tablet will only list HardProximity.
|
||||
bool InkCollector::IsHardProximityTablet(IInkTablet* aTablet) const
|
||||
{
|
||||
if (aTablet) {
|
||||
TabletHardwareCapabilities caps;
|
||||
if (SUCCEEDED(aTablet->get_HardwareCapabilities(&caps))) {
|
||||
return (TabletHardwareCapabilities::THWC_HardProximity & caps);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
HRESULT __stdcall InkCollector::QueryInterface(REFIID aRiid, void **aObject)
|
||||
{
|
||||
// Validate the input
|
||||
if (!aObject) {
|
||||
return E_POINTER;
|
||||
}
|
||||
HRESULT result = E_NOINTERFACE;
|
||||
// This object supports IUnknown/IDispatch/IInkCollectorEvents
|
||||
if ((IID_IUnknown == aRiid) ||
|
||||
(IID_IDispatch == aRiid) ||
|
||||
(DIID__IInkCollectorEvents == aRiid)) {
|
||||
*aObject = this;
|
||||
// AddRef should be called when we give info about interface
|
||||
NS_ADDREF_THIS();
|
||||
result = S_OK;
|
||||
} else if (IID_IMarshal == aRiid) {
|
||||
// Assert that the free threaded marshaller has been initialized.
|
||||
// It is necessary to call Initialize() before invoking this method.
|
||||
NS_ASSERTION(mMarshaller, "Free threaded marshaller is null!");
|
||||
// Use free threaded marshalling.
|
||||
result = mMarshaller->QueryInterface(aRiid, aObject);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
HRESULT InkCollector::Invoke(DISPID aDispIdMember, REFIID /*aRiid*/,
|
||||
LCID /*aId*/, WORD /*wFlags*/,
|
||||
DISPPARAMS* aDispParams, VARIANT* /*aVarResult*/,
|
||||
EXCEPINFO* /*aExcepInfo*/, UINT* /*aArgErr*/)
|
||||
{
|
||||
switch (aDispIdMember) {
|
||||
case DISPID_ICECursorOutOfRange: {
|
||||
if (aDispParams && aDispParams->cArgs) {
|
||||
CursorOutOfRange(static_cast<IInkCursor*>(aDispParams->rgvarg[0].pdispVal));
|
||||
}
|
||||
break;
|
||||
}
|
||||
};
|
||||
// Release should be called after all usage of this method.
|
||||
NS_RELEASE_THIS();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void InkCollector::CursorOutOfRange(IInkCursor* aCursor) const
|
||||
{
|
||||
IInkTablet* curTablet = nullptr;
|
||||
if (FAILED(aCursor->get_Tablet(&curTablet))) {
|
||||
return;
|
||||
}
|
||||
// All events should be suppressed except
|
||||
// from tablets with hard proximity.
|
||||
if (!IsHardProximityTablet(curTablet)) {
|
||||
return;
|
||||
}
|
||||
// Notify current target window.
|
||||
if (mTargetWindow) {
|
||||
::PostMessage(mTargetWindow, MOZ_WM_PEN_LEAVES_HOVER_OF_DIGITIZER, 0, 0);
|
||||
}
|
||||
}
|
71
widget/windows/InkCollector.h
Normal file
71
widget/windows/InkCollector.h
Normal file
@ -0,0 +1,71 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: set ts=2 sw=2 et tw=78:
|
||||
* 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 InkCollector_h__
|
||||
#define InkCollector_h__
|
||||
|
||||
#include <msinkaut.h>
|
||||
#include "StaticPtr.h"
|
||||
|
||||
#define MOZ_WM_PEN_LEAVES_HOVER_OF_DIGITIZER WM_USER + 0x83
|
||||
|
||||
class InkCollector : public _IInkCollectorEvents
|
||||
{
|
||||
public:
|
||||
InkCollector();
|
||||
|
||||
void Shutdown();
|
||||
void SetTarget(HWND aTargetWindow);
|
||||
|
||||
static StaticRefPtr<InkCollector> sInkCollector;
|
||||
friend StaticRefPtr<InkCollector>;
|
||||
|
||||
protected:
|
||||
// IUnknown
|
||||
virtual ULONG STDMETHODCALLTYPE AddRef() { return ++mRefCount; }
|
||||
virtual ULONG STDMETHODCALLTYPE Release()
|
||||
{
|
||||
MOZ_ASSERT(mRefCount);
|
||||
if (!--mRefCount) {
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
return mRefCount;
|
||||
}
|
||||
HRESULT __stdcall QueryInterface(REFIID aRiid, void **aObject);
|
||||
|
||||
// IDispatch
|
||||
STDMETHOD(GetTypeInfoCount)(UINT* aInfo) { return E_NOTIMPL; }
|
||||
STDMETHOD(GetTypeInfo)(UINT aInfo, LCID aId, ITypeInfo** aTInfo) { return E_NOTIMPL; }
|
||||
STDMETHOD(GetIDsOfNames)(REFIID aRiid, LPOLESTR* aStrNames, UINT aNames,
|
||||
LCID aId, DISPID* aDispId) { return E_NOTIMPL; }
|
||||
STDMETHOD(Invoke)(DISPID aDispIdMember, REFIID aRiid,
|
||||
LCID aId, WORD wFlags,
|
||||
DISPPARAMS* aDispParams, VARIANT* aVarResult,
|
||||
EXCEPINFO* aExcepInfo, UINT* aArgErr);
|
||||
|
||||
// InkCollector
|
||||
virtual ~InkCollector();
|
||||
void Initialize();
|
||||
void OnInitialize();
|
||||
void Enable(bool aNewState);
|
||||
void CursorOutOfRange(IInkCursor* aCursor) const;
|
||||
bool IsHardProximityTablet(IInkTablet* aTablet) const;
|
||||
|
||||
private:
|
||||
nsRefPtr<IUnknown> mMarshaller;
|
||||
nsRefPtr<IInkCollector> mInkCollector;
|
||||
nsRefPtr<IConnectionPoint> mConnectionPoint;
|
||||
|
||||
uint32_t mRefCount = 0;
|
||||
DWORD mCookie = 0;
|
||||
HWND mTargetWindow = 0;
|
||||
bool mComInitialized = false;
|
||||
bool mEnabled = false;
|
||||
};
|
||||
|
||||
#endif // nsInkCollector_h_
|
@ -20,6 +20,7 @@ UNIFIED_SOURCES += [
|
||||
'AudioSession.cpp',
|
||||
'GfxInfo.cpp',
|
||||
'IEnumFE.cpp',
|
||||
'InkCollector.cpp',
|
||||
'JumpListItem.cpp',
|
||||
'KeyboardLayout.cpp',
|
||||
'nsAppShell.cpp',
|
||||
|
@ -175,6 +175,8 @@
|
||||
|
||||
#include <d3d11.h>
|
||||
|
||||
#include "InkCollector.h"
|
||||
|
||||
#if !defined(SM_CONVERTIBLESLATEMODE)
|
||||
#define SM_CONVERTIBLESLATEMODE 0x2003
|
||||
#endif
|
||||
@ -395,6 +397,7 @@ nsWindow::nsWindow() : nsWindowBase()
|
||||
// Init theme data
|
||||
nsUXThemeData::UpdateNativeThemeInfo();
|
||||
RedirectedKeyDownMessageManager::Forget();
|
||||
InkCollector::sInkCollector = new InkCollector();
|
||||
|
||||
Preferences::AddBoolVarCache(&gIsPointerEventsEnabled,
|
||||
"dom.w3c_pointer_events.enabled",
|
||||
@ -428,6 +431,8 @@ nsWindow::~nsWindow()
|
||||
|
||||
// Global shutdown
|
||||
if (sInstanceCount == 0) {
|
||||
InkCollector::sInkCollector->Shutdown();
|
||||
InkCollector::sInkCollector = nullptr;
|
||||
IMEHandler::Terminate();
|
||||
NS_IF_RELEASE(sCursorImgContainer);
|
||||
if (sIsOleInitialized) {
|
||||
@ -650,6 +655,7 @@ nsWindow::Create(nsIWidget *aParent,
|
||||
!nsUXThemeData::sTitlebarInfoPopulatedAero)) {
|
||||
nsUXThemeData::UpdateTitlebarInfo(mWnd);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -3774,6 +3780,20 @@ bool nsWindow::DispatchMouseEvent(uint32_t aEventType, WPARAM wParam,
|
||||
return result;
|
||||
}
|
||||
|
||||
// Checking for NS_MOUSE_MOVE prevents a largest waterfall of unused initializations.
|
||||
if (NS_MOUSE_MOVE != aEventType
|
||||
// Since it is unclear whether a user will use the digitizer,
|
||||
// Postpone initialization until first PEN message will be found.
|
||||
&& nsIDOMMouseEvent::MOZ_SOURCE_PEN == aInputSource
|
||||
// Messages should be only at topLevel window.
|
||||
&& nsWindowType::eWindowType_toplevel == mWindowType
|
||||
// Currently this scheme is used only when pointer events is enabled.
|
||||
&& gfxPrefs::PointerEventsEnabled()
|
||||
// NS_MOUSE_EXIT is received, when InkCollector has been already initialized.
|
||||
&& NS_MOUSE_EXIT != aEventType) {
|
||||
InkCollector::sInkCollector->SetTarget(mWnd);
|
||||
}
|
||||
|
||||
switch (aEventType) {
|
||||
case NS_MOUSE_BUTTON_DOWN:
|
||||
CaptureMouse(true);
|
||||
@ -4895,6 +4915,15 @@ nsWindow::ProcessMessage(UINT msg, WPARAM& wParam, LPARAM& lParam,
|
||||
}
|
||||
break;
|
||||
|
||||
case MOZ_WM_PEN_LEAVES_HOVER_OF_DIGITIZER:
|
||||
{
|
||||
LPARAM pos = lParamToClient(::GetMessagePos());
|
||||
DispatchMouseEvent(NS_MOUSE_EXIT, wParam, pos, false,
|
||||
WidgetMouseEvent::eLeftButton,
|
||||
nsIDOMMouseEvent::MOZ_SOURCE_PEN);
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_CONTEXTMENU:
|
||||
{
|
||||
// if the context menu is brought up from the keyboard, |lParam|
|
||||
|
Loading…
Reference in New Issue
Block a user