/* | |
* Copyright 2017 Google Inc. All Rights Reserved. | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*/ | |
#include "starboard/shared/uwp/analog_thumbstick_input.h" | |
#include <Windows.Gaming.Input.h> | |
#include <algorithm> | |
#include "starboard/log.h" | |
#include "starboard/shared/win32/error_utils.h" | |
#include "starboard/types.h" | |
#pragma comment(lib, "xinput9_1_0.lib") | |
using Windows::Foundation::Collections::IVectorView; | |
using Windows::Gaming::Input::Gamepad; | |
using Windows::Gaming::Input::GamepadReading; | |
using Windows::Gaming::Input::RawGameController; | |
namespace starboard { | |
namespace shared { | |
namespace uwp { | |
namespace { | |
const int kMaxPlayerCounter = 4; | |
const float kDeadZoneThreshold = .24f; | |
float ApplyLinearDeadZone(float value, float maxValue, float deadZoneSize) { | |
if (value < -deadZoneSize) { | |
// Increase negative values to remove the deadzone discontinuity. | |
value += deadZoneSize; | |
} else if (value > deadZoneSize) { | |
// Decrease positive values to remove the deadzone discontinuity. | |
value -= deadZoneSize; | |
} else { | |
// Values inside the deadzone come out zero. | |
return 0; | |
} | |
// Scale into 0-1 range. | |
float scaledValue = value / (maxValue - deadZoneSize); | |
return std::max(-1.f, std::min(scaledValue, 1.f)); | |
} | |
void ApplyStickDeadZone(float x, | |
float y, | |
float max_value, | |
float dead_zone_size, | |
float* result_x, | |
float* result_y) { | |
*result_x = ApplyLinearDeadZone(x, max_value, dead_zone_size); | |
*result_y = ApplyLinearDeadZone(y, max_value, dead_zone_size); | |
} | |
ThumbSticks ReadThumbStick(Gamepad ^ controller) { | |
ThumbSticks output; | |
GamepadReading reading = controller->GetCurrentReading(); | |
ApplyStickDeadZone(static_cast<float>(reading.LeftThumbstickX), | |
static_cast<float>(reading.LeftThumbstickY), 1.f, | |
kDeadZoneThreshold, &output.left_x, &output.left_y); | |
ApplyStickDeadZone(static_cast<float>(reading.RightThumbstickX), | |
static_cast<float>(reading.RightThumbstickY), 1.f, | |
kDeadZoneThreshold, &output.right_x, &output.right_y); | |
return output; | |
} | |
} // namespace | |
void GetGamepadThumbSticks(std::vector<ThumbSticks>* destination) { | |
destination->erase(destination->begin(), destination->end()); | |
// This profiled to an average time of 33us to execute. | |
IVectorView<Gamepad ^> ^ gamepads = Gamepad::Gamepads; | |
// This profiled to take on average 9us of time to read controller state. | |
const uint32_t n = gamepads->Size; | |
for (uint32_t i = 0; i < n; ++i) { | |
Gamepad ^ gamepad = gamepads->GetAt(i); | |
ThumbSticks thumb_stick = ReadThumbStick(gamepad); | |
destination->push_back(thumb_stick); | |
} | |
} | |
} // namespace uwp | |
} // namespace shared | |
} // namespace starboard |