[HID] Honor `is_active()` in SDL input backend.

This commit is contained in:
Joel Linn 2020-11-28 15:46:25 +01:00 committed by Rick Gibbed
parent 7931dbe180
commit ff56fbdf46
2 changed files with 32 additions and 8 deletions

View File

@ -193,7 +193,11 @@ X_RESULT SDLInputDriver::GetState(uint32_t user_index,
return X_ERROR_BAD_ARGUMENTS; return X_ERROR_BAD_ARGUMENTS;
} }
QueueControllerUpdate(); auto is_active = this->is_active();
if (is_active) {
QueueControllerUpdate();
}
std::unique_lock<std::mutex> guard(controllers_mutex_); std::unique_lock<std::mutex> guard(controllers_mutex_);
@ -203,12 +207,20 @@ X_RESULT SDLInputDriver::GetState(uint32_t user_index,
} }
// Make sure packet_number is only incremented by 1, even if there have been // Make sure packet_number is only incremented by 1, even if there have been
// multiple updates between GetState calls. // multiple updates between GetState calls. Also track `is_active` to
if (controller->state_changed) { // increment the packet number if it changed.
if ((is_active != controller->is_active) ||
(is_active && controller->state_changed)) {
controller->state.packet_number++; controller->state.packet_number++;
controller->is_active = is_active;
controller->state_changed = false; controller->state_changed = false;
} }
*out_state = controller->state; std::memcpy(out_state, &controller->state, sizeof(*out_state));
if (!is_active) {
// Simulate an "untouched" controller. When we become active again the
// pressed buttons aren't lost and will be visible again.
std::memset(&out_state->gamepad, 0, sizeof(out_state->gamepad));
}
return X_ERROR_SUCCESS; return X_ERROR_SUCCESS;
} }
@ -242,6 +254,8 @@ X_RESULT SDLInputDriver::SetState(uint32_t user_index,
X_RESULT SDLInputDriver::GetKeystroke(uint32_t users, uint32_t flags, X_RESULT SDLInputDriver::GetKeystroke(uint32_t users, uint32_t flags,
X_INPUT_KEYSTROKE* out_keystroke) { X_INPUT_KEYSTROKE* out_keystroke) {
// TODO(JoelLinn): Figure out the flags
// https://github.com/evilC/UCR/blob/0489929e2a8e39caa3484c67f3993d3fba39e46f/Libraries/XInput.ahk#L85-L98
assert(sdl_events_initialized_ && sdl_gamecontroller_initialized_); assert(sdl_events_initialized_ && sdl_gamecontroller_initialized_);
bool user_any = users == 0xFF; bool user_any = users == 0xFF;
if (users >= HID_SDL_USER_COUNT && !user_any) { if (users >= HID_SDL_USER_COUNT && !user_any) {
@ -296,7 +310,11 @@ X_RESULT SDLInputDriver::GetKeystroke(uint32_t users, uint32_t flags,
X_INPUT_GAMEPAD_VK_RTHUMB_DOWNLEFT, X_INPUT_GAMEPAD_VK_RTHUMB_DOWNLEFT,
}; };
QueueControllerUpdate(); auto is_active = this->is_active();
if (is_active) {
QueueControllerUpdate();
}
std::unique_lock<std::mutex> guard(controllers_mutex_); std::unique_lock<std::mutex> guard(controllers_mutex_);
@ -311,8 +329,13 @@ X_RESULT SDLInputDriver::GetKeystroke(uint32_t users, uint32_t flags,
} }
} }
const uint64_t curr_butts = controller->state.gamepad.buttons | // If input is not active (e.g. due to a dialog overlay), force buttons to
AnalogToKeyfield(controller->state.gamepad); // "unpressed". The algorithm will automatically send UP events when
// `is_active()` goes low and DOWN events when it goes high again.
const uint64_t curr_butts =
is_active ? (controller->state.gamepad.buttons |
AnalogToKeyfield(controller->state.gamepad))
: uint64_t(0);
KeystrokeState& last = keystroke_states_.at(user_index); KeystrokeState& last = keystroke_states_.at(user_index);
// Handle repeating // Handle repeating

View File

@ -44,8 +44,9 @@ class SDLInputDriver : public InputDriver {
protected: protected:
struct ControllerState { struct ControllerState {
SDL_GameController* sdl; SDL_GameController* sdl;
bool state_changed;
X_INPUT_STATE state; X_INPUT_STATE state;
bool state_changed;
bool is_active;
}; };
enum class RepeatState { enum class RepeatState {