mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 05:40:04 +00:00 
			
		
		
		
	move MotionEmu from core/frontend to input_common as a InputDevice
This commit is contained in:
		
							parent
							
								
									867eabd6b7
								
							
						
					
					
						commit
						188194908c
					
				
					 17 changed files with 221 additions and 244 deletions
				
			
		|  | @ -2,12 +2,14 @@ set(SRCS | |||
|             analog_from_button.cpp | ||||
|             keyboard.cpp | ||||
|             main.cpp | ||||
|             motion_emu.cpp | ||||
|             ) | ||||
| 
 | ||||
| set(HEADERS | ||||
|             analog_from_button.h | ||||
|             keyboard.h | ||||
|             main.h | ||||
|             motion_emu.h | ||||
|             ) | ||||
| 
 | ||||
| if(SDL2_FOUND) | ||||
|  |  | |||
|  | @ -7,6 +7,7 @@ | |||
| #include "input_common/analog_from_button.h" | ||||
| #include "input_common/keyboard.h" | ||||
| #include "input_common/main.h" | ||||
| #include "input_common/motion_emu.h" | ||||
| #ifdef HAVE_SDL2 | ||||
| #include "input_common/sdl/sdl.h" | ||||
| #endif | ||||
|  | @ -14,12 +15,16 @@ | |||
| namespace InputCommon { | ||||
| 
 | ||||
| static std::shared_ptr<Keyboard> keyboard; | ||||
| static std::shared_ptr<MotionEmu> motion_emu; | ||||
| 
 | ||||
| void Init() { | ||||
|     keyboard = std::make_shared<InputCommon::Keyboard>(); | ||||
|     keyboard = std::make_shared<Keyboard>(); | ||||
|     Input::RegisterFactory<Input::ButtonDevice>("keyboard", keyboard); | ||||
|     Input::RegisterFactory<Input::AnalogDevice>("analog_from_button", | ||||
|                                                 std::make_shared<InputCommon::AnalogFromButton>()); | ||||
|                                                 std::make_shared<AnalogFromButton>()); | ||||
|     motion_emu = std::make_shared<MotionEmu>(); | ||||
|     Input::RegisterFactory<Input::MotionDevice>("motion_emu", motion_emu); | ||||
| 
 | ||||
| #ifdef HAVE_SDL2 | ||||
|     SDL::Init(); | ||||
| #endif | ||||
|  | @ -29,6 +34,8 @@ void Shutdown() { | |||
|     Input::UnregisterFactory<Input::ButtonDevice>("keyboard"); | ||||
|     keyboard.reset(); | ||||
|     Input::UnregisterFactory<Input::AnalogDevice>("analog_from_button"); | ||||
|     Input::UnregisterFactory<Input::MotionDevice>("motion_emu"); | ||||
|     motion_emu.reset(); | ||||
| 
 | ||||
| #ifdef HAVE_SDL2 | ||||
|     SDL::Shutdown(); | ||||
|  | @ -39,6 +46,10 @@ Keyboard* GetKeyboard() { | |||
|     return keyboard.get(); | ||||
| } | ||||
| 
 | ||||
| MotionEmu* GetMotionEmu() { | ||||
|     return motion_emu.get(); | ||||
| } | ||||
| 
 | ||||
| std::string GenerateKeyboardParam(int key_code) { | ||||
|     Common::ParamPackage param{ | ||||
|         {"engine", "keyboard"}, {"code", std::to_string(key_code)}, | ||||
|  |  | |||
|  | @ -19,6 +19,11 @@ class Keyboard; | |||
| /// Gets the keyboard button device factory.
 | ||||
| Keyboard* GetKeyboard(); | ||||
| 
 | ||||
| class MotionEmu; | ||||
| 
 | ||||
| /// Gets the motion emulation factory.
 | ||||
| MotionEmu* GetMotionEmu(); | ||||
| 
 | ||||
| /// Generates a serialized param package for creating a keyboard button device
 | ||||
| std::string GenerateKeyboardParam(int key_code); | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										159
									
								
								src/input_common/motion_emu.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										159
									
								
								src/input_common/motion_emu.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,159 @@ | |||
| // Copyright 2017 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include "common/math_util.h" | ||||
| #include "common/quaternion.h" | ||||
| #include "input_common/motion_emu.h" | ||||
| 
 | ||||
| namespace InputCommon { | ||||
| 
 | ||||
| // Implementation class of the motion emulation device
 | ||||
| class MotionEmuDevice { | ||||
| public: | ||||
|     MotionEmuDevice(int update_millisecond, float sensitivity) | ||||
|         : update_millisecond(update_millisecond), | ||||
|           update_duration(std::chrono::duration_cast<std::chrono::steady_clock::duration>( | ||||
|               std::chrono::milliseconds(update_millisecond))), | ||||
|           sensitivity(sensitivity), motion_emu_thread(&MotionEmuDevice::MotionEmuThread, this) {} | ||||
| 
 | ||||
|     ~MotionEmuDevice() { | ||||
|         if (motion_emu_thread.joinable()) { | ||||
|             shutdown_event.Set(); | ||||
|             motion_emu_thread.join(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void BeginTilt(int x, int y) { | ||||
|         mouse_origin = Math::MakeVec(x, y); | ||||
|         is_tilting = true; | ||||
|     } | ||||
| 
 | ||||
|     void Tilt(int x, int y) { | ||||
|         auto mouse_move = Math::MakeVec(x, y) - mouse_origin; | ||||
|         if (is_tilting) { | ||||
|             std::lock_guard<std::mutex> guard(tilt_mutex); | ||||
|             if (mouse_move.x == 0 && mouse_move.y == 0) { | ||||
|                 tilt_angle = 0; | ||||
|             } else { | ||||
|                 tilt_direction = mouse_move.Cast<float>(); | ||||
|                 tilt_angle = MathUtil::Clamp(tilt_direction.Normalize() * sensitivity, 0.0f, | ||||
|                                              MathUtil::PI * 0.5f); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void EndTilt() { | ||||
|         std::lock_guard<std::mutex> guard(tilt_mutex); | ||||
|         tilt_angle = 0; | ||||
|         is_tilting = false; | ||||
|     } | ||||
| 
 | ||||
|     std::tuple<Math::Vec3<float>, Math::Vec3<float>> GetStatus() { | ||||
|         std::lock_guard<std::mutex> guard(status_mutex); | ||||
|         return status; | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     const int update_millisecond; | ||||
|     const std::chrono::steady_clock::duration update_duration; | ||||
|     const float sensitivity; | ||||
| 
 | ||||
|     Math::Vec2<int> mouse_origin; | ||||
| 
 | ||||
|     std::mutex tilt_mutex; | ||||
|     Math::Vec2<float> tilt_direction; | ||||
|     float tilt_angle = 0; | ||||
| 
 | ||||
|     bool is_tilting = false; | ||||
| 
 | ||||
|     Common::Event shutdown_event; | ||||
|     std::thread motion_emu_thread; | ||||
| 
 | ||||
|     std::tuple<Math::Vec3<float>, Math::Vec3<float>> status; | ||||
|     std::mutex status_mutex; | ||||
| 
 | ||||
|     void MotionEmuThread() { | ||||
|         auto update_time = std::chrono::steady_clock::now(); | ||||
|         Math::Quaternion<float> q = MakeQuaternion(Math::Vec3<float>(), 0); | ||||
|         Math::Quaternion<float> old_q; | ||||
| 
 | ||||
|         while (!shutdown_event.WaitUntil(update_time)) { | ||||
|             update_time += update_duration; | ||||
|             old_q = q; | ||||
| 
 | ||||
|             { | ||||
|                 std::lock_guard<std::mutex> guard(tilt_mutex); | ||||
| 
 | ||||
|                 // Find the quaternion describing current 3DS tilting
 | ||||
|                 q = MakeQuaternion(Math::MakeVec(-tilt_direction.y, 0.0f, tilt_direction.x), | ||||
|                                    tilt_angle); | ||||
|             } | ||||
| 
 | ||||
|             auto inv_q = q.Inverse(); | ||||
| 
 | ||||
|             // Set the gravity vector in world space
 | ||||
|             auto gravity = Math::MakeVec(0.0f, -1.0f, 0.0f); | ||||
| 
 | ||||
|             // Find the angular rate vector in world space
 | ||||
|             auto angular_rate = ((q - old_q) * inv_q).xyz * 2; | ||||
|             angular_rate *= 1000 / update_millisecond / MathUtil::PI * 180; | ||||
| 
 | ||||
|             // Transform the two vectors from world space to 3DS space
 | ||||
|             gravity = QuaternionRotate(inv_q, gravity); | ||||
|             angular_rate = QuaternionRotate(inv_q, angular_rate); | ||||
| 
 | ||||
|             // Update the sensor state
 | ||||
|             { | ||||
|                 std::lock_guard<std::mutex> guard(status_mutex); | ||||
|                 status = std::make_tuple(gravity, angular_rate); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| // Interface wrapper held by input receiver as a unique_ptr. It holds the implementation class as
 | ||||
| // a shared_ptr, which is also observed by the factory class as a weak_ptr. In this way the factory
 | ||||
| // can forward all the inputs to the implementation only when it is valid.
 | ||||
| class MotionEmuDeviceWrapper : public Input::MotionDevice { | ||||
| public: | ||||
|     MotionEmuDeviceWrapper(int update_millisecond, float sensitivity) { | ||||
|         device = std::make_shared<MotionEmuDevice>(update_millisecond, sensitivity); | ||||
|     } | ||||
| 
 | ||||
|     std::tuple<Math::Vec3<float>, Math::Vec3<float>> GetStatus() const { | ||||
|         return device->GetStatus(); | ||||
|     } | ||||
| 
 | ||||
|     std::shared_ptr<MotionEmuDevice> device; | ||||
| }; | ||||
| 
 | ||||
| std::unique_ptr<Input::MotionDevice> MotionEmu::Create(const Common::ParamPackage& params) { | ||||
|     int update_period = params.Get("update_period", 100); | ||||
|     float sensitivity = params.Get("sensitivity", 0.01f); | ||||
|     auto device_wrapper = std::make_unique<MotionEmuDeviceWrapper>(update_period, sensitivity); | ||||
|     // Previously created device is disconnected here. Having two motion devices for 3DS is not
 | ||||
|     // expected.
 | ||||
|     current_device = device_wrapper->device; | ||||
|     return std::move(device_wrapper); | ||||
| } | ||||
| 
 | ||||
| void MotionEmu::BeginTilt(int x, int y) { | ||||
|     if (auto ptr = current_device.lock()) { | ||||
|         ptr->BeginTilt(x, y); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void MotionEmu::Tilt(int x, int y) { | ||||
|     if (auto ptr = current_device.lock()) { | ||||
|         ptr->Tilt(x, y); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void MotionEmu::EndTilt() { | ||||
|     if (auto ptr = current_device.lock()) { | ||||
|         ptr->EndTilt(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| } // namespace InputCommon
 | ||||
							
								
								
									
										47
									
								
								src/input_common/motion_emu.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								src/input_common/motion_emu.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,47 @@ | |||
| // Copyright 2017 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #pragma once | ||||
| #include "common/thread.h" | ||||
| #include "common/vector_math.h" | ||||
| #include "core/frontend/input.h" | ||||
| 
 | ||||
| namespace InputCommon { | ||||
| 
 | ||||
| class MotionEmuDevice; | ||||
| 
 | ||||
| class MotionEmu : public Input::Factory<Input::MotionDevice> { | ||||
| public: | ||||
|     /**
 | ||||
|      * Creates a motion device emulated from mouse input | ||||
|      * @param params contains parameters for creating the device: | ||||
|      *     - "update_period": update period in milliseconds | ||||
|      *     - "sensitivity": the coefficient converting mouse movement to tilting angle | ||||
|      */ | ||||
|     std::unique_ptr<Input::MotionDevice> Create(const Common::ParamPackage& params) override; | ||||
| 
 | ||||
|     /**
 | ||||
|      * Signals that a motion sensor tilt has begun. | ||||
|      * @param x the x-coordinate of the cursor | ||||
|      * @param y the y-coordinate of the cursor | ||||
|      */ | ||||
|     void BeginTilt(int x, int y); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Signals that a motion sensor tilt is occurring. | ||||
|      * @param x the x-coordinate of the cursor | ||||
|      * @param y the y-coordinate of the cursor | ||||
|      */ | ||||
|     void Tilt(int x, int y); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Signals that a motion sensor tilt has ended. | ||||
|      */ | ||||
|     void EndTilt(); | ||||
| 
 | ||||
| private: | ||||
|     std::weak_ptr<MotionEmuDevice> current_device; | ||||
| }; | ||||
| 
 | ||||
| } // namespace InputCommon
 | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue