| /* |
| * Copyright 2017 The Cobalt Authors. 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_thread.h" |
| |
| #include <algorithm> |
| #include <map> |
| #include <vector> |
| |
| #include "starboard/common/thread.h" |
| #include "starboard/shared/uwp/analog_thumbstick_input.h" |
| #include "starboard/thread.h" |
| |
| namespace starboard { |
| namespace shared { |
| namespace uwp { |
| |
| class AnalogThumbstickThread::Impl : public Thread { |
| public: |
| explicit Impl(Callback* cb) : Thread("AnalogGamepad"), callback_(cb) { |
| stick_is_centered_[kSbKeyGamepadLeftStickLeft] = true; |
| stick_is_centered_[kSbKeyGamepadRightStickLeft] = true; |
| stick_is_centered_[kSbKeyGamepadLeftStickUp] = true; |
| stick_is_centered_[kSbKeyGamepadRightStickUp] = true; |
| |
| Thread::Start(); |
| } |
| ~Impl() { Thread::Join(); } |
| |
| void Run() override { |
| while (!join_called()) { |
| Update(); |
| // 120hz to provide smooth 60fps playback. |
| SbThreadSleep(kSbTimeSecond / kPollingFrequency); |
| } |
| } |
| |
| void Update() { |
| ThumbSticks thumb_state = GetCombinedThumbStickState(); |
| |
| FireEventIfNecessary(kSbKeyGamepadLeftStickLeft, thumb_state.left_x); |
| FireEventIfNecessary(kSbKeyGamepadLeftStickUp, thumb_state.left_y); |
| FireEventIfNecessary(kSbKeyGamepadRightStickLeft, thumb_state.right_x); |
| FireEventIfNecessary(kSbKeyGamepadRightStickUp, thumb_state.right_y); |
| } |
| |
| void FireEventIfNecessary(SbKey sb_key, float value) { |
| if (value == 0.0f) { |
| if (stick_is_centered_[sb_key]) { |
| // The previous stick input is in center position, so it is not |
| // necessary to inject another center input event. |
| return; |
| } |
| stick_is_centered_[sb_key] = true; |
| } else { |
| stick_is_centered_[sb_key] = false; |
| } |
| |
| SbInputVector input_vector = {0, 0}; |
| |
| switch (sb_key) { |
| case kSbKeyGamepadRightStickLeft: |
| case kSbKeyGamepadLeftStickLeft: { |
| input_vector.x = value; |
| break; |
| } |
| case kSbKeyGamepadRightStickUp: |
| case kSbKeyGamepadLeftStickUp: { |
| input_vector.y = -value; |
| break; |
| } |
| default: { |
| SB_NOTREACHED(); |
| break; |
| } |
| } |
| callback_->OnJoystickUpdate(sb_key, input_vector); |
| } |
| |
| ThumbSticks GetCombinedThumbStickState() { |
| ThumbSticks all_thumb_state; |
| GetGamepadThumbSticks(&thumb_sticks_); |
| |
| for (int i = 0; i < thumb_sticks_.size(); ++i) { |
| ThumbSticks thumb_state = thumb_sticks_[i]; |
| |
| all_thumb_state.left_x += thumb_state.left_x; |
| all_thumb_state.left_y += thumb_state.left_y; |
| all_thumb_state.right_x += thumb_state.right_x; |
| all_thumb_state.right_y += thumb_state.right_y; |
| } |
| |
| all_thumb_state.left_x = ClampToZeroOne(all_thumb_state.left_x); |
| all_thumb_state.left_y = ClampToZeroOne(all_thumb_state.left_y); |
| all_thumb_state.right_x = ClampToZeroOne(all_thumb_state.right_x); |
| all_thumb_state.right_y = ClampToZeroOne(all_thumb_state.right_y); |
| |
| return all_thumb_state; |
| } |
| |
| static float ClampToZeroOne(float in) { |
| return std::max(-1.0f, std::min(1.0f, in)); |
| } |
| Callback* callback_; |
| std::map<SbKey, bool> stick_is_centered_; |
| std::vector<ThumbSticks> thumb_sticks_; |
| }; |
| |
| AnalogThumbstickThread::AnalogThumbstickThread(Callback* cb) { |
| impl_.reset(new Impl(cb)); |
| } |
| |
| AnalogThumbstickThread::~AnalogThumbstickThread() { |
| impl_.reset(nullptr); |
| } |
| |
| } // namespace uwp |
| } // namespace shared |
| } // namespace starboard |