Skip to content
Permalink
Browse files

controller: added vibration support

  • Loading branch information
JaCzekanski committed Sep 5, 2019
1 parent 22a451f commit bd640f2c9e7446c602af9e92356a04adc865c0aa
@@ -13,6 +13,8 @@ See [Avocado compatibility list](https://avocado-db.czekanski.info)

## Changelog

*5.09.2019* - Vibration support

*2.09.2019* - Anti-Modchip and LibCrypt protected games support

*13.03.2019* - merged MDEC (video decoder) support
@@ -246,6 +246,7 @@ project "avocado"
"stdc++fs", -- for experimental/filesystem
"glad",
"imgui",
"pthread",
}
buildoptions {getOutput("sdl2-config --cflags")}
linkoptions {getOutput("sdl2-config --libs")}
@@ -98,12 +98,25 @@ uint8_t AnalogController::handleReadAnalog(uint8_t byte) {
(void)byte;
switch (state) {
case 2: state++; return 0x5a;
case 3: state++; return ~buttons._byte[0];
case 4: state++; return ~buttons._byte[1];
case 3:
state++;
vibration.small = byte != 0;
return ~buttons._byte[0];
case 4:
state++;
vibration.big = byte;
return ~buttons._byte[1];
case 5: state++; return right.x;
case 6: state++; return right.y;
case 7: state++; return left.x;
case 8: state = 0; return left.y;
case 8:
state = 0;
// Do not send vibration events on continuous 0 values
if (vibration != prevVibration || vibration != 0) {
bus.notify(Event::Controller::Vibration{port, vibration.small, vibration.big});
}
prevVibration = vibration;
return left.y;

default: return 0xff;
}
@@ -28,6 +28,17 @@ struct AnalogController : public DigitalController {
Stick() : x(0x80), y(0x80) {}
};

struct Vibration {
// Small vibration motor is on/off
// Big has 256 values of vibration strength
bool small = false;
uint8_t big = 0;

bool operator==(const Vibration& r) { return small == r.small && big == r.big; }
bool operator!=(const Vibration& r) { return !(*this == r); }
bool operator!=(const int r) { return small != r || small != r; }
};

uint8_t _handle(uint8_t byte); // Wrapper for handler for catching return value
uint8_t handleReadAnalog(uint8_t byte);
uint8_t handleEnterConfiguration(uint8_t byte);
@@ -44,6 +55,7 @@ struct AnalogController : public DigitalController {
bool analogEnabled = false;
bool ledEnabled = false;
bool configurationMode = false;
Vibration prevVibration, vibration;

public:
AnalogController(int Port);
@@ -113,7 +113,7 @@ void openFile() {
ImGui::NextColumn();

if (!fs::is_directory(f)) {
std::string fileSize = formatFileSize(f.file_size());
std::string fileSize = formatFileSize(fs::file_size(f));

ImVec2 size = ImGui::CalcTextSize(fileSize.c_str());
size.x += 8;
@@ -2,6 +2,54 @@
#include "utils/math.h"
#include "utils/string.h"

SdlInputManager::SdlInputManager() {
vibrationThread = std::thread(&SdlInputManager::vibrationThreadFunc, this);
busToken = bus.listen<Event::Controller::Vibration>(std::bind(&SdlInputManager::onVibrationEvent, this, std::placeholders::_1));
}

SdlInputManager::~SdlInputManager() {
bus.unlistenAll(busToken);

// Notify vibrationThread to stop execution
{
std::unique_lock<std::mutex> lk(vibrationMutex);
vibrationThreadExit = true;
vibrationHasNewData.notify_one();
}
vibrationThread.join();
}

void SdlInputManager::vibrationThreadFunc() {
while (true) {
std::unique_lock<std::mutex> lk(vibrationMutex);
vibrationHasNewData.wait(lk);

if (vibrationThreadExit) {
break;
}
// TODO: Current solution might cut out vibration from different controllers
// Buffer them and send all in bulk at the end of the frame ?
SDL_GameControllerRumble(vibrationData.controller, vibrationData.e.big * 0xff, vibrationData.e.small * 0xffff, 16);
}
}

void SdlInputManager::onVibrationEvent(Event::Controller::Vibration e) {
// Vibration output is choosen by DPAD_UP mapped game controller
std::string keyName = config["controller"][std::to_string(e.port)]["keys"]["dpad_up"];
Key key(keyName);

if (key.type != Key::Type::ControllerMove && key.type != Key::Type::ControllerButton) {
return; // DPAD_UP not mapped to a controller
}

auto controller = controllers[key.controller.id - 1];
if (controller != nullptr) {
std::unique_lock<std::mutex> lk(vibrationMutex);
vibrationData = {controller, e};
vibrationHasNewData.notify_one();
}
}

bool SdlInputManager::handleKey(Key key, AnalogValue value) {
if (waitingForKeyPress) {
waitingForKeyPress = false;
@@ -1,24 +1,46 @@
#pragma once
#include <atomic>
#include <condition_variable>
#include <mutex>
#include <thread>
#include <unordered_map>
#include "config.h"
#include "input/input_manager.h"
#include "key.h"

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

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

// Vibration stuff
struct VibrationData {
SDL_GameController* controller;
Event::Controller::Vibration e;
};

std::atomic<bool> vibrationThreadExit = false;
std::mutex vibrationMutex;
std::condition_variable vibrationHasNewData;
VibrationData vibrationData;
std::thread vibrationThread;

void vibrationThreadFunc();
void onVibrationEvent(Event::Controller::Vibration e);

public:
bool mouseCaptured = false;
bool keyboardCaptured = false;
bool mouseLocked = false;
bool waitingForKeyPress = false;
Key lastPressedKey;

SdlInputManager();
~SdlInputManager();
void newFrame();
bool handleEvent(SDL_Event& event);
};
@@ -30,6 +30,14 @@ struct Toast {
};
struct ToggleFullscreen {};
} // namespace Gui

namespace Controller {
struct Vibration {
int port;
bool small;
uint8_t big;
};
} // namespace Controller
}; // namespace Event

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

0 comments on commit bd640f2

Please sign in to comment.
You can’t perform that action at this time.