diff options
Diffstat (limited to 'src/input_common/sdl/sdl.cpp')
| -rw-r--r-- | src/input_common/sdl/sdl.cpp | 183 |
1 files changed, 182 insertions, 1 deletions
diff --git a/src/input_common/sdl/sdl.cpp b/src/input_common/sdl/sdl.cpp index d404afa89..88b557c5d 100644 --- a/src/input_common/sdl/sdl.cpp +++ b/src/input_common/sdl/sdl.cpp | |||
| @@ -3,13 +3,15 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <cmath> | 5 | #include <cmath> |
| 6 | #include <memory> | ||
| 7 | #include <string> | 6 | #include <string> |
| 8 | #include <tuple> | 7 | #include <tuple> |
| 9 | #include <unordered_map> | 8 | #include <unordered_map> |
| 9 | #include <utility> | ||
| 10 | #include <SDL.h> | 10 | #include <SDL.h> |
| 11 | #include "common/logging/log.h" | 11 | #include "common/logging/log.h" |
| 12 | #include "common/math_util.h" | 12 | #include "common/math_util.h" |
| 13 | #include "common/param_package.h" | ||
| 14 | #include "input_common/main.h" | ||
| 13 | #include "input_common/sdl/sdl.h" | 15 | #include "input_common/sdl/sdl.h" |
| 14 | 16 | ||
| 15 | namespace InputCommon { | 17 | namespace InputCommon { |
| @@ -69,6 +71,10 @@ public: | |||
| 69 | return (SDL_JoystickGetHat(joystick.get(), hat) & direction) != 0; | 71 | return (SDL_JoystickGetHat(joystick.get(), hat) & direction) != 0; |
| 70 | } | 72 | } |
| 71 | 73 | ||
| 74 | SDL_JoystickID GetJoystickID() const { | ||
| 75 | return SDL_JoystickInstanceID(joystick.get()); | ||
| 76 | } | ||
| 77 | |||
| 72 | private: | 78 | private: |
| 73 | std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)> joystick; | 79 | std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)> joystick; |
| 74 | }; | 80 | }; |
| @@ -247,5 +253,180 @@ void Shutdown() { | |||
| 247 | } | 253 | } |
| 248 | } | 254 | } |
| 249 | 255 | ||
| 256 | /** | ||
| 257 | * This function converts a joystick ID used in SDL events to the device index. This is necessary | ||
| 258 | * because Citra opens joysticks using their indices, not their IDs. | ||
| 259 | */ | ||
| 260 | static int JoystickIDToDeviceIndex(SDL_JoystickID id) { | ||
| 261 | int num_joysticks = SDL_NumJoysticks(); | ||
| 262 | for (int i = 0; i < num_joysticks; i++) { | ||
| 263 | auto joystick = GetJoystick(i); | ||
| 264 | if (joystick->GetJoystickID() == id) { | ||
| 265 | return i; | ||
| 266 | } | ||
| 267 | } | ||
| 268 | return -1; | ||
| 269 | } | ||
| 270 | |||
| 271 | Common::ParamPackage SDLEventToButtonParamPackage(const SDL_Event& event) { | ||
| 272 | Common::ParamPackage params({{"engine", "sdl"}}); | ||
| 273 | switch (event.type) { | ||
| 274 | case SDL_JOYAXISMOTION: | ||
| 275 | params.Set("joystick", JoystickIDToDeviceIndex(event.jaxis.which)); | ||
| 276 | params.Set("axis", event.jaxis.axis); | ||
| 277 | if (event.jaxis.value > 0) { | ||
| 278 | params.Set("direction", "+"); | ||
| 279 | params.Set("threshold", "0.5"); | ||
| 280 | } else { | ||
| 281 | params.Set("direction", "-"); | ||
| 282 | params.Set("threshold", "-0.5"); | ||
| 283 | } | ||
| 284 | break; | ||
| 285 | case SDL_JOYBUTTONUP: | ||
| 286 | params.Set("joystick", JoystickIDToDeviceIndex(event.jbutton.which)); | ||
| 287 | params.Set("button", event.jbutton.button); | ||
| 288 | break; | ||
| 289 | case SDL_JOYHATMOTION: | ||
| 290 | params.Set("joystick", JoystickIDToDeviceIndex(event.jhat.which)); | ||
| 291 | params.Set("hat", event.jhat.hat); | ||
| 292 | switch (event.jhat.value) { | ||
| 293 | case SDL_HAT_UP: | ||
| 294 | params.Set("direction", "up"); | ||
| 295 | break; | ||
| 296 | case SDL_HAT_DOWN: | ||
| 297 | params.Set("direction", "down"); | ||
| 298 | break; | ||
| 299 | case SDL_HAT_LEFT: | ||
| 300 | params.Set("direction", "left"); | ||
| 301 | break; | ||
| 302 | case SDL_HAT_RIGHT: | ||
| 303 | params.Set("direction", "right"); | ||
| 304 | break; | ||
| 305 | default: | ||
| 306 | return {}; | ||
| 307 | } | ||
| 308 | break; | ||
| 309 | } | ||
| 310 | return params; | ||
| 311 | } | ||
| 312 | |||
| 313 | namespace Polling { | ||
| 314 | |||
| 315 | class SDLPoller : public InputCommon::Polling::DevicePoller { | ||
| 316 | public: | ||
| 317 | SDLPoller() = default; | ||
| 318 | |||
| 319 | ~SDLPoller() = default; | ||
| 320 | |||
| 321 | void Start() override { | ||
| 322 | // SDL joysticks must be opened, otherwise they don't generate events | ||
| 323 | SDL_JoystickUpdate(); | ||
| 324 | int num_joysticks = SDL_NumJoysticks(); | ||
| 325 | for (int i = 0; i < num_joysticks; i++) { | ||
| 326 | joysticks_opened.emplace_back(GetJoystick(i)); | ||
| 327 | } | ||
| 328 | // Empty event queue to get rid of old events. citra-qt doesn't use the queue | ||
| 329 | SDL_Event dummy; | ||
| 330 | while (SDL_PollEvent(&dummy)) { | ||
| 331 | } | ||
| 332 | } | ||
| 333 | |||
| 334 | void Stop() override { | ||
| 335 | joysticks_opened.clear(); | ||
| 336 | } | ||
| 337 | |||
| 338 | private: | ||
| 339 | std::vector<std::shared_ptr<SDLJoystick>> joysticks_opened; | ||
| 340 | }; | ||
| 341 | |||
| 342 | class SDLButtonPoller final : public SDLPoller { | ||
| 343 | public: | ||
| 344 | SDLButtonPoller() = default; | ||
| 345 | |||
| 346 | ~SDLButtonPoller() = default; | ||
| 347 | |||
| 348 | Common::ParamPackage GetNextInput() override { | ||
| 349 | SDL_Event event; | ||
| 350 | while (SDL_PollEvent(&event)) { | ||
| 351 | switch (event.type) { | ||
| 352 | case SDL_JOYAXISMOTION: | ||
| 353 | if (std::abs(event.jaxis.value / 32767.0) < 0.5) { | ||
| 354 | break; | ||
| 355 | } | ||
| 356 | case SDL_JOYBUTTONUP: | ||
| 357 | case SDL_JOYHATMOTION: | ||
| 358 | return SDLEventToButtonParamPackage(event); | ||
| 359 | } | ||
| 360 | } | ||
| 361 | return {}; | ||
| 362 | } | ||
| 363 | }; | ||
| 364 | |||
| 365 | class SDLAnalogPoller final : public SDLPoller { | ||
| 366 | public: | ||
| 367 | SDLAnalogPoller() = default; | ||
| 368 | |||
| 369 | ~SDLAnalogPoller() = default; | ||
| 370 | |||
| 371 | void Start() override { | ||
| 372 | SDLPoller::Start(); | ||
| 373 | |||
| 374 | // Reset stored axes | ||
| 375 | analog_xaxis = -1; | ||
| 376 | analog_yaxis = -1; | ||
| 377 | analog_axes_joystick = -1; | ||
| 378 | } | ||
| 379 | |||
| 380 | Common::ParamPackage GetNextInput() override { | ||
| 381 | SDL_Event event; | ||
| 382 | while (SDL_PollEvent(&event)) { | ||
| 383 | if (event.type != SDL_JOYAXISMOTION || std::abs(event.jaxis.value / 32767.0) < 0.5) { | ||
| 384 | continue; | ||
| 385 | } | ||
| 386 | // An analog device needs two axes, so we need to store the axis for later and wait for | ||
| 387 | // a second SDL event. The axes also must be from the same joystick. | ||
| 388 | int axis = event.jaxis.axis; | ||
| 389 | if (analog_xaxis == -1) { | ||
| 390 | analog_xaxis = axis; | ||
| 391 | analog_axes_joystick = event.jaxis.which; | ||
| 392 | } else if (analog_yaxis == -1 && analog_xaxis != axis && | ||
| 393 | analog_axes_joystick == event.jaxis.which) { | ||
| 394 | analog_yaxis = axis; | ||
| 395 | } | ||
| 396 | } | ||
| 397 | Common::ParamPackage params; | ||
| 398 | if (analog_xaxis != -1 && analog_yaxis != -1) { | ||
| 399 | params.Set("engine", "sdl"); | ||
| 400 | params.Set("joystick", JoystickIDToDeviceIndex(analog_axes_joystick)); | ||
| 401 | params.Set("axis_x", analog_xaxis); | ||
| 402 | params.Set("axis_y", analog_yaxis); | ||
| 403 | analog_xaxis = -1; | ||
| 404 | analog_yaxis = -1; | ||
| 405 | analog_axes_joystick = -1; | ||
| 406 | return params; | ||
| 407 | } | ||
| 408 | return params; | ||
| 409 | } | ||
| 410 | |||
| 411 | private: | ||
| 412 | int analog_xaxis = -1; | ||
| 413 | int analog_yaxis = -1; | ||
| 414 | SDL_JoystickID analog_axes_joystick = -1; | ||
| 415 | }; | ||
| 416 | |||
| 417 | std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> GetPollers( | ||
| 418 | InputCommon::Polling::DeviceType type) { | ||
| 419 | std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> pollers; | ||
| 420 | switch (type) { | ||
| 421 | case InputCommon::Polling::DeviceType::Analog: | ||
| 422 | pollers.push_back(std::make_unique<SDLAnalogPoller>()); | ||
| 423 | break; | ||
| 424 | case InputCommon::Polling::DeviceType::Button: | ||
| 425 | pollers.push_back(std::make_unique<SDLButtonPoller>()); | ||
| 426 | break; | ||
| 427 | } | ||
| 428 | return std::move(pollers); | ||
| 429 | } | ||
| 430 | } // namespace Polling | ||
| 250 | } // namespace SDL | 431 | } // namespace SDL |
| 251 | } // namespace InputCommon | 432 | } // namespace InputCommon |