forked from chromium/chromium
-
Notifications
You must be signed in to change notification settings - Fork 0
/
gamepad_pad_state_provider.cc
151 lines (124 loc) · 4.9 KB
/
gamepad_pad_state_provider.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "device/gamepad/gamepad_pad_state_provider.h"
#include <cmath>
#include "device/gamepad/gamepad_data_fetcher.h"
#include "device/gamepad/gamepad_provider.h"
#include "device/gamepad/public/cpp/gamepads.h"
namespace device {
namespace {
const float kMinAxisResetValue = 0.1f;
} // namespace
PadState::PadState() = default;
PadState::~PadState() = default;
GamepadPadStateProvider::GamepadPadStateProvider() {
pad_states_.reset(new PadState[Gamepads::kItemsLengthCap]);
for (size_t i = 0; i < Gamepads::kItemsLengthCap; ++i)
ClearPadState(pad_states_.get()[i]);
}
GamepadPadStateProvider::~GamepadPadStateProvider() = default;
PadState* GamepadPadStateProvider::GetPadState(GamepadSource source,
int source_id,
bool new_gamepad_recognized) {
// Check to see if the device already has a reserved slot
PadState* empty_slot = nullptr;
PadState* unrecognized_slot = nullptr;
for (size_t i = 0; i < Gamepads::kItemsLengthCap; ++i) {
PadState& state = pad_states_.get()[i];
if (state.source == source && state.source_id == source_id) {
// Retrieving the pad state marks this gamepad as active.
state.is_active = true;
return &state;
}
if (!empty_slot && state.source == GAMEPAD_SOURCE_NONE)
empty_slot = &state;
if (!state.is_recognized)
unrecognized_slot = &state;
}
if (!empty_slot && unrecognized_slot && new_gamepad_recognized) {
DisconnectUnrecognizedGamepad(unrecognized_slot->source,
unrecognized_slot->source_id);
empty_slot = unrecognized_slot;
}
if (empty_slot) {
empty_slot->source = source;
empty_slot->source_id = source_id;
empty_slot->is_active = true;
empty_slot->is_newly_active = true;
empty_slot->is_initialized = false;
empty_slot->is_recognized = new_gamepad_recognized;
}
return empty_slot;
}
PadState* GamepadPadStateProvider::GetConnectedPadState(uint32_t pad_index) {
if (pad_index >= Gamepads::kItemsLengthCap)
return nullptr;
PadState& pad_state = pad_states_.get()[pad_index];
if (pad_state.source == GAMEPAD_SOURCE_NONE)
return nullptr;
return &pad_state;
}
void GamepadPadStateProvider::ClearPadState(PadState& state) {
memset(&state, 0, sizeof(PadState));
}
void GamepadPadStateProvider::InitializeDataFetcher(
GamepadDataFetcher* fetcher) {
fetcher->InitializeProvider(this);
}
void GamepadPadStateProvider::MapAndSanitizeGamepadData(PadState* pad_state,
Gamepad* pad,
bool sanitize) {
DCHECK(pad_state);
DCHECK(pad);
if (!pad_state->data.connected) {
memset(pad, 0, sizeof(Gamepad));
return;
}
// Copy the current state to the output buffer, using the mapping
// function, if there is one available.
if (pad_state->mapper)
pad_state->mapper(pad_state->data, pad);
else
*pad = pad_state->data;
pad->connected = true;
if (!sanitize)
return;
// About sanitization: Gamepads may report input event if the user is not
// interacting with it, due to hardware problems or environmental ones (pad
// has something heavy leaning against an axis.) This may cause user gestures
// to be detected erroniously, exposing gamepad information when the user had
// no intention of doing so. To avoid this we require that each button or axis
// report being at rest (zero) at least once before exposing its value to the
// Gamepad API. This state is tracked by the axis_mask and button_mask
// bitfields. If the bit for an axis or button is 0 it means the axis has
// never reported being at rest, and the value will be forced to zero.
// We can skip axis sanitation if all available axes have been masked.
uint32_t full_axis_mask = (1 << pad->axes_length) - 1;
if (pad_state->axis_mask != full_axis_mask) {
for (size_t axis = 0; axis < pad->axes_length; ++axis) {
if (!(pad_state->axis_mask & 1 << axis)) {
if (fabs(pad->axes[axis]) < kMinAxisResetValue) {
pad_state->axis_mask |= 1 << axis;
} else {
pad->axes[axis] = 0.0f;
}
}
}
}
// We can skip button sanitation if all available buttons have been masked.
uint32_t full_button_mask = (1 << pad->buttons_length) - 1;
if (pad_state->button_mask != full_button_mask) {
for (size_t button = 0; button < pad->buttons_length; ++button) {
if (!(pad_state->button_mask & 1 << button)) {
if (!pad->buttons[button].pressed) {
pad_state->button_mask |= 1 << button;
} else {
pad->buttons[button].pressed = false;
pad->buttons[button].value = 0.0f;
}
}
}
}
}
} // namespace device