/* Copyright (C) 2019 Mr Goldberg This file is part of the Goldberg Emulator The Goldberg Emulator is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. The Goldberg Emulator is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the Goldberg Emulator; if not, see . */ #include "base.h" #include "../controller/gamepad.h" #include struct Controller_Map { std::map> active_digital; std::map, enum EInputSourceMode>> active_analog; }; struct Controller_Action { ControllerHandle_t controller_handle; struct Controller_Map active_map; ControllerDigitalActionHandle_t active_set; Controller_Action(ControllerHandle_t controller_handle) { this->controller_handle = controller_handle; } void activate_action_set(ControllerDigitalActionHandle_t active_set, std::map &controller_maps) { auto map = controller_maps.find(active_set); if (map == controller_maps.end()) return; this->active_set = active_set; this->active_map = map->second; } std::set button_id(ControllerDigitalActionHandle_t handle) { auto a = active_map.active_digital.find(handle); if (a == active_map.active_digital.end()) return {}; return a->second; } std::pair, enum EInputSourceMode> analog_id(ControllerAnalogActionHandle_t handle) { auto a = active_map.active_analog.find(handle); if (a == active_map.active_analog.end()) return std::pair, enum EInputSourceMode>({}, k_EInputSourceMode_None); return a->second; } }; enum EXTRA_GAMEPAD_BUTTONS { BUTTON_LTRIGGER = BUTTON_COUNT + 1, BUTTON_RTRIGGER = BUTTON_COUNT + 2, BUTTON_STICK_LEFT_UP = BUTTON_COUNT + 3, BUTTON_STICK_LEFT_DOWN = BUTTON_COUNT + 4, BUTTON_STICK_LEFT_LEFT = BUTTON_COUNT + 5, BUTTON_STICK_LEFT_RIGHT = BUTTON_COUNT + 6, BUTTON_STICK_RIGHT_UP = BUTTON_COUNT + 7, BUTTON_STICK_RIGHT_DOWN = BUTTON_COUNT + 8, BUTTON_STICK_RIGHT_LEFT = BUTTON_COUNT + 9, BUTTON_STICK_RIGHT_RIGHT = BUTTON_COUNT + 10, }; #define JOY_ID_START 10 class Steam_Controller : public ISteamController001, public ISteamController003, public ISteamController004, public ISteamController005, public ISteamController006, public ISteamController, public ISteamInput { class Settings *settings; class SteamCallResults *callback_results; class SteamCallBacks *callbacks; class RunEveryRunCB *run_every_runcb; std::map button_strings = { {"DUP", BUTTON_DPAD_UP}, {"DDOWN", BUTTON_DPAD_DOWN}, {"DLEFT", BUTTON_DPAD_LEFT}, {"DRIGHT", BUTTON_DPAD_RIGHT}, {"START", BUTTON_START}, {"BACK", BUTTON_BACK}, {"LSTICK", BUTTON_LEFT_THUMB}, {"RSTICK", BUTTON_RIGHT_THUMB}, {"LBUMPER", BUTTON_LEFT_SHOULDER}, {"RBUMPER", BUTTON_RIGHT_SHOULDER}, {"A", BUTTON_A}, {"B", BUTTON_B}, {"X", BUTTON_X}, {"Y", BUTTON_Y}, {"DLTRIGGER", BUTTON_LTRIGGER}, {"DRTRIGGER", BUTTON_RTRIGGER}, {"DLJOYUP", BUTTON_STICK_LEFT_UP}, {"DLJOYDOWN", BUTTON_STICK_LEFT_DOWN}, {"DLJOYLEFT", BUTTON_STICK_LEFT_LEFT}, {"DLJOYRIGHT", BUTTON_STICK_LEFT_RIGHT}, {"DRJOYUP", BUTTON_STICK_RIGHT_UP}, {"DRJOYDOWN", BUTTON_STICK_RIGHT_DOWN}, {"DRJOYLEFT", BUTTON_STICK_RIGHT_LEFT}, {"DRJOYRIGHT", BUTTON_STICK_RIGHT_RIGHT}, }; std::map analog_strings = { {"LTRIGGER", TRIGGER_LEFT}, {"RTRIGGER", TRIGGER_RIGHT}, {"LJOY", STICK_LEFT + JOY_ID_START}, {"RJOY", STICK_RIGHT + JOY_ID_START}, }; std::map analog_input_modes = { {"joystick_move", k_EInputSourceMode_JoystickMove}, {"joystick_camera", k_EInputSourceMode_JoystickCamera}, {"trigger", k_EInputSourceMode_Trigger}, }; std::map action_handles; std::map digital_action_handles; std::map analog_action_handles; std::map controller_maps; std::map controllers; std::map steaminput_glyphs; std::map steamcontroller_glyphs; bool disabled; bool initialized; void set_handles(std::map, std::string>>> action_sets) { uint64 handle_num = 1; for (auto & set : action_sets) { ControllerActionSetHandle_t action_handle_num = handle_num; ++handle_num; action_handles[set.first] = action_handle_num; for (auto & config_key : set.second) { uint64 current_handle_num = handle_num; ++handle_num; for (auto & button_string : config_key.second.first) { auto digital = button_strings.find(button_string); if (digital != button_strings.end()) { ControllerDigitalActionHandle_t digital_handle_num = current_handle_num; if (digital_action_handles.find(config_key.first) == digital_action_handles.end()) { digital_action_handles[config_key.first] = digital_handle_num; } else { digital_handle_num = digital_action_handles[config_key.first]; } controller_maps[action_handle_num].active_digital[digital_handle_num].insert(digital->second); } else { auto analog = analog_strings.find(button_string); if (analog != analog_strings.end()) { ControllerAnalogActionHandle_t analog_handle_num = current_handle_num; enum EInputSourceMode source_mode; if (analog->second == TRIGGER_LEFT || analog->second == TRIGGER_RIGHT) { source_mode = k_EInputSourceMode_Trigger; } else { source_mode = k_EInputSourceMode_JoystickMove; } auto input_mode = analog_input_modes.find(config_key.second.second); if (input_mode != analog_input_modes.end()) { source_mode = input_mode->second; } if (analog_action_handles.find(config_key.first) == analog_action_handles.end()) { analog_action_handles[config_key.first] = analog_handle_num; } else { analog_handle_num = analog_action_handles[config_key.first]; } controller_maps[action_handle_num].active_analog[analog_handle_num].first.insert(analog->second); controller_maps[action_handle_num].active_analog[analog_handle_num].second = source_mode; } else { PRINT_DEBUG("Did not recognize controller button %s\n", button_string.c_str()); continue; } } } } } } public: static void steam_run_every_runcb(void *object) { PRINT_DEBUG("steam_controller_run_every_runcb\n"); Steam_Controller *steam_controller = (Steam_Controller *)object; steam_controller->RunCallbacks(); } Steam_Controller(class Settings *settings, class SteamCallResults *callback_results, class SteamCallBacks *callbacks, class RunEveryRunCB *run_every_runcb) { this->settings = settings; this->run_every_runcb = run_every_runcb; this->run_every_runcb->add(&Steam_Controller::steam_run_every_runcb, this); this->callback_results = callback_results; this->callbacks = callbacks; set_handles(settings->controller_settings.action_sets); disabled = !action_handles.size(); initialized = false; } ~Steam_Controller() { //TODO rm network callbacks this->run_every_runcb->remove(&Steam_Controller::steam_run_every_runcb, this); } // Init and Shutdown must be called when starting/ending use of this interface bool Init() { PRINT_DEBUG("Steam_Controller::Init()\n"); std::lock_guard lock(global_mutex); if (disabled) { return true; } GamepadInit(); GamepadUpdate(); for (int i = 1; i < 5; ++i) { struct Controller_Action cont_action(i); //Activate the action set if there is only one present. //TODO: I don't know if one gets activated by default when there's more than one if (action_handles.size() == 1) { cont_action.activate_action_set(action_handles.begin()->second, controller_maps); } controllers.insert(std::pair(i, cont_action)); } initialized = true; return true; } bool Init( const char *pchAbsolutePathToControllerConfigVDF ) { PRINT_DEBUG("Steam_Controller::Init() old\n"); return Init(); } bool Shutdown() { PRINT_DEBUG("Steam_Controller::Shutdown()\n"); std::lock_guard lock(global_mutex); if (disabled) { return true; } GamepadShutdown(); return true; } void SetOverrideMode( const char *pchMode ) { PRINT_DEBUG("Steam_Controller::SetOverrideMode\n"); } // Synchronize API state with the latest Steam Controller inputs available. This // is performed automatically by SteamAPI_RunCallbacks, but for the absolute lowest // possible latency, you call this directly before reading controller state. void RunFrame() { PRINT_DEBUG("Steam_Controller::RunFrame()\n"); if (disabled || !initialized) { return; } GamepadUpdate(); } bool GetControllerState( uint32 unControllerIndex, SteamControllerState001_t *pState ) { PRINT_DEBUG("Steam_Controller::GetControllerState()\n"); return false; } // Enumerate currently connected controllers // handlesOut should point to a STEAM_CONTROLLER_MAX_COUNT sized array of ControllerHandle_t handles // Returns the number of handles written to handlesOut int GetConnectedControllers( ControllerHandle_t *handlesOut ) { PRINT_DEBUG("Steam_Controller::GetConnectedControllers\n"); if (!handlesOut) return 0; if (disabled) { return 0; } int count = 0; if (GamepadIsConnected(GAMEPAD_0)) {*handlesOut = GAMEPAD_0 + 1; ++handlesOut; ++count;}; if (GamepadIsConnected(GAMEPAD_1)) {*handlesOut = GAMEPAD_1 + 1; ++handlesOut; ++count;}; if (GamepadIsConnected(GAMEPAD_2)) {*handlesOut = GAMEPAD_2 + 1; ++handlesOut; ++count;}; if (GamepadIsConnected(GAMEPAD_3)) {*handlesOut = GAMEPAD_3 + 1; ++handlesOut; ++count;}; PRINT_DEBUG("returned %i connected controllers\n", count); return count; } // Invokes the Steam overlay and brings up the binding screen // Returns false is overlay is disabled / unavailable, or the user is not in Big Picture mode bool ShowBindingPanel( ControllerHandle_t controllerHandle ) { PRINT_DEBUG("Steam_Controller::ShowBindingPanel\n"); return false; } // ACTION SETS // Lookup the handle for an Action Set. Best to do this once on startup, and store the handles for all future API calls. ControllerActionSetHandle_t GetActionSetHandle( const char *pszActionSetName ) { PRINT_DEBUG("Steam_Controller::GetActionSetHandle %s\n", pszActionSetName); if (!pszActionSetName) return 0; std::string upper_action_name(pszActionSetName); std::transform(upper_action_name.begin(), upper_action_name.end(), upper_action_name.begin(),[](unsigned char c){ return std::toupper(c); }); auto set_handle = action_handles.find(upper_action_name); if (set_handle == action_handles.end()) return 0; return set_handle->second; } // Reconfigure the controller to use the specified action set (ie 'Menu', 'Walk' or 'Drive') // This is cheap, and can be safely called repeatedly. It's often easier to repeatedly call it in // your state loops, instead of trying to place it in all of your state transitions. void ActivateActionSet( ControllerHandle_t controllerHandle, ControllerActionSetHandle_t actionSetHandle ) { PRINT_DEBUG("Steam_Controller::ActivateActionSet %llu %llu\n", controllerHandle, actionSetHandle); if (controllerHandle == STEAM_CONTROLLER_HANDLE_ALL_CONTROLLERS) { for (auto & c: controllers) { c.second.activate_action_set(actionSetHandle, controller_maps); } } auto controller = controllers.find(controllerHandle); if (controller == controllers.end()) return; controller->second.activate_action_set(actionSetHandle, controller_maps); } ControllerActionSetHandle_t GetCurrentActionSet( ControllerHandle_t controllerHandle ) { PRINT_DEBUG("Steam_Controller::GetCurrentActionSet %llu\n", controllerHandle); auto controller = controllers.find(controllerHandle); if (controller == controllers.end()) return 0; return controller->second.active_set; } void ActivateActionSetLayer( ControllerHandle_t controllerHandle, ControllerActionSetHandle_t actionSetLayerHandle ) { PRINT_DEBUG("Steam_Controller::ActivateActionSetLayer\n"); } void DeactivateActionSetLayer( ControllerHandle_t controllerHandle, ControllerActionSetHandle_t actionSetLayerHandle ) { PRINT_DEBUG("Steam_Controller::DeactivateActionSetLayer\n"); } void DeactivateAllActionSetLayers( ControllerHandle_t controllerHandle ) { PRINT_DEBUG("Steam_Controller::DeactivateAllActionSetLayers\n"); } int GetActiveActionSetLayers( ControllerHandle_t controllerHandle, ControllerActionSetHandle_t *handlesOut ) { PRINT_DEBUG("Steam_Controller::GetActiveActionSetLayers\n"); return 0; } // ACTIONS // Lookup the handle for a digital action. Best to do this once on startup, and store the handles for all future API calls. ControllerDigitalActionHandle_t GetDigitalActionHandle( const char *pszActionName ) { PRINT_DEBUG("Steam_Controller::GetDigitalActionHandle %s\n", pszActionName); if (!pszActionName) return 0; std::string upper_action_name(pszActionName); std::transform(upper_action_name.begin(), upper_action_name.end(), upper_action_name.begin(),[](unsigned char c){ return std::toupper(c); }); auto handle = digital_action_handles.find(upper_action_name); if (handle == digital_action_handles.end()) return 0; return handle->second; } // Returns the current state of the supplied digital game action ControllerDigitalActionData_t GetDigitalActionData( ControllerHandle_t controllerHandle, ControllerDigitalActionHandle_t digitalActionHandle ) { PRINT_DEBUG("Steam_Controller::GetDigitalActionData %llu %llu\n", controllerHandle, digitalActionHandle); ControllerDigitalActionData_t digitalData; digitalData.bActive = false; digitalData.bState = false; auto controller = controllers.find(controllerHandle); if (controller == controllers.end()) return digitalData; std::set buttons = controller->second.button_id(digitalActionHandle); if (!buttons.size()) return digitalData; digitalData.bActive = true; GAMEPAD_DEVICE device = (GAMEPAD_DEVICE)(controllerHandle - 1); for (auto button : buttons) { bool pressed = false; if (button < BUTTON_COUNT) { pressed = GamepadButtonDown(device, (GAMEPAD_BUTTON)button); } else { switch (button) { case BUTTON_LTRIGGER: pressed = GamepadTriggerLength(device, TRIGGER_LEFT) > 0.8; break; case BUTTON_RTRIGGER: pressed = GamepadTriggerLength(device, TRIGGER_RIGHT) > 0.8; break; case BUTTON_STICK_LEFT_UP: case BUTTON_STICK_LEFT_DOWN: case BUTTON_STICK_LEFT_LEFT: case BUTTON_STICK_LEFT_RIGHT: pressed = GamepadStickLength(device, STICK_LEFT) > 0.1 && ((int)GamepadStickDir(device, STICK_LEFT) == ((button - BUTTON_STICK_LEFT_UP) + 1)); break; case BUTTON_STICK_RIGHT_UP: case BUTTON_STICK_RIGHT_DOWN: case BUTTON_STICK_RIGHT_LEFT: case BUTTON_STICK_RIGHT_RIGHT: pressed = GamepadStickLength(device, STICK_RIGHT) > 0.1 && ((int)GamepadStickDir(device, STICK_RIGHT) == ((button - BUTTON_STICK_RIGHT_UP) + 1)); break; default: break; } } if (pressed) { digitalData.bState = true; break; } } return digitalData; } // Get the origin(s) for a digital action within an action set. Returns the number of origins supplied in originsOut. Use this to display the appropriate on-screen prompt for the action. // originsOut should point to a STEAM_CONTROLLER_MAX_ORIGINS sized array of EControllerActionOrigin handles int GetDigitalActionOrigins( ControllerHandle_t controllerHandle, ControllerActionSetHandle_t actionSetHandle, ControllerDigitalActionHandle_t digitalActionHandle, EControllerActionOrigin *originsOut ) { PRINT_DEBUG("Steam_Controller::GetDigitalActionOrigins\n"); EInputActionOrigin origins[STEAM_CONTROLLER_MAX_ORIGINS]; int ret = GetDigitalActionOrigins(controllerHandle, actionSetHandle, digitalActionHandle, origins ); for (int i = 0; i < ret; ++i) { originsOut[i] = (EControllerActionOrigin)(origins[i] - (k_EInputActionOrigin_XBox360_A - k_EControllerActionOrigin_XBox360_A)); } return ret; } int GetDigitalActionOrigins( InputHandle_t inputHandle, InputActionSetHandle_t actionSetHandle, InputDigitalActionHandle_t digitalActionHandle, EInputActionOrigin *originsOut ) { PRINT_DEBUG("Steam_Controller::GetDigitalActionOrigins steaminput\n"); auto controller = controllers.find(inputHandle); if (controller == controllers.end()) return 0; auto map = controller_maps.find(actionSetHandle); if (map == controller_maps.end()) return 0; auto a = map->second.active_digital.find(digitalActionHandle); if (a == map->second.active_digital.end()) return 0; int count = 0; for (auto button: a->second) { switch (button) { case BUTTON_A: originsOut[count] = k_EInputActionOrigin_XBox360_A; break; case BUTTON_B: originsOut[count] = k_EInputActionOrigin_XBox360_B; break; case BUTTON_X: originsOut[count] = k_EInputActionOrigin_XBox360_X; break; case BUTTON_Y: originsOut[count] = k_EInputActionOrigin_XBox360_Y; break; case BUTTON_LEFT_SHOULDER: originsOut[count] = k_EInputActionOrigin_XBox360_LeftBumper; break; case BUTTON_RIGHT_SHOULDER: originsOut[count] = k_EInputActionOrigin_XBox360_RightBumper; break; case BUTTON_START: originsOut[count] = k_EInputActionOrigin_XBox360_Start; break; case BUTTON_BACK: originsOut[count] = k_EInputActionOrigin_XBox360_Back; break; case BUTTON_LTRIGGER: originsOut[count] = k_EInputActionOrigin_XBox360_LeftTrigger_Click; break; case BUTTON_RTRIGGER: originsOut[count] = k_EInputActionOrigin_XBox360_RightTrigger_Click; break; case BUTTON_LEFT_THUMB: originsOut[count] = k_EInputActionOrigin_XBox360_LeftStick_Click; break; case BUTTON_RIGHT_THUMB: originsOut[count] = k_EInputActionOrigin_XBox360_RightStick_Click; break; case BUTTON_STICK_LEFT_UP: originsOut[count] = k_EInputActionOrigin_XBox360_LeftStick_DPadNorth; break; case BUTTON_STICK_LEFT_DOWN: originsOut[count] = k_EInputActionOrigin_XBox360_LeftStick_DPadSouth; break; case BUTTON_STICK_LEFT_LEFT: originsOut[count] = k_EInputActionOrigin_XBox360_LeftStick_DPadWest; break; case BUTTON_STICK_LEFT_RIGHT: originsOut[count] = k_EInputActionOrigin_XBox360_LeftStick_DPadEast; break; case BUTTON_STICK_RIGHT_UP: originsOut[count] = k_EInputActionOrigin_XBox360_RightStick_DPadNorth; break; case BUTTON_STICK_RIGHT_DOWN: originsOut[count] = k_EInputActionOrigin_XBox360_RightStick_DPadSouth; break; case BUTTON_STICK_RIGHT_LEFT: originsOut[count] = k_EInputActionOrigin_XBox360_RightStick_DPadWest; break; case BUTTON_STICK_RIGHT_RIGHT: originsOut[count] = k_EInputActionOrigin_XBox360_RightStick_DPadEast; break; case BUTTON_DPAD_UP: originsOut[count] = k_EInputActionOrigin_XBox360_DPad_North; break; case BUTTON_DPAD_DOWN: originsOut[count] = k_EInputActionOrigin_XBox360_DPad_South; break; case BUTTON_DPAD_LEFT: originsOut[count] = k_EInputActionOrigin_XBox360_DPad_West; break; case BUTTON_DPAD_RIGHT: originsOut[count] = k_EInputActionOrigin_XBox360_DPad_East; break; default: originsOut[count] = k_EInputActionOrigin_None; break; } ++count; if (count >= STEAM_INPUT_MAX_ORIGINS) { break; } } return count; } // Lookup the handle for an analog action. Best to do this once on startup, and store the handles for all future API calls. ControllerAnalogActionHandle_t GetAnalogActionHandle( const char *pszActionName ) { PRINT_DEBUG("Steam_Controller::GetAnalogActionHandle %s\n", pszActionName); if (!pszActionName) return 0; std::string upper_action_name(pszActionName); std::transform(upper_action_name.begin(), upper_action_name.end(), upper_action_name.begin(),[](unsigned char c){ return std::toupper(c); }); auto handle = analog_action_handles.find(upper_action_name); if (handle == analog_action_handles.end()) return 0; return handle->second; } // Returns the current state of these supplied analog game action ControllerAnalogActionData_t GetAnalogActionData( ControllerHandle_t controllerHandle, ControllerAnalogActionHandle_t analogActionHandle ) { PRINT_DEBUG("Steam_Controller::GetAnalogActionData %llu %llu\n", controllerHandle, analogActionHandle); ControllerAnalogActionData_t data; data.eMode = k_EInputSourceMode_None; data.x = data.y = 0; data.bActive = false; auto controller = controllers.find(controllerHandle); if (controller == controllers.end()) return data; auto analog = controller->second.analog_id(analogActionHandle); if (!analog.first.size()) return data; data.bActive = true; data.eMode = analog.second; for (auto a : analog.first) { if (a >= JOY_ID_START) { int joystick_id = a - JOY_ID_START; GamepadStickNormXY((GAMEPAD_DEVICE)(controllerHandle - 1), (GAMEPAD_STICK) joystick_id, &data.x, &data.y); float length = GamepadStickLength((GAMEPAD_DEVICE)(controllerHandle - 1), (GAMEPAD_STICK) joystick_id); data.x = data.x * length; data.y = data.y * length; } else { data.x = GamepadTriggerLength((GAMEPAD_DEVICE)(controllerHandle - 1), (GAMEPAD_TRIGGER) a); } if (data.x || data.y) { break; } } return data; } // Get the origin(s) for an analog action within an action set. Returns the number of origins supplied in originsOut. Use this to display the appropriate on-screen prompt for the action. // originsOut should point to a STEAM_CONTROLLER_MAX_ORIGINS sized array of EControllerActionOrigin handles int GetAnalogActionOrigins( ControllerHandle_t controllerHandle, ControllerActionSetHandle_t actionSetHandle, ControllerAnalogActionHandle_t analogActionHandle, EControllerActionOrigin *originsOut ) { PRINT_DEBUG("Steam_Controller::GetAnalogActionOrigins\n"); EInputActionOrigin origins[STEAM_CONTROLLER_MAX_ORIGINS]; int ret = GetAnalogActionOrigins(controllerHandle, actionSetHandle, analogActionHandle, origins ); for (int i = 0; i < ret; ++i) { originsOut[i] = (EControllerActionOrigin)(origins[i] - (k_EInputActionOrigin_XBox360_A - k_EControllerActionOrigin_XBox360_A)); } return ret; } int GetAnalogActionOrigins( InputHandle_t inputHandle, InputActionSetHandle_t actionSetHandle, InputAnalogActionHandle_t analogActionHandle, EInputActionOrigin *originsOut ) { PRINT_DEBUG("Steam_Controller::GetAnalogActionOrigins steaminput\n"); auto controller = controllers.find(inputHandle); if (controller == controllers.end()) return 0; auto map = controller_maps.find(actionSetHandle); if (map == controller_maps.end()) return 0; auto a = map->second.active_analog.find(analogActionHandle); if (a == map->second.active_analog.end()) return 0; int count = 0; for (auto b: a->second.first) { switch (b) { case TRIGGER_LEFT: originsOut[count] = k_EInputActionOrigin_XBox360_LeftTrigger_Pull; break; case TRIGGER_RIGHT: originsOut[count] = k_EInputActionOrigin_XBox360_RightTrigger_Pull; break; case STICK_LEFT + JOY_ID_START: originsOut[count] = k_EInputActionOrigin_XBox360_LeftStick_Move; break; case STICK_RIGHT + JOY_ID_START: originsOut[count] = k_EInputActionOrigin_XBox360_RightStick_Move; break; default: originsOut[count] = k_EInputActionOrigin_None; break; } ++count; if (count >= STEAM_INPUT_MAX_ORIGINS) { break; } } return count; } void StopAnalogActionMomentum( ControllerHandle_t controllerHandle, ControllerAnalogActionHandle_t eAction ) { PRINT_DEBUG("Steam_Controller::StopAnalogActionMomentum %llu %llu\n", controllerHandle, eAction); } // Trigger a haptic pulse on a controller void TriggerHapticPulse( ControllerHandle_t controllerHandle, ESteamControllerPad eTargetPad, unsigned short usDurationMicroSec ) { PRINT_DEBUG("Steam_Controller::TriggerHapticPulse\n"); } void TriggerHapticPulse( uint32 unControllerIndex, ESteamControllerPad eTargetPad, unsigned short usDurationMicroSec ) { PRINT_DEBUG("Steam_Controller::TriggerHapticPulse old\n"); TriggerHapticPulse(unControllerIndex, eTargetPad, usDurationMicroSec ); } // Trigger a pulse with a duty cycle of usDurationMicroSec / usOffMicroSec, unRepeat times. // nFlags is currently unused and reserved for future use. void TriggerRepeatedHapticPulse( ControllerHandle_t controllerHandle, ESteamControllerPad eTargetPad, unsigned short usDurationMicroSec, unsigned short usOffMicroSec, unsigned short unRepeat, unsigned int nFlags ) { PRINT_DEBUG("Steam_Controller::TriggerRepeatedHapticPulse\n"); } // Tigger a vibration event on supported controllers. void TriggerVibration( ControllerHandle_t controllerHandle, unsigned short usLeftSpeed, unsigned short usRightSpeed ) { PRINT_DEBUG("Steam_Controller::TriggerVibration %hu %hu\n", usLeftSpeed, usRightSpeed); auto controller = controllers.find(controllerHandle); if (controller == controllers.end()) return; unsigned int rumble_length_ms = 0; #if defined(__linux__) //FIXME: shadow of the tomb raider on linux doesn't seem to turn off the rumble so I made it expire after 100ms. Need to check if this is how linux steam actually behaves. rumble_length_ms = 100; #endif GamepadSetRumble((GAMEPAD_DEVICE)(controllerHandle - 1), ((double)usLeftSpeed) / 65535.0, ((double)usRightSpeed) / 65535.0, rumble_length_ms); } // Set the controller LED color on supported controllers. void SetLEDColor( ControllerHandle_t controllerHandle, uint8 nColorR, uint8 nColorG, uint8 nColorB, unsigned int nFlags ) { PRINT_DEBUG("Steam_Controller::SetLEDColor\n"); } // Returns the associated gamepad index for the specified controller, if emulating a gamepad int GetGamepadIndexForController( ControllerHandle_t ulControllerHandle ) { PRINT_DEBUG("Steam_Controller::GetGamepadIndexForController\n"); return 0; } // Returns the associated controller handle for the specified emulated gamepad ControllerHandle_t GetControllerForGamepadIndex( int nIndex ) { PRINT_DEBUG("Steam_Controller::GetControllerForGamepadIndex\n"); return 0; } // Returns raw motion data from the specified controller ControllerMotionData_t GetMotionData( ControllerHandle_t controllerHandle ) { PRINT_DEBUG("Steam_Controller::GetMotionData\n"); ControllerMotionData_t data = {}; return data; } // Attempt to display origins of given action in the controller HUD, for the currently active action set // Returns false is overlay is disabled / unavailable, or the user is not in Big Picture mode bool ShowDigitalActionOrigins( ControllerHandle_t controllerHandle, ControllerDigitalActionHandle_t digitalActionHandle, float flScale, float flXPosition, float flYPosition ) { PRINT_DEBUG("Steam_Controller::ShowDigitalActionOrigins\n"); return true; } bool ShowAnalogActionOrigins( ControllerHandle_t controllerHandle, ControllerAnalogActionHandle_t analogActionHandle, float flScale, float flXPosition, float flYPosition ) { PRINT_DEBUG("Steam_Controller::ShowAnalogActionOrigins\n"); return true; } // Returns a localized string (from Steam's language setting) for the specified origin const char *GetStringForActionOrigin( EControllerActionOrigin eOrigin ) { PRINT_DEBUG("Steam_Controller::GetStringForActionOrigin\n"); return "Button String"; } const char *GetStringForActionOrigin( EInputActionOrigin eOrigin ) { PRINT_DEBUG("Steam_Controller::GetStringForActionOrigin steaminput\n"); return "Button String"; } // Get a local path to art for on-screen glyph for a particular origin const char *GetGlyphForActionOrigin( EControllerActionOrigin eOrigin ) { PRINT_DEBUG("Steam_Controller::GetGlyphForActionOrigin %i\n", eOrigin); if (steamcontroller_glyphs.empty()) { std::string dir = settings->glyphs_directory; steamcontroller_glyphs[k_EControllerActionOrigin_XBox360_A] = dir + "button_a.png"; steamcontroller_glyphs[k_EControllerActionOrigin_XBox360_B] = dir + "button_b.png"; steamcontroller_glyphs[k_EControllerActionOrigin_XBox360_X] = dir + "button_x.png"; steamcontroller_glyphs[k_EControllerActionOrigin_XBox360_Y] = dir + "button_y.png"; steamcontroller_glyphs[k_EControllerActionOrigin_XBox360_LeftBumper] = dir + "shoulder_l.png"; steamcontroller_glyphs[k_EControllerActionOrigin_XBox360_RightBumper] = dir + "shoulder_r.png"; steamcontroller_glyphs[k_EControllerActionOrigin_XBox360_Start] = dir + "xbox_button_start.png"; steamcontroller_glyphs[k_EControllerActionOrigin_XBox360_Back] = dir + "xbox_button_select.png"; steamcontroller_glyphs[k_EControllerActionOrigin_XBox360_LeftTrigger_Pull] = dir + "trigger_l_pull.png"; steamcontroller_glyphs[k_EControllerActionOrigin_XBox360_LeftTrigger_Click] = dir + "trigger_l_click.png"; steamcontroller_glyphs[k_EControllerActionOrigin_XBox360_RightTrigger_Pull] = dir + "trigger_r_pull.png"; steamcontroller_glyphs[k_EControllerActionOrigin_XBox360_RightTrigger_Click] = dir + "trigger_r_click.png"; steamcontroller_glyphs[k_EControllerActionOrigin_XBox360_LeftStick_Move] = dir + "stick_l_move.png"; steamcontroller_glyphs[k_EControllerActionOrigin_XBox360_LeftStick_Click] = dir + "stick_l_click.png"; steamcontroller_glyphs[k_EControllerActionOrigin_XBox360_LeftStick_DPadNorth] = dir + "stick_dpad_n.png"; steamcontroller_glyphs[k_EControllerActionOrigin_XBox360_LeftStick_DPadSouth] = dir + "stick_dpad_s.png"; steamcontroller_glyphs[k_EControllerActionOrigin_XBox360_LeftStick_DPadWest] = dir + "stick_dpad_w.png"; steamcontroller_glyphs[k_EControllerActionOrigin_XBox360_LeftStick_DPadEast] = dir + "stick_dpad_e.png"; steamcontroller_glyphs[k_EControllerActionOrigin_XBox360_RightStick_Move] = dir + "stick_r_move.png"; steamcontroller_glyphs[k_EControllerActionOrigin_XBox360_RightStick_Click] = dir + "stick_r_click.png"; steamcontroller_glyphs[k_EControllerActionOrigin_XBox360_RightStick_DPadNorth] = dir + "stick_dpad_n.png"; steamcontroller_glyphs[k_EControllerActionOrigin_XBox360_RightStick_DPadSouth] = dir + "stick_dpad_s.png"; steamcontroller_glyphs[k_EControllerActionOrigin_XBox360_RightStick_DPadWest] = dir + "stick_dpad_w.png"; steamcontroller_glyphs[k_EControllerActionOrigin_XBox360_RightStick_DPadEast] = dir + "stick_dpad_e.png"; steamcontroller_glyphs[k_EControllerActionOrigin_XBox360_DPad_North] = dir + "xbox_button_dpad_n.png"; steamcontroller_glyphs[k_EControllerActionOrigin_XBox360_DPad_South] = dir + "xbox_button_dpad_s.png"; steamcontroller_glyphs[k_EControllerActionOrigin_XBox360_DPad_West] = dir + "xbox_button_dpad_w.png"; steamcontroller_glyphs[k_EControllerActionOrigin_XBox360_DPad_East] = dir + "xbox_button_dpad_e.png"; steamcontroller_glyphs[k_EControllerActionOrigin_XBox360_DPad_Move] = dir + "xbox_button_dpad_move.png"; } auto glyph = steamcontroller_glyphs.find(eOrigin); if (glyph == steamcontroller_glyphs.end()) return ""; return glyph->second.c_str(); } const char *GetGlyphForActionOrigin( EInputActionOrigin eOrigin ) { PRINT_DEBUG("Steam_Controller::GetGlyphForActionOrigin steaminput %i\n", eOrigin); if (steaminput_glyphs.empty()) { std::string dir = settings->glyphs_directory; steaminput_glyphs[k_EInputActionOrigin_XBox360_A] = dir + "button_a.png"; steaminput_glyphs[k_EInputActionOrigin_XBox360_B] = dir + "button_b.png"; steaminput_glyphs[k_EInputActionOrigin_XBox360_X] = dir + "button_x.png"; steaminput_glyphs[k_EInputActionOrigin_XBox360_Y] = dir + "button_y.png"; steaminput_glyphs[k_EInputActionOrigin_XBox360_LeftBumper] = dir + "shoulder_l.png"; steaminput_glyphs[k_EInputActionOrigin_XBox360_RightBumper] = dir + "shoulder_r.png"; steaminput_glyphs[k_EInputActionOrigin_XBox360_Start] = dir + "xbox_button_start.png"; steaminput_glyphs[k_EInputActionOrigin_XBox360_Back] = dir + "xbox_button_select.png"; steaminput_glyphs[k_EInputActionOrigin_XBox360_LeftTrigger_Pull] = dir + "trigger_l_pull.png"; steaminput_glyphs[k_EInputActionOrigin_XBox360_LeftTrigger_Click] = dir + "trigger_l_click.png"; steaminput_glyphs[k_EInputActionOrigin_XBox360_RightTrigger_Pull] = dir + "trigger_r_pull.png"; steaminput_glyphs[k_EInputActionOrigin_XBox360_RightTrigger_Click] = dir + "trigger_r_click.png"; steaminput_glyphs[k_EInputActionOrigin_XBox360_LeftStick_Move] = dir + "stick_l_move.png"; steaminput_glyphs[k_EInputActionOrigin_XBox360_LeftStick_Click] = dir + "stick_l_click.png"; steaminput_glyphs[k_EInputActionOrigin_XBox360_LeftStick_DPadNorth] = dir + "stick_dpad_n.png"; steaminput_glyphs[k_EInputActionOrigin_XBox360_LeftStick_DPadSouth] = dir + "stick_dpad_s.png"; steaminput_glyphs[k_EInputActionOrigin_XBox360_LeftStick_DPadWest] = dir + "stick_dpad_w.png"; steaminput_glyphs[k_EInputActionOrigin_XBox360_LeftStick_DPadEast] = dir + "stick_dpad_e.png"; steaminput_glyphs[k_EInputActionOrigin_XBox360_RightStick_Move] = dir + "stick_r_move.png"; steaminput_glyphs[k_EInputActionOrigin_XBox360_RightStick_Click] = dir + "stick_r_click.png"; steaminput_glyphs[k_EInputActionOrigin_XBox360_RightStick_DPadNorth] = dir + "stick_dpad_n.png"; steaminput_glyphs[k_EInputActionOrigin_XBox360_RightStick_DPadSouth] = dir + "stick_dpad_s.png"; steaminput_glyphs[k_EInputActionOrigin_XBox360_RightStick_DPadWest] = dir + "stick_dpad_w.png"; steaminput_glyphs[k_EInputActionOrigin_XBox360_RightStick_DPadEast] = dir + "stick_dpad_e.png"; steaminput_glyphs[k_EInputActionOrigin_XBox360_DPad_North] = dir + "xbox_button_dpad_n.png"; steaminput_glyphs[k_EInputActionOrigin_XBox360_DPad_South] = dir + "xbox_button_dpad_s.png"; steaminput_glyphs[k_EInputActionOrigin_XBox360_DPad_West] = dir + "xbox_button_dpad_w.png"; steaminput_glyphs[k_EInputActionOrigin_XBox360_DPad_East] = dir + "xbox_button_dpad_e.png"; steaminput_glyphs[k_EInputActionOrigin_XBox360_DPad_Move] = dir + "xbox_button_dpad_move.png"; //steaminput_glyphs[] = dir + ""; } auto glyph = steaminput_glyphs.find(eOrigin); if (glyph == steaminput_glyphs.end()) return ""; return glyph->second.c_str(); } // Returns the input type for a particular handle ESteamInputType GetInputTypeForHandle( ControllerHandle_t controllerHandle ) { PRINT_DEBUG("Steam_Controller::GetInputTypeForHandle\n"); auto controller = controllers.find(controllerHandle); if (controller == controllers.end()) return k_ESteamInputType_Unknown; return k_ESteamInputType_XBox360Controller; } const char *GetStringForXboxOrigin( EXboxOrigin eOrigin ) { PRINT_DEBUG("Steam_Controller::GetStringForXboxOrigin\n"); return ""; } const char *GetGlyphForXboxOrigin( EXboxOrigin eOrigin ) { PRINT_DEBUG("Steam_Controller::GetGlyphForXboxOrigin\n"); return ""; } EControllerActionOrigin GetActionOriginFromXboxOrigin_( ControllerHandle_t controllerHandle, EXboxOrigin eOrigin ) { PRINT_DEBUG("Steam_Controller::GetActionOriginFromXboxOrigin\n"); return k_EControllerActionOrigin_None; } EInputActionOrigin GetActionOriginFromXboxOrigin( InputHandle_t inputHandle, EXboxOrigin eOrigin ) { PRINT_DEBUG("Steam_Controller::GetActionOriginFromXboxOrigin steaminput\n"); return k_EInputActionOrigin_None; } EControllerActionOrigin TranslateActionOrigin( ESteamInputType eDestinationInputType, EControllerActionOrigin eSourceOrigin ) { PRINT_DEBUG("Steam_Controller::TranslateActionOrigin\n"); return k_EControllerActionOrigin_None; } EInputActionOrigin TranslateActionOrigin( ESteamInputType eDestinationInputType, EInputActionOrigin eSourceOrigin ) { PRINT_DEBUG("Steam_Controller::TranslateActionOrigin steaminput\n"); return k_EInputActionOrigin_None; } bool GetControllerBindingRevision( ControllerHandle_t controllerHandle, int *pMajor, int *pMinor ) { PRINT_DEBUG("Steam_Controller::GetControllerBindingRevision\n"); return false; } bool GetDeviceBindingRevision( InputHandle_t inputHandle, int *pMajor, int *pMinor ) { PRINT_DEBUG("Steam_Controller::GetDeviceBindingRevision\n"); return false; } uint32 GetRemotePlaySessionID( InputHandle_t inputHandle ) { PRINT_DEBUG("Steam_Controller::GetRemotePlaySessionID\n"); return 0; } void RunCallbacks() { RunFrame(); } };