Skip to content

Commit 5a9a84c

Browse files
committed
controller: added vibration support
1 parent 22a451f commit 5a9a84c

File tree

6 files changed

+108
-3
lines changed

6 files changed

+108
-3
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ See [Avocado compatibility list](https://avocado-db.czekanski.info)
1313

1414
## Changelog
1515

16+
*5.09.2019* - Vibration support
17+
1618
*2.09.2019* - Anti-Modchip and LibCrypt protected games support
1719

1820
*13.03.2019* - merged MDEC (video decoder) support

src/device/controller/peripherals/analog_controller.cpp

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,12 +98,25 @@ uint8_t AnalogController::handleReadAnalog(uint8_t byte) {
9898
(void)byte;
9999
switch (state) {
100100
case 2: state++; return 0x5a;
101-
case 3: state++; return ~buttons._byte[0];
102-
case 4: state++; return ~buttons._byte[1];
101+
case 3:
102+
state++;
103+
vibration.small = byte != 0;
104+
return ~buttons._byte[0];
105+
case 4:
106+
state++;
107+
vibration.big = byte;
108+
return ~buttons._byte[1];
103109
case 5: state++; return right.x;
104110
case 6: state++; return right.y;
105111
case 7: state++; return left.x;
106-
case 8: state = 0; return left.y;
112+
case 8:
113+
state = 0;
114+
// Do not send vibration events on continuous 0 values
115+
if (vibration != prevVibration || vibration != 0) {
116+
bus.notify(Event::Controller::Vibration{port, vibration.small, vibration.big});
117+
}
118+
prevVibration = vibration;
119+
return left.y;
107120

108121
default: return 0xff;
109122
}

src/device/controller/peripherals/analog_controller.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,17 @@ struct AnalogController : public DigitalController {
2828
Stick() : x(0x80), y(0x80) {}
2929
};
3030

31+
struct Vibration {
32+
// Small vibration motor is on/off
33+
// Big has 256 values of vibration strength
34+
bool small = false;
35+
uint8_t big = 0;
36+
37+
bool operator==(const Vibration& r) { return small == r.small && big == r.big; }
38+
bool operator!=(const Vibration& r) { return !(*this == r); }
39+
bool operator!=(const int r) { return small != r || small != r; }
40+
};
41+
3142
uint8_t _handle(uint8_t byte); // Wrapper for handler for catching return value
3243
uint8_t handleReadAnalog(uint8_t byte);
3344
uint8_t handleEnterConfiguration(uint8_t byte);
@@ -44,6 +55,7 @@ struct AnalogController : public DigitalController {
4455
bool analogEnabled = false;
4556
bool ledEnabled = false;
4657
bool configurationMode = false;
58+
Vibration prevVibration, vibration;
4759

4860
public:
4961
AnalogController(int Port);

src/platform/windows/input/sdl_input_manager.cpp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,54 @@
22
#include "utils/math.h"
33
#include "utils/string.h"
44

5+
SdlInputManager::SdlInputManager() {
6+
vibrationThread = std::thread(&SdlInputManager::vibrationThreadFunc, this);
7+
busToken = bus.listen<Event::Controller::Vibration>(std::bind(&SdlInputManager::onVibrationEvent, this, std::placeholders::_1));
8+
}
9+
10+
SdlInputManager::~SdlInputManager() {
11+
bus.unlistenAll(busToken);
12+
13+
// Notify vibrationThread to stop execution
14+
{
15+
std::unique_lock<std::mutex> lk(vibrationMutex);
16+
vibrationThreadExit = true;
17+
vibrationHasNewData.notify_one();
18+
}
19+
vibrationThread.join();
20+
}
21+
22+
void SdlInputManager::vibrationThreadFunc() {
23+
while (true) {
24+
std::unique_lock<std::mutex> lk(vibrationMutex);
25+
vibrationHasNewData.wait(lk);
26+
27+
if (vibrationThreadExit) {
28+
break;
29+
}
30+
// TODO: Current solution might cut out vibration from different controllers
31+
// Buffer them and send all in bulk at the end of the frame ?
32+
SDL_GameControllerRumble(vibrationData.controller, vibrationData.e.big * 0xff, vibrationData.e.small * 0xffff, 16);
33+
}
34+
}
35+
36+
void SdlInputManager::onVibrationEvent(Event::Controller::Vibration e) {
37+
// Vibration output is choosen by DPAD_UP mapped game controller
38+
std::string keyName = config["controller"][std::to_string(e.port)]["keys"]["dpad_up"];
39+
Key key(keyName);
40+
41+
if (key.type != Key::Type::ControllerMove && key.type != Key::Type::ControllerButton) {
42+
return; // DPAD_UP not mapped to a controller
43+
}
44+
45+
auto controller = controllers[key.controller.id - 1];
46+
if (controller != nullptr) {
47+
std::unique_lock<std::mutex> lk(vibrationMutex);
48+
vibrationData = {controller, e};
49+
vibrationHasNewData.notify_one();
50+
}
51+
}
52+
553
bool SdlInputManager::handleKey(Key key, AnalogValue value) {
654
if (waitingForKeyPress) {
755
waitingForKeyPress = false;
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,46 @@
11
#pragma once
2+
#include <atomic>
3+
#include <condition_variable>
4+
#include <mutex>
5+
#include <thread>
26
#include <unordered_map>
37
#include "config.h"
48
#include "input/input_manager.h"
59
#include "key.h"
610

711
class SdlInputManager : public InputManager {
12+
int busToken;
813
std::unordered_map<int, SDL_GameController*> controllers;
914
int32_t mouseX = 0; // Track mouse movement in frame
1015
int32_t mouseY = 0;
1116

1217
bool handleKey(Key key, AnalogValue value);
1318
void fixControllerId(SDL_Event& event);
1419

20+
// Vibration stuff
21+
struct VibrationData {
22+
SDL_GameController* controller;
23+
Event::Controller::Vibration e;
24+
};
25+
26+
std::atomic<bool> vibrationThreadExit = false;
27+
std::mutex vibrationMutex;
28+
std::condition_variable vibrationHasNewData;
29+
VibrationData vibrationData;
30+
std::thread vibrationThread;
31+
32+
void vibrationThreadFunc();
33+
void onVibrationEvent(Event::Controller::Vibration e);
34+
1535
public:
1636
bool mouseCaptured = false;
1737
bool keyboardCaptured = false;
1838
bool mouseLocked = false;
1939
bool waitingForKeyPress = false;
2040
Key lastPressedKey;
2141

42+
SdlInputManager();
43+
~SdlInputManager();
2244
void newFrame();
2345
bool handleEvent(SDL_Event& event);
2446
};

src/utils/event.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,14 @@ struct Toast {
3030
};
3131
struct ToggleFullscreen {};
3232
} // namespace Gui
33+
34+
namespace Controller {
35+
struct Vibration {
36+
int port;
37+
bool small;
38+
uint8_t big;
39+
};
40+
} // namespace Controller
3341
}; // namespace Event
3442

3543
void toast(const std::string& message);

0 commit comments

Comments
 (0)