1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=2 sw=2 et tw=78:
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/.
8 #include "InkCollector.h"
10 // Msinkaut_i.c and Msinkaut.h should both be included
11 // https://msdn.microsoft.com/en-us/library/windows/desktop/ms695519.aspx
12 #include <msinkaut_i.c>
14 StaticAutoPtr
<InkCollector
> InkCollector::sInkCollector
;
16 InkCollector::~InkCollector() {
18 MOZ_ASSERT(!mCookie
&& !mEnabled
&& !mComInitialized
&& !mMarshaller
&&
19 !mInkCollector
&& !mConnectionPoint
&& !mInkCollectorEvent
);
22 void InkCollector::Initialize() {
23 // Possibly, we can use mConnectionPoint for checking,
24 // But if errors exist (perhaps COM object is unavailable),
25 // Initialize() will be called more times.
26 static bool sInkCollectorCreated
= false;
27 if (sInkCollectorCreated
) {
30 sInkCollectorCreated
= true;
32 // COM could get uninitialized due to previous initialization.
33 mComInitialized
= SUCCEEDED(::CoInitialize(nullptr));
35 // Set up instance of InkCollectorEvent.
36 mInkCollectorEvent
= new InkCollectorEvent();
38 // Set up a free threaded marshaler.
39 if (FAILED(::CoCreateFreeThreadedMarshaler(mInkCollectorEvent
,
40 getter_AddRefs(mMarshaller
)))) {
44 // Create the ink collector.
45 if (FAILED(::CoCreateInstance(CLSID_InkCollector
, NULL
, CLSCTX_INPROC_SERVER
,
47 getter_AddRefs(mInkCollector
)))) {
51 // Set up connection between sink and InkCollector.
52 RefPtr
<IConnectionPointContainer
> connPointContainer
;
54 // Get the connection point container.
55 if (SUCCEEDED(mInkCollector
->QueryInterface(
56 IID_IConnectionPointContainer
, getter_AddRefs(connPointContainer
)))) {
57 // Find the connection point for Ink Collector events.
58 if (SUCCEEDED(connPointContainer
->FindConnectionPoint(
59 __uuidof(_IInkCollectorEvents
),
60 getter_AddRefs(mConnectionPoint
)))) {
61 // Hook up sink to connection point.
62 if (SUCCEEDED(mConnectionPoint
->Advise(mInkCollectorEvent
, &mCookie
))) {
69 void InkCollector::Shutdown() {
71 if (mConnectionPoint
) {
72 // Remove the connection of the sink to the Ink Collector.
73 mConnectionPoint
->Unadvise(mCookie
);
75 mConnectionPoint
= nullptr;
77 mInkCollector
= nullptr;
78 mMarshaller
= nullptr;
79 mInkCollectorEvent
= nullptr;
81 // Let uninitialization get handled in a place where it got inited.
82 if (mComInitialized
) {
84 mComInitialized
= false;
88 void InkCollector::OnInitialize() {
89 // Suppress all events to do not allow performance decreasing.
90 // https://msdn.microsoft.com/en-us/library/ms820347.aspx
91 mInkCollector
->SetEventInterest(InkCollectorEventInterest::ICEI_AllEvents
,
94 // Sets a value that indicates whether an object or control has interest in a
96 mInkCollector
->SetEventInterest(
97 InkCollectorEventInterest::ICEI_CursorOutOfRange
, VARIANT_TRUE
);
99 // If the MousePointer property is set to IMP_Custom and the MouseIcon
100 // property is NULL, Then the ink collector no longer handles mouse cursor
102 // https://msdn.microsoft.com/en-us/library/windows/desktop/ms700686.aspx
103 mInkCollector
->put_MouseIcon(nullptr);
104 mInkCollector
->put_MousePointer(InkMousePointer::IMP_Custom
);
106 // This mode allows an ink collector to collect ink from any tablet attached
107 // to the Tablet PC. The Boolean value that indicates whether to use the mouse
108 // as an input device. If TRUE, the mouse is used for input.
109 // https://msdn.microsoft.com/en-us/library/ms820346.aspx
110 mInkCollector
->SetAllTabletsMode(VARIANT_FALSE
);
112 // Sets the value that specifies whether ink is rendered as it is drawn.
113 // VARIANT_TRUE to render ink as it is drawn on the display.
114 // VARIANT_FALSE to not have the ink appear on the display as strokes are
116 // https://msdn.microsoft.com/en-us/library/windows/desktop/dd314598.aspx
117 mInkCollector
->put_DynamicRendering(VARIANT_FALSE
);
119 // Set AutoRedraw to false to prevent repainting the ink when the window is
121 mInkCollector
->put_AutoRedraw(VARIANT_FALSE
);
124 // Sets a value that specifies whether the InkCollector object collects pen
125 // input. This property must be set to FALSE before setting or calling specific
126 // properties and methods of the object.
127 // https://msdn.microsoft.com/en-us/library/windows/desktop/ms701721.aspx
128 void InkCollector::Enable(bool aNewState
) {
129 if (aNewState
!= mEnabled
) {
131 if (SUCCEEDED(mInkCollector
->put_Enabled(aNewState
? VARIANT_TRUE
133 mEnabled
= aNewState
;
135 NS_WARNING("InkCollector did not change status successfully");
138 NS_WARNING("InkCollector should be exist");
143 HWND
InkCollector::GetTarget() { return mTargetWindow
; }
145 void InkCollector::SetTarget(HWND aTargetWindow
) {
146 NS_ASSERTION(aTargetWindow
, "aTargetWindow should be exist");
147 if (aTargetWindow
&& (aTargetWindow
!= mTargetWindow
)) {
151 if (SUCCEEDED(mInkCollector
->put_hWnd((LONG_PTR
)aTargetWindow
))) {
152 mTargetWindow
= aTargetWindow
;
154 NS_WARNING("InkCollector did not change window property successfully");
161 void InkCollector::ClearTarget() {
162 if (mTargetWindow
&& mInkCollector
) {
164 if (SUCCEEDED(mInkCollector
->put_hWnd(0))) {
167 NS_WARNING("InkCollector did not clear window property successfully");
172 uint16_t InkCollector::GetPointerId() { return mPointerId
; }
174 void InkCollector::SetPointerId(uint16_t aPointerId
) {
175 mPointerId
= aPointerId
;
178 void InkCollector::ClearPointerId() { mPointerId
= 0; }
180 // The display and the digitizer have quite different properties.
181 // The display has CursorMustTouch, the mouse pointer alway touches the display
182 // surface. The digitizer lists Integrated and HardProximity. When the stylus is
183 // in the proximity of the tablet its movements are also detected. An external
184 // tablet will only list HardProximity.
185 bool InkCollectorEvent::IsHardProximityTablet(IInkTablet
* aTablet
) const {
187 TabletHardwareCapabilities caps
;
188 if (SUCCEEDED(aTablet
->get_HardwareCapabilities(&caps
))) {
189 return (TabletHardwareCapabilities::THWC_HardProximity
& caps
);
195 HRESULT __stdcall
InkCollectorEvent::QueryInterface(REFIID aRiid
,
197 // Validate the input
201 HRESULT result
= E_NOINTERFACE
;
202 // This object supports IUnknown/IDispatch/IInkCollectorEvents
203 if ((IID_IUnknown
== aRiid
) || (IID_IDispatch
== aRiid
) ||
204 (DIID__IInkCollectorEvents
== aRiid
)) {
206 // AddRef should be called when we give info about interface
213 HRESULT
InkCollectorEvent::Invoke(DISPID aDispIdMember
, REFIID
/*aRiid*/,
214 LCID
/*aId*/, WORD
/*wFlags*/,
215 DISPPARAMS
* aDispParams
,
216 VARIANT
* /*aVarResult*/,
217 EXCEPINFO
* /*aExcepInfo*/,
219 switch (aDispIdMember
) {
220 case DISPID_ICECursorOutOfRange
: {
221 if (aDispParams
&& aDispParams
->cArgs
) {
223 static_cast<IInkCursor
*>(aDispParams
->rgvarg
[0].pdispVal
));
231 void InkCollectorEvent::CursorOutOfRange(IInkCursor
* aCursor
) const {
232 IInkTablet
* curTablet
= nullptr;
233 if (FAILED(aCursor
->get_Tablet(&curTablet
))) {
236 // All events should be suppressed except
237 // from tablets with hard proximity.
238 if (!IsHardProximityTablet(curTablet
)) {
241 // Notify current target window.
242 if (HWND targetWindow
= InkCollector::sInkCollector
->GetTarget()) {
243 ::SendMessage(targetWindow
, MOZ_WM_PEN_LEAVES_HOVER_OF_DIGITIZER
, 0, 0);