1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 #include "device/vr/windows_mixed_reality/wrappers/wmr_input_manager.h"
5
6 #include <windows.perception.h>
7 #include <windows.ui.input.spatial.h>
8 #include <wrl.h>
9
10 #include <memory>
11 #include <vector>
12
13 #include "base/callback_list.h"
14 #include "base/logging.h"
15 #include "base/strings/string_util.h"
16 #include "base/win/core_winrt_util.h"
17 #include "base/win/scoped_hstring.h"
18 #include "device/vr/windows_mixed_reality/mixed_reality_statics.h"
19 #include "device/vr/windows_mixed_reality/wrappers/test/mock_wmr_input_manager.h"
20 #include "device/vr/windows_mixed_reality/wrappers/wmr_input_source_state.h"
21
22 using ABI::Windows::Foundation::ITypedEventHandler;
23 using ABI::Windows::Foundation::Collections::IVectorView;
24 using ABI::Windows::Perception::IPerceptionTimestamp;
25 using ABI::Windows::UI::Input::Spatial::ISpatialInteractionManager;
26 using ABI::Windows::UI::Input::Spatial::ISpatialInteractionSourceEventArgs;
27 using ABI::Windows::UI::Input::Spatial::ISpatialInteractionSourceEventArgs2;
28 using ABI::Windows::UI::Input::Spatial::ISpatialInteractionSourceState;
29 using ABI::Windows::UI::Input::Spatial::SpatialInteractionManager;
30 using ABI::Windows::UI::Input::Spatial::SpatialInteractionSourceEventArgs;
31 using ABI::Windows::UI::Input::Spatial::SpatialInteractionSourceState;
32 using Microsoft::WRL::Callback;
33 using Microsoft::WRL::ComPtr;
34
35 using WMRPressKind =
36 ABI::Windows::UI::Input::Spatial::SpatialInteractionPressKind;
37
38 typedef ITypedEventHandler<SpatialInteractionManager*,
39 SpatialInteractionSourceEventArgs*>
40 SpatialInteractionSourceEventHandler;
41
42 namespace device {
WMRInputSourceEventArgsImpl(ComPtr<ISpatialInteractionSourceEventArgs> args)43 WMRInputSourceEventArgsImpl::WMRInputSourceEventArgsImpl(
44 ComPtr<ISpatialInteractionSourceEventArgs> args)
45 : args_(args) {
46 DCHECK(args_);
47 HRESULT hr = args_.As(&args2_);
48 DCHECK(SUCCEEDED(hr));
49 }
50
51 WMRInputSourceEventArgsImpl::~WMRInputSourceEventArgsImpl() = default;
52
PressKind() const53 WMRPressKind WMRInputSourceEventArgsImpl::PressKind() const {
54 WMRPressKind press_kind;
55 HRESULT hr = args2_->get_PressKind(&press_kind);
56 DCHECK(SUCCEEDED(hr));
57 return press_kind;
58 }
59
State() const60 std::unique_ptr<WMRInputSourceState> WMRInputSourceEventArgsImpl::State()
61 const {
62 ComPtr<ISpatialInteractionSourceState> wmr_state;
63 HRESULT hr = args_->get_State(&wmr_state);
64 DCHECK(SUCCEEDED(hr));
65 return std::make_unique<WMRInputSourceStateImpl>(wmr_state);
66 }
67
WMRInputManagerImpl(ComPtr<ISpatialInteractionManager> manager)68 WMRInputManagerImpl::WMRInputManagerImpl(
69 ComPtr<ISpatialInteractionManager> manager)
70 : manager_(manager) {
71 DCHECK(manager_);
72 pressed_token_.value = 0;
73 released_token_.value = 0;
74 SubscribeEvents();
75 }
76
~WMRInputManagerImpl()77 WMRInputManagerImpl::~WMRInputManagerImpl() {
78 UnsubscribeEvents();
79 }
80
81 std::vector<std::unique_ptr<WMRInputSourceState>>
GetDetectedSourcesAtTimestamp(ComPtr<IPerceptionTimestamp> timestamp)82 WMRInputManagerImpl::GetDetectedSourcesAtTimestamp(
83 ComPtr<IPerceptionTimestamp> timestamp) {
84 std::vector<std::unique_ptr<WMRInputSourceState>> input_states;
85 ComPtr<IVectorView<SpatialInteractionSourceState*>> source_states;
86 if (FAILED(manager_->GetDetectedSourcesAtTimestamp(timestamp.Get(),
87 &source_states)))
88 return input_states;
89
90 uint32_t size;
91 HRESULT hr = source_states->get_Size(&size);
92 DCHECK(SUCCEEDED(hr));
93
94 for (uint32_t i = 0; i < size; i++) {
95 ComPtr<ISpatialInteractionSourceState> source_state_wmr;
96 hr = source_states->GetAt(i, &source_state_wmr);
97 DCHECK(SUCCEEDED(hr));
98 input_states.push_back(
99 std::make_unique<WMRInputSourceStateImpl>(source_state_wmr));
100 }
101
102 return input_states;
103 }
104
105 std::unique_ptr<WMRInputManager::InputEventCallbackList::Subscription>
AddPressedCallback(const InputEventCallback & cb)106 WMRInputManagerImpl::AddPressedCallback(const InputEventCallback& cb) {
107 return pressed_callback_list_.Add(cb);
108 }
109
110 std::unique_ptr<WMRInputManager::InputEventCallbackList::Subscription>
AddReleasedCallback(const InputEventCallback & cb)111 WMRInputManagerImpl::AddReleasedCallback(const InputEventCallback& cb) {
112 return released_callback_list_.Add(cb);
113 }
114
OnSourcePressed(ISpatialInteractionManager * sender,ISpatialInteractionSourceEventArgs * raw_args)115 HRESULT WMRInputManagerImpl::OnSourcePressed(
116 ISpatialInteractionManager* sender,
117 ISpatialInteractionSourceEventArgs* raw_args) {
118 ComPtr<ISpatialInteractionSourceEventArgs> wmr_args(raw_args);
119 WMRInputSourceEventArgsImpl args(wmr_args);
120 pressed_callback_list_.Notify(args);
121 return S_OK;
122 }
123
OnSourceReleased(ISpatialInteractionManager * sender,ISpatialInteractionSourceEventArgs * raw_args)124 HRESULT WMRInputManagerImpl::OnSourceReleased(
125 ISpatialInteractionManager* sender,
126 ISpatialInteractionSourceEventArgs* raw_args) {
127 ComPtr<ISpatialInteractionSourceEventArgs> wmr_args(raw_args);
128 WMRInputSourceEventArgsImpl args(wmr_args);
129 released_callback_list_.Notify(args);
130 return S_OK;
131 }
132
SubscribeEvents()133 void WMRInputManagerImpl::SubscribeEvents() {
134 DCHECK(manager_);
135 DCHECK(pressed_token_.value == 0);
136 DCHECK(released_token_.value == 0);
137
138 // The destructor ensures that we're unsubscribed so raw this is fine.
139 auto pressed_callback = Callback<SpatialInteractionSourceEventHandler>(
140 this, &WMRInputManagerImpl::OnSourcePressed);
141 HRESULT hr =
142 manager_->add_SourcePressed(pressed_callback.Get(), &pressed_token_);
143 DCHECK(SUCCEEDED(hr));
144
145 // The destructor ensures that we're unsubscribed so raw this is fine.
146 auto released_callback = Callback<SpatialInteractionSourceEventHandler>(
147 this, &WMRInputManagerImpl::OnSourceReleased);
148 hr = manager_->add_SourceReleased(released_callback.Get(), &released_token_);
149 DCHECK(SUCCEEDED(hr));
150 }
151
UnsubscribeEvents()152 void WMRInputManagerImpl::UnsubscribeEvents() {
153 if (!manager_)
154 return;
155
156 HRESULT hr = S_OK;
157 if (pressed_token_.value != 0) {
158 hr = manager_->remove_SourcePressed(pressed_token_);
159 pressed_token_.value = 0;
160 DCHECK(SUCCEEDED(hr));
161 }
162
163 if (released_token_.value != 0) {
164 hr = manager_->remove_SourceReleased(released_token_);
165 released_token_.value = 0;
166 DCHECK(SUCCEEDED(hr));
167 }
168 }
169
170 } // namespace device
171