blob: 838afcc2a768aa25c448911897136472cf14558f (
plain)
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
|
// Copyright 2022 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <string>
#include "Common/Matrix.h"
#include "InputCommon/ControllerEmu/StickGate.h"
#include "InputCommon/ControllerInterface/CoreDevice.h"
namespace ControllerEmu
{
class EmulatedController;
} // namespace ControllerEmu
namespace ciface::MappingCommon
{
enum class Quote
{
On,
Off
};
std::string GetExpressionForControl(const std::string& control_name,
const Core::DeviceQualifier& control_device,
const Core::DeviceQualifier& default_device,
Quote quote = Quote::On);
std::string BuildExpression(const Core::InputDetector::Results&,
const Core::DeviceQualifier& default_device, Quote quote);
void RemoveSpuriousTriggerCombinations(Core::InputDetector::Results*);
void RemoveDetectionsAfterTimePoint(Core::InputDetector::Results*, Clock::time_point after);
bool ContainsCompleteDetection(const Core::InputDetector::Results&);
// class for detecting four directional input mappings in sequence.
class ReshapableInputMapper
{
public:
// Four cardinal directions.
static constexpr std::size_t REQUIRED_INPUT_COUNT = 4;
// Caller should hold the "StateLock".
ReshapableInputMapper(const Core::DeviceContainer& container,
std::span<const std::string> device_strings);
// Reads inputs and updates internal state.
// Returns true if an input was detected in this call.
// (useful for UI animation)
// Caller should hold the "StateLock".
bool Update();
// A counter-clockwise angle in radians for the currently desired input direction.
// Used for a graphical indicator in the UI.
// 0 == East
float GetCurrentAngle() const;
// True if all four directions have been detected or the timer expired.
bool IsComplete() const;
// Returns true if "analog" inputs were detected and calibration should be performed.
// Must use *before* ApplyResults.
bool IsCalibrationNeeded() const;
// Use when IsComplete returns true.
// Updates the mappings on the provided ReshapableInput.
// Caller should hold the "StateLock".
bool ApplyResults(ControllerEmu::EmulatedController*, ControllerEmu::ReshapableInput* stick);
private:
Core::InputDetector m_input_detector;
};
class CalibrationBuilder
{
public:
// Provide nullopt if you want to calibrate the center on first Update.
explicit CalibrationBuilder(std::optional<Common::DVec2> center = Common::DVec2{});
// Updates the calibration data using the provided point and the previous point.
void Update(Common::DVec2 point);
// Returns true when the calibration data seems to be reasonably filled in.
// Used to update the UI to encourage the user to click the "Finish" button.
bool IsCalibrationDataSensible() const;
// Returns true when the calibration data seems sensible,
// and the input then approaches the center position.
bool IsComplete() const;
// Grabs the calibration value at the provided angle.
// Used to render the calibration in the UI while it's in progress.
ControlState GetCalibrationRadiusAtAngle(double angle) const;
// Sets the calibration data of the provided ReshapableInput.
// Caller should hold the "StateLock".
void ApplyResults(ControllerEmu::ReshapableInput* stick);
Common::DVec2 GetCenter() const;
private:
ControllerEmu::ReshapableInput::CalibrationData m_calibration_data;
std::optional<Common::DVec2> m_center = std::nullopt;
Common::DVec2 m_prev_point{};
};
} // namespace ciface::MappingCommon
|