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 #include "nsISupportsUtils.h"
12 // Msinkaut_i.c and Msinkaut.h should both be included
13 // https://msdn.microsoft.com/en-us/library/windows/desktop/ms695519.aspx
14 #include <msinkaut_i.c>
16 mozilla::StaticAutoPtr
<InkCollector
> InkCollector::sInkCollector
;
18 InkCollector::~InkCollector() {
20 MOZ_ASSERT(!mCookie
&& !mEnabled
&& !mComInitialized
&& !mMarshaller
&&
21 !mInkCollector
&& !mConnectionPoint
&& !mInkCollectorEvent
);
24 void InkCollector::Initialize() {
25 // Possibly, we can use mConnectionPoint for checking,
26 // But if errors exist (perhaps COM object is unavailable),
27 // Initialize() will be called more times.
28 static bool sInkCollectorCreated
= false;
29 if (sInkCollectorCreated
) {
32 sInkCollectorCreated
= true;
34 // COM could get uninitialized due to previous initialization.
35 mComInitialized
= SUCCEEDED(::CoInitialize(nullptr));
37 // Set up instance of InkCollectorEvent.
38 mInkCollectorEvent
= new InkCollectorEvent();
40 // Set up a free threaded marshaler.
41 if (FAILED(::CoCreateFreeThreadedMarshaler(mInkCollectorEvent
,
42 getter_AddRefs(mMarshaller
)))) {
46 // Create the ink collector.
47 if (FAILED(::CoCreateInstance(CLSID_InkCollector
, NULL
, CLSCTX_INPROC_SERVER
,
49 getter_AddRefs(mInkCollector
)))) {
53 // Set up connection between sink and InkCollector.
54 RefPtr
<IConnectionPointContainer
> connPointContainer
;
56 // Get the connection point container.
57 if (SUCCEEDED(mInkCollector
->QueryInterface(
58 IID_IConnectionPointContainer
, getter_AddRefs(connPointContainer
)))) {
59 // Find the connection point for Ink Collector events.
60 if (SUCCEEDED(connPointContainer
->FindConnectionPoint(
61 __uuidof(_IInkCollectorEvents
),
62 getter_AddRefs(mConnectionPoint
)))) {
63 // Hook up sink to connection point.
64 if (SUCCEEDED(mConnectionPoint
->Advise(mInkCollectorEvent
, &mCookie
))) {
71 void InkCollector::Shutdown() {
73 if (mConnectionPoint
) {
74 // Remove the connection of the sink to the Ink Collector.
75 mConnectionPoint
->Unadvise(mCookie
);
77 mConnectionPoint
= nullptr;
79 mInkCollector
= nullptr;
80 mMarshaller
= nullptr;
81 mInkCollectorEvent
= nullptr;
83 // Let uninitialization get handled in a place where it got inited.
84 if (mComInitialized
) {
86 mComInitialized
= false;
90 void InkCollector::OnInitialize() {
91 // Suppress all events to do not allow performance decreasing.
92 // https://msdn.microsoft.com/en-us/library/ms820347.aspx
93 mInkCollector
->SetEventInterest(InkCollectorEventInterest::ICEI_AllEvents
,
96 // Sets a value that indicates whether an object or control has interest in a
98 mInkCollector
->SetEventInterest(
99 InkCollectorEventInterest::ICEI_CursorOutOfRange
, VARIANT_TRUE
);
101 // If the MousePointer property is set to IMP_Custom and the MouseIcon
102 // property is NULL, Then the ink collector no longer handles mouse cursor
104 // https://msdn.microsoft.com/en-us/library/windows/desktop/ms700686.aspx
105 mInkCollector
->put_MouseIcon(nullptr);
106 mInkCollector
->put_MousePointer(InkMousePointer::IMP_Custom
);
108 // This mode allows an ink collector to collect ink from any tablet attached
109 // to the Tablet PC. The Boolean value that indicates whether to use the mouse
110 // as an input device. If TRUE, the mouse is used for input.
111 // https://msdn.microsoft.com/en-us/library/ms820346.aspx
112 mInkCollector
->SetAllTabletsMode(VARIANT_FALSE
);
114 // Sets the value that specifies whether ink is rendered as it is drawn.
115 // VARIANT_TRUE to render ink as it is drawn on the display.
116 // VARIANT_FALSE to not have the ink appear on the display as strokes are
118 // https://msdn.microsoft.com/en-us/library/windows/desktop/dd314598.aspx
119 mInkCollector
->put_DynamicRendering(VARIANT_FALSE
);
121 // Set AutoRedraw to false to prevent repainting the ink when the window is
123 mInkCollector
->put_AutoRedraw(VARIANT_FALSE
);
126 // Sets a value that specifies whether the InkCollector object collects pen
127 // input. This property must be set to FALSE before setting or calling specific
128 // properties and methods of the object.
129 // https://msdn.microsoft.com/en-us/library/windows/desktop/ms701721.aspx
130 void InkCollector::Enable(bool aNewState
) {
131 if (aNewState
!= mEnabled
) {
133 if (SUCCEEDED(mInkCollector
->put_Enabled(aNewState
? VARIANT_TRUE
135 mEnabled
= aNewState
;
137 NS_WARNING("InkCollector did not change status successfully");
140 NS_WARNING("InkCollector should be exist");
145 HWND
InkCollector::GetTarget() { return mTargetWindow
; }
147 void InkCollector::SetTarget(HWND aTargetWindow
) {
148 NS_ASSERTION(aTargetWindow
, "aTargetWindow should be exist");
149 if (aTargetWindow
&& (aTargetWindow
!= mTargetWindow
)) {
153 if (SUCCEEDED(mInkCollector
->put_hWnd((LONG_PTR
)aTargetWindow
))) {
154 mTargetWindow
= aTargetWindow
;
156 NS_WARNING("InkCollector did not change window property successfully");
163 void InkCollector::ClearTarget() {
164 if (mTargetWindow
&& mInkCollector
) {
166 if (SUCCEEDED(mInkCollector
->put_hWnd(0))) {
169 NS_WARNING("InkCollector did not clear window property successfully");
174 uint16_t InkCollector::GetPointerId() { return mPointerId
; }
176 void InkCollector::SetPointerId(uint16_t aPointerId
) {
177 mPointerId
= aPointerId
;
180 void InkCollector::ClearPointerId() { mPointerId
= 0; }
182 // The display and the digitizer have quite different properties.
183 // The display has CursorMustTouch, the mouse pointer alway touches the display
184 // surface. The digitizer lists Integrated and HardProximity. When the stylus is
185 // in the proximity of the tablet its movements are also detected. An external
186 // tablet will only list HardProximity.
187 bool InkCollectorEvent::IsHardProximityTablet(IInkTablet
* aTablet
) const {
189 TabletHardwareCapabilities caps
;
190 if (SUCCEEDED(aTablet
->get_HardwareCapabilities(&caps
))) {
191 return (TabletHardwareCapabilities::THWC_HardProximity
& caps
);
197 HRESULT __stdcall
InkCollectorEvent::QueryInterface(REFIID aRiid
,
199 // Validate the input
203 HRESULT result
= E_NOINTERFACE
;
204 // This object supports IUnknown/IDispatch/IInkCollectorEvents
205 if ((IID_IUnknown
== aRiid
) || (IID_IDispatch
== aRiid
) ||
206 (DIID__IInkCollectorEvents
== aRiid
)) {
208 // AddRef should be called when we give info about interface
215 HRESULT
InkCollectorEvent::Invoke(DISPID aDispIdMember
, REFIID
/*aRiid*/,
216 LCID
/*aId*/, WORD
/*wFlags*/,
217 DISPPARAMS
* aDispParams
,
218 VARIANT
* /*aVarResult*/,
219 EXCEPINFO
* /*aExcepInfo*/,
221 switch (aDispIdMember
) {
222 case DISPID_ICECursorOutOfRange
: {
223 if (aDispParams
&& aDispParams
->cArgs
) {
225 static_cast<IInkCursor
*>(aDispParams
->rgvarg
[0].pdispVal
));
233 void InkCollectorEvent::CursorOutOfRange(IInkCursor
* aCursor
) const {
234 IInkTablet
* curTablet
= nullptr;
235 if (FAILED(aCursor
->get_Tablet(&curTablet
))) {
238 // All events should be suppressed except
239 // from tablets with hard proximity.
240 if (!IsHardProximityTablet(curTablet
)) {
243 // Notify current target window.
244 if (HWND targetWindow
= InkCollector::sInkCollector
->GetTarget()) {
245 ::SendMessage(targetWindow
, MOZ_WM_PEN_LEAVES_HOVER_OF_DIGITIZER
, 0, 0);