diff options
Diffstat (limited to '')
-rw-r--r-- | src/core/hle/service/audio/audren_u.cpp | 39 | ||||
-rw-r--r-- | src/core/hle/service/audio/audren_u.h | 2 | ||||
-rw-r--r-- | src/core/hle/service/hid/controllers/gesture.cpp | 347 | ||||
-rw-r--r-- | src/core/hle/service/hid/controllers/gesture.h | 69 | ||||
-rw-r--r-- | src/core/hle/service/service.cpp | 55 | ||||
-rw-r--r-- | src/core/hle/service/service.h | 35 | ||||
-rw-r--r-- | src/core/hle/service/sm/controller.cpp | 14 | ||||
-rw-r--r-- | src/core/hle/service/sm/sm.cpp | 107 | ||||
-rw-r--r-- | src/core/hle/service/sm/sm.h | 10 | ||||
-rw-r--r-- | src/core/hle/service/ssl/ssl.cpp | 42 |
10 files changed, 557 insertions, 163 deletions
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp index 513bd3730..65887011f 100644 --- a/src/core/hle/service/audio/audren_u.cpp +++ b/src/core/hle/service/audio/audren_u.cpp @@ -169,10 +169,9 @@ private: class IAudioDevice final : public ServiceFramework<IAudioDevice> { public: - explicit IAudioDevice(Core::System& system_, u32_le revision_num) - : ServiceFramework{system_, "IAudioDevice"}, revision{revision_num}, - buffer_event{system.Kernel()}, audio_input_device_switch_event{system.Kernel()}, - audio_output_device_switch_event{system.Kernel()} { + explicit IAudioDevice(Core::System& system_, Kernel::KEvent& buffer_event_, u32_le revision_) + : ServiceFramework{system_, "IAudioDevice"}, buffer_event{buffer_event_}, revision{ + revision_} { static const FunctionInfo functions[] = { {0, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceName"}, {1, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolume"}, @@ -189,18 +188,6 @@ public: {13, nullptr, "GetAudioSystemMasterVolumeSetting"}, }; RegisterHandlers(functions); - - Kernel::KAutoObject::Create(std::addressof(buffer_event)); - buffer_event.Initialize("IAudioOutBufferReleasedEvent"); - - // Should be similar to audio_output_device_switch_event - Kernel::KAutoObject::Create(std::addressof(audio_input_device_switch_event)); - audio_input_device_switch_event.Initialize("IAudioDevice:AudioInputDeviceSwitchedEvent"); - - // Should only be signalled when an audio output device has been changed, example: speaker - // to headset - Kernel::KAutoObject::Create(std::addressof(audio_output_device_switch_event)); - audio_output_device_switch_event.Initialize("IAudioDevice:AudioOutputDeviceSwitchedEvent"); } private: @@ -310,7 +297,7 @@ private: IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(audio_input_device_switch_event.GetReadableEvent()); + rb.PushCopyObjects(buffer_event.GetReadableEvent()); } void QueryAudioDeviceOutputEvent(Kernel::HLERequestContext& ctx) { @@ -318,17 +305,16 @@ private: IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(audio_output_device_switch_event.GetReadableEvent()); + rb.PushCopyObjects(buffer_event.GetReadableEvent()); } + Kernel::KEvent& buffer_event; u32_le revision = 0; - Kernel::KEvent buffer_event; - Kernel::KEvent audio_input_device_switch_event; - Kernel::KEvent audio_output_device_switch_event; +}; -}; // namespace Audio +AudRenU::AudRenU(Core::System& system_) + : ServiceFramework{system_, "audren:u"}, buffer_event{system.Kernel()} { -AudRenU::AudRenU(Core::System& system_) : ServiceFramework{system_, "audren:u"} { // clang-format off static const FunctionInfo functions[] = { {0, &AudRenU::OpenAudioRenderer, "OpenAudioRenderer"}, @@ -340,6 +326,9 @@ AudRenU::AudRenU(Core::System& system_) : ServiceFramework{system_, "audren:u"} // clang-format on RegisterHandlers(functions); + + Kernel::KAutoObject::Create(std::addressof(buffer_event)); + buffer_event.Initialize("IAudioOutBufferReleasedEvent"); } AudRenU::~AudRenU() = default; @@ -662,7 +651,7 @@ void AudRenU::GetAudioDeviceService(Kernel::HLERequestContext& ctx) { // always assumes the initial release revision (REV1). IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<IAudioDevice>(system, Common::MakeMagic('R', 'E', 'V', '1')); + rb.PushIpcInterface<IAudioDevice>(system, buffer_event, Common::MakeMagic('R', 'E', 'V', '1')); } void AudRenU::OpenAudioRendererForManualExecution(Kernel::HLERequestContext& ctx) { @@ -684,7 +673,7 @@ void AudRenU::GetAudioDeviceServiceWithRevisionInfo(Kernel::HLERequestContext& c IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<IAudioDevice>(system, revision); + rb.PushIpcInterface<IAudioDevice>(system, buffer_event, revision); } void AudRenU::OpenAudioRendererImpl(Kernel::HLERequestContext& ctx) { diff --git a/src/core/hle/service/audio/audren_u.h b/src/core/hle/service/audio/audren_u.h index 37e8b4716..0ee6f9542 100644 --- a/src/core/hle/service/audio/audren_u.h +++ b/src/core/hle/service/audio/audren_u.h @@ -4,6 +4,7 @@ #pragma once +#include "core/hle/kernel/k_event.h" #include "core/hle/service/service.h" namespace Core { @@ -31,6 +32,7 @@ private: void OpenAudioRendererImpl(Kernel::HLERequestContext& ctx); std::size_t audren_instance_count = 0; + Kernel::KEvent buffer_event; }; // Describes a particular audio feature that may be supported in a particular revision. diff --git a/src/core/hle/service/hid/controllers/gesture.cpp b/src/core/hle/service/hid/controllers/gesture.cpp index bb77d8959..9e5df3bb7 100644 --- a/src/core/hle/service/hid/controllers/gesture.cpp +++ b/src/core/hle/service/hid/controllers/gesture.cpp @@ -1,10 +1,9 @@ -// Copyright 2018 yuzu emulator team +// Copyright 2021 yuzu Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include <cstring> -#include "common/common_types.h" #include "common/logging/log.h" +#include "common/math_util.h" #include "common/settings.h" #include "core/core_timing.h" #include "core/frontend/emu_window.h" @@ -12,10 +11,19 @@ namespace Service::HID { constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3BA00; -constexpr f32 angle_threshold = 0.08f; -constexpr f32 pinch_threshold = 100.0f; -Controller_Gesture::Controller_Gesture(Core::System& system_) : ControllerBase{system_} {} +// HW is around 700, value is set to 400 to make it easier to trigger with mouse +constexpr f32 swipe_threshold = 400.0f; // Threshold in pixels/s +constexpr f32 angle_threshold = 0.015f; // Threshold in radians +constexpr f32 pinch_threshold = 0.5f; // Threshold in pixels +constexpr f32 press_delay = 0.5f; // Time in seconds +constexpr f32 double_tap_delay = 0.35f; // Time in seconds + +constexpr f32 Square(s32 num) { + return static_cast<f32>(num * num); +} + +Controller_Gesture::Controller_Gesture(Core::System& system) : ControllerBase(system) {} Controller_Gesture::~Controller_Gesture() = default; void Controller_Gesture::OnInit() { @@ -24,6 +32,8 @@ void Controller_Gesture::OnInit() { keyboard_finger_id[id] = MAX_POINTS; udp_finger_id[id] = MAX_POINTS; } + shared_memory.header.entry_count = 0; + force_update = true; } void Controller_Gesture::OnRelease() {} @@ -38,17 +48,23 @@ void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing, u shared_memory.header.last_entry_index = 0; return; } - shared_memory.header.entry_count = 16; - const auto& last_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; - shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17; - auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; + ReadTouchInput(); - cur_entry.sampling_number = last_entry.sampling_number + 1; - cur_entry.sampling_number2 = cur_entry.sampling_number; + GestureProperties gesture = GetGestureProperties(); + f32 time_difference = static_cast<f32>(shared_memory.header.timestamp - last_update_timestamp) / + (1000 * 1000 * 1000); - // TODO(german77): Implement all gesture types + // Only update if necesary + if (!ShouldUpdateGesture(gesture, time_difference)) { + return; + } + last_update_timestamp = shared_memory.header.timestamp; + UpdateGestureSharedMemory(data, size, gesture, time_difference); +} + +void Controller_Gesture::ReadTouchInput() { const Input::TouchStatus& mouse_status = touch_mouse_device->GetStatus(); const Input::TouchStatus& udp_status = touch_udp_device->GetStatus(); for (std::size_t id = 0; id < mouse_status.size(); ++id) { @@ -63,50 +79,71 @@ void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing, u UpdateTouchInputEvent(keyboard_status[id], keyboard_finger_id[id]); } } +} - TouchType type = TouchType::Idle; - Attribute attributes{}; - GestureProperties gesture = GetGestureProperties(); - if (last_gesture.active_points != gesture.active_points) { - ++last_gesture.detection_count; +bool Controller_Gesture::ShouldUpdateGesture(const GestureProperties& gesture, + f32 time_difference) { + const auto& last_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; + if (force_update) { + force_update = false; + return true; } - if (gesture.active_points > 0) { - if (last_gesture.active_points == 0) { - attributes.is_new_touch.Assign(true); - last_gesture.average_distance = gesture.average_distance; - last_gesture.angle = gesture.angle; - } - type = TouchType::Touch; - if (gesture.mid_point.x != last_entry.x || gesture.mid_point.y != last_entry.y) { - type = TouchType::Pan; - } - if (std::abs(gesture.average_distance - last_gesture.average_distance) > pinch_threshold) { - type = TouchType::Pinch; - } - if (std::abs(gesture.angle - last_gesture.angle) > angle_threshold) { - type = TouchType::Rotate; + // Update if coordinates change + for (size_t id = 0; id < MAX_POINTS; id++) { + if (gesture.points[id].x != last_gesture.points[id].x || + gesture.points[id].y != last_gesture.points[id].y) { + return true; } + } + + // Update on press and hold event after 0.5 seconds + if (last_entry.type == TouchType::Touch && last_entry.point_count == 1 && + time_difference > press_delay) { + return enable_press_and_tap; + } + + return false; +} + +void Controller_Gesture::UpdateGestureSharedMemory(u8* data, std::size_t size, + GestureProperties& gesture, + f32 time_difference) { + TouchType type = TouchType::Idle; + Attribute attributes{}; + + const auto& last_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; + shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17; + auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; - cur_entry.delta_x = gesture.mid_point.x - last_entry.x; - cur_entry.delta_y = gesture.mid_point.y - last_entry.y; - // TODO: Find how velocities are calculated - cur_entry.vel_x = static_cast<float>(cur_entry.delta_x) * 150.1f; - cur_entry.vel_y = static_cast<float>(cur_entry.delta_y) * 150.1f; + if (shared_memory.header.entry_count < 16) { + shared_memory.header.entry_count++; + } - // Slowdown the rate of change for less flapping - last_gesture.average_distance = - (last_gesture.average_distance * 0.9f) + (gesture.average_distance * 0.1f); - last_gesture.angle = (last_gesture.angle * 0.9f) + (gesture.angle * 0.1f); + cur_entry.sampling_number = last_entry.sampling_number + 1; + cur_entry.sampling_number2 = cur_entry.sampling_number; + // Reset values to default + cur_entry.delta_x = 0; + cur_entry.delta_y = 0; + cur_entry.vel_x = 0; + cur_entry.vel_y = 0; + cur_entry.direction = Direction::None; + cur_entry.rotation_angle = 0; + cur_entry.scale = 0; + + if (gesture.active_points > 0) { + if (last_gesture.active_points == 0) { + NewGesture(gesture, type, attributes); + } else { + UpdateExistingGesture(gesture, type, time_difference); + } } else { - cur_entry.delta_x = 0; - cur_entry.delta_y = 0; - cur_entry.vel_x = 0; - cur_entry.vel_y = 0; + EndGesture(gesture, last_gesture, type, attributes, time_difference); } - last_gesture.active_points = gesture.active_points; - cur_entry.detection_count = last_gesture.detection_count; + + // Apply attributes + cur_entry.detection_count = gesture.detection_count; cur_entry.type = type; cur_entry.attributes = attributes; cur_entry.x = gesture.mid_point.x; @@ -116,12 +153,190 @@ void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing, u cur_entry.points[id].x = gesture.points[id].x; cur_entry.points[id].y = gesture.points[id].y; } - cur_entry.rotation_angle = 0; - cur_entry.scale = 0; + last_gesture = gesture; std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory)); } +void Controller_Gesture::NewGesture(GestureProperties& gesture, TouchType& type, + Attribute& attributes) { + const auto& last_entry = + shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17]; + gesture.detection_count++; + type = TouchType::Touch; + + // New touch after cancel is not considered new + if (last_entry.type != TouchType::Cancel) { + attributes.is_new_touch.Assign(1); + enable_press_and_tap = true; + } +} + +void Controller_Gesture::UpdateExistingGesture(GestureProperties& gesture, TouchType& type, + f32 time_difference) { + const auto& last_entry = + shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17]; + + // Promote to pan type if touch moved + for (size_t id = 0; id < MAX_POINTS; id++) { + if (gesture.points[id].x != last_gesture.points[id].x || + gesture.points[id].y != last_gesture.points[id].y) { + type = TouchType::Pan; + break; + } + } + + // Number of fingers changed cancel the last event and clear data + if (gesture.active_points != last_gesture.active_points) { + type = TouchType::Cancel; + enable_press_and_tap = false; + gesture.active_points = 0; + gesture.mid_point = {}; + for (size_t id = 0; id < MAX_POINTS; id++) { + gesture.points[id].x = 0; + gesture.points[id].y = 0; + } + return; + } + + // Calculate extra parameters of panning + if (type == TouchType::Pan) { + UpdatePanEvent(gesture, last_gesture, type, time_difference); + return; + } + + // Promote to press type + if (last_entry.type == TouchType::Touch) { + type = TouchType::Press; + } +} + +void Controller_Gesture::EndGesture(GestureProperties& gesture, GestureProperties& last_gesture, + TouchType& type, Attribute& attributes, f32 time_difference) { + const auto& last_entry = + shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17]; + if (last_gesture.active_points != 0) { + switch (last_entry.type) { + case TouchType::Touch: + if (enable_press_and_tap) { + SetTapEvent(gesture, last_gesture, type, attributes); + return; + } + type = TouchType::Cancel; + force_update = true; + break; + case TouchType::Press: + case TouchType::Tap: + case TouchType::Swipe: + case TouchType::Pinch: + case TouchType::Rotate: + type = TouchType::Complete; + force_update = true; + break; + case TouchType::Pan: + EndPanEvent(gesture, last_gesture, type, time_difference); + break; + default: + break; + } + return; + } + if (last_entry.type == TouchType::Complete || last_entry.type == TouchType::Cancel) { + gesture.detection_count++; + } +} + +void Controller_Gesture::SetTapEvent(GestureProperties& gesture, GestureProperties& last_gesture, + TouchType& type, Attribute& attributes) { + type = TouchType::Tap; + gesture = last_gesture; + force_update = true; + f32 tap_time_difference = + static_cast<f32>(last_update_timestamp - last_tap_timestamp) / (1000 * 1000 * 1000); + last_tap_timestamp = last_update_timestamp; + if (tap_time_difference < double_tap_delay) { + attributes.is_double_tap.Assign(1); + } +} + +void Controller_Gesture::UpdatePanEvent(GestureProperties& gesture, GestureProperties& last_gesture, + TouchType& type, f32 time_difference) { + auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; + const auto& last_entry = + shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17]; + cur_entry.delta_x = gesture.mid_point.x - last_entry.x; + cur_entry.delta_y = gesture.mid_point.y - last_entry.y; + + cur_entry.vel_x = static_cast<f32>(cur_entry.delta_x) / time_difference; + cur_entry.vel_y = static_cast<f32>(cur_entry.delta_y) / time_difference; + last_pan_time_difference = time_difference; + + // Promote to pinch type + if (std::abs(gesture.average_distance - last_gesture.average_distance) > pinch_threshold) { + type = TouchType::Pinch; + cur_entry.scale = gesture.average_distance / last_gesture.average_distance; + } + + const f32 angle_between_two_lines = std::atan((gesture.angle - last_gesture.angle) / + (1 + (gesture.angle * last_gesture.angle))); + // Promote to rotate type + if (std::abs(angle_between_two_lines) > angle_threshold) { + type = TouchType::Rotate; + cur_entry.scale = 0; + cur_entry.rotation_angle = angle_between_two_lines * 180.0f / Common::PI; + } +} + +void Controller_Gesture::EndPanEvent(GestureProperties& gesture, GestureProperties& last_gesture, + TouchType& type, f32 time_difference) { + auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; + const auto& last_entry = + shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17]; + cur_entry.vel_x = + static_cast<f32>(last_entry.delta_x) / (last_pan_time_difference + time_difference); + cur_entry.vel_y = + static_cast<f32>(last_entry.delta_y) / (last_pan_time_difference + time_difference); + const f32 curr_vel = + std::sqrt((cur_entry.vel_x * cur_entry.vel_x) + (cur_entry.vel_y * cur_entry.vel_y)); + + // Set swipe event with parameters + if (curr_vel > swipe_threshold) { + SetSwipeEvent(gesture, last_gesture, type); + return; + } + + // End panning without swipe + type = TouchType::Complete; + cur_entry.vel_x = 0; + cur_entry.vel_y = 0; + force_update = true; +} + +void Controller_Gesture::SetSwipeEvent(GestureProperties& gesture, GestureProperties& last_gesture, + TouchType& type) { + auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; + const auto& last_entry = + shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17]; + type = TouchType::Swipe; + gesture = last_gesture; + force_update = true; + cur_entry.delta_x = last_entry.delta_x; + cur_entry.delta_y = last_entry.delta_y; + if (std::abs(cur_entry.delta_x) > std::abs(cur_entry.delta_y)) { + if (cur_entry.delta_x > 0) { + cur_entry.direction = Direction::Right; + return; + } + cur_entry.direction = Direction::Left; + return; + } + if (cur_entry.delta_y > 0) { + cur_entry.direction = Direction::Down; + return; + } + cur_entry.direction = Direction::Up; +} + void Controller_Gesture::OnLoadInputDevices() { touch_mouse_device = Input::CreateDevice<Input::TouchDevice>("engine:emu_window"); touch_udp_device = Input::CreateDevice<Input::TouchDevice>("engine:cemuhookudp"); @@ -183,23 +398,33 @@ Controller_Gesture::GestureProperties Controller_Gesture::GetGestureProperties() for (size_t id = 0; id < gesture.active_points; ++id) { gesture.points[id].x = - static_cast<int>(active_fingers[id].x * Layout::ScreenUndocked::Width); + static_cast<s32>(active_fingers[id].x * Layout::ScreenUndocked::Width); gesture.points[id].y = - static_cast<int>(active_fingers[id].y * Layout::ScreenUndocked::Height); - gesture.mid_point.x += static_cast<int>(gesture.points[id].x / gesture.active_points); - gesture.mid_point.y += static_cast<int>(gesture.points[id].y / gesture.active_points); + static_cast<s32>(active_fingers[id].y * Layout::ScreenUndocked::Height); + + // Hack: There is no touch in docked but games still allow it + if (Settings::values.use_docked_mode.GetValue()) { + gesture.points[id].x = + static_cast<s32>(active_fingers[id].x * Layout::ScreenDocked::Width); + gesture.points[id].y = + static_cast<s32>(active_fingers[id].y * Layout::ScreenDocked::Height); + } + + gesture.mid_point.x += static_cast<s32>(gesture.points[id].x / gesture.active_points); + gesture.mid_point.y += static_cast<s32>(gesture.points[id].y / gesture.active_points); } for (size_t id = 0; id < gesture.active_points; ++id) { - const double distance = - std::pow(static_cast<float>(gesture.mid_point.x - gesture.points[id].x), 2) + - std::pow(static_cast<float>(gesture.mid_point.y - gesture.points[id].y), 2); - gesture.average_distance += - static_cast<float>(distance) / static_cast<float>(gesture.active_points); + const f32 distance = std::sqrt(Square(gesture.mid_point.x - gesture.points[id].x) + + Square(gesture.mid_point.y - gesture.points[id].y)); + gesture.average_distance += distance / static_cast<f32>(gesture.active_points); } - gesture.angle = std::atan2(static_cast<float>(gesture.mid_point.y - gesture.points[0].y), - static_cast<float>(gesture.mid_point.x - gesture.points[0].x)); + gesture.angle = std::atan2(static_cast<f32>(gesture.mid_point.y - gesture.points[0].y), + static_cast<f32>(gesture.mid_point.x - gesture.points[0].x)); + + gesture.detection_count = last_gesture.detection_count; + return gesture; } diff --git a/src/core/hle/service/hid/controllers/gesture.h b/src/core/hle/service/hid/controllers/gesture.h index 7c357b977..18110a6ad 100644 --- a/src/core/hle/service/hid/controllers/gesture.h +++ b/src/core/hle/service/hid/controllers/gesture.h @@ -1,4 +1,4 @@ -// Copyright 2018 yuzu emulator team +// Copyright 2021 yuzu Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -7,7 +7,6 @@ #include <array> #include "common/bit_field.h" #include "common/common_types.h" -#include "common/swap.h" #include "core/frontend/input.h" #include "core/hle/service/hid/controllers/controller_base.h" @@ -35,10 +34,10 @@ private: enum class TouchType : u32 { Idle, // Nothing touching the screen - Complete, // Unknown. End of touch? - Cancel, // Never triggered - Touch, // Pressing without movement - Press, // Never triggered + Complete, // Set at the end of a touch event + Cancel, // Set when the number of fingers change + Touch, // A finger just touched the screen + Press, // Set if last type is touch and the finger hasn't moved Tap, // Fast press then release Pan, // All points moving together across the screen Swipe, // Fast press movement and release of a single point @@ -58,8 +57,8 @@ private: union { u32_le raw{}; - BitField<0, 1, u32> is_new_touch; - BitField<1, 1, u32> is_double_tap; + BitField<4, 1, u32> is_new_touch; + BitField<8, 1, u32> is_double_tap; }; }; static_assert(sizeof(Attribute) == 4, "Attribute is an invalid size"); @@ -73,10 +72,9 @@ private: struct GestureState { s64_le sampling_number; s64_le sampling_number2; - s64_le detection_count; TouchType type; - Direction dir; + Direction direction; s32_le x; s32_le y; s32_le delta_x; @@ -84,8 +82,8 @@ private: f32 vel_x; f32 vel_y; Attribute attributes; - u32 scale; - u32 rotation_angle; + f32 scale; + f32 rotation_angle; s32_le point_count; std::array<Points, 4> points; }; @@ -109,10 +107,46 @@ private: Points mid_point{}; s64_le detection_count{}; u64_le delta_time{}; - float average_distance{}; - float angle{}; + f32 average_distance{}; + f32 angle{}; }; + // Reads input from all available input engines + void ReadTouchInput(); + + // Returns true if gesture state needs to be updated + bool ShouldUpdateGesture(const GestureProperties& gesture, f32 time_difference); + + // Updates the shared memory to the next state + void UpdateGestureSharedMemory(u8* data, std::size_t size, GestureProperties& gesture, + f32 time_difference); + + // Initializes new gesture + void NewGesture(GestureProperties& gesture, TouchType& type, Attribute& attributes); + + // Updates existing gesture state + void UpdateExistingGesture(GestureProperties& gesture, TouchType& type, f32 time_difference); + + // Terminates exiting gesture + void EndGesture(GestureProperties& gesture, GestureProperties& last_gesture, TouchType& type, + Attribute& attributes, f32 time_difference); + + // Set current event to a tap event + void SetTapEvent(GestureProperties& gesture, GestureProperties& last_gesture, TouchType& type, + Attribute& attributes); + + // Calculates and set the extra parameters related to a pan event + void UpdatePanEvent(GestureProperties& gesture, GestureProperties& last_gesture, + TouchType& type, f32 time_difference); + + // Terminates the pan event + void EndPanEvent(GestureProperties& gesture, GestureProperties& last_gesture, TouchType& type, + f32 time_difference); + + // Set current event to a swipe event + void SetSwipeEvent(GestureProperties& gesture, GestureProperties& last_gesture, + TouchType& type); + // Returns an unused finger id, if there is no fingers avaliable MAX_FINGERS will be returned std::optional<size_t> GetUnusedFingerID() const; @@ -134,6 +168,11 @@ private: std::array<size_t, MAX_FINGERS> keyboard_finger_id; std::array<size_t, MAX_FINGERS> udp_finger_id; std::array<Finger, MAX_POINTS> fingers; - GestureProperties last_gesture; + GestureProperties last_gesture{}; + s64_le last_update_timestamp{}; + s64_le last_tap_timestamp{}; + f32 last_pan_time_difference{}; + bool force_update{false}; + bool enable_press_and_tap{false}; }; } // namespace Service::HID diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 00e683c2f..2c9b2ce6d 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -111,7 +111,7 @@ void ServiceFrameworkBase::InstallAsService(SM::ServiceManager& service_manager) port_installed = true; } -void ServiceFrameworkBase::InstallAsNamedPort(Kernel::KernelCore& kernel) { +Kernel::KClientPort& ServiceFrameworkBase::CreatePort(Kernel::KernelCore& kernel) { const auto guard = LockService(); ASSERT(!port_installed); @@ -119,9 +119,10 @@ void ServiceFrameworkBase::InstallAsNamedPort(Kernel::KernelCore& kernel) { auto* port = Kernel::KPort::Create(kernel); port->Initialize(max_sessions, false, service_name); port->GetServerPort().SetHleHandler(shared_from_this()); - kernel.AddNamedPort(service_name, &port->GetClientPort()); port_installed = true; + + return port->GetClientPort(); } void ServiceFrameworkBase::RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n) { @@ -132,6 +133,16 @@ void ServiceFrameworkBase::RegisterHandlersBase(const FunctionInfoBase* function } } +void ServiceFrameworkBase::RegisterHandlersBaseTipc(const FunctionInfoBase* functions, + std::size_t n) { + handlers_tipc.reserve(handlers_tipc.size() + n); + for (std::size_t i = 0; i < n; ++i) { + // Usually this array is sorted by id already, so hint to insert at the end + handlers_tipc.emplace_hint(handlers_tipc.cend(), functions[i].expected_header, + functions[i]); + } +} + void ServiceFrameworkBase::ReportUnimplementedFunction(Kernel::HLERequestContext& ctx, const FunctionInfoBase* info) { auto cmd_buf = ctx.CommandBuffer(); @@ -166,33 +177,55 @@ void ServiceFrameworkBase::InvokeRequest(Kernel::HLERequestContext& ctx) { handler_invoker(this, info->handler_callback, ctx); } -ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& context) { +void ServiceFrameworkBase::InvokeRequestTipc(Kernel::HLERequestContext& ctx) { + boost::container::flat_map<u32, FunctionInfoBase>::iterator itr; + + itr = handlers_tipc.find(ctx.GetCommand()); + + const FunctionInfoBase* info = itr == handlers_tipc.end() ? nullptr : &itr->second; + if (info == nullptr || info->handler_callback == nullptr) { + return ReportUnimplementedFunction(ctx, info); + } + + LOG_TRACE(Service, "{}", MakeFunctionString(info->name, GetServiceName(), ctx.CommandBuffer())); + handler_invoker(this, info->handler_callback, ctx); +} + +ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::KServerSession& session, + Kernel::HLERequestContext& ctx) { const auto guard = LockService(); - switch (context.GetCommandType()) { - case IPC::CommandType::Close: { - IPC::ResponseBuilder rb{context, 2}; + switch (ctx.GetCommandType()) { + case IPC::CommandType::Close: + case IPC::CommandType::TIPC_Close: { + session.Close(); + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); return IPC::ERR_REMOTE_PROCESS_DEAD; } case IPC::CommandType::ControlWithContext: case IPC::CommandType::Control: { - system.ServiceManager().InvokeControlRequest(context); + system.ServiceManager().InvokeControlRequest(ctx); break; } case IPC::CommandType::RequestWithContext: case IPC::CommandType::Request: { - InvokeRequest(context); + InvokeRequest(ctx); break; } default: - UNIMPLEMENTED_MSG("command_type={}", context.GetCommandType()); + if (ctx.IsTipc()) { + InvokeRequestTipc(ctx); + break; + } + + UNIMPLEMENTED_MSG("command_type={}", ctx.GetCommandType()); } // If emulation was shutdown, we are closing service threads, do not write the response back to // memory that may be shutting down as well. if (system.IsPoweredOn()) { - context.WriteToOutgoingCommandBuffer(context.GetThread()); + ctx.WriteToOutgoingCommandBuffer(ctx.GetThread()); } return RESULT_SUCCESS; @@ -207,7 +240,7 @@ Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system system.GetFileSystemController().CreateFactories(*system.GetFilesystem(), false); - SM::ServiceManager::InstallInterfaces(sm, system); + system.Kernel().RegisterNamedService("sm:", SM::ServiceManager::InterfaceFactory); Account::InstallInterfaces(system); AM::InstallInterfaces(*sm, *nv_flinger, system); diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index 884951428..3dfb0740a 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -21,7 +21,9 @@ class System; namespace Kernel { class HLERequestContext; -} +class KClientPort; +class KServerSession; +} // namespace Kernel namespace Service { @@ -64,12 +66,19 @@ public: /// Creates a port pair and registers this service with the given ServiceManager. void InstallAsService(SM::ServiceManager& service_manager); - /// Creates a port pair and registers it on the kernel's global port registry. - void InstallAsNamedPort(Kernel::KernelCore& kernel); - /// Invokes a service request routine. + + /// Invokes a service request routine using the HIPC protocol. void InvokeRequest(Kernel::HLERequestContext& ctx); + + /// Invokes a service request routine using the HIPC protocol. + void InvokeRequestTipc(Kernel::HLERequestContext& ctx); + + /// Creates a port pair and registers it on the kernel's global port registry. + Kernel::KClientPort& CreatePort(Kernel::KernelCore& kernel); + /// Handles a synchronization request for the service. - ResultCode HandleSyncRequest(Kernel::HLERequestContext& context) override; + ResultCode HandleSyncRequest(Kernel::KServerSession& session, + Kernel::HLERequestContext& context) override; protected: /// Member-function pointer type of SyncRequest handlers. @@ -102,6 +111,7 @@ private: ~ServiceFrameworkBase() override; void RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n); + void RegisterHandlersBaseTipc(const FunctionInfoBase* functions, std::size_t n); void ReportUnimplementedFunction(Kernel::HLERequestContext& ctx, const FunctionInfoBase* info); /// Identifier string used to connect to the service. @@ -116,6 +126,7 @@ private: /// Function used to safely up-cast pointers to the derived class before invoking a handler. InvokerFn* handler_invoker; boost::container::flat_map<u32, FunctionInfoBase> handlers; + boost::container::flat_map<u32, FunctionInfoBase> handlers_tipc; /// Used to gain exclusive access to the service members, e.g. from CoreTiming thread. Common::SpinLock lock_service; @@ -183,6 +194,20 @@ protected: RegisterHandlersBase(functions, n); } + /// Registers handlers in the service. + template <std::size_t N> + void RegisterHandlersTipc(const FunctionInfo (&functions)[N]) { + RegisterHandlersTipc(functions, N); + } + + /** + * Registers handlers in the service. Usually prefer using the other RegisterHandlers + * overload in order to avoid needing to specify the array size. + */ + void RegisterHandlersTipc(const FunctionInfo* functions, std::size_t n) { + RegisterHandlersBaseTipc(functions, n); + } + private: /** * This function is used to allow invocation of pointers to handlers stored in the base class diff --git a/src/core/hle/service/sm/controller.cpp b/src/core/hle/service/sm/controller.cpp index ee026e22f..de530cbfb 100644 --- a/src/core/hle/service/sm/controller.cpp +++ b/src/core/hle/service/sm/controller.cpp @@ -26,15 +26,23 @@ void Controller::CloneCurrentObject(Kernel::HLERequestContext& ctx) { // TODO(bunnei): This is just creating a new handle to the same Session. I assume this is wrong // and that we probably want to actually make an entirely new Session, but we still need to // verify this on hardware. + LOG_DEBUG(Service, "called"); + auto session = ctx.Session()->GetParent(); + + // Open a reference to the session to simulate a new one being created. + session->Open(); + session->GetClientSession().Open(); + session->GetServerSession().Open(); + IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; rb.Push(RESULT_SUCCESS); - rb.PushMoveObjects(ctx.Session()->GetParent()->GetClientSession()); + rb.PushMoveObjects(session->GetClientSession()); } void Controller::CloneCurrentObjectEx(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service, "(STUBBED) called, using CloneCurrentObject"); + LOG_DEBUG(Service, "called"); CloneCurrentObject(ctx); } @@ -44,7 +52,7 @@ void Controller::QueryPointerBufferSize(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); - rb.Push<u16>(0x1000); + rb.Push<u16>(0x8000); } // https://switchbrew.org/wiki/IPC_Marshalling diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp index 568effbc9..8cc9aee8a 100644 --- a/src/core/hle/service/sm/sm.cpp +++ b/src/core/hle/service/sm/sm.cpp @@ -9,6 +9,7 @@ #include "core/hle/kernel/k_client_port.h" #include "core/hle/kernel/k_client_session.h" #include "core/hle/kernel/k_port.h" +#include "core/hle/kernel/k_scoped_resource_reservation.h" #include "core/hle/kernel/k_server_port.h" #include "core/hle/kernel/k_server_session.h" #include "core/hle/kernel/k_session.h" @@ -18,6 +19,7 @@ namespace Service::SM { +constexpr ResultCode ERR_NOT_INITIALIZED(ErrorModule::SM, 2); constexpr ResultCode ERR_ALREADY_REGISTERED(ErrorModule::SM, 4); constexpr ResultCode ERR_INVALID_NAME(ErrorModule::SM, 6); constexpr ResultCode ERR_SERVICE_NOT_REGISTERED(ErrorModule::SM, 7); @@ -34,20 +36,17 @@ static ResultCode ValidateServiceName(const std::string& name) { LOG_ERROR(Service_SM, "Invalid service name! service={}", name); return ERR_INVALID_NAME; } - if (name.rfind('\0') != std::string::npos) { - LOG_ERROR(Service_SM, "A non null terminated service was passed"); - return ERR_INVALID_NAME; - } return RESULT_SUCCESS; } -void ServiceManager::InstallInterfaces(std::shared_ptr<ServiceManager> self, Core::System& system) { - ASSERT(self->sm_interface.expired()); +Kernel::KClientPort& ServiceManager::InterfaceFactory(ServiceManager& self, Core::System& system) { + ASSERT(self.sm_interface.expired()); auto sm = std::make_shared<SM>(self, system); - sm->InstallAsNamedPort(system.Kernel()); - self->sm_interface = sm; - self->controller_interface = std::make_unique<Controller>(system); + self.sm_interface = sm; + self.controller_interface = std::make_unique<Controller>(system); + + return sm->CreatePort(system.Kernel()); } ResultVal<Kernel::KServerPort*> ServiceManager::RegisterService(std::string name, @@ -107,33 +106,68 @@ SM::~SM() = default; void SM::Initialize(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_SM, "called"); + is_initialized = true; + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } void SM::GetService(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; + auto result = GetServiceImpl(ctx); + if (result.Succeeded()) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; + rb.Push(result.Code()); + rb.PushMoveObjects(result.Unwrap()); + } else { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result.Code()); + } +} + +void SM::GetServiceTipc(Kernel::HLERequestContext& ctx) { + auto result = GetServiceImpl(ctx); + IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; + rb.Push(result.Code()); + rb.PushMoveObjects(result.Succeeded() ? result.Unwrap() : nullptr); +} + +static std::string PopServiceName(IPC::RequestParser& rp) { auto name_buf = rp.PopRaw<std::array<char, 8>>(); - auto end = std::find(name_buf.begin(), name_buf.end(), '\0'); + std::string result; + for (const auto& c : name_buf) { + if (c >= ' ' && c <= '~') { + result.push_back(c); + } + } + return result; +} - std::string name(name_buf.begin(), end); +ResultVal<Kernel::KClientSession*> SM::GetServiceImpl(Kernel::HLERequestContext& ctx) { + if (!is_initialized) { + return ERR_NOT_INITIALIZED; + } + + IPC::RequestParser rp{ctx}; + std::string name(PopServiceName(rp)); - auto result = service_manager->GetServicePort(name); + auto result = service_manager.GetServicePort(name); if (result.Failed()) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result.Code()); LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, result.Code().raw); - if (name.length() == 0) - return; // LibNX Fix - UNIMPLEMENTED(); - return; + return result.Code(); } auto* port = result.Unwrap(); + // Kernel::KScopedResourceReservation session_reservation( + // kernel.CurrentProcess()->GetResourceLimit(), Kernel::LimitableResource::Sessions); + // R_UNLESS(session_reservation.Succeeded(), Kernel::ResultLimitReached); + auto* session = Kernel::KSession::Create(kernel); session->Initialize(&port->GetClientPort(), std::move(name)); + // Commit the session reservation. + // session_reservation.Commit(); + if (port->GetServerPort().GetHLEHandler()) { port->GetServerPort().GetHLEHandler()->ClientConnected(&session->GetServerSession()); } else { @@ -141,18 +175,12 @@ void SM::GetService(Kernel::HLERequestContext& ctx) { } LOG_DEBUG(Service_SM, "called service={} -> session={}", name, session->GetId()); - IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; - rb.Push(RESULT_SUCCESS); - rb.PushMoveObjects(session->GetClientSession()); + return MakeResult(&session->GetClientSession()); } void SM::RegisterService(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - - const auto name_buf = rp.PopRaw<std::array<char, 8>>(); - const auto end = std::find(name_buf.begin(), name_buf.end(), '\0'); - - const std::string name(name_buf.begin(), end); + std::string name(PopServiceName(rp)); const auto is_light = static_cast<bool>(rp.PopRaw<u32>()); const auto max_session_count = rp.PopRaw<u32>(); @@ -160,7 +188,7 @@ void SM::RegisterService(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_SM, "called with name={}, max_session_count={}, is_light={}", name, max_session_count, is_light); - auto handle = service_manager->RegisterService(name, max_session_count); + auto handle = service_manager.RegisterService(name, max_session_count); if (handle.Failed()) { LOG_ERROR(Service_SM, "failed to register service with error_code={:08X}", handle.Code().raw); @@ -178,28 +206,31 @@ void SM::RegisterService(Kernel::HLERequestContext& ctx) { void SM::UnregisterService(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; + std::string name(PopServiceName(rp)); - const auto name_buf = rp.PopRaw<std::array<char, 8>>(); - const auto end = std::find(name_buf.begin(), name_buf.end(), '\0'); - - const std::string name(name_buf.begin(), end); LOG_DEBUG(Service_SM, "called with name={}", name); IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(service_manager->UnregisterService(name)); + rb.Push(service_manager.UnregisterService(name)); } -SM::SM(std::shared_ptr<ServiceManager> service_manager_, Core::System& system_) +SM::SM(ServiceManager& service_manager_, Core::System& system_) : ServiceFramework{system_, "sm:", 4}, - service_manager{std::move(service_manager_)}, kernel{system_.Kernel()} { - static const FunctionInfo functions[] = { + service_manager{service_manager_}, kernel{system_.Kernel()} { + RegisterHandlers({ {0, &SM::Initialize, "Initialize"}, {1, &SM::GetService, "GetService"}, {2, &SM::RegisterService, "RegisterService"}, {3, &SM::UnregisterService, "UnregisterService"}, {4, nullptr, "DetachClient"}, - }; - RegisterHandlers(functions); + }); + RegisterHandlersTipc({ + {0, &SM::Initialize, "Initialize"}, + {1, &SM::GetServiceTipc, "GetService"}, + {2, &SM::RegisterService, "RegisterService"}, + {3, &SM::UnregisterService, "UnregisterService"}, + {4, nullptr, "DetachClient"}, + }); } } // namespace Service::SM diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h index af5010c3b..60f0b3f8a 100644 --- a/src/core/hle/service/sm/sm.h +++ b/src/core/hle/service/sm/sm.h @@ -34,22 +34,26 @@ class Controller; /// Interface to "sm:" service class SM final : public ServiceFramework<SM> { public: - explicit SM(std::shared_ptr<ServiceManager> service_manager_, Core::System& system_); + explicit SM(ServiceManager& service_manager_, Core::System& system_); ~SM() override; private: void Initialize(Kernel::HLERequestContext& ctx); void GetService(Kernel::HLERequestContext& ctx); + void GetServiceTipc(Kernel::HLERequestContext& ctx); void RegisterService(Kernel::HLERequestContext& ctx); void UnregisterService(Kernel::HLERequestContext& ctx); - std::shared_ptr<ServiceManager> service_manager; + ResultVal<Kernel::KClientSession*> GetServiceImpl(Kernel::HLERequestContext& ctx); + + ServiceManager& service_manager; + bool is_initialized{}; Kernel::KernelCore& kernel; }; class ServiceManager { public: - static void InstallInterfaces(std::shared_ptr<ServiceManager> self, Core::System& system); + static Kernel::KClientPort& InterfaceFactory(ServiceManager& self, Core::System& system); explicit ServiceManager(Kernel::KernelCore& kernel_); ~ServiceManager(); diff --git a/src/core/hle/service/ssl/ssl.cpp b/src/core/hle/service/ssl/ssl.cpp index dc2baca4a..2c8899ae0 100644 --- a/src/core/hle/service/ssl/ssl.cpp +++ b/src/core/hle/service/ssl/ssl.cpp @@ -10,6 +10,11 @@ namespace Service::SSL { +enum class CertificateFormat : u32 { + Pem = 1, + Der = 2, +}; + class ISslConnection final : public ServiceFramework<ISslConnection> { public: explicit ISslConnection(Core::System& system_) : ServiceFramework{system_, "ISslConnection"} { @@ -58,8 +63,8 @@ public: {1, nullptr, "GetOption"}, {2, &ISslContext::CreateConnection, "CreateConnection"}, {3, nullptr, "GetConnectionCount"}, - {4, nullptr, "ImportServerPki"}, - {5, nullptr, "ImportClientPki"}, + {4, &ISslContext::ImportServerPki, "ImportServerPki"}, + {5, &ISslContext::ImportClientPki, "ImportClientPki"}, {6, nullptr, "RemoveServerPki"}, {7, nullptr, "RemoveClientPki"}, {8, nullptr, "RegisterInternalPki"}, @@ -94,6 +99,39 @@ private: rb.Push(RESULT_SUCCESS); rb.PushIpcInterface<ISslConnection>(system); } + + void ImportServerPki(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto certificate_format = rp.PopEnum<CertificateFormat>(); + const auto pkcs_12_certificates = ctx.ReadBuffer(0); + + constexpr u64 server_id = 0; + + LOG_WARNING(Service_SSL, "(STUBBED) called, certificate_format={}", certificate_format); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(RESULT_SUCCESS); + rb.Push(server_id); + } + + void ImportClientPki(Kernel::HLERequestContext& ctx) { + const auto pkcs_12_certificate = ctx.ReadBuffer(0); + const auto ascii_password = [&ctx] { + if (ctx.CanReadBuffer(1)) { + return ctx.ReadBuffer(1); + } + + return std::vector<u8>{}; + }(); + + constexpr u64 client_id = 0; + + LOG_WARNING(Service_SSL, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + rb.Push(client_id); + } }; class SSL final : public ServiceFramework<SSL> { |