diff options
Diffstat (limited to 'src')
85 files changed, 2041 insertions, 1096 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1e1245160..a45439481 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt | |||
| @@ -5,6 +5,7 @@ add_subdirectory(common) | |||
| 5 | add_subdirectory(core) | 5 | add_subdirectory(core) |
| 6 | add_subdirectory(video_core) | 6 | add_subdirectory(video_core) |
| 7 | add_subdirectory(audio_core) | 7 | add_subdirectory(audio_core) |
| 8 | add_subdirectory(input_common) | ||
| 8 | add_subdirectory(tests) | 9 | add_subdirectory(tests) |
| 9 | if (ENABLE_SDL2) | 10 | if (ENABLE_SDL2) |
| 10 | add_subdirectory(citra) | 11 | add_subdirectory(citra) |
diff --git a/src/citra/CMakeLists.txt b/src/citra/CMakeLists.txt index ecb5d2dfe..47231ba71 100644 --- a/src/citra/CMakeLists.txt +++ b/src/citra/CMakeLists.txt | |||
| @@ -18,7 +18,7 @@ create_directory_groups(${SRCS} ${HEADERS}) | |||
| 18 | include_directories(${SDL2_INCLUDE_DIR}) | 18 | include_directories(${SDL2_INCLUDE_DIR}) |
| 19 | 19 | ||
| 20 | add_executable(citra ${SRCS} ${HEADERS}) | 20 | add_executable(citra ${SRCS} ${HEADERS}) |
| 21 | target_link_libraries(citra core video_core audio_core common) | 21 | target_link_libraries(citra core video_core audio_core common input_common) |
| 22 | target_link_libraries(citra ${SDL2_LIBRARY} ${OPENGL_gl_LIBRARY} inih glad) | 22 | target_link_libraries(citra ${SDL2_LIBRARY} ${OPENGL_gl_LIBRARY} inih glad) |
| 23 | if (MSVC) | 23 | if (MSVC) |
| 24 | target_link_libraries(citra getopt) | 24 | target_link_libraries(citra getopt) |
diff --git a/src/citra/config.cpp b/src/citra/config.cpp index fac1c9a0e..a4162e9ad 100644 --- a/src/citra/config.cpp +++ b/src/citra/config.cpp | |||
| @@ -8,8 +8,10 @@ | |||
| 8 | #include "citra/default_ini.h" | 8 | #include "citra/default_ini.h" |
| 9 | #include "common/file_util.h" | 9 | #include "common/file_util.h" |
| 10 | #include "common/logging/log.h" | 10 | #include "common/logging/log.h" |
| 11 | #include "common/param_package.h" | ||
| 11 | #include "config.h" | 12 | #include "config.h" |
| 12 | #include "core/settings.h" | 13 | #include "core/settings.h" |
| 14 | #include "input_common/main.h" | ||
| 13 | 15 | ||
| 14 | Config::Config() { | 16 | Config::Config() { |
| 15 | // TODO: Don't hardcode the path; let the frontend decide where to put the config files. | 17 | // TODO: Don't hardcode the path; let the frontend decide where to put the config files. |
| @@ -37,25 +39,40 @@ bool Config::LoadINI(const std::string& default_contents, bool retry) { | |||
| 37 | return true; | 39 | return true; |
| 38 | } | 40 | } |
| 39 | 41 | ||
| 40 | static const std::array<int, Settings::NativeInput::NUM_INPUTS> defaults = { | 42 | static const std::array<int, Settings::NativeButton::NumButtons> default_buttons = { |
| 41 | // directly mapped keys | 43 | SDL_SCANCODE_A, SDL_SCANCODE_S, SDL_SCANCODE_Z, SDL_SCANCODE_X, SDL_SCANCODE_T, |
| 42 | SDL_SCANCODE_A, SDL_SCANCODE_S, SDL_SCANCODE_Z, SDL_SCANCODE_X, SDL_SCANCODE_Q, SDL_SCANCODE_W, | 44 | SDL_SCANCODE_G, SDL_SCANCODE_F, SDL_SCANCODE_H, SDL_SCANCODE_Q, SDL_SCANCODE_W, |
| 43 | SDL_SCANCODE_1, SDL_SCANCODE_2, SDL_SCANCODE_M, SDL_SCANCODE_N, SDL_SCANCODE_B, SDL_SCANCODE_T, | 45 | SDL_SCANCODE_M, SDL_SCANCODE_N, SDL_SCANCODE_1, SDL_SCANCODE_2, SDL_SCANCODE_B, |
| 44 | SDL_SCANCODE_G, SDL_SCANCODE_F, SDL_SCANCODE_H, SDL_SCANCODE_I, SDL_SCANCODE_K, SDL_SCANCODE_J, | ||
| 45 | SDL_SCANCODE_L, | ||
| 46 | |||
| 47 | // indirectly mapped keys | ||
| 48 | SDL_SCANCODE_UP, SDL_SCANCODE_DOWN, SDL_SCANCODE_LEFT, SDL_SCANCODE_RIGHT, SDL_SCANCODE_D, | ||
| 49 | }; | 46 | }; |
| 50 | 47 | ||
| 48 | static const std::array<std::array<int, 5>, Settings::NativeAnalog::NumAnalogs> default_analogs{{ | ||
| 49 | { | ||
| 50 | SDL_SCANCODE_UP, SDL_SCANCODE_DOWN, SDL_SCANCODE_LEFT, SDL_SCANCODE_RIGHT, SDL_SCANCODE_D, | ||
| 51 | }, | ||
| 52 | { | ||
| 53 | SDL_SCANCODE_I, SDL_SCANCODE_K, SDL_SCANCODE_J, SDL_SCANCODE_L, SDL_SCANCODE_D, | ||
| 54 | }, | ||
| 55 | }}; | ||
| 56 | |||
| 51 | void Config::ReadValues() { | 57 | void Config::ReadValues() { |
| 52 | // Controls | 58 | // Controls |
| 53 | for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) { | 59 | for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { |
| 54 | Settings::values.input_mappings[Settings::NativeInput::All[i]] = | 60 | std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); |
| 55 | sdl2_config->GetInteger("Controls", Settings::NativeInput::Mapping[i], defaults[i]); | 61 | Settings::values.buttons[i] = |
| 62 | sdl2_config->Get("Controls", Settings::NativeButton::mapping[i], default_param); | ||
| 63 | if (Settings::values.buttons[i].empty()) | ||
| 64 | Settings::values.buttons[i] = default_param; | ||
| 65 | } | ||
| 66 | |||
| 67 | for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { | ||
| 68 | std::string default_param = InputCommon::GenerateAnalogParamFromKeys( | ||
| 69 | default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], | ||
| 70 | default_analogs[i][3], default_analogs[i][4], 0.5f); | ||
| 71 | Settings::values.analogs[i] = | ||
| 72 | sdl2_config->Get("Controls", Settings::NativeAnalog::mapping[i], default_param); | ||
| 73 | if (Settings::values.analogs[i].empty()) | ||
| 74 | Settings::values.analogs[i] = default_param; | ||
| 56 | } | 75 | } |
| 57 | Settings::values.pad_circle_modifier_scale = | ||
| 58 | (float)sdl2_config->GetReal("Controls", "pad_circle_modifier_scale", 0.5); | ||
| 59 | 76 | ||
| 60 | // Core | 77 | // Core |
| 61 | Settings::values.use_cpu_jit = sdl2_config->GetBoolean("Core", "use_cpu_jit", true); | 78 | Settings::values.use_cpu_jit = sdl2_config->GetBoolean("Core", "use_cpu_jit", true); |
| @@ -77,6 +94,23 @@ void Config::ReadValues() { | |||
| 77 | Settings::values.layout_option = | 94 | Settings::values.layout_option = |
| 78 | static_cast<Settings::LayoutOption>(sdl2_config->GetInteger("Layout", "layout_option", 0)); | 95 | static_cast<Settings::LayoutOption>(sdl2_config->GetInteger("Layout", "layout_option", 0)); |
| 79 | Settings::values.swap_screen = sdl2_config->GetBoolean("Layout", "swap_screen", false); | 96 | Settings::values.swap_screen = sdl2_config->GetBoolean("Layout", "swap_screen", false); |
| 97 | Settings::values.custom_layout = sdl2_config->GetBoolean("Layout", "custom_layout", false); | ||
| 98 | Settings::values.custom_top_left = | ||
| 99 | static_cast<u16>(sdl2_config->GetInteger("Layout", "custom_top_left", 0)); | ||
| 100 | Settings::values.custom_top_top = | ||
| 101 | static_cast<u16>(sdl2_config->GetInteger("Layout", "custom_top_top", 0)); | ||
| 102 | Settings::values.custom_top_right = | ||
| 103 | static_cast<u16>(sdl2_config->GetInteger("Layout", "custom_top_right", 400)); | ||
| 104 | Settings::values.custom_top_bottom = | ||
| 105 | static_cast<u16>(sdl2_config->GetInteger("Layout", "custom_top_bottom", 240)); | ||
| 106 | Settings::values.custom_bottom_left = | ||
| 107 | static_cast<u16>(sdl2_config->GetInteger("Layout", "custom_bottom_left", 40)); | ||
| 108 | Settings::values.custom_bottom_top = | ||
| 109 | static_cast<u16>(sdl2_config->GetInteger("Layout", "custom_bottom_top", 240)); | ||
| 110 | Settings::values.custom_bottom_right = | ||
| 111 | static_cast<u16>(sdl2_config->GetInteger("Layout", "custom_bottom_right", 360)); | ||
| 112 | Settings::values.custom_bottom_bottom = | ||
| 113 | static_cast<u16>(sdl2_config->GetInteger("Layout", "custom_bottom_bottom", 480)); | ||
| 80 | 114 | ||
| 81 | // Audio | 115 | // Audio |
| 82 | Settings::values.sink_id = sdl2_config->Get("Audio", "output_engine", "auto"); | 116 | Settings::values.sink_id = sdl2_config->Get("Audio", "output_engine", "auto"); |
diff --git a/src/citra/default_ini.h b/src/citra/default_ini.h index 435ba6f00..084372df4 100644 --- a/src/citra/default_ini.h +++ b/src/citra/default_ini.h | |||
| @@ -8,34 +8,47 @@ namespace DefaultINI { | |||
| 8 | 8 | ||
| 9 | const char* sdl2_config_file = R"( | 9 | const char* sdl2_config_file = R"( |
| 10 | [Controls] | 10 | [Controls] |
| 11 | pad_start = | 11 | # The input devices and parameters for each 3DS native input |
| 12 | pad_select = | 12 | # It should be in the format of "engine:[engine_name],[param1]:[value1],[param2]:[value2]..." |
| 13 | pad_home = | 13 | # Escape characters $0 (for ':'), $1 (for ',') and $2 (for '$') can be used in values |
| 14 | pad_dup = | 14 | |
| 15 | pad_ddown = | 15 | # for button input, the following devices are avaible: |
| 16 | pad_dleft = | 16 | # - "keyboard" (default) for keyboard input. Required parameters: |
| 17 | pad_dright = | 17 | # - "code": the code of the key to bind |
| 18 | pad_a = | 18 | # - "sdl" for joystick input using SDL. Required parameters: |
| 19 | pad_b = | 19 | # - "joystick": the index of the joystick to bind |
| 20 | pad_x = | 20 | # - "button"(optional): the index of the button to bind |
| 21 | pad_y = | 21 | # - "hat"(optional): the index of the hat to bind as direction buttons |
| 22 | pad_l = | 22 | # - "direction"(only used for hat): the direction name of the hat to bind. Can be "up", "down", "left" or "right" |
| 23 | pad_r = | 23 | button_a= |
| 24 | pad_zl = | 24 | button_b= |
| 25 | pad_zr = | 25 | button_x= |
| 26 | pad_cup = | 26 | button_y= |
| 27 | pad_cdown = | 27 | button_up= |
| 28 | pad_cleft = | 28 | button_down= |
| 29 | pad_cright = | 29 | button_left= |
| 30 | pad_circle_up = | 30 | button_right= |
| 31 | pad_circle_down = | 31 | button_l= |
| 32 | pad_circle_left = | 32 | button_r= |
| 33 | pad_circle_right = | 33 | button_start= |
| 34 | pad_circle_modifier = | 34 | button_select= |
| 35 | 35 | button_zl= | |
| 36 | # The applied modifier scale to circle pad. | 36 | button_zr= |
| 37 | # Must be in range of 0.0-1.0. Defaults to 0.5 | 37 | button_home= |
| 38 | pad_circle_modifier_scale = | 38 | |
| 39 | # for analog input, the following devices are avaible: | ||
| 40 | # - "analog_from_button" (default) for emulating analog input from direction buttons. Required parameters: | ||
| 41 | # - "up", "down", "left", "right": sub-devices for each direction. | ||
| 42 | # Should be in the format as a button input devices using escape characters, for example, "engine$0keyboard$1code$00" | ||
| 43 | # - "modifier": sub-devices as a modifier. | ||
| 44 | # - "modifier_scale": a float number representing the applied modifier scale to the analog input. | ||
| 45 | # Must be in range of 0.0-1.0. Defaults to 0.5 | ||
| 46 | # - "sdl" for joystick input using SDL. Required parameters: | ||
| 47 | # - "joystick": the index of the joystick to bind | ||
| 48 | # - "axis_x": the index of the axis to bind as x-axis (default to 0) | ||
| 49 | # - "axis_y": the index of the axis to bind as y-axis (default to 1) | ||
| 50 | circle_pad= | ||
| 51 | c_stick= | ||
| 39 | 52 | ||
| 40 | [Core] | 53 | [Core] |
| 41 | # Whether to use the Just-In-Time (JIT) compiler for CPU emulation | 54 | # Whether to use the Just-In-Time (JIT) compiler for CPU emulation |
| @@ -71,6 +84,21 @@ bg_green = | |||
| 71 | # 0 (default): Default Top Bottom Screen, 1: Single Screen Only, 2: Large Screen Small Screen | 84 | # 0 (default): Default Top Bottom Screen, 1: Single Screen Only, 2: Large Screen Small Screen |
| 72 | layout_option = | 85 | layout_option = |
| 73 | 86 | ||
| 87 | # Toggle custom layout (using the settings below) on or off. | ||
| 88 | # 0 (default): Off , 1: On | ||
| 89 | custom_layout = | ||
| 90 | |||
| 91 | # Screen placement when using Custom layout option | ||
| 92 | # 0x, 0y is the top left corner of the render window. | ||
| 93 | custom_top_left = | ||
| 94 | custom_top_top = | ||
| 95 | custom_top_right = | ||
| 96 | custom_top_bottom = | ||
| 97 | custom_bottom_left = | ||
| 98 | custom_bottom_top = | ||
| 99 | custom_bottom_right = | ||
| 100 | custom_bottom_bottom = | ||
| 101 | |||
| 74 | #Whether to toggle frame limiter on or off. | 102 | #Whether to toggle frame limiter on or off. |
| 75 | # 0: Off , 1 (default): On | 103 | # 0: Off , 1 (default): On |
| 76 | toggle_framelimit = | 104 | toggle_framelimit = |
diff --git a/src/citra/emu_window/emu_window_sdl2.cpp b/src/citra/emu_window/emu_window_sdl2.cpp index 00d00905a..6bc0b0d00 100644 --- a/src/citra/emu_window/emu_window_sdl2.cpp +++ b/src/citra/emu_window/emu_window_sdl2.cpp | |||
| @@ -12,9 +12,9 @@ | |||
| 12 | #include "common/logging/log.h" | 12 | #include "common/logging/log.h" |
| 13 | #include "common/scm_rev.h" | 13 | #include "common/scm_rev.h" |
| 14 | #include "common/string_util.h" | 14 | #include "common/string_util.h" |
| 15 | #include "core/frontend/key_map.h" | ||
| 16 | #include "core/hle/service/hid/hid.h" | ||
| 17 | #include "core/settings.h" | 15 | #include "core/settings.h" |
| 16 | #include "input_common/keyboard.h" | ||
| 17 | #include "input_common/main.h" | ||
| 18 | #include "video_core/video_core.h" | 18 | #include "video_core/video_core.h" |
| 19 | 19 | ||
| 20 | void EmuWindow_SDL2::OnMouseMotion(s32 x, s32 y) { | 20 | void EmuWindow_SDL2::OnMouseMotion(s32 x, s32 y) { |
| @@ -40,9 +40,9 @@ void EmuWindow_SDL2::OnMouseButton(u32 button, u8 state, s32 x, s32 y) { | |||
| 40 | 40 | ||
| 41 | void EmuWindow_SDL2::OnKeyEvent(int key, u8 state) { | 41 | void EmuWindow_SDL2::OnKeyEvent(int key, u8 state) { |
| 42 | if (state == SDL_PRESSED) { | 42 | if (state == SDL_PRESSED) { |
| 43 | KeyMap::PressKey(*this, {key, keyboard_id}); | 43 | InputCommon::GetKeyboard()->PressKey(key); |
| 44 | } else if (state == SDL_RELEASED) { | 44 | } else if (state == SDL_RELEASED) { |
| 45 | KeyMap::ReleaseKey(*this, {key, keyboard_id}); | 45 | InputCommon::GetKeyboard()->ReleaseKey(key); |
| 46 | } | 46 | } |
| 47 | } | 47 | } |
| 48 | 48 | ||
| @@ -57,9 +57,8 @@ void EmuWindow_SDL2::OnResize() { | |||
| 57 | } | 57 | } |
| 58 | 58 | ||
| 59 | EmuWindow_SDL2::EmuWindow_SDL2() { | 59 | EmuWindow_SDL2::EmuWindow_SDL2() { |
| 60 | keyboard_id = KeyMap::NewDeviceId(); | 60 | InputCommon::Init(); |
| 61 | 61 | ||
| 62 | ReloadSetKeymaps(); | ||
| 63 | motion_emu = std::make_unique<Motion::MotionEmu>(*this); | 62 | motion_emu = std::make_unique<Motion::MotionEmu>(*this); |
| 64 | 63 | ||
| 65 | SDL_SetMainReady(); | 64 | SDL_SetMainReady(); |
| @@ -117,6 +116,7 @@ EmuWindow_SDL2::~EmuWindow_SDL2() { | |||
| 117 | SDL_GL_DeleteContext(gl_context); | 116 | SDL_GL_DeleteContext(gl_context); |
| 118 | SDL_Quit(); | 117 | SDL_Quit(); |
| 119 | motion_emu = nullptr; | 118 | motion_emu = nullptr; |
| 119 | InputCommon::Shutdown(); | ||
| 120 | } | 120 | } |
| 121 | 121 | ||
| 122 | void EmuWindow_SDL2::SwapBuffers() { | 122 | void EmuWindow_SDL2::SwapBuffers() { |
| @@ -169,15 +169,6 @@ void EmuWindow_SDL2::DoneCurrent() { | |||
| 169 | SDL_GL_MakeCurrent(render_window, nullptr); | 169 | SDL_GL_MakeCurrent(render_window, nullptr); |
| 170 | } | 170 | } |
| 171 | 171 | ||
| 172 | void EmuWindow_SDL2::ReloadSetKeymaps() { | ||
| 173 | KeyMap::ClearKeyMapping(keyboard_id); | ||
| 174 | for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) { | ||
| 175 | KeyMap::SetKeyMapping( | ||
| 176 | {Settings::values.input_mappings[Settings::NativeInput::All[i]], keyboard_id}, | ||
| 177 | KeyMap::mapping_targets[i]); | ||
| 178 | } | ||
| 179 | } | ||
| 180 | |||
| 181 | void EmuWindow_SDL2::OnMinimalClientAreaChangeRequest( | 172 | void EmuWindow_SDL2::OnMinimalClientAreaChangeRequest( |
| 182 | const std::pair<unsigned, unsigned>& minimal_size) { | 173 | const std::pair<unsigned, unsigned>& minimal_size) { |
| 183 | 174 | ||
diff --git a/src/citra/emu_window/emu_window_sdl2.h b/src/citra/emu_window/emu_window_sdl2.h index b1cbf16d7..1ce2991f7 100644 --- a/src/citra/emu_window/emu_window_sdl2.h +++ b/src/citra/emu_window/emu_window_sdl2.h | |||
| @@ -31,9 +31,6 @@ public: | |||
| 31 | /// Whether the window is still open, and a close request hasn't yet been sent | 31 | /// Whether the window is still open, and a close request hasn't yet been sent |
| 32 | bool IsOpen() const; | 32 | bool IsOpen() const; |
| 33 | 33 | ||
| 34 | /// Load keymap from configuration | ||
| 35 | void ReloadSetKeymaps() override; | ||
| 36 | |||
| 37 | private: | 34 | private: |
| 38 | /// Called by PollEvents when a key is pressed or released. | 35 | /// Called by PollEvents when a key is pressed or released. |
| 39 | void OnKeyEvent(int key, u8 state); | 36 | void OnKeyEvent(int key, u8 state); |
| @@ -61,9 +58,6 @@ private: | |||
| 61 | /// The OpenGL context associated with the window | 58 | /// The OpenGL context associated with the window |
| 62 | SDL_GLContext gl_context; | 59 | SDL_GLContext gl_context; |
| 63 | 60 | ||
| 64 | /// Device id of keyboard for use with KeyMap | ||
| 65 | int keyboard_id; | ||
| 66 | |||
| 67 | /// Motion sensors emulation | 61 | /// Motion sensors emulation |
| 68 | std::unique_ptr<Motion::MotionEmu> motion_emu; | 62 | std::unique_ptr<Motion::MotionEmu> motion_emu; |
| 69 | }; | 63 | }; |
diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt index 15a6ccf9a..3e6106f0a 100644 --- a/src/citra_qt/CMakeLists.txt +++ b/src/citra_qt/CMakeLists.txt | |||
| @@ -3,7 +3,14 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) | |||
| 3 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/CMakeModules) | 3 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/CMakeModules) |
| 4 | 4 | ||
| 5 | set(SRCS | 5 | set(SRCS |
| 6 | config.cpp | 6 | configuration/config.cpp |
| 7 | configuration/configure_audio.cpp | ||
| 8 | configuration/configure_debug.cpp | ||
| 9 | configuration/configure_dialog.cpp | ||
| 10 | configuration/configure_general.cpp | ||
| 11 | configuration/configure_graphics.cpp | ||
| 12 | configuration/configure_input.cpp | ||
| 13 | configuration/configure_system.cpp | ||
| 7 | debugger/callstack.cpp | 14 | debugger/callstack.cpp |
| 8 | debugger/disassembler.cpp | 15 | debugger/disassembler.cpp |
| 9 | debugger/graphics/graphics.cpp | 16 | debugger/graphics/graphics.cpp |
| @@ -19,13 +26,6 @@ set(SRCS | |||
| 19 | util/spinbox.cpp | 26 | util/spinbox.cpp |
| 20 | util/util.cpp | 27 | util/util.cpp |
| 21 | bootmanager.cpp | 28 | bootmanager.cpp |
| 22 | configure_audio.cpp | ||
| 23 | configure_debug.cpp | ||
| 24 | configure_dialog.cpp | ||
| 25 | configure_general.cpp | ||
| 26 | configure_graphics.cpp | ||
| 27 | configure_system.cpp | ||
| 28 | configure_input.cpp | ||
| 29 | game_list.cpp | 29 | game_list.cpp |
| 30 | hotkeys.cpp | 30 | hotkeys.cpp |
| 31 | main.cpp | 31 | main.cpp |
| @@ -35,7 +35,14 @@ set(SRCS | |||
| 35 | ) | 35 | ) |
| 36 | 36 | ||
| 37 | set(HEADERS | 37 | set(HEADERS |
| 38 | config.h | 38 | configuration/config.h |
| 39 | configuration/configure_audio.h | ||
| 40 | configuration/configure_debug.h | ||
| 41 | configuration/configure_dialog.h | ||
| 42 | configuration/configure_general.h | ||
| 43 | configuration/configure_graphics.h | ||
| 44 | configuration/configure_input.h | ||
| 45 | configuration/configure_system.h | ||
| 39 | debugger/callstack.h | 46 | debugger/callstack.h |
| 40 | debugger/disassembler.h | 47 | debugger/disassembler.h |
| 41 | debugger/graphics/graphics.h | 48 | debugger/graphics/graphics.h |
| @@ -52,13 +59,6 @@ set(HEADERS | |||
| 52 | util/spinbox.h | 59 | util/spinbox.h |
| 53 | util/util.h | 60 | util/util.h |
| 54 | bootmanager.h | 61 | bootmanager.h |
| 55 | configure_audio.h | ||
| 56 | configure_debug.h | ||
| 57 | configure_dialog.h | ||
| 58 | configure_general.h | ||
| 59 | configure_graphics.h | ||
| 60 | configure_system.h | ||
| 61 | configure_input.h | ||
| 62 | game_list.h | 62 | game_list.h |
| 63 | game_list_p.h | 63 | game_list_p.h |
| 64 | hotkeys.h | 64 | hotkeys.h |
| @@ -67,16 +67,16 @@ set(HEADERS | |||
| 67 | ) | 67 | ) |
| 68 | 68 | ||
| 69 | set(UIS | 69 | set(UIS |
| 70 | configuration/configure.ui | ||
| 71 | configuration/configure_audio.ui | ||
| 72 | configuration/configure_debug.ui | ||
| 73 | configuration/configure_general.ui | ||
| 74 | configuration/configure_graphics.ui | ||
| 75 | configuration/configure_input.ui | ||
| 76 | configuration/configure_system.ui | ||
| 70 | debugger/callstack.ui | 77 | debugger/callstack.ui |
| 71 | debugger/disassembler.ui | 78 | debugger/disassembler.ui |
| 72 | debugger/registers.ui | 79 | debugger/registers.ui |
| 73 | configure.ui | ||
| 74 | configure_audio.ui | ||
| 75 | configure_debug.ui | ||
| 76 | configure_general.ui | ||
| 77 | configure_graphics.ui | ||
| 78 | configure_system.ui | ||
| 79 | configure_input.ui | ||
| 80 | hotkeys.ui | 80 | hotkeys.ui |
| 81 | main.ui | 81 | main.ui |
| 82 | ) | 82 | ) |
| @@ -97,7 +97,7 @@ if (APPLE) | |||
| 97 | else() | 97 | else() |
| 98 | add_executable(citra-qt ${SRCS} ${HEADERS} ${UI_HDRS}) | 98 | add_executable(citra-qt ${SRCS} ${HEADERS} ${UI_HDRS}) |
| 99 | endif() | 99 | endif() |
| 100 | target_link_libraries(citra-qt core video_core audio_core common) | 100 | target_link_libraries(citra-qt core video_core audio_core common input_common) |
| 101 | target_link_libraries(citra-qt ${OPENGL_gl_LIBRARY} ${CITRA_QT_LIBS}) | 101 | target_link_libraries(citra-qt ${OPENGL_gl_LIBRARY} ${CITRA_QT_LIBS}) |
| 102 | target_link_libraries(citra-qt ${PLATFORM_LIBRARIES} Threads::Threads) | 102 | target_link_libraries(citra-qt ${PLATFORM_LIBRARIES} Threads::Threads) |
| 103 | 103 | ||
diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp index 69d18cf0c..bae576d6a 100644 --- a/src/citra_qt/bootmanager.cpp +++ b/src/citra_qt/bootmanager.cpp | |||
| @@ -13,7 +13,9 @@ | |||
| 13 | #include "common/scm_rev.h" | 13 | #include "common/scm_rev.h" |
| 14 | #include "common/string_util.h" | 14 | #include "common/string_util.h" |
| 15 | #include "core/core.h" | 15 | #include "core/core.h" |
| 16 | #include "core/frontend/key_map.h" | 16 | #include "core/settings.h" |
| 17 | #include "input_common/keyboard.h" | ||
| 18 | #include "input_common/main.h" | ||
| 17 | #include "video_core/debug_utils/debug_utils.h" | 19 | #include "video_core/debug_utils/debug_utils.h" |
| 18 | #include "video_core/video_core.h" | 20 | #include "video_core/video_core.h" |
| 19 | 21 | ||
| @@ -99,14 +101,17 @@ private: | |||
| 99 | }; | 101 | }; |
| 100 | 102 | ||
| 101 | GRenderWindow::GRenderWindow(QWidget* parent, EmuThread* emu_thread) | 103 | GRenderWindow::GRenderWindow(QWidget* parent, EmuThread* emu_thread) |
| 102 | : QWidget(parent), child(nullptr), keyboard_id(0), emu_thread(emu_thread) { | 104 | : QWidget(parent), child(nullptr), emu_thread(emu_thread) { |
| 103 | 105 | ||
| 104 | std::string window_title = Common::StringFromFormat("Citra %s| %s-%s", Common::g_build_name, | 106 | std::string window_title = Common::StringFromFormat("Citra %s| %s-%s", Common::g_build_name, |
| 105 | Common::g_scm_branch, Common::g_scm_desc); | 107 | Common::g_scm_branch, Common::g_scm_desc); |
| 106 | setWindowTitle(QString::fromStdString(window_title)); | 108 | setWindowTitle(QString::fromStdString(window_title)); |
| 107 | 109 | ||
| 108 | keyboard_id = KeyMap::NewDeviceId(); | 110 | InputCommon::Init(); |
| 109 | ReloadSetKeymaps(); | 111 | } |
| 112 | |||
| 113 | GRenderWindow::~GRenderWindow() { | ||
| 114 | InputCommon::Shutdown(); | ||
| 110 | } | 115 | } |
| 111 | 116 | ||
| 112 | void GRenderWindow::moveContext() { | 117 | void GRenderWindow::moveContext() { |
| @@ -197,11 +202,11 @@ void GRenderWindow::closeEvent(QCloseEvent* event) { | |||
| 197 | } | 202 | } |
| 198 | 203 | ||
| 199 | void GRenderWindow::keyPressEvent(QKeyEvent* event) { | 204 | void GRenderWindow::keyPressEvent(QKeyEvent* event) { |
| 200 | KeyMap::PressKey(*this, {event->key(), keyboard_id}); | 205 | InputCommon::GetKeyboard()->PressKey(event->key()); |
| 201 | } | 206 | } |
| 202 | 207 | ||
| 203 | void GRenderWindow::keyReleaseEvent(QKeyEvent* event) { | 208 | void GRenderWindow::keyReleaseEvent(QKeyEvent* event) { |
| 204 | KeyMap::ReleaseKey(*this, {event->key(), keyboard_id}); | 209 | InputCommon::GetKeyboard()->ReleaseKey(event->key()); |
| 205 | } | 210 | } |
| 206 | 211 | ||
| 207 | void GRenderWindow::mousePressEvent(QMouseEvent* event) { | 212 | void GRenderWindow::mousePressEvent(QMouseEvent* event) { |
| @@ -230,13 +235,9 @@ void GRenderWindow::mouseReleaseEvent(QMouseEvent* event) { | |||
| 230 | motion_emu->EndTilt(); | 235 | motion_emu->EndTilt(); |
| 231 | } | 236 | } |
| 232 | 237 | ||
| 233 | void GRenderWindow::ReloadSetKeymaps() { | 238 | void GRenderWindow::focusOutEvent(QFocusEvent* event) { |
| 234 | KeyMap::ClearKeyMapping(keyboard_id); | 239 | QWidget::focusOutEvent(event); |
| 235 | for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) { | 240 | InputCommon::GetKeyboard()->ReleaseAllKeys(); |
| 236 | KeyMap::SetKeyMapping( | ||
| 237 | {Settings::values.input_mappings[Settings::NativeInput::All[i]], keyboard_id}, | ||
| 238 | KeyMap::mapping_targets[i]); | ||
| 239 | } | ||
| 240 | } | 241 | } |
| 241 | 242 | ||
| 242 | void GRenderWindow::OnClientAreaResized(unsigned width, unsigned height) { | 243 | void GRenderWindow::OnClientAreaResized(unsigned width, unsigned height) { |
diff --git a/src/citra_qt/bootmanager.h b/src/citra_qt/bootmanager.h index 7dac1c480..9d39f1af8 100644 --- a/src/citra_qt/bootmanager.h +++ b/src/citra_qt/bootmanager.h | |||
| @@ -104,6 +104,7 @@ class GRenderWindow : public QWidget, public EmuWindow { | |||
| 104 | 104 | ||
| 105 | public: | 105 | public: |
| 106 | GRenderWindow(QWidget* parent, EmuThread* emu_thread); | 106 | GRenderWindow(QWidget* parent, EmuThread* emu_thread); |
| 107 | ~GRenderWindow(); | ||
| 107 | 108 | ||
| 108 | // EmuWindow implementation | 109 | // EmuWindow implementation |
| 109 | void SwapBuffers() override; | 110 | void SwapBuffers() override; |
| @@ -127,7 +128,7 @@ public: | |||
| 127 | void mouseMoveEvent(QMouseEvent* event) override; | 128 | void mouseMoveEvent(QMouseEvent* event) override; |
| 128 | void mouseReleaseEvent(QMouseEvent* event) override; | 129 | void mouseReleaseEvent(QMouseEvent* event) override; |
| 129 | 130 | ||
| 130 | void ReloadSetKeymaps() override; | 131 | void focusOutEvent(QFocusEvent* event) override; |
| 131 | 132 | ||
| 132 | void OnClientAreaResized(unsigned width, unsigned height); | 133 | void OnClientAreaResized(unsigned width, unsigned height); |
| 133 | 134 | ||
| @@ -152,9 +153,6 @@ private: | |||
| 152 | 153 | ||
| 153 | QByteArray geometry; | 154 | QByteArray geometry; |
| 154 | 155 | ||
| 155 | /// Device id of keyboard for use with KeyMap | ||
| 156 | int keyboard_id; | ||
| 157 | |||
| 158 | EmuThread* emu_thread; | 156 | EmuThread* emu_thread; |
| 159 | 157 | ||
| 160 | /// Motion sensors emulation | 158 | /// Motion sensors emulation |
diff --git a/src/citra_qt/config.cpp b/src/citra_qt/configuration/config.cpp index 5fe57dfa2..0b9b73f9e 100644 --- a/src/citra_qt/config.cpp +++ b/src/citra_qt/configuration/config.cpp | |||
| @@ -3,9 +3,10 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <QSettings> | 5 | #include <QSettings> |
| 6 | #include "citra_qt/config.h" | 6 | #include "citra_qt/configuration/config.h" |
| 7 | #include "citra_qt/ui_settings.h" | 7 | #include "citra_qt/ui_settings.h" |
| 8 | #include "common/file_util.h" | 8 | #include "common/file_util.h" |
| 9 | #include "input_common/main.h" | ||
| 9 | 10 | ||
| 10 | Config::Config() { | 11 | Config::Config() { |
| 11 | // TODO: Don't hardcode the path; let the frontend decide where to put the config files. | 12 | // TODO: Don't hardcode the path; let the frontend decide where to put the config files. |
| @@ -16,25 +17,46 @@ Config::Config() { | |||
| 16 | Reload(); | 17 | Reload(); |
| 17 | } | 18 | } |
| 18 | 19 | ||
| 19 | const std::array<QVariant, Settings::NativeInput::NUM_INPUTS> Config::defaults = { | 20 | const std::array<int, Settings::NativeButton::NumButtons> Config::default_buttons = { |
| 20 | // directly mapped keys | 21 | Qt::Key_A, Qt::Key_S, Qt::Key_Z, Qt::Key_X, Qt::Key_T, Qt::Key_G, Qt::Key_F, Qt::Key_H, |
| 21 | Qt::Key_A, Qt::Key_S, Qt::Key_Z, Qt::Key_X, Qt::Key_Q, Qt::Key_W, Qt::Key_1, Qt::Key_2, | 22 | Qt::Key_Q, Qt::Key_W, Qt::Key_M, Qt::Key_N, Qt::Key_1, Qt::Key_2, Qt::Key_B, |
| 22 | Qt::Key_M, Qt::Key_N, Qt::Key_B, Qt::Key_T, Qt::Key_G, Qt::Key_F, Qt::Key_H, Qt::Key_I, | ||
| 23 | Qt::Key_K, Qt::Key_J, Qt::Key_L, | ||
| 24 | |||
| 25 | // indirectly mapped keys | ||
| 26 | Qt::Key_Up, Qt::Key_Down, Qt::Key_Left, Qt::Key_Right, Qt::Key_D, | ||
| 27 | }; | 23 | }; |
| 28 | 24 | ||
| 25 | const std::array<std::array<int, 5>, Settings::NativeAnalog::NumAnalogs> Config::default_analogs{{ | ||
| 26 | { | ||
| 27 | Qt::Key_Up, Qt::Key_Down, Qt::Key_Left, Qt::Key_Right, Qt::Key_D, | ||
| 28 | }, | ||
| 29 | { | ||
| 30 | Qt::Key_I, Qt::Key_K, Qt::Key_J, Qt::Key_L, Qt::Key_D, | ||
| 31 | }, | ||
| 32 | }}; | ||
| 33 | |||
| 29 | void Config::ReadValues() { | 34 | void Config::ReadValues() { |
| 30 | qt_config->beginGroup("Controls"); | 35 | qt_config->beginGroup("Controls"); |
| 31 | for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) { | 36 | for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { |
| 32 | Settings::values.input_mappings[Settings::NativeInput::All[i]] = | 37 | std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); |
| 33 | qt_config->value(QString::fromStdString(Settings::NativeInput::Mapping[i]), defaults[i]) | 38 | Settings::values.buttons[i] = |
| 34 | .toInt(); | 39 | qt_config |
| 40 | ->value(Settings::NativeButton::mapping[i], QString::fromStdString(default_param)) | ||
| 41 | .toString() | ||
| 42 | .toStdString(); | ||
| 43 | if (Settings::values.buttons[i].empty()) | ||
| 44 | Settings::values.buttons[i] = default_param; | ||
| 45 | } | ||
| 46 | |||
| 47 | for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { | ||
| 48 | std::string default_param = InputCommon::GenerateAnalogParamFromKeys( | ||
| 49 | default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], | ||
| 50 | default_analogs[i][3], default_analogs[i][4], 0.5f); | ||
| 51 | Settings::values.analogs[i] = | ||
| 52 | qt_config | ||
| 53 | ->value(Settings::NativeAnalog::mapping[i], QString::fromStdString(default_param)) | ||
| 54 | .toString() | ||
| 55 | .toStdString(); | ||
| 56 | if (Settings::values.analogs[i].empty()) | ||
| 57 | Settings::values.analogs[i] = default_param; | ||
| 35 | } | 58 | } |
| 36 | Settings::values.pad_circle_modifier_scale = | 59 | |
| 37 | qt_config->value("pad_circle_modifier_scale", 0.5).toFloat(); | ||
| 38 | qt_config->endGroup(); | 60 | qt_config->endGroup(); |
| 39 | 61 | ||
| 40 | qt_config->beginGroup("Core"); | 62 | qt_config->beginGroup("Core"); |
| @@ -57,6 +79,15 @@ void Config::ReadValues() { | |||
| 57 | Settings::values.layout_option = | 79 | Settings::values.layout_option = |
| 58 | static_cast<Settings::LayoutOption>(qt_config->value("layout_option").toInt()); | 80 | static_cast<Settings::LayoutOption>(qt_config->value("layout_option").toInt()); |
| 59 | Settings::values.swap_screen = qt_config->value("swap_screen", false).toBool(); | 81 | Settings::values.swap_screen = qt_config->value("swap_screen", false).toBool(); |
| 82 | Settings::values.custom_layout = qt_config->value("custom_layout", false).toBool(); | ||
| 83 | Settings::values.custom_top_left = qt_config->value("custom_top_left", 0).toInt(); | ||
| 84 | Settings::values.custom_top_top = qt_config->value("custom_top_top", 0).toInt(); | ||
| 85 | Settings::values.custom_top_right = qt_config->value("custom_top_right", 400).toInt(); | ||
| 86 | Settings::values.custom_top_bottom = qt_config->value("custom_top_bottom", 240).toInt(); | ||
| 87 | Settings::values.custom_bottom_left = qt_config->value("custom_bottom_left", 40).toInt(); | ||
| 88 | Settings::values.custom_bottom_top = qt_config->value("custom_bottom_top", 240).toInt(); | ||
| 89 | Settings::values.custom_bottom_right = qt_config->value("custom_bottom_right", 360).toInt(); | ||
| 90 | Settings::values.custom_bottom_bottom = qt_config->value("custom_bottom_bottom", 480).toInt(); | ||
| 60 | qt_config->endGroup(); | 91 | qt_config->endGroup(); |
| 61 | 92 | ||
| 62 | qt_config->beginGroup("Audio"); | 93 | qt_config->beginGroup("Audio"); |
| @@ -155,12 +186,14 @@ void Config::ReadValues() { | |||
| 155 | 186 | ||
| 156 | void Config::SaveValues() { | 187 | void Config::SaveValues() { |
| 157 | qt_config->beginGroup("Controls"); | 188 | qt_config->beginGroup("Controls"); |
| 158 | for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) { | 189 | for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { |
| 159 | qt_config->setValue(QString::fromStdString(Settings::NativeInput::Mapping[i]), | 190 | qt_config->setValue(QString::fromStdString(Settings::NativeButton::mapping[i]), |
| 160 | Settings::values.input_mappings[Settings::NativeInput::All[i]]); | 191 | QString::fromStdString(Settings::values.buttons[i])); |
| 192 | } | ||
| 193 | for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { | ||
| 194 | qt_config->setValue(QString::fromStdString(Settings::NativeAnalog::mapping[i]), | ||
| 195 | QString::fromStdString(Settings::values.analogs[i])); | ||
| 161 | } | 196 | } |
| 162 | qt_config->setValue("pad_circle_modifier_scale", | ||
| 163 | (double)Settings::values.pad_circle_modifier_scale); | ||
| 164 | qt_config->endGroup(); | 197 | qt_config->endGroup(); |
| 165 | 198 | ||
| 166 | qt_config->beginGroup("Core"); | 199 | qt_config->beginGroup("Core"); |
| @@ -183,6 +216,15 @@ void Config::SaveValues() { | |||
| 183 | qt_config->beginGroup("Layout"); | 216 | qt_config->beginGroup("Layout"); |
| 184 | qt_config->setValue("layout_option", static_cast<int>(Settings::values.layout_option)); | 217 | qt_config->setValue("layout_option", static_cast<int>(Settings::values.layout_option)); |
| 185 | qt_config->setValue("swap_screen", Settings::values.swap_screen); | 218 | qt_config->setValue("swap_screen", Settings::values.swap_screen); |
| 219 | qt_config->setValue("custom_layout", Settings::values.custom_layout); | ||
| 220 | qt_config->setValue("custom_top_left", Settings::values.custom_top_left); | ||
| 221 | qt_config->setValue("custom_top_top", Settings::values.custom_top_top); | ||
| 222 | qt_config->setValue("custom_top_right", Settings::values.custom_top_right); | ||
| 223 | qt_config->setValue("custom_top_bottom", Settings::values.custom_top_bottom); | ||
| 224 | qt_config->setValue("custom_bottom_left", Settings::values.custom_bottom_left); | ||
| 225 | qt_config->setValue("custom_bottom_top", Settings::values.custom_bottom_top); | ||
| 226 | qt_config->setValue("custom_bottom_right", Settings::values.custom_bottom_right); | ||
| 227 | qt_config->setValue("custom_bottom_bottom", Settings::values.custom_bottom_bottom); | ||
| 186 | qt_config->endGroup(); | 228 | qt_config->endGroup(); |
| 187 | 229 | ||
| 188 | qt_config->beginGroup("Audio"); | 230 | qt_config->beginGroup("Audio"); |
diff --git a/src/citra_qt/config.h b/src/citra_qt/configuration/config.h index 79c901804..cbf745ea2 100644 --- a/src/citra_qt/config.h +++ b/src/citra_qt/configuration/config.h | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <array> | ||
| 7 | #include <string> | 8 | #include <string> |
| 8 | #include <QVariant> | 9 | #include <QVariant> |
| 9 | #include "core/settings.h" | 10 | #include "core/settings.h" |
| @@ -23,5 +24,7 @@ public: | |||
| 23 | 24 | ||
| 24 | void Reload(); | 25 | void Reload(); |
| 25 | void Save(); | 26 | void Save(); |
| 26 | static const std::array<QVariant, Settings::NativeInput::NUM_INPUTS> defaults; | 27 | |
| 28 | static const std::array<int, Settings::NativeButton::NumButtons> default_buttons; | ||
| 29 | static const std::array<std::array<int, 5>, Settings::NativeAnalog::NumAnalogs> default_analogs; | ||
| 27 | }; | 30 | }; |
diff --git a/src/citra_qt/configure.ui b/src/citra_qt/configuration/configure.ui index 28b4a3b90..85e206e42 100644 --- a/src/citra_qt/configure.ui +++ b/src/citra_qt/configuration/configure.ui | |||
| @@ -64,37 +64,37 @@ | |||
| 64 | <customwidget> | 64 | <customwidget> |
| 65 | <class>ConfigureGeneral</class> | 65 | <class>ConfigureGeneral</class> |
| 66 | <extends>QWidget</extends> | 66 | <extends>QWidget</extends> |
| 67 | <header>configure_general.h</header> | 67 | <header>configuration/configure_general.h</header> |
| 68 | <container>1</container> | 68 | <container>1</container> |
| 69 | </customwidget> | 69 | </customwidget> |
| 70 | <customwidget> | 70 | <customwidget> |
| 71 | <class>ConfigureSystem</class> | 71 | <class>ConfigureSystem</class> |
| 72 | <extends>QWidget</extends> | 72 | <extends>QWidget</extends> |
| 73 | <header>configure_system.h</header> | 73 | <header>configuration/configure_system.h</header> |
| 74 | <container>1</container> | 74 | <container>1</container> |
| 75 | </customwidget> | 75 | </customwidget> |
| 76 | <customwidget> | 76 | <customwidget> |
| 77 | <class>ConfigureAudio</class> | 77 | <class>ConfigureAudio</class> |
| 78 | <extends>QWidget</extends> | 78 | <extends>QWidget</extends> |
| 79 | <header>configure_audio.h</header> | 79 | <header>configuration/configure_audio.h</header> |
| 80 | <container>1</container> | 80 | <container>1</container> |
| 81 | </customwidget> | 81 | </customwidget> |
| 82 | <customwidget> | 82 | <customwidget> |
| 83 | <class>ConfigureDebug</class> | 83 | <class>ConfigureDebug</class> |
| 84 | <extends>QWidget</extends> | 84 | <extends>QWidget</extends> |
| 85 | <header>configure_debug.h</header> | 85 | <header>configuration/configure_debug.h</header> |
| 86 | <container>1</container> | 86 | <container>1</container> |
| 87 | </customwidget> | 87 | </customwidget> |
| 88 | <customwidget> | 88 | <customwidget> |
| 89 | <class>ConfigureInput</class> | 89 | <class>ConfigureInput</class> |
| 90 | <extends>QWidget</extends> | 90 | <extends>QWidget</extends> |
| 91 | <header>configure_input.h</header> | 91 | <header>configuration/configure_input.h</header> |
| 92 | <container>1</container> | 92 | <container>1</container> |
| 93 | </customwidget> | 93 | </customwidget> |
| 94 | <customwidget> | 94 | <customwidget> |
| 95 | <class>ConfigureGraphics</class> | 95 | <class>ConfigureGraphics</class> |
| 96 | <extends>QWidget</extends> | 96 | <extends>QWidget</extends> |
| 97 | <header>configure_graphics.h</header> | 97 | <header>configuration/configure_graphics.h</header> |
| 98 | <container>1</container> | 98 | <container>1</container> |
| 99 | </customwidget> | 99 | </customwidget> |
| 100 | </customwidgets> | 100 | </customwidgets> |
diff --git a/src/citra_qt/configure_audio.cpp b/src/citra_qt/configuration/configure_audio.cpp index 3ddcf9232..3fd1d127a 100644 --- a/src/citra_qt/configure_audio.cpp +++ b/src/citra_qt/configuration/configure_audio.cpp | |||
| @@ -6,7 +6,7 @@ | |||
| 6 | #include "audio_core/audio_core.h" | 6 | #include "audio_core/audio_core.h" |
| 7 | #include "audio_core/sink.h" | 7 | #include "audio_core/sink.h" |
| 8 | #include "audio_core/sink_details.h" | 8 | #include "audio_core/sink_details.h" |
| 9 | #include "citra_qt/configure_audio.h" | 9 | #include "citra_qt/configuration/configure_audio.h" |
| 10 | #include "core/settings.h" | 10 | #include "core/settings.h" |
| 11 | #include "ui_configure_audio.h" | 11 | #include "ui_configure_audio.h" |
| 12 | 12 | ||
diff --git a/src/citra_qt/configure_audio.h b/src/citra_qt/configuration/configure_audio.h index 8190e694f..8190e694f 100644 --- a/src/citra_qt/configure_audio.h +++ b/src/citra_qt/configuration/configure_audio.h | |||
diff --git a/src/citra_qt/configure_audio.ui b/src/citra_qt/configuration/configure_audio.ui index dd870eb61..dd870eb61 100644 --- a/src/citra_qt/configure_audio.ui +++ b/src/citra_qt/configuration/configure_audio.ui | |||
diff --git a/src/citra_qt/configure_debug.cpp b/src/citra_qt/configuration/configure_debug.cpp index dcc398eee..263f73f38 100644 --- a/src/citra_qt/configure_debug.cpp +++ b/src/citra_qt/configuration/configure_debug.cpp | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include "citra_qt/configure_debug.h" | 5 | #include "citra_qt/configuration/configure_debug.h" |
| 6 | #include "core/settings.h" | 6 | #include "core/settings.h" |
| 7 | #include "ui_configure_debug.h" | 7 | #include "ui_configure_debug.h" |
| 8 | 8 | ||
diff --git a/src/citra_qt/configure_debug.h b/src/citra_qt/configuration/configure_debug.h index d167eb996..d167eb996 100644 --- a/src/citra_qt/configure_debug.h +++ b/src/citra_qt/configuration/configure_debug.h | |||
diff --git a/src/citra_qt/configure_debug.ui b/src/citra_qt/configuration/configure_debug.ui index bbbb0e3f4..bbbb0e3f4 100644 --- a/src/citra_qt/configure_debug.ui +++ b/src/citra_qt/configuration/configure_debug.ui | |||
diff --git a/src/citra_qt/configure_dialog.cpp b/src/citra_qt/configuration/configure_dialog.cpp index 525a7cc4e..dfc8c03a7 100644 --- a/src/citra_qt/configure_dialog.cpp +++ b/src/citra_qt/configuration/configure_dialog.cpp | |||
| @@ -2,8 +2,8 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include "citra_qt/config.h" | 5 | #include "citra_qt/configuration/config.h" |
| 6 | #include "citra_qt/configure_dialog.h" | 6 | #include "citra_qt/configuration/configure_dialog.h" |
| 7 | #include "core/settings.h" | 7 | #include "core/settings.h" |
| 8 | #include "ui_configure.h" | 8 | #include "ui_configure.h" |
| 9 | 9 | ||
diff --git a/src/citra_qt/configure_dialog.h b/src/citra_qt/configuration/configure_dialog.h index 21fa1f501..21fa1f501 100644 --- a/src/citra_qt/configure_dialog.h +++ b/src/citra_qt/configuration/configure_dialog.h | |||
diff --git a/src/citra_qt/configure_general.cpp b/src/citra_qt/configuration/configure_general.cpp index ac90a6df4..a21176c34 100644 --- a/src/citra_qt/configure_general.cpp +++ b/src/citra_qt/configuration/configure_general.cpp | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include "citra_qt/configure_general.h" | 5 | #include "citra_qt/configuration/configure_general.h" |
| 6 | #include "citra_qt/ui_settings.h" | 6 | #include "citra_qt/ui_settings.h" |
| 7 | #include "core/core.h" | 7 | #include "core/core.h" |
| 8 | #include "core/settings.h" | 8 | #include "core/settings.h" |
diff --git a/src/citra_qt/configure_general.h b/src/citra_qt/configuration/configure_general.h index 447552d8c..447552d8c 100644 --- a/src/citra_qt/configure_general.h +++ b/src/citra_qt/configuration/configure_general.h | |||
diff --git a/src/citra_qt/configure_general.ui b/src/citra_qt/configuration/configure_general.ui index c739605a4..c739605a4 100644 --- a/src/citra_qt/configure_general.ui +++ b/src/citra_qt/configuration/configure_general.ui | |||
diff --git a/src/citra_qt/configure_graphics.cpp b/src/citra_qt/configuration/configure_graphics.cpp index 54f799b47..b5a5ab1e1 100644 --- a/src/citra_qt/configure_graphics.cpp +++ b/src/citra_qt/configuration/configure_graphics.cpp | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include "citra_qt/configure_graphics.h" | 5 | #include "citra_qt/configuration/configure_graphics.h" |
| 6 | #include "core/core.h" | 6 | #include "core/core.h" |
| 7 | #include "core/settings.h" | 7 | #include "core/settings.h" |
| 8 | #include "ui_configure_graphics.h" | 8 | #include "ui_configure_graphics.h" |
| @@ -14,6 +14,8 @@ ConfigureGraphics::ConfigureGraphics(QWidget* parent) | |||
| 14 | this->setConfiguration(); | 14 | this->setConfiguration(); |
| 15 | 15 | ||
| 16 | ui->toggle_vsync->setEnabled(!Core::System::GetInstance().IsPoweredOn()); | 16 | ui->toggle_vsync->setEnabled(!Core::System::GetInstance().IsPoweredOn()); |
| 17 | |||
| 18 | ui->layoutBox->setEnabled(!Settings::values.custom_layout); | ||
| 17 | } | 19 | } |
| 18 | 20 | ||
| 19 | ConfigureGraphics::~ConfigureGraphics() {} | 21 | ConfigureGraphics::~ConfigureGraphics() {} |
diff --git a/src/citra_qt/configure_graphics.h b/src/citra_qt/configuration/configure_graphics.h index 5497a55f7..5497a55f7 100644 --- a/src/citra_qt/configure_graphics.h +++ b/src/citra_qt/configuration/configure_graphics.h | |||
diff --git a/src/citra_qt/configure_graphics.ui b/src/citra_qt/configuration/configure_graphics.ui index a091f4c60..228f2a869 100644 --- a/src/citra_qt/configure_graphics.ui +++ b/src/citra_qt/configuration/configure_graphics.ui | |||
| @@ -126,7 +126,7 @@ | |||
| 126 | </layout> | 126 | </layout> |
| 127 | </item> | 127 | </item> |
| 128 | <item> | 128 | <item> |
| 129 | <widget class="QGroupBox" name="groupBox2"> | 129 | <widget class="QGroupBox" name="layoutBox"> |
| 130 | <property name="title"> | 130 | <property name="title"> |
| 131 | <string>Layout</string> | 131 | <string>Layout</string> |
| 132 | </property> | 132 | </property> |
diff --git a/src/citra_qt/configuration/configure_input.cpp b/src/citra_qt/configuration/configure_input.cpp new file mode 100644 index 000000000..daac9b63a --- /dev/null +++ b/src/citra_qt/configuration/configure_input.cpp | |||
| @@ -0,0 +1,205 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <algorithm> | ||
| 6 | #include <memory> | ||
| 7 | #include <utility> | ||
| 8 | #include <QTimer> | ||
| 9 | #include "citra_qt/configuration/config.h" | ||
| 10 | #include "citra_qt/configuration/configure_input.h" | ||
| 11 | #include "common/param_package.h" | ||
| 12 | #include "input_common/main.h" | ||
| 13 | |||
| 14 | const std::array<std::string, ConfigureInput::ANALOG_SUB_BUTTONS_NUM> | ||
| 15 | ConfigureInput::analog_sub_buttons{{ | ||
| 16 | "up", "down", "left", "right", "modifier", | ||
| 17 | }}; | ||
| 18 | |||
| 19 | static QString getKeyName(int key_code) { | ||
| 20 | switch (key_code) { | ||
| 21 | case Qt::Key_Shift: | ||
| 22 | return QObject::tr("Shift"); | ||
| 23 | case Qt::Key_Control: | ||
| 24 | return QObject::tr("Ctrl"); | ||
| 25 | case Qt::Key_Alt: | ||
| 26 | return QObject::tr("Alt"); | ||
| 27 | case Qt::Key_Meta: | ||
| 28 | return ""; | ||
| 29 | default: | ||
| 30 | return QKeySequence(key_code).toString(); | ||
| 31 | } | ||
| 32 | } | ||
| 33 | |||
| 34 | static void SetButtonKey(int key, Common::ParamPackage& button_param) { | ||
| 35 | button_param = Common::ParamPackage{InputCommon::GenerateKeyboardParam(key)}; | ||
| 36 | } | ||
| 37 | |||
| 38 | static void SetAnalogKey(int key, Common::ParamPackage& analog_param, | ||
| 39 | const std::string& button_name) { | ||
| 40 | if (analog_param.Get("engine", "") != "analog_from_button") { | ||
| 41 | analog_param = { | ||
| 42 | {"engine", "analog_from_button"}, {"modifier_scale", "0.5"}, | ||
| 43 | }; | ||
| 44 | } | ||
| 45 | analog_param.Set(button_name, InputCommon::GenerateKeyboardParam(key)); | ||
| 46 | } | ||
| 47 | |||
| 48 | ConfigureInput::ConfigureInput(QWidget* parent) | ||
| 49 | : QWidget(parent), ui(std::make_unique<Ui::ConfigureInput>()), | ||
| 50 | timer(std::make_unique<QTimer>()) { | ||
| 51 | |||
| 52 | ui->setupUi(this); | ||
| 53 | setFocusPolicy(Qt::ClickFocus); | ||
| 54 | |||
| 55 | button_map = { | ||
| 56 | ui->buttonA, ui->buttonB, ui->buttonX, ui->buttonY, ui->buttonDpadUp, | ||
| 57 | ui->buttonDpadDown, ui->buttonDpadLeft, ui->buttonDpadRight, ui->buttonL, ui->buttonR, | ||
| 58 | ui->buttonStart, ui->buttonSelect, ui->buttonZL, ui->buttonZR, ui->buttonHome, | ||
| 59 | }; | ||
| 60 | |||
| 61 | analog_map = {{ | ||
| 62 | { | ||
| 63 | ui->buttonCircleUp, ui->buttonCircleDown, ui->buttonCircleLeft, ui->buttonCircleRight, | ||
| 64 | ui->buttonCircleMod, | ||
| 65 | }, | ||
| 66 | { | ||
| 67 | ui->buttonCStickUp, ui->buttonCStickDown, ui->buttonCStickLeft, ui->buttonCStickRight, | ||
| 68 | nullptr, | ||
| 69 | }, | ||
| 70 | }}; | ||
| 71 | |||
| 72 | for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; button_id++) { | ||
| 73 | if (button_map[button_id]) | ||
| 74 | connect(button_map[button_id], &QPushButton::released, [=]() { | ||
| 75 | handleClick(button_map[button_id], | ||
| 76 | [=](int key) { SetButtonKey(key, buttons_param[button_id]); }); | ||
| 77 | }); | ||
| 78 | } | ||
| 79 | |||
| 80 | for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; analog_id++) { | ||
| 81 | for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; sub_button_id++) { | ||
| 82 | if (analog_map[analog_id][sub_button_id] != nullptr) { | ||
| 83 | connect(analog_map[analog_id][sub_button_id], &QPushButton::released, [=]() { | ||
| 84 | handleClick(analog_map[analog_id][sub_button_id], [=](int key) { | ||
| 85 | SetAnalogKey(key, analogs_param[analog_id], | ||
| 86 | analog_sub_buttons[sub_button_id]); | ||
| 87 | }); | ||
| 88 | }); | ||
| 89 | } | ||
| 90 | } | ||
| 91 | } | ||
| 92 | |||
| 93 | connect(ui->buttonRestoreDefaults, &QPushButton::released, [this]() { restoreDefaults(); }); | ||
| 94 | |||
| 95 | timer->setSingleShot(true); | ||
| 96 | connect(timer.get(), &QTimer::timeout, [this]() { | ||
| 97 | releaseKeyboard(); | ||
| 98 | releaseMouse(); | ||
| 99 | key_setter = boost::none; | ||
| 100 | updateButtonLabels(); | ||
| 101 | }); | ||
| 102 | |||
| 103 | this->loadConfiguration(); | ||
| 104 | |||
| 105 | // TODO(wwylele): enable these when the input emulation for them is implemented | ||
| 106 | ui->buttonZL->setEnabled(false); | ||
| 107 | ui->buttonZR->setEnabled(false); | ||
| 108 | ui->buttonHome->setEnabled(false); | ||
| 109 | ui->buttonCStickUp->setEnabled(false); | ||
| 110 | ui->buttonCStickDown->setEnabled(false); | ||
| 111 | ui->buttonCStickLeft->setEnabled(false); | ||
| 112 | ui->buttonCStickRight->setEnabled(false); | ||
| 113 | } | ||
| 114 | |||
| 115 | void ConfigureInput::applyConfiguration() { | ||
| 116 | std::transform(buttons_param.begin(), buttons_param.end(), Settings::values.buttons.begin(), | ||
| 117 | [](const Common::ParamPackage& param) { return param.Serialize(); }); | ||
| 118 | std::transform(analogs_param.begin(), analogs_param.end(), Settings::values.analogs.begin(), | ||
| 119 | [](const Common::ParamPackage& param) { return param.Serialize(); }); | ||
| 120 | |||
| 121 | Settings::Apply(); | ||
| 122 | } | ||
| 123 | |||
| 124 | void ConfigureInput::loadConfiguration() { | ||
| 125 | std::transform(Settings::values.buttons.begin(), Settings::values.buttons.end(), | ||
| 126 | buttons_param.begin(), | ||
| 127 | [](const std::string& str) { return Common::ParamPackage(str); }); | ||
| 128 | std::transform(Settings::values.analogs.begin(), Settings::values.analogs.end(), | ||
| 129 | analogs_param.begin(), | ||
| 130 | [](const std::string& str) { return Common::ParamPackage(str); }); | ||
| 131 | updateButtonLabels(); | ||
| 132 | } | ||
| 133 | |||
| 134 | void ConfigureInput::restoreDefaults() { | ||
| 135 | for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; button_id++) { | ||
| 136 | SetButtonKey(Config::default_buttons[button_id], buttons_param[button_id]); | ||
| 137 | } | ||
| 138 | |||
| 139 | for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; analog_id++) { | ||
| 140 | for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; sub_button_id++) { | ||
| 141 | SetAnalogKey(Config::default_analogs[analog_id][sub_button_id], | ||
| 142 | analogs_param[analog_id], analog_sub_buttons[sub_button_id]); | ||
| 143 | } | ||
| 144 | } | ||
| 145 | updateButtonLabels(); | ||
| 146 | applyConfiguration(); | ||
| 147 | } | ||
| 148 | |||
| 149 | void ConfigureInput::updateButtonLabels() { | ||
| 150 | QString non_keyboard(tr("[non-keyboard]")); | ||
| 151 | |||
| 152 | auto KeyToText = [&non_keyboard](const Common::ParamPackage& param) { | ||
| 153 | if (param.Get("engine", "") != "keyboard") { | ||
| 154 | return non_keyboard; | ||
| 155 | } else { | ||
| 156 | return getKeyName(param.Get("code", 0)); | ||
| 157 | } | ||
| 158 | }; | ||
| 159 | |||
| 160 | for (int button = 0; button < Settings::NativeButton::NumButtons; button++) { | ||
| 161 | button_map[button]->setText(KeyToText(buttons_param[button])); | ||
| 162 | } | ||
| 163 | |||
| 164 | for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; analog_id++) { | ||
| 165 | if (analogs_param[analog_id].Get("engine", "") != "analog_from_button") { | ||
| 166 | for (QPushButton* button : analog_map[analog_id]) { | ||
| 167 | if (button) | ||
| 168 | button->setText(non_keyboard); | ||
| 169 | } | ||
| 170 | } else { | ||
| 171 | for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; sub_button_id++) { | ||
| 172 | Common::ParamPackage param( | ||
| 173 | analogs_param[analog_id].Get(analog_sub_buttons[sub_button_id], "")); | ||
| 174 | if (analog_map[analog_id][sub_button_id]) | ||
| 175 | analog_map[analog_id][sub_button_id]->setText(KeyToText(param)); | ||
| 176 | } | ||
| 177 | } | ||
| 178 | } | ||
| 179 | } | ||
| 180 | |||
| 181 | void ConfigureInput::handleClick(QPushButton* button, std::function<void(int)> new_key_setter) { | ||
| 182 | button->setText(tr("[press key]")); | ||
| 183 | button->setFocus(); | ||
| 184 | |||
| 185 | key_setter = new_key_setter; | ||
| 186 | |||
| 187 | grabKeyboard(); | ||
| 188 | grabMouse(); | ||
| 189 | timer->start(5000); // Cancel after 5 seconds | ||
| 190 | } | ||
| 191 | |||
| 192 | void ConfigureInput::keyPressEvent(QKeyEvent* event) { | ||
| 193 | releaseKeyboard(); | ||
| 194 | releaseMouse(); | ||
| 195 | |||
| 196 | if (!key_setter || !event) | ||
| 197 | return; | ||
| 198 | |||
| 199 | if (event->key() != Qt::Key_Escape) | ||
| 200 | (*key_setter)(event->key()); | ||
| 201 | |||
| 202 | updateButtonLabels(); | ||
| 203 | key_setter = boost::none; | ||
| 204 | timer->stop(); | ||
| 205 | } | ||
diff --git a/src/citra_qt/configuration/configure_input.h b/src/citra_qt/configuration/configure_input.h new file mode 100644 index 000000000..c950fbcb4 --- /dev/null +++ b/src/citra_qt/configuration/configure_input.h | |||
| @@ -0,0 +1,69 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <array> | ||
| 8 | #include <functional> | ||
| 9 | #include <memory> | ||
| 10 | #include <string> | ||
| 11 | #include <QKeyEvent> | ||
| 12 | #include <QWidget> | ||
| 13 | #include <boost/optional.hpp> | ||
| 14 | #include "common/param_package.h" | ||
| 15 | #include "core/settings.h" | ||
| 16 | #include "ui_configure_input.h" | ||
| 17 | |||
| 18 | class QPushButton; | ||
| 19 | class QString; | ||
| 20 | class QTimer; | ||
| 21 | |||
| 22 | namespace Ui { | ||
| 23 | class ConfigureInput; | ||
| 24 | } | ||
| 25 | |||
| 26 | class ConfigureInput : public QWidget { | ||
| 27 | Q_OBJECT | ||
| 28 | |||
| 29 | public: | ||
| 30 | explicit ConfigureInput(QWidget* parent = nullptr); | ||
| 31 | |||
| 32 | /// Save all button configurations to settings file | ||
| 33 | void applyConfiguration(); | ||
| 34 | |||
| 35 | private: | ||
| 36 | std::unique_ptr<Ui::ConfigureInput> ui; | ||
| 37 | |||
| 38 | std::unique_ptr<QTimer> timer; | ||
| 39 | |||
| 40 | /// This will be the the setting function when an input is awaiting configuration. | ||
| 41 | boost::optional<std::function<void(int)>> key_setter; | ||
| 42 | |||
| 43 | std::array<Common::ParamPackage, Settings::NativeButton::NumButtons> buttons_param; | ||
| 44 | std::array<Common::ParamPackage, Settings::NativeAnalog::NumAnalogs> analogs_param; | ||
| 45 | |||
| 46 | static constexpr int ANALOG_SUB_BUTTONS_NUM = 5; | ||
| 47 | |||
| 48 | /// Each button input is represented by a QPushButton. | ||
| 49 | std::array<QPushButton*, Settings::NativeButton::NumButtons> button_map; | ||
| 50 | |||
| 51 | /// Each analog input is represented by five QPushButtons which represents up, down, left, right | ||
| 52 | /// and modifier | ||
| 53 | std::array<std::array<QPushButton*, ANALOG_SUB_BUTTONS_NUM>, Settings::NativeAnalog::NumAnalogs> | ||
| 54 | analog_map; | ||
| 55 | |||
| 56 | static const std::array<std::string, ANALOG_SUB_BUTTONS_NUM> analog_sub_buttons; | ||
| 57 | |||
| 58 | /// Load configuration settings. | ||
| 59 | void loadConfiguration(); | ||
| 60 | /// Restore all buttons to their default values. | ||
| 61 | void restoreDefaults(); | ||
| 62 | /// Update UI to reflect current configuration. | ||
| 63 | void updateButtonLabels(); | ||
| 64 | |||
| 65 | /// Called when the button was pressed. | ||
| 66 | void handleClick(QPushButton* button, std::function<void(int)> new_key_setter); | ||
| 67 | /// Handle key press events. | ||
| 68 | void keyPressEvent(QKeyEvent* event) override; | ||
| 69 | }; | ||
diff --git a/src/citra_qt/configure_input.ui b/src/citra_qt/configuration/configure_input.ui index 2760787e5..2760787e5 100644 --- a/src/citra_qt/configure_input.ui +++ b/src/citra_qt/configuration/configure_input.ui | |||
diff --git a/src/citra_qt/configure_system.cpp b/src/citra_qt/configuration/configure_system.cpp index 040185e82..a3a9015a4 100644 --- a/src/citra_qt/configure_system.cpp +++ b/src/citra_qt/configuration/configure_system.cpp | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include "citra_qt/configure_system.h" | 5 | #include "citra_qt/configuration/configure_system.h" |
| 6 | #include "citra_qt/ui_settings.h" | 6 | #include "citra_qt/ui_settings.h" |
| 7 | #include "core/core.h" | 7 | #include "core/core.h" |
| 8 | #include "core/hle/service/cfg/cfg.h" | 8 | #include "core/hle/service/cfg/cfg.h" |
diff --git a/src/citra_qt/configure_system.h b/src/citra_qt/configuration/configure_system.h index db0ead13c..db0ead13c 100644 --- a/src/citra_qt/configure_system.h +++ b/src/citra_qt/configuration/configure_system.h | |||
diff --git a/src/citra_qt/configure_system.ui b/src/citra_qt/configuration/configure_system.ui index cc54fa37f..cc54fa37f 100644 --- a/src/citra_qt/configure_system.ui +++ b/src/citra_qt/configuration/configure_system.ui | |||
diff --git a/src/citra_qt/configure_input.cpp b/src/citra_qt/configure_input.cpp deleted file mode 100644 index c29652f32..000000000 --- a/src/citra_qt/configure_input.cpp +++ /dev/null | |||
| @@ -1,145 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <memory> | ||
| 6 | #include <utility> | ||
| 7 | #include <QTimer> | ||
| 8 | #include "citra_qt/config.h" | ||
| 9 | #include "citra_qt/configure_input.h" | ||
| 10 | |||
| 11 | static QString getKeyName(Qt::Key key_code) { | ||
| 12 | switch (key_code) { | ||
| 13 | case Qt::Key_Shift: | ||
| 14 | return QObject::tr("Shift"); | ||
| 15 | case Qt::Key_Control: | ||
| 16 | return QObject::tr("Ctrl"); | ||
| 17 | case Qt::Key_Alt: | ||
| 18 | return QObject::tr("Alt"); | ||
| 19 | case Qt::Key_Meta: | ||
| 20 | return ""; | ||
| 21 | default: | ||
| 22 | return QKeySequence(key_code).toString(); | ||
| 23 | } | ||
| 24 | } | ||
| 25 | |||
| 26 | ConfigureInput::ConfigureInput(QWidget* parent) | ||
| 27 | : QWidget(parent), ui(std::make_unique<Ui::ConfigureInput>()), | ||
| 28 | timer(std::make_unique<QTimer>()) { | ||
| 29 | |||
| 30 | ui->setupUi(this); | ||
| 31 | setFocusPolicy(Qt::ClickFocus); | ||
| 32 | |||
| 33 | button_map = { | ||
| 34 | {Settings::NativeInput::Values::A, ui->buttonA}, | ||
| 35 | {Settings::NativeInput::Values::B, ui->buttonB}, | ||
| 36 | {Settings::NativeInput::Values::X, ui->buttonX}, | ||
| 37 | {Settings::NativeInput::Values::Y, ui->buttonY}, | ||
| 38 | {Settings::NativeInput::Values::L, ui->buttonL}, | ||
| 39 | {Settings::NativeInput::Values::R, ui->buttonR}, | ||
| 40 | {Settings::NativeInput::Values::ZL, ui->buttonZL}, | ||
| 41 | {Settings::NativeInput::Values::ZR, ui->buttonZR}, | ||
| 42 | {Settings::NativeInput::Values::START, ui->buttonStart}, | ||
| 43 | {Settings::NativeInput::Values::SELECT, ui->buttonSelect}, | ||
| 44 | {Settings::NativeInput::Values::HOME, ui->buttonHome}, | ||
| 45 | {Settings::NativeInput::Values::DUP, ui->buttonDpadUp}, | ||
| 46 | {Settings::NativeInput::Values::DDOWN, ui->buttonDpadDown}, | ||
| 47 | {Settings::NativeInput::Values::DLEFT, ui->buttonDpadLeft}, | ||
| 48 | {Settings::NativeInput::Values::DRIGHT, ui->buttonDpadRight}, | ||
| 49 | {Settings::NativeInput::Values::CUP, ui->buttonCStickUp}, | ||
| 50 | {Settings::NativeInput::Values::CDOWN, ui->buttonCStickDown}, | ||
| 51 | {Settings::NativeInput::Values::CLEFT, ui->buttonCStickLeft}, | ||
| 52 | {Settings::NativeInput::Values::CRIGHT, ui->buttonCStickRight}, | ||
| 53 | {Settings::NativeInput::Values::CIRCLE_UP, ui->buttonCircleUp}, | ||
| 54 | {Settings::NativeInput::Values::CIRCLE_DOWN, ui->buttonCircleDown}, | ||
| 55 | {Settings::NativeInput::Values::CIRCLE_LEFT, ui->buttonCircleLeft}, | ||
| 56 | {Settings::NativeInput::Values::CIRCLE_RIGHT, ui->buttonCircleRight}, | ||
| 57 | {Settings::NativeInput::Values::CIRCLE_MODIFIER, ui->buttonCircleMod}, | ||
| 58 | }; | ||
| 59 | |||
| 60 | for (const auto& entry : button_map) { | ||
| 61 | const Settings::NativeInput::Values input_id = entry.first; | ||
| 62 | connect(entry.second, &QPushButton::released, | ||
| 63 | [this, input_id]() { handleClick(input_id); }); | ||
| 64 | } | ||
| 65 | |||
| 66 | connect(ui->buttonRestoreDefaults, &QPushButton::released, [this]() { restoreDefaults(); }); | ||
| 67 | |||
| 68 | timer->setSingleShot(true); | ||
| 69 | connect(timer.get(), &QTimer::timeout, [this]() { | ||
| 70 | releaseKeyboard(); | ||
| 71 | releaseMouse(); | ||
| 72 | current_input_id = boost::none; | ||
| 73 | updateButtonLabels(); | ||
| 74 | }); | ||
| 75 | |||
| 76 | this->loadConfiguration(); | ||
| 77 | } | ||
| 78 | |||
| 79 | void ConfigureInput::applyConfiguration() { | ||
| 80 | for (const auto& input_id : Settings::NativeInput::All) { | ||
| 81 | const size_t index = static_cast<size_t>(input_id); | ||
| 82 | Settings::values.input_mappings[index] = static_cast<int>(key_map[input_id]); | ||
| 83 | } | ||
| 84 | Settings::Apply(); | ||
| 85 | } | ||
| 86 | |||
| 87 | void ConfigureInput::loadConfiguration() { | ||
| 88 | for (const auto& input_id : Settings::NativeInput::All) { | ||
| 89 | const size_t index = static_cast<size_t>(input_id); | ||
| 90 | key_map[input_id] = static_cast<Qt::Key>(Settings::values.input_mappings[index]); | ||
| 91 | } | ||
| 92 | updateButtonLabels(); | ||
| 93 | } | ||
| 94 | |||
| 95 | void ConfigureInput::restoreDefaults() { | ||
| 96 | for (const auto& input_id : Settings::NativeInput::All) { | ||
| 97 | const size_t index = static_cast<size_t>(input_id); | ||
| 98 | key_map[input_id] = static_cast<Qt::Key>(Config::defaults[index].toInt()); | ||
| 99 | } | ||
| 100 | updateButtonLabels(); | ||
| 101 | applyConfiguration(); | ||
| 102 | } | ||
| 103 | |||
| 104 | void ConfigureInput::updateButtonLabels() { | ||
| 105 | for (const auto& input_id : Settings::NativeInput::All) { | ||
| 106 | button_map[input_id]->setText(getKeyName(key_map[input_id])); | ||
| 107 | } | ||
| 108 | } | ||
| 109 | |||
| 110 | void ConfigureInput::handleClick(Settings::NativeInput::Values input_id) { | ||
| 111 | QPushButton* button = button_map[input_id]; | ||
| 112 | button->setText(tr("[press key]")); | ||
| 113 | button->setFocus(); | ||
| 114 | |||
| 115 | current_input_id = input_id; | ||
| 116 | |||
| 117 | grabKeyboard(); | ||
| 118 | grabMouse(); | ||
| 119 | timer->start(5000); // Cancel after 5 seconds | ||
| 120 | } | ||
| 121 | |||
| 122 | void ConfigureInput::keyPressEvent(QKeyEvent* event) { | ||
| 123 | releaseKeyboard(); | ||
| 124 | releaseMouse(); | ||
| 125 | |||
| 126 | if (!current_input_id || !event) | ||
| 127 | return; | ||
| 128 | |||
| 129 | if (event->key() != Qt::Key_Escape) | ||
| 130 | setInput(*current_input_id, static_cast<Qt::Key>(event->key())); | ||
| 131 | |||
| 132 | updateButtonLabels(); | ||
| 133 | current_input_id = boost::none; | ||
| 134 | timer->stop(); | ||
| 135 | } | ||
| 136 | |||
| 137 | void ConfigureInput::setInput(Settings::NativeInput::Values input_id, Qt::Key key_pressed) { | ||
| 138 | // Remove duplicates | ||
| 139 | for (auto& pair : key_map) { | ||
| 140 | if (pair.second == key_pressed) | ||
| 141 | pair.second = Qt::Key_unknown; | ||
| 142 | } | ||
| 143 | |||
| 144 | key_map[input_id] = key_pressed; | ||
| 145 | } | ||
diff --git a/src/citra_qt/configure_input.h b/src/citra_qt/configure_input.h deleted file mode 100644 index bc343db83..000000000 --- a/src/citra_qt/configure_input.h +++ /dev/null | |||
| @@ -1,57 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <memory> | ||
| 8 | #include <QKeyEvent> | ||
| 9 | #include <QWidget> | ||
| 10 | #include <boost/optional.hpp> | ||
| 11 | #include "core/settings.h" | ||
| 12 | #include "ui_configure_input.h" | ||
| 13 | |||
| 14 | class QPushButton; | ||
| 15 | class QString; | ||
| 16 | class QTimer; | ||
| 17 | |||
| 18 | namespace Ui { | ||
| 19 | class ConfigureInput; | ||
| 20 | } | ||
| 21 | |||
| 22 | class ConfigureInput : public QWidget { | ||
| 23 | Q_OBJECT | ||
| 24 | |||
| 25 | public: | ||
| 26 | explicit ConfigureInput(QWidget* parent = nullptr); | ||
| 27 | |||
| 28 | /// Save all button configurations to settings file | ||
| 29 | void applyConfiguration(); | ||
| 30 | |||
| 31 | private: | ||
| 32 | std::unique_ptr<Ui::ConfigureInput> ui; | ||
| 33 | |||
| 34 | /// This input is currently awaiting configuration. | ||
| 35 | /// (i.e.: its corresponding QPushButton has been pressed.) | ||
| 36 | boost::optional<Settings::NativeInput::Values> current_input_id; | ||
| 37 | std::unique_ptr<QTimer> timer; | ||
| 38 | |||
| 39 | /// Each input is represented by a QPushButton. | ||
| 40 | std::map<Settings::NativeInput::Values, QPushButton*> button_map; | ||
| 41 | /// Each input is configured to respond to the press of a Qt::Key. | ||
| 42 | std::map<Settings::NativeInput::Values, Qt::Key> key_map; | ||
| 43 | |||
| 44 | /// Load configuration settings. | ||
| 45 | void loadConfiguration(); | ||
| 46 | /// Restore all buttons to their default values. | ||
| 47 | void restoreDefaults(); | ||
| 48 | /// Update UI to reflect current configuration. | ||
| 49 | void updateButtonLabels(); | ||
| 50 | |||
| 51 | /// Called when the button corresponding to input_id was pressed. | ||
| 52 | void handleClick(Settings::NativeInput::Values input_id); | ||
| 53 | /// Handle key press events. | ||
| 54 | void keyPressEvent(QKeyEvent* event) override; | ||
| 55 | /// Configure input input_id to respond to key key_pressed. | ||
| 56 | void setInput(Settings::NativeInput::Values input_id, Qt::Key key_pressed); | ||
| 57 | }; | ||
diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index fd51659b9..73b4dd34f 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp | |||
| @@ -14,8 +14,8 @@ | |||
| 14 | #include <QtGui> | 14 | #include <QtGui> |
| 15 | #include <QtWidgets> | 15 | #include <QtWidgets> |
| 16 | #include "citra_qt/bootmanager.h" | 16 | #include "citra_qt/bootmanager.h" |
| 17 | #include "citra_qt/config.h" | 17 | #include "citra_qt/configuration/config.h" |
| 18 | #include "citra_qt/configure_dialog.h" | 18 | #include "citra_qt/configuration/configure_dialog.h" |
| 19 | #include "citra_qt/debugger/callstack.h" | 19 | #include "citra_qt/debugger/callstack.h" |
| 20 | #include "citra_qt/debugger/disassembler.h" | 20 | #include "citra_qt/debugger/disassembler.h" |
| 21 | #include "citra_qt/debugger/graphics/graphics.h" | 21 | #include "citra_qt/debugger/graphics/graphics.h" |
| @@ -612,7 +612,6 @@ void GMainWindow::OnConfigure() { | |||
| 612 | auto result = configureDialog.exec(); | 612 | auto result = configureDialog.exec(); |
| 613 | if (result == QDialog::Accepted) { | 613 | if (result == QDialog::Accepted) { |
| 614 | configureDialog.applyConfiguration(); | 614 | configureDialog.applyConfiguration(); |
| 615 | render_window->ReloadSetKeymaps(); | ||
| 616 | config->Save(); | 615 | config->Save(); |
| 617 | } | 616 | } |
| 618 | } | 617 | } |
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 8a6170257..13277a5c2 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt | |||
| @@ -35,6 +35,7 @@ set(SRCS | |||
| 35 | memory_util.cpp | 35 | memory_util.cpp |
| 36 | microprofile.cpp | 36 | microprofile.cpp |
| 37 | misc.cpp | 37 | misc.cpp |
| 38 | param_package.cpp | ||
| 38 | scm_rev.cpp | 39 | scm_rev.cpp |
| 39 | string_util.cpp | 40 | string_util.cpp |
| 40 | symbols.cpp | 41 | symbols.cpp |
| @@ -66,6 +67,7 @@ set(HEADERS | |||
| 66 | memory_util.h | 67 | memory_util.h |
| 67 | microprofile.h | 68 | microprofile.h |
| 68 | microprofileui.h | 69 | microprofileui.h |
| 70 | param_package.h | ||
| 69 | platform.h | 71 | platform.h |
| 70 | quaternion.h | 72 | quaternion.h |
| 71 | scm_rev.h | 73 | scm_rev.h |
diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp index df234c225..5ab036b34 100644 --- a/src/common/file_util.cpp +++ b/src/common/file_util.cpp | |||
| @@ -118,8 +118,7 @@ bool IsDirectory(const std::string& filename) { | |||
| 118 | #endif | 118 | #endif |
| 119 | 119 | ||
| 120 | if (result < 0) { | 120 | if (result < 0) { |
| 121 | LOG_WARNING(Common_Filesystem, "stat failed on %s: %s", filename.c_str(), | 121 | LOG_DEBUG(Common_Filesystem, "stat failed on %s: %s", filename.c_str(), GetLastErrorMsg()); |
| 122 | GetLastErrorMsg()); | ||
| 123 | return false; | 122 | return false; |
| 124 | } | 123 | } |
| 125 | 124 | ||
| @@ -129,12 +128,12 @@ bool IsDirectory(const std::string& filename) { | |||
| 129 | // Deletes a given filename, return true on success | 128 | // Deletes a given filename, return true on success |
| 130 | // Doesn't supports deleting a directory | 129 | // Doesn't supports deleting a directory |
| 131 | bool Delete(const std::string& filename) { | 130 | bool Delete(const std::string& filename) { |
| 132 | LOG_INFO(Common_Filesystem, "file %s", filename.c_str()); | 131 | LOG_TRACE(Common_Filesystem, "file %s", filename.c_str()); |
| 133 | 132 | ||
| 134 | // Return true because we care about the file no | 133 | // Return true because we care about the file no |
| 135 | // being there, not the actual delete. | 134 | // being there, not the actual delete. |
| 136 | if (!Exists(filename)) { | 135 | if (!Exists(filename)) { |
| 137 | LOG_WARNING(Common_Filesystem, "%s does not exist", filename.c_str()); | 136 | LOG_DEBUG(Common_Filesystem, "%s does not exist", filename.c_str()); |
| 138 | return true; | 137 | return true; |
| 139 | } | 138 | } |
| 140 | 139 | ||
| @@ -169,8 +168,7 @@ bool CreateDir(const std::string& path) { | |||
| 169 | return true; | 168 | return true; |
| 170 | DWORD error = GetLastError(); | 169 | DWORD error = GetLastError(); |
| 171 | if (error == ERROR_ALREADY_EXISTS) { | 170 | if (error == ERROR_ALREADY_EXISTS) { |
| 172 | LOG_WARNING(Common_Filesystem, "CreateDirectory failed on %s: already exists", | 171 | LOG_DEBUG(Common_Filesystem, "CreateDirectory failed on %s: already exists", path.c_str()); |
| 173 | path.c_str()); | ||
| 174 | return true; | 172 | return true; |
| 175 | } | 173 | } |
| 176 | LOG_ERROR(Common_Filesystem, "CreateDirectory failed on %s: %i", path.c_str(), error); | 174 | LOG_ERROR(Common_Filesystem, "CreateDirectory failed on %s: %i", path.c_str(), error); |
| @@ -182,7 +180,7 @@ bool CreateDir(const std::string& path) { | |||
| 182 | int err = errno; | 180 | int err = errno; |
| 183 | 181 | ||
| 184 | if (err == EEXIST) { | 182 | if (err == EEXIST) { |
| 185 | LOG_WARNING(Common_Filesystem, "mkdir failed on %s: already exists", path.c_str()); | 183 | LOG_DEBUG(Common_Filesystem, "mkdir failed on %s: already exists", path.c_str()); |
| 186 | return true; | 184 | return true; |
| 187 | } | 185 | } |
| 188 | 186 | ||
| @@ -197,7 +195,7 @@ bool CreateFullPath(const std::string& fullPath) { | |||
| 197 | LOG_TRACE(Common_Filesystem, "path %s", fullPath.c_str()); | 195 | LOG_TRACE(Common_Filesystem, "path %s", fullPath.c_str()); |
| 198 | 196 | ||
| 199 | if (FileUtil::Exists(fullPath)) { | 197 | if (FileUtil::Exists(fullPath)) { |
| 200 | LOG_WARNING(Common_Filesystem, "path exists %s", fullPath.c_str()); | 198 | LOG_DEBUG(Common_Filesystem, "path exists %s", fullPath.c_str()); |
| 201 | return true; | 199 | return true; |
| 202 | } | 200 | } |
| 203 | 201 | ||
| @@ -229,7 +227,7 @@ bool CreateFullPath(const std::string& fullPath) { | |||
| 229 | 227 | ||
| 230 | // Deletes a directory filename, returns true on success | 228 | // Deletes a directory filename, returns true on success |
| 231 | bool DeleteDir(const std::string& filename) { | 229 | bool DeleteDir(const std::string& filename) { |
| 232 | LOG_INFO(Common_Filesystem, "directory %s", filename.c_str()); | 230 | LOG_TRACE(Common_Filesystem, "directory %s", filename.c_str()); |
| 233 | 231 | ||
| 234 | // check if a directory | 232 | // check if a directory |
| 235 | if (!FileUtil::IsDirectory(filename)) { | 233 | if (!FileUtil::IsDirectory(filename)) { |
| @@ -693,6 +691,8 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string& new | |||
| 693 | paths[D_USER_IDX] = GetExeDirectory() + DIR_SEP USERDATA_DIR DIR_SEP; | 691 | paths[D_USER_IDX] = GetExeDirectory() + DIR_SEP USERDATA_DIR DIR_SEP; |
| 694 | if (!FileUtil::IsDirectory(paths[D_USER_IDX])) { | 692 | if (!FileUtil::IsDirectory(paths[D_USER_IDX])) { |
| 695 | paths[D_USER_IDX] = AppDataRoamingDirectory() + DIR_SEP EMU_DATA_DIR DIR_SEP; | 693 | paths[D_USER_IDX] = AppDataRoamingDirectory() + DIR_SEP EMU_DATA_DIR DIR_SEP; |
| 694 | } else { | ||
| 695 | LOG_INFO(Common_Filesystem, "Using the local user directory"); | ||
| 696 | } | 696 | } |
| 697 | 697 | ||
| 698 | paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP; | 698 | paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP; |
diff --git a/src/common/framebuffer_layout.cpp b/src/common/framebuffer_layout.cpp index 46c008d9c..a2a0e7dad 100644 --- a/src/common/framebuffer_layout.cpp +++ b/src/common/framebuffer_layout.cpp | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | 6 | ||
| 7 | #include "common/assert.h" | 7 | #include "common/assert.h" |
| 8 | #include "common/framebuffer_layout.h" | 8 | #include "common/framebuffer_layout.h" |
| 9 | #include "core/settings.h" | ||
| 9 | #include "video_core/video_core.h" | 10 | #include "video_core/video_core.h" |
| 10 | 11 | ||
| 11 | namespace Layout { | 12 | namespace Layout { |
| @@ -135,4 +136,22 @@ FramebufferLayout LargeFrameLayout(unsigned width, unsigned height, bool swapped | |||
| 135 | res.bottom_screen = swapped ? large_screen : small_screen; | 136 | res.bottom_screen = swapped ? large_screen : small_screen; |
| 136 | return res; | 137 | return res; |
| 137 | } | 138 | } |
| 139 | |||
| 140 | FramebufferLayout CustomFrameLayout(unsigned width, unsigned height) { | ||
| 141 | ASSERT(width > 0); | ||
| 142 | ASSERT(height > 0); | ||
| 143 | |||
| 144 | FramebufferLayout res{width, height, true, true, {}, {}}; | ||
| 145 | |||
| 146 | MathUtil::Rectangle<unsigned> top_screen{ | ||
| 147 | Settings::values.custom_top_left, Settings::values.custom_top_top, | ||
| 148 | Settings::values.custom_top_right, Settings::values.custom_top_bottom}; | ||
| 149 | MathUtil::Rectangle<unsigned> bot_screen{ | ||
| 150 | Settings::values.custom_bottom_left, Settings::values.custom_bottom_top, | ||
| 151 | Settings::values.custom_bottom_right, Settings::values.custom_bottom_bottom}; | ||
| 152 | |||
| 153 | res.top_screen = top_screen; | ||
| 154 | res.bottom_screen = bot_screen; | ||
| 155 | return res; | ||
| 156 | } | ||
| 138 | } | 157 | } |
diff --git a/src/common/framebuffer_layout.h b/src/common/framebuffer_layout.h index a125646a3..f1df5c55a 100644 --- a/src/common/framebuffer_layout.h +++ b/src/common/framebuffer_layout.h | |||
| @@ -44,4 +44,12 @@ FramebufferLayout SingleFrameLayout(unsigned width, unsigned height, bool is_swa | |||
| 44 | * @return Newly created FramebufferLayout object with default screen regions initialized | 44 | * @return Newly created FramebufferLayout object with default screen regions initialized |
| 45 | */ | 45 | */ |
| 46 | FramebufferLayout LargeFrameLayout(unsigned width, unsigned height, bool is_swapped); | 46 | FramebufferLayout LargeFrameLayout(unsigned width, unsigned height, bool is_swapped); |
| 47 | |||
| 48 | /** | ||
| 49 | * Factory method for constructing a custom FramebufferLayout | ||
| 50 | * @param width Window framebuffer width in pixels | ||
| 51 | * @param height Window framebuffer height in pixels | ||
| 52 | * @return Newly created FramebufferLayout object with default screen regions initialized | ||
| 53 | */ | ||
| 54 | FramebufferLayout CustomFrameLayout(unsigned width, unsigned height); | ||
| 47 | } | 55 | } |
diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp index 737e1d57f..42f6a9918 100644 --- a/src/common/logging/backend.cpp +++ b/src/common/logging/backend.cpp | |||
| @@ -71,6 +71,7 @@ namespace Log { | |||
| 71 | CLS(Audio) \ | 71 | CLS(Audio) \ |
| 72 | SUB(Audio, DSP) \ | 72 | SUB(Audio, DSP) \ |
| 73 | SUB(Audio, Sink) \ | 73 | SUB(Audio, Sink) \ |
| 74 | CLS(Input) \ | ||
| 74 | CLS(Loader) | 75 | CLS(Loader) |
| 75 | 76 | ||
| 76 | // GetClassName is a macro defined by Windows.h, grrr... | 77 | // GetClassName is a macro defined by Windows.h, grrr... |
diff --git a/src/common/logging/log.h b/src/common/logging/log.h index 4b0f8ff03..1b905f66c 100644 --- a/src/common/logging/log.h +++ b/src/common/logging/log.h | |||
| @@ -89,6 +89,7 @@ enum class Class : ClassType { | |||
| 89 | Audio_DSP, ///< The HLE implementation of the DSP | 89 | Audio_DSP, ///< The HLE implementation of the DSP |
| 90 | Audio_Sink, ///< Emulator audio output backend | 90 | Audio_Sink, ///< Emulator audio output backend |
| 91 | Loader, ///< ROM loader | 91 | Loader, ///< ROM loader |
| 92 | Input, ///< Input emulation | ||
| 92 | Count ///< Total number of logging classes | 93 | Count ///< Total number of logging classes |
| 93 | }; | 94 | }; |
| 94 | 95 | ||
diff --git a/src/common/param_package.cpp b/src/common/param_package.cpp new file mode 100644 index 000000000..3a6ef8c27 --- /dev/null +++ b/src/common/param_package.cpp | |||
| @@ -0,0 +1,120 @@ | |||
| 1 | // Copyright 2017 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <array> | ||
| 6 | #include <vector> | ||
| 7 | #include "common/logging/log.h" | ||
| 8 | #include "common/param_package.h" | ||
| 9 | #include "common/string_util.h" | ||
| 10 | |||
| 11 | namespace Common { | ||
| 12 | |||
| 13 | constexpr char KEY_VALUE_SEPARATOR = ':'; | ||
| 14 | constexpr char PARAM_SEPARATOR = ','; | ||
| 15 | constexpr char ESCAPE_CHARACTER = '$'; | ||
| 16 | const std::string KEY_VALUE_SEPARATOR_ESCAPE{ESCAPE_CHARACTER, '0'}; | ||
| 17 | const std::string PARAM_SEPARATOR_ESCAPE{ESCAPE_CHARACTER, '1'}; | ||
| 18 | const std::string ESCAPE_CHARACTER_ESCAPE{ESCAPE_CHARACTER, '2'}; | ||
| 19 | |||
| 20 | ParamPackage::ParamPackage(const std::string& serialized) { | ||
| 21 | std::vector<std::string> pairs; | ||
| 22 | Common::SplitString(serialized, PARAM_SEPARATOR, pairs); | ||
| 23 | |||
| 24 | for (const std::string& pair : pairs) { | ||
| 25 | std::vector<std::string> key_value; | ||
| 26 | Common::SplitString(pair, KEY_VALUE_SEPARATOR, key_value); | ||
| 27 | if (key_value.size() != 2) { | ||
| 28 | LOG_ERROR(Common, "invalid key pair %s", pair.c_str()); | ||
| 29 | continue; | ||
| 30 | } | ||
| 31 | |||
| 32 | for (std::string& part : key_value) { | ||
| 33 | part = Common::ReplaceAll(part, KEY_VALUE_SEPARATOR_ESCAPE, {KEY_VALUE_SEPARATOR}); | ||
| 34 | part = Common::ReplaceAll(part, PARAM_SEPARATOR_ESCAPE, {PARAM_SEPARATOR}); | ||
| 35 | part = Common::ReplaceAll(part, ESCAPE_CHARACTER_ESCAPE, {ESCAPE_CHARACTER}); | ||
| 36 | } | ||
| 37 | |||
| 38 | Set(key_value[0], key_value[1]); | ||
| 39 | } | ||
| 40 | } | ||
| 41 | |||
| 42 | ParamPackage::ParamPackage(std::initializer_list<DataType::value_type> list) : data(list) {} | ||
| 43 | |||
| 44 | std::string ParamPackage::Serialize() const { | ||
| 45 | if (data.empty()) | ||
| 46 | return ""; | ||
| 47 | |||
| 48 | std::string result; | ||
| 49 | |||
| 50 | for (const auto& pair : data) { | ||
| 51 | std::array<std::string, 2> key_value{{pair.first, pair.second}}; | ||
| 52 | for (std::string& part : key_value) { | ||
| 53 | part = Common::ReplaceAll(part, {ESCAPE_CHARACTER}, ESCAPE_CHARACTER_ESCAPE); | ||
| 54 | part = Common::ReplaceAll(part, {PARAM_SEPARATOR}, PARAM_SEPARATOR_ESCAPE); | ||
| 55 | part = Common::ReplaceAll(part, {KEY_VALUE_SEPARATOR}, KEY_VALUE_SEPARATOR_ESCAPE); | ||
| 56 | } | ||
| 57 | result += key_value[0] + KEY_VALUE_SEPARATOR + key_value[1] + PARAM_SEPARATOR; | ||
| 58 | } | ||
| 59 | |||
| 60 | result.pop_back(); // discard the trailing PARAM_SEPARATOR | ||
| 61 | return result; | ||
| 62 | } | ||
| 63 | |||
| 64 | std::string ParamPackage::Get(const std::string& key, const std::string& default_value) const { | ||
| 65 | auto pair = data.find(key); | ||
| 66 | if (pair == data.end()) { | ||
| 67 | LOG_DEBUG(Common, "key %s not found", key.c_str()); | ||
| 68 | return default_value; | ||
| 69 | } | ||
| 70 | |||
| 71 | return pair->second; | ||
| 72 | } | ||
| 73 | |||
| 74 | int ParamPackage::Get(const std::string& key, int default_value) const { | ||
| 75 | auto pair = data.find(key); | ||
| 76 | if (pair == data.end()) { | ||
| 77 | LOG_DEBUG(Common, "key %s not found", key.c_str()); | ||
| 78 | return default_value; | ||
| 79 | } | ||
| 80 | |||
| 81 | try { | ||
| 82 | return std::stoi(pair->second); | ||
| 83 | } catch (const std::logic_error&) { | ||
| 84 | LOG_ERROR(Common, "failed to convert %s to int", pair->second.c_str()); | ||
| 85 | return default_value; | ||
| 86 | } | ||
| 87 | } | ||
| 88 | |||
| 89 | float ParamPackage::Get(const std::string& key, float default_value) const { | ||
| 90 | auto pair = data.find(key); | ||
| 91 | if (pair == data.end()) { | ||
| 92 | LOG_DEBUG(Common, "key %s not found", key.c_str()); | ||
| 93 | return default_value; | ||
| 94 | } | ||
| 95 | |||
| 96 | try { | ||
| 97 | return std::stof(pair->second); | ||
| 98 | } catch (const std::logic_error&) { | ||
| 99 | LOG_ERROR(Common, "failed to convert %s to float", pair->second.c_str()); | ||
| 100 | return default_value; | ||
| 101 | } | ||
| 102 | } | ||
| 103 | |||
| 104 | void ParamPackage::Set(const std::string& key, const std::string& value) { | ||
| 105 | data[key] = value; | ||
| 106 | } | ||
| 107 | |||
| 108 | void ParamPackage::Set(const std::string& key, int value) { | ||
| 109 | data[key] = std::to_string(value); | ||
| 110 | } | ||
| 111 | |||
| 112 | void ParamPackage::Set(const std::string& key, float value) { | ||
| 113 | data[key] = std::to_string(value); | ||
| 114 | } | ||
| 115 | |||
| 116 | bool ParamPackage::Has(const std::string& key) const { | ||
| 117 | return data.find(key) != data.end(); | ||
| 118 | } | ||
| 119 | |||
| 120 | } // namespace Common | ||
diff --git a/src/common/param_package.h b/src/common/param_package.h new file mode 100644 index 000000000..c4c11b221 --- /dev/null +++ b/src/common/param_package.h | |||
| @@ -0,0 +1,40 @@ | |||
| 1 | // Copyright 2017 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <initializer_list> | ||
| 8 | #include <string> | ||
| 9 | #include <unordered_map> | ||
| 10 | |||
| 11 | namespace Common { | ||
| 12 | |||
| 13 | /// A string-based key-value container supporting serializing to and deserializing from a string | ||
| 14 | class ParamPackage { | ||
| 15 | public: | ||
| 16 | using DataType = std::unordered_map<std::string, std::string>; | ||
| 17 | |||
| 18 | ParamPackage() = default; | ||
| 19 | explicit ParamPackage(const std::string& serialized); | ||
| 20 | ParamPackage(std::initializer_list<DataType::value_type> list); | ||
| 21 | ParamPackage(const ParamPackage& other) = default; | ||
| 22 | ParamPackage(ParamPackage&& other) = default; | ||
| 23 | |||
| 24 | ParamPackage& operator=(const ParamPackage& other) = default; | ||
| 25 | ParamPackage& operator=(ParamPackage&& other) = default; | ||
| 26 | |||
| 27 | std::string Serialize() const; | ||
| 28 | std::string Get(const std::string& key, const std::string& default_value) const; | ||
| 29 | int Get(const std::string& key, int default_value) const; | ||
| 30 | float Get(const std::string& key, float default_value) const; | ||
| 31 | void Set(const std::string& key, const std::string& value); | ||
| 32 | void Set(const std::string& key, int value); | ||
| 33 | void Set(const std::string& key, float value); | ||
| 34 | bool Has(const std::string& key) const; | ||
| 35 | |||
| 36 | private: | ||
| 37 | DataType data; | ||
| 38 | }; | ||
| 39 | |||
| 40 | } // namespace Common | ||
diff --git a/src/common/x64/cpu_detect.cpp b/src/common/x64/cpu_detect.cpp index 370ae2c80..2cb3ab9cc 100644 --- a/src/common/x64/cpu_detect.cpp +++ b/src/common/x64/cpu_detect.cpp | |||
| @@ -8,9 +8,9 @@ | |||
| 8 | #include "common/common_types.h" | 8 | #include "common/common_types.h" |
| 9 | #include "cpu_detect.h" | 9 | #include "cpu_detect.h" |
| 10 | 10 | ||
| 11 | namespace Common { | 11 | #ifdef _MSC_VER |
| 12 | 12 | #include <intrin.h> | |
| 13 | #ifndef _MSC_VER | 13 | #else |
| 14 | 14 | ||
| 15 | #if defined(__DragonFly__) || defined(__FreeBSD__) | 15 | #if defined(__DragonFly__) || defined(__FreeBSD__) |
| 16 | // clang-format off | 16 | // clang-format off |
| @@ -37,13 +37,15 @@ static inline void __cpuid(int info[4], int function_id) { | |||
| 37 | } | 37 | } |
| 38 | 38 | ||
| 39 | #define _XCR_XFEATURE_ENABLED_MASK 0 | 39 | #define _XCR_XFEATURE_ENABLED_MASK 0 |
| 40 | static u64 _xgetbv(u32 index) { | 40 | static inline u64 _xgetbv(u32 index) { |
| 41 | u32 eax, edx; | 41 | u32 eax, edx; |
| 42 | __asm__ __volatile__("xgetbv" : "=a"(eax), "=d"(edx) : "c"(index)); | 42 | __asm__ __volatile__("xgetbv" : "=a"(eax), "=d"(edx) : "c"(index)); |
| 43 | return ((u64)edx << 32) | eax; | 43 | return ((u64)edx << 32) | eax; |
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | #endif // ifndef _MSC_VER | 46 | #endif // _MSC_VER |
| 47 | |||
| 48 | namespace Common { | ||
| 47 | 49 | ||
| 48 | // Detects the various CPU features | 50 | // Detects the various CPU features |
| 49 | static CPUCaps Detect() { | 51 | static CPUCaps Detect() { |
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index ffd67f074..61a0b1cc3 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -34,7 +34,6 @@ set(SRCS | |||
| 34 | frontend/camera/factory.cpp | 34 | frontend/camera/factory.cpp |
| 35 | frontend/camera/interface.cpp | 35 | frontend/camera/interface.cpp |
| 36 | frontend/emu_window.cpp | 36 | frontend/emu_window.cpp |
| 37 | frontend/key_map.cpp | ||
| 38 | frontend/motion_emu.cpp | 37 | frontend/motion_emu.cpp |
| 39 | gdbstub/gdbstub.cpp | 38 | gdbstub/gdbstub.cpp |
| 40 | hle/config_mem.cpp | 39 | hle/config_mem.cpp |
| @@ -218,7 +217,7 @@ set(HEADERS | |||
| 218 | frontend/camera/factory.h | 217 | frontend/camera/factory.h |
| 219 | frontend/camera/interface.h | 218 | frontend/camera/interface.h |
| 220 | frontend/emu_window.h | 219 | frontend/emu_window.h |
| 221 | frontend/key_map.h | 220 | frontend/input.h |
| 222 | frontend/motion_emu.h | 221 | frontend/motion_emu.h |
| 223 | gdbstub/gdbstub.h | 222 | gdbstub/gdbstub.h |
| 224 | hle/config_mem.h | 223 | hle/config_mem.h |
diff --git a/src/core/file_sys/archive_extsavedata.cpp b/src/core/file_sys/archive_extsavedata.cpp index dd2fb167f..f454e7840 100644 --- a/src/core/file_sys/archive_extsavedata.cpp +++ b/src/core/file_sys/archive_extsavedata.cpp | |||
| @@ -173,7 +173,7 @@ Path ConstructExtDataBinaryPath(u32 media_type, u32 high, u32 low) { | |||
| 173 | ArchiveFactory_ExtSaveData::ArchiveFactory_ExtSaveData(const std::string& mount_location, | 173 | ArchiveFactory_ExtSaveData::ArchiveFactory_ExtSaveData(const std::string& mount_location, |
| 174 | bool shared) | 174 | bool shared) |
| 175 | : shared(shared), mount_point(GetExtDataContainerPath(mount_location, shared)) { | 175 | : shared(shared), mount_point(GetExtDataContainerPath(mount_location, shared)) { |
| 176 | LOG_INFO(Service_FS, "Directory %s set as base for ExtSaveData.", mount_point.c_str()); | 176 | LOG_DEBUG(Service_FS, "Directory %s set as base for ExtSaveData.", mount_point.c_str()); |
| 177 | } | 177 | } |
| 178 | 178 | ||
| 179 | bool ArchiveFactory_ExtSaveData::Initialize() { | 179 | bool ArchiveFactory_ExtSaveData::Initialize() { |
diff --git a/src/core/file_sys/archive_sdmc.cpp b/src/core/file_sys/archive_sdmc.cpp index 72ff05c65..679909d06 100644 --- a/src/core/file_sys/archive_sdmc.cpp +++ b/src/core/file_sys/archive_sdmc.cpp | |||
| @@ -306,7 +306,7 @@ u64 SDMCArchive::GetFreeBytes() const { | |||
| 306 | 306 | ||
| 307 | ArchiveFactory_SDMC::ArchiveFactory_SDMC(const std::string& sdmc_directory) | 307 | ArchiveFactory_SDMC::ArchiveFactory_SDMC(const std::string& sdmc_directory) |
| 308 | : sdmc_directory(sdmc_directory) { | 308 | : sdmc_directory(sdmc_directory) { |
| 309 | LOG_INFO(Service_FS, "Directory %s set as SDMC.", sdmc_directory.c_str()); | 309 | LOG_DEBUG(Service_FS, "Directory %s set as SDMC.", sdmc_directory.c_str()); |
| 310 | } | 310 | } |
| 311 | 311 | ||
| 312 | bool ArchiveFactory_SDMC::Initialize() { | 312 | bool ArchiveFactory_SDMC::Initialize() { |
diff --git a/src/core/file_sys/archive_sdmcwriteonly.cpp b/src/core/file_sys/archive_sdmcwriteonly.cpp index 2aafc9b1d..244aef48a 100644 --- a/src/core/file_sys/archive_sdmcwriteonly.cpp +++ b/src/core/file_sys/archive_sdmcwriteonly.cpp | |||
| @@ -32,7 +32,7 @@ ResultVal<std::unique_ptr<DirectoryBackend>> SDMCWriteOnlyArchive::OpenDirectory | |||
| 32 | 32 | ||
| 33 | ArchiveFactory_SDMCWriteOnly::ArchiveFactory_SDMCWriteOnly(const std::string& mount_point) | 33 | ArchiveFactory_SDMCWriteOnly::ArchiveFactory_SDMCWriteOnly(const std::string& mount_point) |
| 34 | : sdmc_directory(mount_point) { | 34 | : sdmc_directory(mount_point) { |
| 35 | LOG_INFO(Service_FS, "Directory %s set as SDMCWriteOnly.", sdmc_directory.c_str()); | 35 | LOG_DEBUG(Service_FS, "Directory %s set as SDMCWriteOnly.", sdmc_directory.c_str()); |
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | bool ArchiveFactory_SDMCWriteOnly::Initialize() { | 38 | bool ArchiveFactory_SDMCWriteOnly::Initialize() { |
diff --git a/src/core/file_sys/archive_source_sd_savedata.cpp b/src/core/file_sys/archive_source_sd_savedata.cpp index e01357891..f31a68038 100644 --- a/src/core/file_sys/archive_source_sd_savedata.cpp +++ b/src/core/file_sys/archive_source_sd_savedata.cpp | |||
| @@ -39,7 +39,7 @@ std::string GetSaveDataMetadataPath(const std::string& mount_location, u64 progr | |||
| 39 | 39 | ||
| 40 | ArchiveSource_SDSaveData::ArchiveSource_SDSaveData(const std::string& sdmc_directory) | 40 | ArchiveSource_SDSaveData::ArchiveSource_SDSaveData(const std::string& sdmc_directory) |
| 41 | : mount_point(GetSaveDataContainerPath(sdmc_directory)) { | 41 | : mount_point(GetSaveDataContainerPath(sdmc_directory)) { |
| 42 | LOG_INFO(Service_FS, "Directory %s set as SaveData.", mount_point.c_str()); | 42 | LOG_DEBUG(Service_FS, "Directory %s set as SaveData.", mount_point.c_str()); |
| 43 | } | 43 | } |
| 44 | 44 | ||
| 45 | ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveSource_SDSaveData::Open(u64 program_id) { | 45 | ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveSource_SDSaveData::Open(u64 program_id) { |
diff --git a/src/core/frontend/emu_window.cpp b/src/core/frontend/emu_window.cpp index a155b657d..5fdb3a7e8 100644 --- a/src/core/frontend/emu_window.cpp +++ b/src/core/frontend/emu_window.cpp | |||
| @@ -7,33 +7,9 @@ | |||
| 7 | #include "common/assert.h" | 7 | #include "common/assert.h" |
| 8 | #include "core/core.h" | 8 | #include "core/core.h" |
| 9 | #include "core/frontend/emu_window.h" | 9 | #include "core/frontend/emu_window.h" |
| 10 | #include "core/frontend/key_map.h" | 10 | #include "core/settings.h" |
| 11 | #include "video_core/video_core.h" | 11 | #include "video_core/video_core.h" |
| 12 | 12 | ||
| 13 | void EmuWindow::ButtonPressed(Service::HID::PadState pad) { | ||
| 14 | pad_state.hex |= pad.hex; | ||
| 15 | } | ||
| 16 | |||
| 17 | void EmuWindow::ButtonReleased(Service::HID::PadState pad) { | ||
| 18 | pad_state.hex &= ~pad.hex; | ||
| 19 | } | ||
| 20 | |||
| 21 | void EmuWindow::CirclePadUpdated(float x, float y) { | ||
| 22 | constexpr int MAX_CIRCLEPAD_POS = 0x9C; // Max value for a circle pad position | ||
| 23 | |||
| 24 | // Make sure the coordinates are in the unit circle, | ||
| 25 | // otherwise normalize it. | ||
| 26 | float r = x * x + y * y; | ||
| 27 | if (r > 1) { | ||
| 28 | r = std::sqrt(r); | ||
| 29 | x /= r; | ||
| 30 | y /= r; | ||
| 31 | } | ||
| 32 | |||
| 33 | circle_pad_x = static_cast<s16>(x * MAX_CIRCLEPAD_POS); | ||
| 34 | circle_pad_y = static_cast<s16>(y * MAX_CIRCLEPAD_POS); | ||
| 35 | } | ||
| 36 | |||
| 37 | /** | 13 | /** |
| 38 | * Check if the given x/y coordinates are within the touchpad specified by the framebuffer layout | 14 | * Check if the given x/y coordinates are within the touchpad specified by the framebuffer layout |
| 39 | * @param layout FramebufferLayout object describing the framebuffer size and screen positions | 15 | * @param layout FramebufferLayout object describing the framebuffer size and screen positions |
| @@ -113,17 +89,21 @@ void EmuWindow::GyroscopeChanged(float x, float y, float z) { | |||
| 113 | 89 | ||
| 114 | void EmuWindow::UpdateCurrentFramebufferLayout(unsigned width, unsigned height) { | 90 | void EmuWindow::UpdateCurrentFramebufferLayout(unsigned width, unsigned height) { |
| 115 | Layout::FramebufferLayout layout; | 91 | Layout::FramebufferLayout layout; |
| 116 | switch (Settings::values.layout_option) { | 92 | if (Settings::values.custom_layout == true) { |
| 117 | case Settings::LayoutOption::SingleScreen: | 93 | layout = Layout::CustomFrameLayout(width, height); |
| 118 | layout = Layout::SingleFrameLayout(width, height, Settings::values.swap_screen); | 94 | } else { |
| 119 | break; | 95 | switch (Settings::values.layout_option) { |
| 120 | case Settings::LayoutOption::LargeScreen: | 96 | case Settings::LayoutOption::SingleScreen: |
| 121 | layout = Layout::LargeFrameLayout(width, height, Settings::values.swap_screen); | 97 | layout = Layout::SingleFrameLayout(width, height, Settings::values.swap_screen); |
| 122 | break; | 98 | break; |
| 123 | case Settings::LayoutOption::Default: | 99 | case Settings::LayoutOption::LargeScreen: |
| 124 | default: | 100 | layout = Layout::LargeFrameLayout(width, height, Settings::values.swap_screen); |
| 125 | layout = Layout::DefaultFrameLayout(width, height, Settings::values.swap_screen); | 101 | break; |
| 126 | break; | 102 | case Settings::LayoutOption::Default: |
| 103 | default: | ||
| 104 | layout = Layout::DefaultFrameLayout(width, height, Settings::values.swap_screen); | ||
| 105 | break; | ||
| 106 | } | ||
| 127 | } | 107 | } |
| 128 | NotifyFramebufferLayoutChanged(layout); | 108 | NotifyFramebufferLayoutChanged(layout); |
| 129 | } | 109 | } |
diff --git a/src/core/frontend/emu_window.h b/src/core/frontend/emu_window.h index 1ba64c92b..36f2667fa 100644 --- a/src/core/frontend/emu_window.h +++ b/src/core/frontend/emu_window.h | |||
| @@ -10,7 +10,6 @@ | |||
| 10 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 11 | #include "common/framebuffer_layout.h" | 11 | #include "common/framebuffer_layout.h" |
| 12 | #include "common/math_util.h" | 12 | #include "common/math_util.h" |
| 13 | #include "core/hle/service/hid/hid.h" | ||
| 14 | 13 | ||
| 15 | /** | 14 | /** |
| 16 | * Abstraction class used to provide an interface between emulation code and the frontend | 15 | * Abstraction class used to provide an interface between emulation code and the frontend |
| @@ -52,30 +51,6 @@ public: | |||
| 52 | /// Releases (dunno if this is the "right" word) the GLFW context from the caller thread | 51 | /// Releases (dunno if this is the "right" word) the GLFW context from the caller thread |
| 53 | virtual void DoneCurrent() = 0; | 52 | virtual void DoneCurrent() = 0; |
| 54 | 53 | ||
| 55 | virtual void ReloadSetKeymaps() = 0; | ||
| 56 | |||
| 57 | /** | ||
| 58 | * Signals a button press action to the HID module. | ||
| 59 | * @param pad_state indicates which button to press | ||
| 60 | * @note only handles real buttons (A/B/X/Y/...), excluding analog inputs like the circle pad. | ||
| 61 | */ | ||
| 62 | void ButtonPressed(Service::HID::PadState pad_state); | ||
| 63 | |||
| 64 | /** | ||
| 65 | * Signals a button release action to the HID module. | ||
| 66 | * @param pad_state indicates which button to press | ||
| 67 | * @note only handles real buttons (A/B/X/Y/...), excluding analog inputs like the circle pad. | ||
| 68 | */ | ||
| 69 | void ButtonReleased(Service::HID::PadState pad_state); | ||
| 70 | |||
| 71 | /** | ||
| 72 | * Signals a circle pad change action to the HID module. | ||
| 73 | * @param x new x-coordinate of the circle pad, in the range [-1.0, 1.0] | ||
| 74 | * @param y new y-coordinate of the circle pad, in the range [-1.0, 1.0] | ||
| 75 | * @note the coordinates will be normalized if the radius is larger than 1 | ||
| 76 | */ | ||
| 77 | void CirclePadUpdated(float x, float y); | ||
| 78 | |||
| 79 | /** | 54 | /** |
| 80 | * Signal that a touch pressed event has occurred (e.g. mouse click pressed) | 55 | * Signal that a touch pressed event has occurred (e.g. mouse click pressed) |
| 81 | * @param framebuffer_x Framebuffer x-coordinate that was pressed | 56 | * @param framebuffer_x Framebuffer x-coordinate that was pressed |
| @@ -115,27 +90,6 @@ public: | |||
| 115 | void GyroscopeChanged(float x, float y, float z); | 90 | void GyroscopeChanged(float x, float y, float z); |
| 116 | 91 | ||
| 117 | /** | 92 | /** |
| 118 | * Gets the current pad state (which buttons are pressed). | ||
| 119 | * @note This should be called by the core emu thread to get a state set by the window thread. | ||
| 120 | * @note This doesn't include analog input like circle pad direction | ||
| 121 | * @todo Fix this function to be thread-safe. | ||
| 122 | * @return PadState object indicating the current pad state | ||
| 123 | */ | ||
| 124 | Service::HID::PadState GetPadState() const { | ||
| 125 | return pad_state; | ||
| 126 | } | ||
| 127 | |||
| 128 | /** | ||
| 129 | * Gets the current circle pad state. | ||
| 130 | * @note This should be called by the core emu thread to get a state set by the window thread. | ||
| 131 | * @todo Fix this function to be thread-safe. | ||
| 132 | * @return std::tuple of (x, y), where `x` and `y` are the circle pad coordinates | ||
| 133 | */ | ||
| 134 | std::tuple<s16, s16> GetCirclePadState() const { | ||
| 135 | return std::make_tuple(circle_pad_x, circle_pad_y); | ||
| 136 | } | ||
| 137 | |||
| 138 | /** | ||
| 139 | * Gets the current touch screen state (touch X/Y coordinates and whether or not it is pressed). | 93 | * Gets the current touch screen state (touch X/Y coordinates and whether or not it is pressed). |
| 140 | * @note This should be called by the core emu thread to get a state set by the window thread. | 94 | * @note This should be called by the core emu thread to get a state set by the window thread. |
| 141 | * @todo Fix this function to be thread-safe. | 95 | * @todo Fix this function to be thread-safe. |
| @@ -230,11 +184,8 @@ protected: | |||
| 230 | // TODO: Find a better place to set this. | 184 | // TODO: Find a better place to set this. |
| 231 | config.min_client_area_size = std::make_pair(400u, 480u); | 185 | config.min_client_area_size = std::make_pair(400u, 480u); |
| 232 | active_config = config; | 186 | active_config = config; |
| 233 | pad_state.hex = 0; | ||
| 234 | touch_x = 0; | 187 | touch_x = 0; |
| 235 | touch_y = 0; | 188 | touch_y = 0; |
| 236 | circle_pad_x = 0; | ||
| 237 | circle_pad_y = 0; | ||
| 238 | touch_pressed = false; | 189 | touch_pressed = false; |
| 239 | accel_x = 0; | 190 | accel_x = 0; |
| 240 | accel_y = -512; | 191 | accel_y = -512; |
| @@ -304,9 +255,6 @@ private: | |||
| 304 | u16 touch_x; ///< Touchpad X-position in native 3DS pixel coordinates (0-320) | 255 | u16 touch_x; ///< Touchpad X-position in native 3DS pixel coordinates (0-320) |
| 305 | u16 touch_y; ///< Touchpad Y-position in native 3DS pixel coordinates (0-240) | 256 | u16 touch_y; ///< Touchpad Y-position in native 3DS pixel coordinates (0-240) |
| 306 | 257 | ||
| 307 | s16 circle_pad_x; ///< Circle pad X-position in native 3DS pixel coordinates (-156 - 156) | ||
| 308 | s16 circle_pad_y; ///< Circle pad Y-position in native 3DS pixel coordinates (-156 - 156) | ||
| 309 | |||
| 310 | std::mutex accel_mutex; | 258 | std::mutex accel_mutex; |
| 311 | s16 accel_x; ///< Accelerometer X-axis value in native 3DS units | 259 | s16 accel_x; ///< Accelerometer X-axis value in native 3DS units |
| 312 | s16 accel_y; ///< Accelerometer Y-axis value in native 3DS units | 260 | s16 accel_y; ///< Accelerometer Y-axis value in native 3DS units |
| @@ -321,6 +269,4 @@ private: | |||
| 321 | * Clip the provided coordinates to be inside the touchscreen area. | 269 | * Clip the provided coordinates to be inside the touchscreen area. |
| 322 | */ | 270 | */ |
| 323 | std::tuple<unsigned, unsigned> ClipToTouchScreen(unsigned new_x, unsigned new_y); | 271 | std::tuple<unsigned, unsigned> ClipToTouchScreen(unsigned new_x, unsigned new_y); |
| 324 | |||
| 325 | Service::HID::PadState pad_state; | ||
| 326 | }; | 272 | }; |
diff --git a/src/core/frontend/input.h b/src/core/frontend/input.h new file mode 100644 index 000000000..0a5713dc0 --- /dev/null +++ b/src/core/frontend/input.h | |||
| @@ -0,0 +1,110 @@ | |||
| 1 | // Copyright 2017 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <memory> | ||
| 8 | #include <string> | ||
| 9 | #include <tuple> | ||
| 10 | #include <unordered_map> | ||
| 11 | #include <utility> | ||
| 12 | #include "common/logging/log.h" | ||
| 13 | #include "common/param_package.h" | ||
| 14 | |||
| 15 | namespace Input { | ||
| 16 | |||
| 17 | /// An abstract class template for an input device (a button, an analog input, etc.). | ||
| 18 | template <typename StatusType> | ||
| 19 | class InputDevice { | ||
| 20 | public: | ||
| 21 | virtual ~InputDevice() = default; | ||
| 22 | virtual StatusType GetStatus() const { | ||
| 23 | return {}; | ||
| 24 | } | ||
| 25 | }; | ||
| 26 | |||
| 27 | /// An abstract class template for a factory that can create input devices. | ||
| 28 | template <typename InputDeviceType> | ||
| 29 | class Factory { | ||
| 30 | public: | ||
| 31 | virtual ~Factory() = default; | ||
| 32 | virtual std::unique_ptr<InputDeviceType> Create(const Common::ParamPackage&) = 0; | ||
| 33 | }; | ||
| 34 | |||
| 35 | namespace Impl { | ||
| 36 | |||
| 37 | template <typename InputDeviceType> | ||
| 38 | using FactoryListType = std::unordered_map<std::string, std::shared_ptr<Factory<InputDeviceType>>>; | ||
| 39 | |||
| 40 | template <typename InputDeviceType> | ||
| 41 | struct FactoryList { | ||
| 42 | static FactoryListType<InputDeviceType> list; | ||
| 43 | }; | ||
| 44 | |||
| 45 | template <typename InputDeviceType> | ||
| 46 | FactoryListType<InputDeviceType> FactoryList<InputDeviceType>::list; | ||
| 47 | |||
| 48 | } // namespace Impl | ||
| 49 | |||
| 50 | /** | ||
| 51 | * Registers an input device factory. | ||
| 52 | * @tparam InputDeviceType the type of input devices the factory can create | ||
| 53 | * @param name the name of the factory. Will be used to match the "engine" parameter when creating | ||
| 54 | * a device | ||
| 55 | * @param factory the factory object to register | ||
| 56 | */ | ||
| 57 | template <typename InputDeviceType> | ||
| 58 | void RegisterFactory(const std::string& name, std::shared_ptr<Factory<InputDeviceType>> factory) { | ||
| 59 | auto pair = std::make_pair(name, std::move(factory)); | ||
| 60 | if (!Impl::FactoryList<InputDeviceType>::list.insert(std::move(pair)).second) { | ||
| 61 | LOG_ERROR(Input, "Factory %s already registered", name.c_str()); | ||
| 62 | } | ||
| 63 | } | ||
| 64 | |||
| 65 | /** | ||
| 66 | * Unregisters an input device factory. | ||
| 67 | * @tparam InputDeviceType the type of input devices the factory can create | ||
| 68 | * @param name the name of the factory to unregister | ||
| 69 | */ | ||
| 70 | template <typename InputDeviceType> | ||
| 71 | void UnregisterFactory(const std::string& name) { | ||
| 72 | if (Impl::FactoryList<InputDeviceType>::list.erase(name) == 0) { | ||
| 73 | LOG_ERROR(Input, "Factory %s not registered", name.c_str()); | ||
| 74 | } | ||
| 75 | } | ||
| 76 | |||
| 77 | /** | ||
| 78 | * Create an input device from given paramters. | ||
| 79 | * @tparam InputDeviceType the type of input devices to create | ||
| 80 | * @param params a serialized ParamPackage string contains all parameters for creating the device | ||
| 81 | */ | ||
| 82 | template <typename InputDeviceType> | ||
| 83 | std::unique_ptr<InputDeviceType> CreateDevice(const std::string& params) { | ||
| 84 | const Common::ParamPackage package(params); | ||
| 85 | const std::string engine = package.Get("engine", "null"); | ||
| 86 | const auto& factory_list = Impl::FactoryList<InputDeviceType>::list; | ||
| 87 | const auto pair = factory_list.find(engine); | ||
| 88 | if (pair == factory_list.end()) { | ||
| 89 | if (engine != "null") { | ||
| 90 | LOG_ERROR(Input, "Unknown engine name: %s", engine.c_str()); | ||
| 91 | } | ||
| 92 | return std::make_unique<InputDeviceType>(); | ||
| 93 | } | ||
| 94 | return pair->second->Create(package); | ||
| 95 | } | ||
| 96 | |||
| 97 | /** | ||
| 98 | * A button device is an input device that returns bool as status. | ||
| 99 | * true for pressed; false for released. | ||
| 100 | */ | ||
| 101 | using ButtonDevice = InputDevice<bool>; | ||
| 102 | |||
| 103 | /** | ||
| 104 | * An analog device is an input device that returns a tuple of x and y coordinates as status. The | ||
| 105 | * coordinates are within the unit circle. x+ is defined as right direction, and y+ is defined as up | ||
| 106 | * direction | ||
| 107 | */ | ||
| 108 | using AnalogDevice = InputDevice<std::tuple<float, float>>; | ||
| 109 | |||
| 110 | } // namespace Input | ||
diff --git a/src/core/frontend/key_map.cpp b/src/core/frontend/key_map.cpp deleted file mode 100644 index 15f0e079c..000000000 --- a/src/core/frontend/key_map.cpp +++ /dev/null | |||
| @@ -1,152 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <map> | ||
| 6 | #include "core/frontend/emu_window.h" | ||
| 7 | #include "core/frontend/key_map.h" | ||
| 8 | |||
| 9 | namespace KeyMap { | ||
| 10 | |||
| 11 | // TODO (wwylele): currently we treat c-stick as four direction buttons | ||
| 12 | // and map it directly to EmuWindow::ButtonPressed. | ||
| 13 | // It should go the analog input way like circle pad does. | ||
| 14 | const std::array<KeyTarget, Settings::NativeInput::NUM_INPUTS> mapping_targets = {{ | ||
| 15 | Service::HID::PAD_A, | ||
| 16 | Service::HID::PAD_B, | ||
| 17 | Service::HID::PAD_X, | ||
| 18 | Service::HID::PAD_Y, | ||
| 19 | Service::HID::PAD_L, | ||
| 20 | Service::HID::PAD_R, | ||
| 21 | Service::HID::PAD_ZL, | ||
| 22 | Service::HID::PAD_ZR, | ||
| 23 | Service::HID::PAD_START, | ||
| 24 | Service::HID::PAD_SELECT, | ||
| 25 | Service::HID::PAD_NONE, | ||
| 26 | Service::HID::PAD_UP, | ||
| 27 | Service::HID::PAD_DOWN, | ||
| 28 | Service::HID::PAD_LEFT, | ||
| 29 | Service::HID::PAD_RIGHT, | ||
| 30 | Service::HID::PAD_C_UP, | ||
| 31 | Service::HID::PAD_C_DOWN, | ||
| 32 | Service::HID::PAD_C_LEFT, | ||
| 33 | Service::HID::PAD_C_RIGHT, | ||
| 34 | |||
| 35 | IndirectTarget::CirclePadUp, | ||
| 36 | IndirectTarget::CirclePadDown, | ||
| 37 | IndirectTarget::CirclePadLeft, | ||
| 38 | IndirectTarget::CirclePadRight, | ||
| 39 | IndirectTarget::CirclePadModifier, | ||
| 40 | }}; | ||
| 41 | |||
| 42 | static std::map<HostDeviceKey, KeyTarget> key_map; | ||
| 43 | static int next_device_id = 0; | ||
| 44 | |||
| 45 | static bool circle_pad_up = false; | ||
| 46 | static bool circle_pad_down = false; | ||
| 47 | static bool circle_pad_left = false; | ||
| 48 | static bool circle_pad_right = false; | ||
| 49 | static bool circle_pad_modifier = false; | ||
| 50 | |||
| 51 | static void UpdateCirclePad(EmuWindow& emu_window) { | ||
| 52 | constexpr float SQRT_HALF = 0.707106781f; | ||
| 53 | int x = 0, y = 0; | ||
| 54 | |||
| 55 | if (circle_pad_right) | ||
| 56 | ++x; | ||
| 57 | if (circle_pad_left) | ||
| 58 | --x; | ||
| 59 | if (circle_pad_up) | ||
| 60 | ++y; | ||
| 61 | if (circle_pad_down) | ||
| 62 | --y; | ||
| 63 | |||
| 64 | float modifier = circle_pad_modifier ? Settings::values.pad_circle_modifier_scale : 1.0f; | ||
| 65 | emu_window.CirclePadUpdated(x * modifier * (y == 0 ? 1.0f : SQRT_HALF), | ||
| 66 | y * modifier * (x == 0 ? 1.0f : SQRT_HALF)); | ||
| 67 | } | ||
| 68 | |||
| 69 | int NewDeviceId() { | ||
| 70 | return next_device_id++; | ||
| 71 | } | ||
| 72 | |||
| 73 | void SetKeyMapping(HostDeviceKey key, KeyTarget target) { | ||
| 74 | key_map[key] = target; | ||
| 75 | } | ||
| 76 | |||
| 77 | void ClearKeyMapping(int device_id) { | ||
| 78 | auto iter = key_map.begin(); | ||
| 79 | while (iter != key_map.end()) { | ||
| 80 | if (iter->first.device_id == device_id) | ||
| 81 | key_map.erase(iter++); | ||
| 82 | else | ||
| 83 | ++iter; | ||
| 84 | } | ||
| 85 | } | ||
| 86 | |||
| 87 | void PressKey(EmuWindow& emu_window, HostDeviceKey key) { | ||
| 88 | auto target = key_map.find(key); | ||
| 89 | if (target == key_map.end()) | ||
| 90 | return; | ||
| 91 | |||
| 92 | if (target->second.direct) { | ||
| 93 | emu_window.ButtonPressed({{target->second.target.direct_target_hex}}); | ||
| 94 | } else { | ||
| 95 | switch (target->second.target.indirect_target) { | ||
| 96 | case IndirectTarget::CirclePadUp: | ||
| 97 | circle_pad_up = true; | ||
| 98 | UpdateCirclePad(emu_window); | ||
| 99 | break; | ||
| 100 | case IndirectTarget::CirclePadDown: | ||
| 101 | circle_pad_down = true; | ||
| 102 | UpdateCirclePad(emu_window); | ||
| 103 | break; | ||
| 104 | case IndirectTarget::CirclePadLeft: | ||
| 105 | circle_pad_left = true; | ||
| 106 | UpdateCirclePad(emu_window); | ||
| 107 | break; | ||
| 108 | case IndirectTarget::CirclePadRight: | ||
| 109 | circle_pad_right = true; | ||
| 110 | UpdateCirclePad(emu_window); | ||
| 111 | break; | ||
| 112 | case IndirectTarget::CirclePadModifier: | ||
| 113 | circle_pad_modifier = true; | ||
| 114 | UpdateCirclePad(emu_window); | ||
| 115 | break; | ||
| 116 | } | ||
| 117 | } | ||
| 118 | } | ||
| 119 | |||
| 120 | void ReleaseKey(EmuWindow& emu_window, HostDeviceKey key) { | ||
| 121 | auto target = key_map.find(key); | ||
| 122 | if (target == key_map.end()) | ||
| 123 | return; | ||
| 124 | |||
| 125 | if (target->second.direct) { | ||
| 126 | emu_window.ButtonReleased({{target->second.target.direct_target_hex}}); | ||
| 127 | } else { | ||
| 128 | switch (target->second.target.indirect_target) { | ||
| 129 | case IndirectTarget::CirclePadUp: | ||
| 130 | circle_pad_up = false; | ||
| 131 | UpdateCirclePad(emu_window); | ||
| 132 | break; | ||
| 133 | case IndirectTarget::CirclePadDown: | ||
| 134 | circle_pad_down = false; | ||
| 135 | UpdateCirclePad(emu_window); | ||
| 136 | break; | ||
| 137 | case IndirectTarget::CirclePadLeft: | ||
| 138 | circle_pad_left = false; | ||
| 139 | UpdateCirclePad(emu_window); | ||
| 140 | break; | ||
| 141 | case IndirectTarget::CirclePadRight: | ||
| 142 | circle_pad_right = false; | ||
| 143 | UpdateCirclePad(emu_window); | ||
| 144 | break; | ||
| 145 | case IndirectTarget::CirclePadModifier: | ||
| 146 | circle_pad_modifier = false; | ||
| 147 | UpdateCirclePad(emu_window); | ||
| 148 | break; | ||
| 149 | } | ||
| 150 | } | ||
| 151 | } | ||
| 152 | } | ||
diff --git a/src/core/frontend/key_map.h b/src/core/frontend/key_map.h deleted file mode 100644 index 040794578..000000000 --- a/src/core/frontend/key_map.h +++ /dev/null | |||
| @@ -1,93 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <array> | ||
| 8 | #include <tuple> | ||
| 9 | #include "core/hle/service/hid/hid.h" | ||
| 10 | |||
| 11 | class EmuWindow; | ||
| 12 | |||
| 13 | namespace KeyMap { | ||
| 14 | |||
| 15 | /** | ||
| 16 | * Represents key mapping targets that are not real 3DS buttons. | ||
| 17 | * They will be handled by KeyMap and translated to 3DS input. | ||
| 18 | */ | ||
| 19 | enum class IndirectTarget { | ||
| 20 | CirclePadUp, | ||
| 21 | CirclePadDown, | ||
| 22 | CirclePadLeft, | ||
| 23 | CirclePadRight, | ||
| 24 | CirclePadModifier, | ||
| 25 | }; | ||
| 26 | |||
| 27 | /** | ||
| 28 | * Represents a key mapping target. It can be a PadState that represents real 3DS buttons, | ||
| 29 | * or an IndirectTarget. | ||
| 30 | */ | ||
| 31 | struct KeyTarget { | ||
| 32 | bool direct; | ||
| 33 | union { | ||
| 34 | u32 direct_target_hex; | ||
| 35 | IndirectTarget indirect_target; | ||
| 36 | } target; | ||
| 37 | |||
| 38 | KeyTarget() : direct(true) { | ||
| 39 | target.direct_target_hex = 0; | ||
| 40 | } | ||
| 41 | |||
| 42 | KeyTarget(Service::HID::PadState pad) : direct(true) { | ||
| 43 | target.direct_target_hex = pad.hex; | ||
| 44 | } | ||
| 45 | |||
| 46 | KeyTarget(IndirectTarget i) : direct(false) { | ||
| 47 | target.indirect_target = i; | ||
| 48 | } | ||
| 49 | }; | ||
| 50 | |||
| 51 | /** | ||
| 52 | * Represents a key for a specific host device. | ||
| 53 | */ | ||
| 54 | struct HostDeviceKey { | ||
| 55 | int key_code; | ||
| 56 | int device_id; ///< Uniquely identifies a host device | ||
| 57 | |||
| 58 | bool operator<(const HostDeviceKey& other) const { | ||
| 59 | return std::tie(key_code, device_id) < std::tie(other.key_code, other.device_id); | ||
| 60 | } | ||
| 61 | |||
| 62 | bool operator==(const HostDeviceKey& other) const { | ||
| 63 | return std::tie(key_code, device_id) == std::tie(other.key_code, other.device_id); | ||
| 64 | } | ||
| 65 | }; | ||
| 66 | |||
| 67 | extern const std::array<KeyTarget, Settings::NativeInput::NUM_INPUTS> mapping_targets; | ||
| 68 | |||
| 69 | /** | ||
| 70 | * Generates a new device id, which uniquely identifies a host device within KeyMap. | ||
| 71 | */ | ||
| 72 | int NewDeviceId(); | ||
| 73 | |||
| 74 | /** | ||
| 75 | * Maps a device-specific key to a target (a PadState or an IndirectTarget). | ||
| 76 | */ | ||
| 77 | void SetKeyMapping(HostDeviceKey key, KeyTarget target); | ||
| 78 | |||
| 79 | /** | ||
| 80 | * Clears all key mappings belonging to one device. | ||
| 81 | */ | ||
| 82 | void ClearKeyMapping(int device_id); | ||
| 83 | |||
| 84 | /** | ||
| 85 | * Maps a key press action and call the corresponding function in EmuWindow | ||
| 86 | */ | ||
| 87 | void PressKey(EmuWindow& emu_window, HostDeviceKey key); | ||
| 88 | |||
| 89 | /** | ||
| 90 | * Maps a key release action and call the corresponding function in EmuWindow | ||
| 91 | */ | ||
| 92 | void ReleaseKey(EmuWindow& emu_window, HostDeviceKey key); | ||
| 93 | } | ||
diff --git a/src/core/hle/function_wrappers.h b/src/core/hle/function_wrappers.h index 7875971ce..f6eb900f0 100644 --- a/src/core/hle/function_wrappers.h +++ b/src/core/hle/function_wrappers.h | |||
| @@ -256,9 +256,9 @@ void Wrap() { | |||
| 256 | func(((s64)PARAM(1) << 32) | PARAM(0)); | 256 | func(((s64)PARAM(1) << 32) | PARAM(0)); |
| 257 | } | 257 | } |
| 258 | 258 | ||
| 259 | template <void func(const char*)> | 259 | template <void func(const char*, int len)> |
| 260 | void Wrap() { | 260 | void Wrap() { |
| 261 | func((char*)Memory::GetPointer(PARAM(0))); | 261 | func((char*)Memory::GetPointer(PARAM(0)), PARAM(1)); |
| 262 | } | 262 | } |
| 263 | 263 | ||
| 264 | template <void func(u8)> | 264 | template <void func(u8)> |
diff --git a/src/core/hle/ipc.h b/src/core/hle/ipc.h index cd9a5863d..3a5d481a5 100644 --- a/src/core/hle/ipc.h +++ b/src/core/hle/ipc.h | |||
| @@ -10,7 +10,8 @@ | |||
| 10 | 10 | ||
| 11 | namespace Kernel { | 11 | namespace Kernel { |
| 12 | 12 | ||
| 13 | static const int kCommandHeaderOffset = 0x80; ///< Offset into command buffer of header | 13 | /// Offset into command buffer of header |
| 14 | static const int kCommandHeaderOffset = 0x80; | ||
| 14 | 15 | ||
| 15 | /** | 16 | /** |
| 16 | * Returns a pointer to the command buffer in the current thread's TLS | 17 | * Returns a pointer to the command buffer in the current thread's TLS |
| @@ -26,8 +27,8 @@ inline u32* GetCommandBuffer(const int offset = 0) { | |||
| 26 | offset); | 27 | offset); |
| 27 | } | 28 | } |
| 28 | 29 | ||
| 29 | static const int kStaticBuffersOffset = | 30 | /// Offset into static buffers, relative to command buffer header |
| 30 | 0x100; ///< Offset into static buffers, relative to command buffer header | 31 | static const int kStaticBuffersOffset = 0x100; |
| 31 | 32 | ||
| 32 | /** | 33 | /** |
| 33 | * Returns a pointer to the static buffers area in the current thread's TLS | 34 | * Returns a pointer to the static buffers area in the current thread's TLS |
diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h index 323158bb5..06c4c5a85 100644 --- a/src/core/hle/ipc_helpers.h +++ b/src/core/hle/ipc_helpers.h | |||
| @@ -27,6 +27,24 @@ public: | |||
| 27 | DEBUG_ASSERT_MSG(index == TotalSize(), "Operations do not match the header (cmd 0x%x)", | 27 | DEBUG_ASSERT_MSG(index == TotalSize(), "Operations do not match the header (cmd 0x%x)", |
| 28 | header.raw); | 28 | header.raw); |
| 29 | } | 29 | } |
| 30 | |||
| 31 | void Skip(unsigned size_in_words, bool set_to_null) { | ||
| 32 | if (set_to_null) | ||
| 33 | memset(cmdbuf + index, 0, size_in_words * sizeof(u32)); | ||
| 34 | index += size_in_words; | ||
| 35 | } | ||
| 36 | |||
| 37 | /** | ||
| 38 | * @brief Retrieves the address of a static buffer, used when a buffer is needed for output | ||
| 39 | * @param buffer_id The index of the static buffer | ||
| 40 | * @param data_size If non-null, will store the size of the buffer | ||
| 41 | */ | ||
| 42 | VAddr PeekStaticBuffer(u8 buffer_id, size_t* data_size = nullptr) const { | ||
| 43 | u32* static_buffer = cmdbuf + Kernel::kStaticBuffersOffset / sizeof(u32) + buffer_id * 2; | ||
| 44 | if (data_size) | ||
| 45 | *data_size = StaticBufferDescInfo{static_buffer[0]}.size; | ||
| 46 | return static_buffer[1]; | ||
| 47 | } | ||
| 30 | }; | 48 | }; |
| 31 | 49 | ||
| 32 | class RequestBuilder : public RequestHelperBase { | 50 | class RequestBuilder : public RequestHelperBase { |
| @@ -50,14 +68,8 @@ public: | |||
| 50 | template <typename T> | 68 | template <typename T> |
| 51 | void Push(T value); | 69 | void Push(T value); |
| 52 | 70 | ||
| 53 | void Push(u32 value) { | ||
| 54 | cmdbuf[index++] = value; | ||
| 55 | } | ||
| 56 | template <typename First, typename... Other> | 71 | template <typename First, typename... Other> |
| 57 | void Push(const First& first_value, const Other&... other_values) { | 72 | void Push(const First& first_value, const Other&... other_values); |
| 58 | Push(first_value); | ||
| 59 | Push(other_values...); | ||
| 60 | } | ||
| 61 | 73 | ||
| 62 | /** | 74 | /** |
| 63 | * @brief Copies the content of the given trivially copyable class to the buffer as a normal | 75 | * @brief Copies the content of the given trivially copyable class to the buffer as a normal |
| @@ -65,59 +77,96 @@ public: | |||
| 65 | * @note: The input class must be correctly packed/padded to fit hardware layout. | 77 | * @note: The input class must be correctly packed/padded to fit hardware layout. |
| 66 | */ | 78 | */ |
| 67 | template <typename T> | 79 | template <typename T> |
| 68 | void PushRaw(const T& value) { | 80 | void PushRaw(const T& value); |
| 69 | static_assert(std::is_trivially_copyable<T>(), "Raw types should be trivially copyable"); | ||
| 70 | std::memcpy(cmdbuf + index, &value, sizeof(T)); | ||
| 71 | index += (sizeof(T) + 3) / 4; // round up to word length | ||
| 72 | } | ||
| 73 | 81 | ||
| 74 | // TODO : ensure that translate params are added after all regular params | 82 | // TODO : ensure that translate params are added after all regular params |
| 75 | template <typename... H> | 83 | template <typename... H> |
| 76 | void PushCopyHandles(H... handles) { | 84 | void PushCopyHandles(H... handles); |
| 77 | Push(CopyHandleDesc(sizeof...(H))); | ||
| 78 | Push(static_cast<Kernel::Handle>(handles)...); | ||
| 79 | } | ||
| 80 | 85 | ||
| 81 | template <typename... H> | 86 | template <typename... H> |
| 82 | void PushMoveHandles(H... handles) { | 87 | void PushMoveHandles(H... handles); |
| 83 | Push(MoveHandleDesc(sizeof...(H))); | ||
| 84 | Push(static_cast<Kernel::Handle>(handles)...); | ||
| 85 | } | ||
| 86 | 88 | ||
| 87 | void PushCurrentPIDHandle() { | 89 | void PushCurrentPIDHandle(); |
| 88 | Push(CallingPidDesc()); | ||
| 89 | Push(u32(0)); | ||
| 90 | } | ||
| 91 | 90 | ||
| 92 | void PushStaticBuffer(VAddr buffer_vaddr, u32 size, u8 buffer_id) { | 91 | void PushStaticBuffer(VAddr buffer_vaddr, u32 size, u8 buffer_id); |
| 93 | Push(StaticBufferDesc(size, buffer_id)); | ||
| 94 | Push(buffer_vaddr); | ||
| 95 | } | ||
| 96 | 92 | ||
| 97 | void PushMappedBuffer(VAddr buffer_vaddr, u32 size, MappedBufferPermissions perms) { | 93 | void PushMappedBuffer(VAddr buffer_vaddr, u32 size, MappedBufferPermissions perms); |
| 98 | Push(MappedBufferDesc(size, perms)); | ||
| 99 | Push(buffer_vaddr); | ||
| 100 | } | ||
| 101 | }; | 94 | }; |
| 102 | 95 | ||
| 103 | /// Push /// | 96 | /// Push /// |
| 104 | 97 | ||
| 105 | template <> | 98 | template <> |
| 106 | inline void RequestBuilder::Push<u32>(u32 value) { | 99 | inline void RequestBuilder::Push(u32 value) { |
| 107 | Push(value); | 100 | cmdbuf[index++] = value; |
| 101 | } | ||
| 102 | |||
| 103 | template <typename T> | ||
| 104 | void RequestBuilder::PushRaw(const T& value) { | ||
| 105 | static_assert(std::is_trivially_copyable<T>(), "Raw types should be trivially copyable"); | ||
| 106 | std::memcpy(cmdbuf + index, &value, sizeof(T)); | ||
| 107 | index += (sizeof(T) + 3) / 4; // round up to word length | ||
| 108 | } | 108 | } |
| 109 | 109 | ||
| 110 | template <> | 110 | template <> |
| 111 | inline void RequestBuilder::Push<u64>(u64 value) { | 111 | inline void RequestBuilder::Push(u8 value) { |
| 112 | PushRaw(value); | ||
| 113 | } | ||
| 114 | |||
| 115 | template <> | ||
| 116 | inline void RequestBuilder::Push(u16 value) { | ||
| 117 | PushRaw(value); | ||
| 118 | } | ||
| 119 | |||
| 120 | template <> | ||
| 121 | inline void RequestBuilder::Push(u64 value) { | ||
| 112 | Push(static_cast<u32>(value)); | 122 | Push(static_cast<u32>(value)); |
| 113 | Push(static_cast<u32>(value >> 32)); | 123 | Push(static_cast<u32>(value >> 32)); |
| 114 | } | 124 | } |
| 115 | 125 | ||
| 116 | template <> | 126 | template <> |
| 117 | inline void RequestBuilder::Push<ResultCode>(ResultCode value) { | 127 | inline void RequestBuilder::Push(bool value) { |
| 128 | Push(static_cast<u8>(value)); | ||
| 129 | } | ||
| 130 | |||
| 131 | template <> | ||
| 132 | inline void RequestBuilder::Push(ResultCode value) { | ||
| 118 | Push(value.raw); | 133 | Push(value.raw); |
| 119 | } | 134 | } |
| 120 | 135 | ||
| 136 | template <typename First, typename... Other> | ||
| 137 | void RequestBuilder::Push(const First& first_value, const Other&... other_values) { | ||
| 138 | Push(first_value); | ||
| 139 | Push(other_values...); | ||
| 140 | } | ||
| 141 | |||
| 142 | template <typename... H> | ||
| 143 | inline void RequestBuilder::PushCopyHandles(H... handles) { | ||
| 144 | Push(CopyHandleDesc(sizeof...(H))); | ||
| 145 | Push(static_cast<Kernel::Handle>(handles)...); | ||
| 146 | } | ||
| 147 | |||
| 148 | template <typename... H> | ||
| 149 | inline void RequestBuilder::PushMoveHandles(H... handles) { | ||
| 150 | Push(MoveHandleDesc(sizeof...(H))); | ||
| 151 | Push(static_cast<Kernel::Handle>(handles)...); | ||
| 152 | } | ||
| 153 | |||
| 154 | inline void RequestBuilder::PushCurrentPIDHandle() { | ||
| 155 | Push(CallingPidDesc()); | ||
| 156 | Push(u32(0)); | ||
| 157 | } | ||
| 158 | |||
| 159 | inline void RequestBuilder::PushStaticBuffer(VAddr buffer_vaddr, u32 size, u8 buffer_id) { | ||
| 160 | Push(StaticBufferDesc(size, buffer_id)); | ||
| 161 | Push(buffer_vaddr); | ||
| 162 | } | ||
| 163 | |||
| 164 | inline void RequestBuilder::PushMappedBuffer(VAddr buffer_vaddr, u32 size, | ||
| 165 | MappedBufferPermissions perms) { | ||
| 166 | Push(MappedBufferDesc(size, perms)); | ||
| 167 | Push(buffer_vaddr); | ||
| 168 | } | ||
| 169 | |||
| 121 | class RequestParser : public RequestHelperBase { | 170 | class RequestParser : public RequestHelperBase { |
| 122 | public: | 171 | public: |
| 123 | RequestParser(u32* command_buffer, Header command_header) | 172 | RequestParser(u32* command_buffer, Header command_header) |
| @@ -185,24 +234,60 @@ public: | |||
| 185 | */ | 234 | */ |
| 186 | template <typename T> | 235 | template <typename T> |
| 187 | void PopRaw(T& value); | 236 | void PopRaw(T& value); |
| 237 | |||
| 238 | /** | ||
| 239 | * @brief Reads the next normal parameters as a struct, by copying it into a new value | ||
| 240 | * @note: The output class must be correctly packed/padded to fit hardware layout. | ||
| 241 | */ | ||
| 242 | template <typename T> | ||
| 243 | T PopRaw(); | ||
| 188 | }; | 244 | }; |
| 189 | 245 | ||
| 190 | /// Pop /// | 246 | /// Pop /// |
| 191 | 247 | ||
| 192 | template <> | 248 | template <> |
| 193 | inline u32 RequestParser::Pop<u32>() { | 249 | inline u32 RequestParser::Pop() { |
| 194 | return cmdbuf[index++]; | 250 | return cmdbuf[index++]; |
| 195 | } | 251 | } |
| 196 | 252 | ||
| 253 | template <typename T> | ||
| 254 | void RequestParser::PopRaw(T& value) { | ||
| 255 | static_assert(std::is_trivially_copyable<T>(), "Raw types should be trivially copyable"); | ||
| 256 | std::memcpy(&value, cmdbuf + index, sizeof(T)); | ||
| 257 | index += (sizeof(T) + 3) / 4; // round up to word length | ||
| 258 | } | ||
| 259 | |||
| 260 | template <typename T> | ||
| 261 | T RequestParser::PopRaw() { | ||
| 262 | T value; | ||
| 263 | PopRaw(value); | ||
| 264 | return value; | ||
| 265 | } | ||
| 266 | |||
| 267 | template <> | ||
| 268 | inline u8 RequestParser::Pop() { | ||
| 269 | return PopRaw<u8>(); | ||
| 270 | } | ||
| 271 | |||
| 197 | template <> | 272 | template <> |
| 198 | inline u64 RequestParser::Pop<u64>() { | 273 | inline u16 RequestParser::Pop() { |
| 274 | return PopRaw<u16>(); | ||
| 275 | } | ||
| 276 | |||
| 277 | template <> | ||
| 278 | inline u64 RequestParser::Pop() { | ||
| 199 | const u64 lsw = Pop<u32>(); | 279 | const u64 lsw = Pop<u32>(); |
| 200 | const u64 msw = Pop<u32>(); | 280 | const u64 msw = Pop<u32>(); |
| 201 | return msw << 32 | lsw; | 281 | return msw << 32 | lsw; |
| 202 | } | 282 | } |
| 203 | 283 | ||
| 204 | template <> | 284 | template <> |
| 205 | inline ResultCode RequestParser::Pop<ResultCode>() { | 285 | inline bool RequestParser::Pop() { |
| 286 | return Pop<u8>() != 0; | ||
| 287 | } | ||
| 288 | |||
| 289 | template <> | ||
| 290 | inline ResultCode RequestParser::Pop() { | ||
| 206 | return ResultCode{Pop<u32>()}; | 291 | return ResultCode{Pop<u32>()}; |
| 207 | } | 292 | } |
| 208 | 293 | ||
| @@ -265,11 +350,4 @@ inline VAddr RequestParser::PopMappedBuffer(size_t* data_size, | |||
| 265 | return Pop<VAddr>(); | 350 | return Pop<VAddr>(); |
| 266 | } | 351 | } |
| 267 | 352 | ||
| 268 | template <typename T> | ||
| 269 | void RequestParser::PopRaw(T& value) { | ||
| 270 | static_assert(std::is_trivially_copyable<T>(), "Raw types should be trivially copyable"); | ||
| 271 | std::memcpy(&value, cmdbuf + index, sizeof(T)); | ||
| 272 | index += (sizeof(T) + 3) / 4; // round up to word length | ||
| 273 | } | ||
| 274 | |||
| 275 | } // namespace IPC | 353 | } // namespace IPC |
diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp index e57b19c2d..366d1eacf 100644 --- a/src/core/hle/service/apt/apt.cpp +++ b/src/core/hle/service/apt/apt.cpp | |||
| @@ -49,13 +49,13 @@ void SendParameter(const MessageParameter& parameter) { | |||
| 49 | } | 49 | } |
| 50 | 50 | ||
| 51 | void Initialize(Service::Interface* self) { | 51 | void Initialize(Service::Interface* self) { |
| 52 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 52 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x2, 2, 0); // 0x20080 |
| 53 | u32 app_id = cmd_buff[1]; | 53 | u32 app_id = rp.Pop<u32>(); |
| 54 | u32 flags = cmd_buff[2]; | 54 | u32 flags = rp.Pop<u32>(); |
| 55 | 55 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 3); | |
| 56 | cmd_buff[2] = IPC::CopyHandleDesc(2); | 56 | rb.Push(RESULT_SUCCESS); |
| 57 | cmd_buff[3] = Kernel::g_handle_table.Create(notification_event).MoveFrom(); | 57 | rb.PushCopyHandles(Kernel::g_handle_table.Create(notification_event).MoveFrom(), |
| 58 | cmd_buff[4] = Kernel::g_handle_table.Create(parameter_event).MoveFrom(); | 58 | Kernel::g_handle_table.Create(parameter_event).MoveFrom()); |
| 59 | 59 | ||
| 60 | // TODO(bunnei): Check if these events are cleared every time Initialize is called. | 60 | // TODO(bunnei): Check if these events are cleared every time Initialize is called. |
| 61 | notification_event->Clear(); | 61 | notification_event->Clear(); |
| @@ -64,18 +64,16 @@ void Initialize(Service::Interface* self) { | |||
| 64 | ASSERT_MSG((nullptr != lock), "Cannot initialize without lock"); | 64 | ASSERT_MSG((nullptr != lock), "Cannot initialize without lock"); |
| 65 | lock->Release(); | 65 | lock->Release(); |
| 66 | 66 | ||
| 67 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 68 | |||
| 69 | LOG_DEBUG(Service_APT, "called app_id=0x%08X, flags=0x%08X", app_id, flags); | 67 | LOG_DEBUG(Service_APT, "called app_id=0x%08X, flags=0x%08X", app_id, flags); |
| 70 | } | 68 | } |
| 71 | 69 | ||
| 72 | void GetSharedFont(Service::Interface* self) { | 70 | void GetSharedFont(Service::Interface* self) { |
| 73 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 71 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x44, 0, 0); // 0x00440000 |
| 74 | 72 | IPC::RequestBuilder rb = rp.MakeBuilder(2, 2); | |
| 75 | if (!shared_font_mem) { | 73 | if (!shared_font_mem) { |
| 76 | LOG_ERROR(Service_APT, "shared font file missing - go dump it from your 3ds"); | 74 | LOG_ERROR(Service_APT, "shared font file missing - go dump it from your 3ds"); |
| 77 | cmd_buff[0] = IPC::MakeHeader(0x44, 2, 2); | 75 | rb.Push<u32>(-1); // TODO: Find the right error code |
| 78 | cmd_buff[1] = -1; // TODO: Find the right error code | 76 | rb.Skip(1 + 2, true); |
| 79 | return; | 77 | return; |
| 80 | } | 78 | } |
| 81 | 79 | ||
| @@ -87,103 +85,110 @@ void GetSharedFont(Service::Interface* self) { | |||
| 87 | BCFNT::RelocateSharedFont(shared_font_mem, target_address); | 85 | BCFNT::RelocateSharedFont(shared_font_mem, target_address); |
| 88 | shared_font_relocated = true; | 86 | shared_font_relocated = true; |
| 89 | } | 87 | } |
| 90 | cmd_buff[0] = IPC::MakeHeader(0x44, 2, 2); | 88 | |
| 91 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | 89 | rb.Push(RESULT_SUCCESS); // No error |
| 92 | // Since the SharedMemory interface doesn't provide the address at which the memory was | 90 | // Since the SharedMemory interface doesn't provide the address at which the memory was |
| 93 | // allocated, the real APT service calculates this address by scanning the entire address space | 91 | // allocated, the real APT service calculates this address by scanning the entire address space |
| 94 | // (using svcQueryMemory) and searches for an allocation of the same size as the Shared Font. | 92 | // (using svcQueryMemory) and searches for an allocation of the same size as the Shared Font. |
| 95 | cmd_buff[2] = target_address; | 93 | rb.Push(target_address); |
| 96 | cmd_buff[3] = IPC::CopyHandleDesc(); | 94 | rb.PushCopyHandles(Kernel::g_handle_table.Create(shared_font_mem).MoveFrom()); |
| 97 | cmd_buff[4] = Kernel::g_handle_table.Create(shared_font_mem).MoveFrom(); | ||
| 98 | } | 95 | } |
| 99 | 96 | ||
| 100 | void NotifyToWait(Service::Interface* self) { | 97 | void NotifyToWait(Service::Interface* self) { |
| 101 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 98 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x43, 1, 0); // 0x430040 |
| 102 | u32 app_id = cmd_buff[1]; | 99 | u32 app_id = rp.Pop<u32>(); |
| 103 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | 100 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); |
| 101 | rb.Push(RESULT_SUCCESS); // No error | ||
| 104 | LOG_WARNING(Service_APT, "(STUBBED) app_id=%u", app_id); | 102 | LOG_WARNING(Service_APT, "(STUBBED) app_id=%u", app_id); |
| 105 | } | 103 | } |
| 106 | 104 | ||
| 107 | void GetLockHandle(Service::Interface* self) { | 105 | void GetLockHandle(Service::Interface* self) { |
| 108 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 106 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1, 1, 0); // 0x10040 |
| 107 | |||
| 109 | // Bits [0:2] are the applet type (System, Library, etc) | 108 | // Bits [0:2] are the applet type (System, Library, etc) |
| 110 | // Bit 5 tells the application that there's a pending APT parameter, | 109 | // Bit 5 tells the application that there's a pending APT parameter, |
| 111 | // this will cause the app to wait until parameter_event is signaled. | 110 | // this will cause the app to wait until parameter_event is signaled. |
| 112 | u32 applet_attributes = cmd_buff[1]; | 111 | u32 applet_attributes = rp.Pop<u32>(); |
| 113 | 112 | IPC::RequestBuilder rb = rp.MakeBuilder(3, 2); | |
| 114 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | 113 | rb.Push(RESULT_SUCCESS); // No error |
| 115 | 114 | rb.Push(applet_attributes); // Applet Attributes, this value is passed to Enable. | |
| 116 | cmd_buff[2] = applet_attributes; // Applet Attributes, this value is passed to Enable. | 115 | rb.Push<u32>(0); // Least significant bit = power button state |
| 117 | cmd_buff[3] = 0; // Least significant bit = power button state | 116 | Kernel::Handle handle_copy = Kernel::g_handle_table.Create(lock).MoveFrom(); |
| 118 | cmd_buff[4] = IPC::CopyHandleDesc(); | 117 | rb.PushCopyHandles(handle_copy); |
| 119 | cmd_buff[5] = Kernel::g_handle_table.Create(lock).MoveFrom(); | 118 | |
| 120 | 119 | LOG_WARNING(Service_APT, "(STUBBED) called handle=0x%08X applet_attributes=0x%08X", handle_copy, | |
| 121 | LOG_WARNING(Service_APT, "(STUBBED) called handle=0x%08X applet_attributes=0x%08X", cmd_buff[5], | ||
| 122 | applet_attributes); | 120 | applet_attributes); |
| 123 | } | 121 | } |
| 124 | 122 | ||
| 125 | void Enable(Service::Interface* self) { | 123 | void Enable(Service::Interface* self) { |
| 126 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 124 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x3, 1, 0); // 0x30040 |
| 127 | u32 attributes = cmd_buff[1]; | 125 | u32 attributes = rp.Pop<u32>(); |
| 128 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | 126 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); |
| 129 | parameter_event->Signal(); // Let the application know that it has been started | 127 | rb.Push(RESULT_SUCCESS); // No error |
| 128 | parameter_event->Signal(); // Let the application know that it has been started | ||
| 130 | LOG_WARNING(Service_APT, "(STUBBED) called attributes=0x%08X", attributes); | 129 | LOG_WARNING(Service_APT, "(STUBBED) called attributes=0x%08X", attributes); |
| 131 | } | 130 | } |
| 132 | 131 | ||
| 133 | void GetAppletManInfo(Service::Interface* self) { | 132 | void GetAppletManInfo(Service::Interface* self) { |
| 134 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 133 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x5, 1, 0); // 0x50040 |
| 135 | u32 unk = cmd_buff[1]; | 134 | u32 unk = rp.Pop<u32>(); |
| 136 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | 135 | IPC::RequestBuilder rb = rp.MakeBuilder(5, 0); |
| 137 | cmd_buff[2] = 0; | 136 | rb.Push(RESULT_SUCCESS); // No error |
| 138 | cmd_buff[3] = 0; | 137 | rb.Push<u32>(0); |
| 139 | cmd_buff[4] = static_cast<u32>(AppletId::HomeMenu); // Home menu AppID | 138 | rb.Push<u32>(0); |
| 140 | cmd_buff[5] = static_cast<u32>(AppletId::Application); // TODO(purpasmart96): Do this correctly | 139 | rb.Push(static_cast<u32>(AppletId::HomeMenu)); // Home menu AppID |
| 140 | rb.Push(static_cast<u32>(AppletId::Application)); // TODO(purpasmart96): Do this correctly | ||
| 141 | 141 | ||
| 142 | LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X", unk); | 142 | LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X", unk); |
| 143 | } | 143 | } |
| 144 | 144 | ||
| 145 | void IsRegistered(Service::Interface* self) { | 145 | void IsRegistered(Service::Interface* self) { |
| 146 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 146 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x9, 1, 0); // 0x90040 |
| 147 | u32 app_id = cmd_buff[1]; | 147 | u32 app_id = rp.Pop<u32>(); |
| 148 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | 148 | IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); |
| 149 | rb.Push(RESULT_SUCCESS); // No error | ||
| 149 | 150 | ||
| 150 | // TODO(Subv): An application is considered "registered" if it has already called APT::Enable | 151 | // TODO(Subv): An application is considered "registered" if it has already called APT::Enable |
| 151 | // handle this properly once we implement multiprocess support. | 152 | // handle this properly once we implement multiprocess support. |
| 152 | cmd_buff[2] = 0; // Set to not registered by default | 153 | bool is_registered = false; // Set to not registered by default |
| 153 | 154 | ||
| 154 | if (app_id == static_cast<u32>(AppletId::AnyLibraryApplet)) { | 155 | if (app_id == static_cast<u32>(AppletId::AnyLibraryApplet)) { |
| 155 | cmd_buff[2] = HLE::Applets::IsLibraryAppletRunning() ? 1 : 0; | 156 | is_registered = HLE::Applets::IsLibraryAppletRunning(); |
| 156 | } else if (auto applet = HLE::Applets::Applet::Get(static_cast<AppletId>(app_id))) { | 157 | } else if (auto applet = HLE::Applets::Applet::Get(static_cast<AppletId>(app_id))) { |
| 157 | cmd_buff[2] = 1; // Set to registered | 158 | is_registered = true; // Set to registered |
| 158 | } | 159 | } |
| 160 | rb.Push(is_registered); | ||
| 161 | |||
| 159 | LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X", app_id); | 162 | LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X", app_id); |
| 160 | } | 163 | } |
| 161 | 164 | ||
| 162 | void InquireNotification(Service::Interface* self) { | 165 | void InquireNotification(Service::Interface* self) { |
| 163 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 166 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0xB, 1, 0); // 0xB0040 |
| 164 | u32 app_id = cmd_buff[1]; | 167 | u32 app_id = rp.Pop<u32>(); |
| 165 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | 168 | IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); |
| 166 | cmd_buff[2] = static_cast<u32>(SignalType::None); // Signal type | 169 | rb.Push(RESULT_SUCCESS); // No error |
| 170 | rb.Push(static_cast<u32>(SignalType::None)); // Signal type | ||
| 167 | LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X", app_id); | 171 | LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X", app_id); |
| 168 | } | 172 | } |
| 169 | 173 | ||
| 170 | void SendParameter(Service::Interface* self) { | 174 | void SendParameter(Service::Interface* self) { |
| 171 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 175 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0xC, 4, 4); // 0xC0104 |
| 172 | u32 src_app_id = cmd_buff[1]; | 176 | u32 src_app_id = rp.Pop<u32>(); |
| 173 | u32 dst_app_id = cmd_buff[2]; | 177 | u32 dst_app_id = rp.Pop<u32>(); |
| 174 | u32 signal_type = cmd_buff[3]; | 178 | u32 signal_type = rp.Pop<u32>(); |
| 175 | u32 buffer_size = cmd_buff[4]; | 179 | u32 buffer_size = rp.Pop<u32>(); |
| 176 | u32 value = cmd_buff[5]; | 180 | Kernel::Handle handle = rp.PopHandle(); |
| 177 | u32 handle = cmd_buff[6]; | 181 | size_t size; |
| 178 | u32 size = cmd_buff[7]; | 182 | VAddr buffer = rp.PopStaticBuffer(&size); |
| 179 | u32 buffer = cmd_buff[8]; | ||
| 180 | 183 | ||
| 181 | std::shared_ptr<HLE::Applets::Applet> dest_applet = | 184 | std::shared_ptr<HLE::Applets::Applet> dest_applet = |
| 182 | HLE::Applets::Applet::Get(static_cast<AppletId>(dst_app_id)); | 185 | HLE::Applets::Applet::Get(static_cast<AppletId>(dst_app_id)); |
| 183 | 186 | ||
| 187 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 188 | |||
| 184 | if (dest_applet == nullptr) { | 189 | if (dest_applet == nullptr) { |
| 185 | LOG_ERROR(Service_APT, "Unknown applet id=0x%08X", dst_app_id); | 190 | LOG_ERROR(Service_APT, "Unknown applet id=0x%08X", dst_app_id); |
| 186 | cmd_buff[1] = -1; // TODO(Subv): Find the right error code | 191 | rb.Push<u32>(-1); // TODO(Subv): Find the right error code |
| 187 | return; | 192 | return; |
| 188 | } | 193 | } |
| 189 | 194 | ||
| @@ -195,88 +200,104 @@ void SendParameter(Service::Interface* self) { | |||
| 195 | param.buffer.resize(buffer_size); | 200 | param.buffer.resize(buffer_size); |
| 196 | Memory::ReadBlock(buffer, param.buffer.data(), param.buffer.size()); | 201 | Memory::ReadBlock(buffer, param.buffer.data(), param.buffer.size()); |
| 197 | 202 | ||
| 198 | cmd_buff[1] = dest_applet->ReceiveParameter(param).raw; | 203 | rb.Push(dest_applet->ReceiveParameter(param)); |
| 199 | 204 | ||
| 200 | LOG_WARNING( | 205 | LOG_WARNING(Service_APT, |
| 201 | Service_APT, | 206 | "(STUBBED) called src_app_id=0x%08X, dst_app_id=0x%08X, signal_type=0x%08X," |
| 202 | "(STUBBED) called src_app_id=0x%08X, dst_app_id=0x%08X, signal_type=0x%08X," | 207 | "buffer_size=0x%08X, handle=0x%08X, size=0x%08zX, in_param_buffer_ptr=0x%08X", |
| 203 | "buffer_size=0x%08X, value=0x%08X, handle=0x%08X, size=0x%08X, in_param_buffer_ptr=0x%08X", | 208 | src_app_id, dst_app_id, signal_type, buffer_size, handle, size, buffer); |
| 204 | src_app_id, dst_app_id, signal_type, buffer_size, value, handle, size, buffer); | ||
| 205 | } | 209 | } |
| 206 | 210 | ||
| 207 | void ReceiveParameter(Service::Interface* self) { | 211 | void ReceiveParameter(Service::Interface* self) { |
| 208 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 212 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0xD, 2, 0); // 0xD0080 |
| 209 | u32 app_id = cmd_buff[1]; | 213 | u32 app_id = rp.Pop<u32>(); |
| 210 | u32 buffer_size = cmd_buff[2]; | 214 | u32 buffer_size = rp.Pop<u32>(); |
| 211 | VAddr buffer = cmd_buff[0x104 >> 2]; | 215 | |
| 212 | 216 | size_t static_buff_size; | |
| 213 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | 217 | VAddr buffer = rp.PeekStaticBuffer(0, &static_buff_size); |
| 214 | cmd_buff[2] = next_parameter.sender_id; | 218 | if (buffer_size > static_buff_size) |
| 215 | cmd_buff[3] = next_parameter.signal; // Signal type | 219 | LOG_WARNING( |
| 216 | cmd_buff[4] = next_parameter.buffer.size(); // Parameter buffer size | 220 | Service_APT, |
| 217 | cmd_buff[5] = 0x10; | 221 | "buffer_size is bigger than the size in the buffer descriptor (0x%08X > 0x%08zX)", |
| 218 | cmd_buff[6] = 0; | 222 | buffer_size, static_buff_size); |
| 219 | if (next_parameter.object != nullptr) | 223 | |
| 220 | cmd_buff[6] = Kernel::g_handle_table.Create(next_parameter.object).MoveFrom(); | 224 | IPC::RequestBuilder rb = rp.MakeBuilder(4, 4); |
| 221 | cmd_buff[7] = (next_parameter.buffer.size() << 14) | 2; | 225 | rb.Push(RESULT_SUCCESS); // No error |
| 222 | cmd_buff[8] = buffer; | 226 | rb.Push(next_parameter.sender_id); |
| 227 | rb.Push(next_parameter.signal); // Signal type | ||
| 228 | ASSERT_MSG(next_parameter.buffer.size() <= buffer_size, "Input static buffer is too small !"); | ||
| 229 | rb.Push(static_cast<u32>(next_parameter.buffer.size())); // Parameter buffer size | ||
| 230 | |||
| 231 | rb.PushMoveHandles((next_parameter.object != nullptr) | ||
| 232 | ? Kernel::g_handle_table.Create(next_parameter.object).MoveFrom() | ||
| 233 | : 0); | ||
| 234 | rb.PushStaticBuffer(buffer, static_cast<u32>(next_parameter.buffer.size()), 0); | ||
| 223 | 235 | ||
| 224 | Memory::WriteBlock(buffer, next_parameter.buffer.data(), next_parameter.buffer.size()); | 236 | Memory::WriteBlock(buffer, next_parameter.buffer.data(), next_parameter.buffer.size()); |
| 225 | 237 | ||
| 226 | LOG_WARNING(Service_APT, "called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size); | 238 | LOG_WARNING(Service_APT, "called app_id=0x%08X, buffer_size=0x%08zX", app_id, buffer_size); |
| 227 | } | 239 | } |
| 228 | 240 | ||
| 229 | void GlanceParameter(Service::Interface* self) { | 241 | void GlanceParameter(Service::Interface* self) { |
| 230 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 242 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0xE, 2, 0); // 0xE0080 |
| 231 | u32 app_id = cmd_buff[1]; | 243 | u32 app_id = rp.Pop<u32>(); |
| 232 | u32 buffer_size = cmd_buff[2]; | 244 | u32 buffer_size = rp.Pop<u32>(); |
| 233 | VAddr buffer = cmd_buff[0x104 >> 2]; | 245 | |
| 246 | size_t static_buff_size; | ||
| 247 | VAddr buffer = rp.PeekStaticBuffer(0, &static_buff_size); | ||
| 248 | if (buffer_size > static_buff_size) | ||
| 249 | LOG_WARNING( | ||
| 250 | Service_APT, | ||
| 251 | "buffer_size is bigger than the size in the buffer descriptor (0x%08X > 0x%08zX)", | ||
| 252 | buffer_size, static_buff_size); | ||
| 234 | 253 | ||
| 235 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | 254 | IPC::RequestBuilder rb = rp.MakeBuilder(4, 4); |
| 236 | cmd_buff[2] = next_parameter.sender_id; | 255 | rb.Push(RESULT_SUCCESS); // No error |
| 237 | cmd_buff[3] = next_parameter.signal; // Signal type | 256 | rb.Push(next_parameter.sender_id); |
| 238 | cmd_buff[4] = next_parameter.buffer.size(); // Parameter buffer size | 257 | rb.Push(next_parameter.signal); // Signal type |
| 239 | cmd_buff[5] = 0x10; | 258 | ASSERT_MSG(next_parameter.buffer.size() <= buffer_size, "Input static buffer is too small !"); |
| 240 | cmd_buff[6] = 0; | 259 | rb.Push(static_cast<u32>(next_parameter.buffer.size())); // Parameter buffer size |
| 241 | if (next_parameter.object != nullptr) | ||
| 242 | cmd_buff[6] = Kernel::g_handle_table.Create(next_parameter.object).MoveFrom(); | ||
| 243 | cmd_buff[7] = (next_parameter.buffer.size() << 14) | 2; | ||
| 244 | cmd_buff[8] = buffer; | ||
| 245 | 260 | ||
| 246 | Memory::WriteBlock(buffer, next_parameter.buffer.data(), | 261 | rb.PushCopyHandles((next_parameter.object != nullptr) |
| 247 | std::min(static_cast<size_t>(buffer_size), next_parameter.buffer.size())); | 262 | ? Kernel::g_handle_table.Create(next_parameter.object).MoveFrom() |
| 263 | : 0); | ||
| 264 | rb.PushStaticBuffer(buffer, static_cast<u32>(next_parameter.buffer.size()), 0); | ||
| 248 | 265 | ||
| 249 | LOG_WARNING(Service_APT, "called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size); | 266 | Memory::WriteBlock(buffer, next_parameter.buffer.data(), next_parameter.buffer.size()); |
| 267 | |||
| 268 | LOG_WARNING(Service_APT, "called app_id=0x%08X, buffer_size=0x%08zX", app_id, buffer_size); | ||
| 250 | } | 269 | } |
| 251 | 270 | ||
| 252 | void CancelParameter(Service::Interface* self) { | 271 | void CancelParameter(Service::Interface* self) { |
| 253 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 272 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0xF, 4, 0); // 0xF0100 |
| 254 | u32 flag1 = cmd_buff[1]; | ||
| 255 | u32 unk = cmd_buff[2]; | ||
| 256 | u32 flag2 = cmd_buff[3]; | ||
| 257 | u32 app_id = cmd_buff[4]; | ||
| 258 | 273 | ||
| 259 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | 274 | u32 check_sender = rp.Pop<u32>(); |
| 260 | cmd_buff[2] = 1; // Set to Success | 275 | u32 sender_appid = rp.Pop<u32>(); |
| 276 | u32 check_receiver = rp.Pop<u32>(); | ||
| 277 | u32 receiver_appid = rp.Pop<u32>(); | ||
| 278 | IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); | ||
| 279 | rb.Push(RESULT_SUCCESS); // No error | ||
| 280 | rb.Push(true); // Set to Success | ||
| 261 | 281 | ||
| 262 | LOG_WARNING(Service_APT, | 282 | LOG_WARNING(Service_APT, "(STUBBED) called check_sender=0x%08X, sender_appid=0x%08X, " |
| 263 | "(STUBBED) called flag1=0x%08X, unk=0x%08X, flag2=0x%08X, app_id=0x%08X", flag1, | 283 | "check_receiver=0x%08X, receiver_appid=0x%08X", |
| 264 | unk, flag2, app_id); | 284 | check_sender, sender_appid, check_receiver, receiver_appid); |
| 265 | } | 285 | } |
| 266 | 286 | ||
| 267 | void PrepareToStartApplication(Service::Interface* self) { | 287 | void PrepareToStartApplication(Service::Interface* self) { |
| 268 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 288 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x15, 5, 0); // 0x00150140 |
| 269 | u32 title_info1 = cmd_buff[1]; | 289 | u32 title_info1 = rp.Pop<u32>(); |
| 270 | u32 title_info2 = cmd_buff[2]; | 290 | u32 title_info2 = rp.Pop<u32>(); |
| 271 | u32 title_info3 = cmd_buff[3]; | 291 | u32 title_info3 = rp.Pop<u32>(); |
| 272 | u32 title_info4 = cmd_buff[4]; | 292 | u32 title_info4 = rp.Pop<u32>(); |
| 273 | u32 flags = cmd_buff[5]; | 293 | u32 flags = rp.Pop<u32>(); |
| 274 | 294 | ||
| 275 | if (flags & 0x00000100) { | 295 | if (flags & 0x00000100) { |
| 276 | unknown_ns_state_field = 1; | 296 | unknown_ns_state_field = 1; |
| 277 | } | 297 | } |
| 278 | 298 | ||
| 279 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | 299 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); |
| 300 | rb.Push(RESULT_SUCCESS); // No error | ||
| 280 | 301 | ||
| 281 | LOG_WARNING(Service_APT, | 302 | LOG_WARNING(Service_APT, |
| 282 | "(STUBBED) called title_info1=0x%08X, title_info2=0x%08X, title_info3=0x%08X," | 303 | "(STUBBED) called title_info1=0x%08X, title_info2=0x%08X, title_info3=0x%08X," |
| @@ -285,172 +306,188 @@ void PrepareToStartApplication(Service::Interface* self) { | |||
| 285 | } | 306 | } |
| 286 | 307 | ||
| 287 | void StartApplication(Service::Interface* self) { | 308 | void StartApplication(Service::Interface* self) { |
| 288 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 309 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1B, 3, 4); // 0x001B00C4 |
| 289 | u32 buffer1_size = cmd_buff[1]; | 310 | u32 buffer1_size = rp.Pop<u32>(); |
| 290 | u32 buffer2_size = cmd_buff[2]; | 311 | u32 buffer2_size = rp.Pop<u32>(); |
| 291 | u32 flag = cmd_buff[3]; | 312 | u32 flag = rp.Pop<u32>(); |
| 292 | u32 size1 = cmd_buff[4]; | 313 | size_t size1; |
| 293 | u32 buffer1_ptr = cmd_buff[5]; | 314 | VAddr buffer1_ptr = rp.PopStaticBuffer(&size1); |
| 294 | u32 size2 = cmd_buff[6]; | 315 | size_t size2; |
| 295 | u32 buffer2_ptr = cmd_buff[7]; | 316 | VAddr buffer2_ptr = rp.PopStaticBuffer(&size2); |
| 296 | 317 | ||
| 297 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | 318 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); |
| 319 | rb.Push(RESULT_SUCCESS); // No error | ||
| 298 | 320 | ||
| 299 | LOG_WARNING(Service_APT, | 321 | LOG_WARNING(Service_APT, |
| 300 | "(STUBBED) called buffer1_size=0x%08X, buffer2_size=0x%08X, flag=0x%08X," | 322 | "(STUBBED) called buffer1_size=0x%08X, buffer2_size=0x%08X, flag=0x%08X," |
| 301 | "size1=0x%08X, buffer1_ptr=0x%08X, size2=0x%08X, buffer2_ptr=0x%08X", | 323 | "size1=0x%08zX, buffer1_ptr=0x%08X, size2=0x%08zX, buffer2_ptr=0x%08X", |
| 302 | buffer1_size, buffer2_size, flag, size1, buffer1_ptr, size2, buffer2_ptr); | 324 | buffer1_size, buffer2_size, flag, size1, buffer1_ptr, size2, buffer2_ptr); |
| 303 | } | 325 | } |
| 304 | 326 | ||
| 305 | void AppletUtility(Service::Interface* self) { | 327 | void AppletUtility(Service::Interface* self) { |
| 306 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 328 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x4B, 3, 2); // 0x004B00C2 |
| 307 | 329 | ||
| 308 | // These are from 3dbrew - I'm not really sure what they're used for. | 330 | // These are from 3dbrew - I'm not really sure what they're used for. |
| 309 | u32 command = cmd_buff[1]; | 331 | u32 utility_command = rp.Pop<u32>(); |
| 310 | u32 buffer1_size = cmd_buff[2]; | 332 | u32 input_size = rp.Pop<u32>(); |
| 311 | u32 buffer2_size = cmd_buff[3]; | 333 | u32 output_size = rp.Pop<u32>(); |
| 312 | u32 buffer1_addr = cmd_buff[5]; | 334 | VAddr input_addr = rp.PopStaticBuffer(); |
| 313 | u32 buffer2_addr = cmd_buff[65]; | 335 | |
| 336 | VAddr output_addr = rp.PeekStaticBuffer(0); | ||
| 314 | 337 | ||
| 315 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | 338 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); |
| 339 | rb.Push(RESULT_SUCCESS); // No error | ||
| 316 | 340 | ||
| 317 | LOG_WARNING(Service_APT, | 341 | LOG_WARNING(Service_APT, |
| 318 | "(STUBBED) called command=0x%08X, buffer1_size=0x%08X, buffer2_size=0x%08X, " | 342 | "(STUBBED) called command=0x%08X, input_size=0x%08X, output_size=0x%08X, " |
| 319 | "buffer1_addr=0x%08X, buffer2_addr=0x%08X", | 343 | "input_addr=0x%08X, output_addr=0x%08X", |
| 320 | command, buffer1_size, buffer2_size, buffer1_addr, buffer2_addr); | 344 | utility_command, input_size, output_size, input_addr, output_addr); |
| 321 | } | 345 | } |
| 322 | 346 | ||
| 323 | void SetAppCpuTimeLimit(Service::Interface* self) { | 347 | void SetAppCpuTimeLimit(Service::Interface* self) { |
| 324 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 348 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x4F, 2, 0); // 0x4F0080 |
| 325 | u32 value = cmd_buff[1]; | 349 | u32 value = rp.Pop<u32>(); |
| 326 | cpu_percent = cmd_buff[2]; | 350 | cpu_percent = rp.Pop<u32>(); |
| 327 | 351 | ||
| 328 | if (value != 1) { | 352 | if (value != 1) { |
| 329 | LOG_ERROR(Service_APT, "This value should be one, but is actually %u!", value); | 353 | LOG_ERROR(Service_APT, "This value should be one, but is actually %u!", value); |
| 330 | } | 354 | } |
| 331 | 355 | ||
| 332 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | 356 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); |
| 357 | rb.Push(RESULT_SUCCESS); // No error | ||
| 333 | 358 | ||
| 334 | LOG_WARNING(Service_APT, "(STUBBED) called cpu_percent=%u, value=%u", cpu_percent, value); | 359 | LOG_WARNING(Service_APT, "(STUBBED) called cpu_percent=%u, value=%u", cpu_percent, value); |
| 335 | } | 360 | } |
| 336 | 361 | ||
| 337 | void GetAppCpuTimeLimit(Service::Interface* self) { | 362 | void GetAppCpuTimeLimit(Service::Interface* self) { |
| 338 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 363 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x50, 1, 0); // 0x500040 |
| 339 | u32 value = cmd_buff[1]; | 364 | u32 value = rp.Pop<u32>(); |
| 340 | 365 | ||
| 341 | if (value != 1) { | 366 | if (value != 1) { |
| 342 | LOG_ERROR(Service_APT, "This value should be one, but is actually %u!", value); | 367 | LOG_ERROR(Service_APT, "This value should be one, but is actually %u!", value); |
| 343 | } | 368 | } |
| 344 | 369 | ||
| 345 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | 370 | IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); |
| 346 | cmd_buff[2] = cpu_percent; | 371 | rb.Push(RESULT_SUCCESS); // No error |
| 372 | rb.Push(cpu_percent); | ||
| 347 | 373 | ||
| 348 | LOG_WARNING(Service_APT, "(STUBBED) called value=%u", value); | 374 | LOG_WARNING(Service_APT, "(STUBBED) called value=%u", value); |
| 349 | } | 375 | } |
| 350 | 376 | ||
| 351 | void PrepareToStartLibraryApplet(Service::Interface* self) { | 377 | void PrepareToStartLibraryApplet(Service::Interface* self) { |
| 352 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 378 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x18, 1, 0); // 0x180040 |
| 353 | AppletId applet_id = static_cast<AppletId>(cmd_buff[1]); | 379 | AppletId applet_id = static_cast<AppletId>(rp.Pop<u32>()); |
| 380 | |||
| 381 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 354 | auto applet = HLE::Applets::Applet::Get(applet_id); | 382 | auto applet = HLE::Applets::Applet::Get(applet_id); |
| 355 | if (applet) { | 383 | if (applet) { |
| 356 | LOG_WARNING(Service_APT, "applet has already been started id=%08X", applet_id); | 384 | LOG_WARNING(Service_APT, "applet has already been started id=%08X", applet_id); |
| 357 | cmd_buff[1] = RESULT_SUCCESS.raw; | 385 | rb.Push(RESULT_SUCCESS); |
| 358 | } else { | 386 | } else { |
| 359 | cmd_buff[1] = HLE::Applets::Applet::Create(applet_id).raw; | 387 | rb.Push(HLE::Applets::Applet::Create(applet_id)); |
| 360 | } | 388 | } |
| 361 | LOG_DEBUG(Service_APT, "called applet_id=%08X", applet_id); | 389 | LOG_DEBUG(Service_APT, "called applet_id=%08X", applet_id); |
| 362 | } | 390 | } |
| 363 | 391 | ||
| 364 | void PreloadLibraryApplet(Service::Interface* self) { | 392 | void PreloadLibraryApplet(Service::Interface* self) { |
| 365 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 393 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x16, 1, 0); // 0x160040 |
| 366 | AppletId applet_id = static_cast<AppletId>(cmd_buff[1]); | 394 | AppletId applet_id = static_cast<AppletId>(rp.Pop<u32>()); |
| 395 | |||
| 396 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 367 | auto applet = HLE::Applets::Applet::Get(applet_id); | 397 | auto applet = HLE::Applets::Applet::Get(applet_id); |
| 368 | if (applet) { | 398 | if (applet) { |
| 369 | LOG_WARNING(Service_APT, "applet has already been started id=%08X", applet_id); | 399 | LOG_WARNING(Service_APT, "applet has already been started id=%08X", applet_id); |
| 370 | cmd_buff[1] = RESULT_SUCCESS.raw; | 400 | rb.Push(RESULT_SUCCESS); |
| 371 | } else { | 401 | } else { |
| 372 | cmd_buff[1] = HLE::Applets::Applet::Create(applet_id).raw; | 402 | rb.Push(HLE::Applets::Applet::Create(applet_id)); |
| 373 | } | 403 | } |
| 374 | LOG_DEBUG(Service_APT, "called applet_id=%08X", applet_id); | 404 | LOG_DEBUG(Service_APT, "called applet_id=%08X", applet_id); |
| 375 | } | 405 | } |
| 376 | 406 | ||
| 377 | void StartLibraryApplet(Service::Interface* self) { | 407 | void StartLibraryApplet(Service::Interface* self) { |
| 378 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 408 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1E, 2, 4); // 0x1E0084 |
| 379 | AppletId applet_id = static_cast<AppletId>(cmd_buff[1]); | 409 | AppletId applet_id = static_cast<AppletId>(rp.Pop<u32>()); |
| 380 | std::shared_ptr<HLE::Applets::Applet> applet = HLE::Applets::Applet::Get(applet_id); | 410 | std::shared_ptr<HLE::Applets::Applet> applet = HLE::Applets::Applet::Get(applet_id); |
| 381 | 411 | ||
| 382 | LOG_DEBUG(Service_APT, "called applet_id=%08X", applet_id); | 412 | LOG_DEBUG(Service_APT, "called applet_id=%08X", applet_id); |
| 383 | 413 | ||
| 384 | if (applet == nullptr) { | 414 | if (applet == nullptr) { |
| 385 | LOG_ERROR(Service_APT, "unknown applet id=%08X", applet_id); | 415 | LOG_ERROR(Service_APT, "unknown applet id=%08X", applet_id); |
| 386 | cmd_buff[1] = -1; // TODO(Subv): Find the right error code | 416 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0, false); |
| 417 | rb.Push<u32>(-1); // TODO(Subv): Find the right error code | ||
| 387 | return; | 418 | return; |
| 388 | } | 419 | } |
| 389 | 420 | ||
| 390 | size_t buffer_size = cmd_buff[2]; | 421 | size_t buffer_size = rp.Pop<u32>(); |
| 391 | VAddr buffer_addr = cmd_buff[6]; | 422 | Kernel::Handle handle = rp.PopHandle(); |
| 423 | VAddr buffer_addr = rp.PopStaticBuffer(); | ||
| 392 | 424 | ||
| 393 | AppletStartupParameter parameter; | 425 | AppletStartupParameter parameter; |
| 394 | parameter.object = Kernel::g_handle_table.GetGeneric(cmd_buff[4]); | 426 | parameter.object = Kernel::g_handle_table.GetGeneric(handle); |
| 395 | parameter.buffer.resize(buffer_size); | 427 | parameter.buffer.resize(buffer_size); |
| 396 | Memory::ReadBlock(buffer_addr, parameter.buffer.data(), parameter.buffer.size()); | 428 | Memory::ReadBlock(buffer_addr, parameter.buffer.data(), parameter.buffer.size()); |
| 397 | 429 | ||
| 398 | cmd_buff[1] = applet->Start(parameter).raw; | 430 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); |
| 431 | rb.Push(applet->Start(parameter)); | ||
| 399 | } | 432 | } |
| 400 | 433 | ||
| 401 | void CancelLibraryApplet(Service::Interface* self) { | 434 | void CancelLibraryApplet(Service::Interface* self) { |
| 402 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 435 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x3B, 1, 0); // 0x003B0040 |
| 403 | u32 exiting = cmd_buff[1] & 0xFF; | 436 | bool exiting = rp.Pop<bool>(); |
| 404 | 437 | ||
| 405 | cmd_buff[1] = 1; // TODO: Find the return code meaning | 438 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); |
| 439 | rb.Push<u32>(1); // TODO: Find the return code meaning | ||
| 406 | 440 | ||
| 407 | LOG_WARNING(Service_APT, "(STUBBED) called exiting=%u", exiting); | 441 | LOG_WARNING(Service_APT, "(STUBBED) called exiting=%d", exiting); |
| 408 | } | 442 | } |
| 409 | 443 | ||
| 410 | void SetScreenCapPostPermission(Service::Interface* self) { | 444 | void SetScreenCapPostPermission(Service::Interface* self) { |
| 411 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 445 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x55, 1, 0); // 0x00550040 |
| 412 | 446 | ||
| 413 | screen_capture_post_permission = static_cast<ScreencapPostPermission>(cmd_buff[1] & 0xF); | 447 | screen_capture_post_permission = static_cast<ScreencapPostPermission>(rp.Pop<u32>() & 0xF); |
| 414 | 448 | ||
| 415 | cmd_buff[0] = IPC::MakeHeader(0x55, 1, 0); | 449 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); |
| 416 | cmd_buff[1] = RESULT_SUCCESS.raw; | 450 | rb.Push(RESULT_SUCCESS); // No error |
| 417 | LOG_WARNING(Service_APT, "(STUBBED) screen_capture_post_permission=%u", | 451 | LOG_WARNING(Service_APT, "(STUBBED) screen_capture_post_permission=%u", |
| 418 | screen_capture_post_permission); | 452 | screen_capture_post_permission); |
| 419 | } | 453 | } |
| 420 | 454 | ||
| 421 | void GetScreenCapPostPermission(Service::Interface* self) { | 455 | void GetScreenCapPostPermission(Service::Interface* self) { |
| 422 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 456 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x56, 0, 0); // 0x00560000 |
| 423 | 457 | ||
| 424 | cmd_buff[0] = IPC::MakeHeader(0x56, 2, 0); | 458 | IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); |
| 425 | cmd_buff[1] = RESULT_SUCCESS.raw; | 459 | rb.Push(RESULT_SUCCESS); // No error |
| 426 | cmd_buff[2] = static_cast<u32>(screen_capture_post_permission); | 460 | rb.Push(static_cast<u32>(screen_capture_post_permission)); |
| 427 | LOG_WARNING(Service_APT, "(STUBBED) screen_capture_post_permission=%u", | 461 | LOG_WARNING(Service_APT, "(STUBBED) screen_capture_post_permission=%u", |
| 428 | screen_capture_post_permission); | 462 | screen_capture_post_permission); |
| 429 | } | 463 | } |
| 430 | 464 | ||
| 431 | void GetAppletInfo(Service::Interface* self) { | 465 | void GetAppletInfo(Service::Interface* self) { |
| 432 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 466 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x6, 1, 0); // 0x60040 |
| 433 | auto app_id = static_cast<AppletId>(cmd_buff[1]); | 467 | auto app_id = static_cast<AppletId>(rp.Pop<u32>()); |
| 434 | 468 | ||
| 435 | if (auto applet = HLE::Applets::Applet::Get(app_id)) { | 469 | if (auto applet = HLE::Applets::Applet::Get(app_id)) { |
| 436 | // TODO(Subv): Get the title id for the current applet and write it in the response[2-3] | 470 | // TODO(Subv): Get the title id for the current applet and write it in the response[2-3] |
| 437 | cmd_buff[1] = RESULT_SUCCESS.raw; | 471 | IPC::RequestBuilder rb = rp.MakeBuilder(7, 0); |
| 438 | cmd_buff[4] = static_cast<u32>(Service::FS::MediaType::NAND); | 472 | rb.Push(RESULT_SUCCESS); |
| 439 | cmd_buff[5] = 1; // Registered | 473 | u64 title_id = 0; |
| 440 | cmd_buff[6] = 1; // Loaded | 474 | rb.Push(title_id); |
| 441 | cmd_buff[7] = 0; // Applet Attributes | 475 | rb.Push(static_cast<u32>(Service::FS::MediaType::NAND)); |
| 476 | rb.Push(true); // Registered | ||
| 477 | rb.Push(true); // Loaded | ||
| 478 | rb.Push<u32>(0); // Applet Attributes | ||
| 442 | } else { | 479 | } else { |
| 443 | cmd_buff[1] = ResultCode(ErrorDescription::NotFound, ErrorModule::Applet, | 480 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); |
| 444 | ErrorSummary::NotFound, ErrorLevel::Status) | 481 | rb.Push(ResultCode(ErrorDescription::NotFound, ErrorModule::Applet, ErrorSummary::NotFound, |
| 445 | .raw; | 482 | ErrorLevel::Status)); |
| 446 | } | 483 | } |
| 447 | LOG_WARNING(Service_APT, "(stubbed) called appid=%u", app_id); | 484 | LOG_WARNING(Service_APT, "(stubbed) called appid=%u", app_id); |
| 448 | } | 485 | } |
| 449 | 486 | ||
| 450 | void GetStartupArgument(Service::Interface* self) { | 487 | void GetStartupArgument(Service::Interface* self) { |
| 451 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 488 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x51, 2, 0); // 0x00510080 |
| 452 | u32 parameter_size = cmd_buff[1]; | 489 | u32 parameter_size = rp.Pop<u32>(); |
| 453 | StartupArgumentType startup_argument_type = static_cast<StartupArgumentType>(cmd_buff[2]); | 490 | StartupArgumentType startup_argument_type = static_cast<StartupArgumentType>(rp.Pop<u8>()); |
| 454 | 491 | ||
| 455 | if (parameter_size >= 0x300) { | 492 | if (parameter_size >= 0x300) { |
| 456 | LOG_ERROR( | 493 | LOG_ERROR( |
| @@ -460,7 +497,14 @@ void GetStartupArgument(Service::Interface* self) { | |||
| 460 | return; | 497 | return; |
| 461 | } | 498 | } |
| 462 | 499 | ||
| 463 | u32 addr = cmd_buff[65]; | 500 | size_t static_buff_size; |
| 501 | VAddr addr = rp.PeekStaticBuffer(0, &static_buff_size); | ||
| 502 | if (parameter_size > static_buff_size) | ||
| 503 | LOG_WARNING( | ||
| 504 | Service_APT, | ||
| 505 | "parameter_size is bigger than the size in the buffer descriptor (0x%08X > 0x%08zX)", | ||
| 506 | parameter_size, static_buff_size); | ||
| 507 | |||
| 464 | if (addr && parameter_size) { | 508 | if (addr && parameter_size) { |
| 465 | Memory::ZeroBlock(addr, parameter_size); | 509 | Memory::ZeroBlock(addr, parameter_size); |
| 466 | } | 510 | } |
| @@ -468,8 +512,10 @@ void GetStartupArgument(Service::Interface* self) { | |||
| 468 | LOG_WARNING(Service_APT, "(stubbed) called startup_argument_type=%u , parameter_size=0x%08x", | 512 | LOG_WARNING(Service_APT, "(stubbed) called startup_argument_type=%u , parameter_size=0x%08x", |
| 469 | startup_argument_type, parameter_size); | 513 | startup_argument_type, parameter_size); |
| 470 | 514 | ||
| 471 | cmd_buff[1] = RESULT_SUCCESS.raw; | 515 | IPC::RequestBuilder rb = rp.MakeBuilder(2, 2); |
| 472 | cmd_buff[2] = 0; | 516 | rb.Push(RESULT_SUCCESS); |
| 517 | rb.Push<u32>(0); | ||
| 518 | rb.PushStaticBuffer(addr, parameter_size, 0); | ||
| 473 | } | 519 | } |
| 474 | 520 | ||
| 475 | void Wrap(Service::Interface* self) { | 521 | void Wrap(Service::Interface* self) { |
| @@ -554,7 +600,7 @@ void Unwrap(Service::Interface* self) { | |||
| 554 | // Decrypts the ciphertext using AES-CCM | 600 | // Decrypts the ciphertext using AES-CCM |
| 555 | auto pdata = HW::AES::DecryptVerifyCCM(cipher, nonce, HW::AES::KeySlotID::APTWrap); | 601 | auto pdata = HW::AES::DecryptVerifyCCM(cipher, nonce, HW::AES::KeySlotID::APTWrap); |
| 556 | 602 | ||
| 557 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | 603 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 4); |
| 558 | if (!pdata.empty()) { | 604 | if (!pdata.empty()) { |
| 559 | // Splits the plaintext and put the nonce in between | 605 | // Splits the plaintext and put the nonce in between |
| 560 | Memory::WriteBlock(output, pdata.data(), nonce_offset); | 606 | Memory::WriteBlock(output, pdata.data(), nonce_offset); |
| @@ -574,25 +620,25 @@ void Unwrap(Service::Interface* self) { | |||
| 574 | } | 620 | } |
| 575 | 621 | ||
| 576 | void CheckNew3DSApp(Service::Interface* self) { | 622 | void CheckNew3DSApp(Service::Interface* self) { |
| 577 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 623 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x101, 0, 0); // 0x01010000 |
| 578 | 624 | ||
| 625 | IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); | ||
| 579 | if (unknown_ns_state_field) { | 626 | if (unknown_ns_state_field) { |
| 580 | cmd_buff[1] = RESULT_SUCCESS.raw; | 627 | rb.Push(RESULT_SUCCESS); |
| 581 | cmd_buff[2] = 0; | 628 | rb.Push<u32>(0); |
| 582 | } else { | 629 | } else { |
| 583 | PTM::CheckNew3DS(self); | 630 | PTM::CheckNew3DS(rb); |
| 584 | } | 631 | } |
| 585 | 632 | ||
| 586 | cmd_buff[0] = IPC::MakeHeader(0x101, 2, 0); | ||
| 587 | LOG_WARNING(Service_APT, "(STUBBED) called"); | 633 | LOG_WARNING(Service_APT, "(STUBBED) called"); |
| 588 | } | 634 | } |
| 589 | 635 | ||
| 590 | void CheckNew3DS(Service::Interface* self) { | 636 | void CheckNew3DS(Service::Interface* self) { |
| 591 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 637 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x102, 0, 0); // 0x01020000 |
| 638 | IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); | ||
| 592 | 639 | ||
| 593 | PTM::CheckNew3DS(self); | 640 | PTM::CheckNew3DS(rb); |
| 594 | 641 | ||
| 595 | cmd_buff[0] = IPC::MakeHeader(0x102, 2, 0); | ||
| 596 | LOG_WARNING(Service_APT, "(STUBBED) called"); | 642 | LOG_WARNING(Service_APT, "(STUBBED) called"); |
| 597 | } | 643 | } |
| 598 | 644 | ||
diff --git a/src/core/hle/service/cfg/cfg.cpp b/src/core/hle/service/cfg/cfg.cpp index 6f13cde27..4ddb1bc90 100644 --- a/src/core/hle/service/cfg/cfg.cpp +++ b/src/core/hle/service/cfg/cfg.cpp | |||
| @@ -3,6 +3,8 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <algorithm> | 5 | #include <algorithm> |
| 6 | #include <array> | ||
| 7 | #include <cryptopp/sha.h> | ||
| 6 | #include "common/file_util.h" | 8 | #include "common/file_util.h" |
| 7 | #include "common/logging/log.h" | 9 | #include "common/logging/log.h" |
| 8 | #include "common/string_util.h" | 10 | #include "common/string_util.h" |
| @@ -176,14 +178,29 @@ void SecureInfoGetRegion(Service::Interface* self) { | |||
| 176 | } | 178 | } |
| 177 | 179 | ||
| 178 | void GenHashConsoleUnique(Service::Interface* self) { | 180 | void GenHashConsoleUnique(Service::Interface* self) { |
| 179 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 181 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x03, 1, 0); |
| 180 | u32 app_id_salt = cmd_buff[1]; | 182 | const u32 app_id_salt = rp.Pop<u32>() & 0x000FFFFF; |
| 181 | 183 | ||
| 182 | cmd_buff[1] = RESULT_SUCCESS.raw; | 184 | IPC::RequestBuilder rb = rp.MakeBuilder(3, 0); |
| 183 | cmd_buff[2] = 0x33646D6F ^ (app_id_salt & 0xFFFFF); // 3dmoo hash | 185 | |
| 184 | cmd_buff[3] = 0x6F534841 ^ (app_id_salt & 0xFFFFF); | 186 | std::array<u8, 12> buffer; |
| 187 | const ResultCode result = GetConfigInfoBlock(ConsoleUniqueID2BlockID, 8, 2, buffer.data()); | ||
| 188 | rb.Push(result); | ||
| 189 | if (result.IsSuccess()) { | ||
| 190 | std::memcpy(&buffer[8], &app_id_salt, sizeof(u32)); | ||
| 191 | std::array<u8, CryptoPP::SHA256::DIGESTSIZE> hash; | ||
| 192 | CryptoPP::SHA256().CalculateDigest(hash.data(), buffer.data(), sizeof(buffer)); | ||
| 193 | u32 low, high; | ||
| 194 | memcpy(&low, &hash[hash.size() - 8], sizeof(u32)); | ||
| 195 | memcpy(&high, &hash[hash.size() - 4], sizeof(u32)); | ||
| 196 | rb.Push(low); | ||
| 197 | rb.Push(high); | ||
| 198 | } else { | ||
| 199 | rb.Push<u32>(0); | ||
| 200 | rb.Push<u32>(0); | ||
| 201 | } | ||
| 185 | 202 | ||
| 186 | LOG_WARNING(Service_CFG, "(STUBBED) called app_id_salt=0x%X", app_id_salt); | 203 | LOG_DEBUG(Service_CFG, "called app_id_salt=0x%X", app_id_salt); |
| 187 | } | 204 | } |
| 188 | 205 | ||
| 189 | void GetRegionCanadaUSA(Service::Interface* self) { | 206 | void GetRegionCanadaUSA(Service::Interface* self) { |
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index fb3acb507..b19e831fe 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp | |||
| @@ -2,10 +2,14 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <algorithm> | ||
| 6 | #include <atomic> | ||
| 5 | #include <cmath> | 7 | #include <cmath> |
| 8 | #include <memory> | ||
| 6 | #include "common/logging/log.h" | 9 | #include "common/logging/log.h" |
| 7 | #include "core/core_timing.h" | 10 | #include "core/core_timing.h" |
| 8 | #include "core/frontend/emu_window.h" | 11 | #include "core/frontend/emu_window.h" |
| 12 | #include "core/frontend/input.h" | ||
| 9 | #include "core/hle/kernel/event.h" | 13 | #include "core/hle/kernel/event.h" |
| 10 | #include "core/hle/kernel/shared_memory.h" | 14 | #include "core/hle/kernel/shared_memory.h" |
| 11 | #include "core/hle/service/hid/hid.h" | 15 | #include "core/hle/service/hid/hid.h" |
| @@ -44,6 +48,11 @@ constexpr u64 pad_update_ticks = BASE_CLOCK_RATE_ARM11 / 234; | |||
| 44 | constexpr u64 accelerometer_update_ticks = BASE_CLOCK_RATE_ARM11 / 104; | 48 | constexpr u64 accelerometer_update_ticks = BASE_CLOCK_RATE_ARM11 / 104; |
| 45 | constexpr u64 gyroscope_update_ticks = BASE_CLOCK_RATE_ARM11 / 101; | 49 | constexpr u64 gyroscope_update_ticks = BASE_CLOCK_RATE_ARM11 / 101; |
| 46 | 50 | ||
| 51 | static std::atomic<bool> is_device_reload_pending; | ||
| 52 | static std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::NUM_BUTTONS_HID> | ||
| 53 | buttons; | ||
| 54 | static std::unique_ptr<Input::AnalogDevice> circle_pad; | ||
| 55 | |||
| 47 | static PadState GetCirclePadDirectionState(s16 circle_pad_x, s16 circle_pad_y) { | 56 | static PadState GetCirclePadDirectionState(s16 circle_pad_x, s16 circle_pad_y) { |
| 48 | // 30 degree and 60 degree are angular thresholds for directions | 57 | // 30 degree and 60 degree are angular thresholds for directions |
| 49 | constexpr float TAN30 = 0.577350269f; | 58 | constexpr float TAN30 = 0.577350269f; |
| @@ -74,14 +83,48 @@ static PadState GetCirclePadDirectionState(s16 circle_pad_x, s16 circle_pad_y) { | |||
| 74 | return state; | 83 | return state; |
| 75 | } | 84 | } |
| 76 | 85 | ||
| 86 | static void LoadInputDevices() { | ||
| 87 | std::transform(Settings::values.buttons.begin() + Settings::NativeButton::BUTTON_HID_BEGIN, | ||
| 88 | Settings::values.buttons.begin() + Settings::NativeButton::BUTTON_HID_END, | ||
| 89 | buttons.begin(), Input::CreateDevice<Input::ButtonDevice>); | ||
| 90 | circle_pad = Input::CreateDevice<Input::AnalogDevice>( | ||
| 91 | Settings::values.analogs[Settings::NativeAnalog::CirclePad]); | ||
| 92 | } | ||
| 93 | |||
| 94 | static void UnloadInputDevices() { | ||
| 95 | for (auto& button : buttons) { | ||
| 96 | button.reset(); | ||
| 97 | } | ||
| 98 | circle_pad.reset(); | ||
| 99 | } | ||
| 100 | |||
| 77 | static void UpdatePadCallback(u64 userdata, int cycles_late) { | 101 | static void UpdatePadCallback(u64 userdata, int cycles_late) { |
| 78 | SharedMem* mem = reinterpret_cast<SharedMem*>(shared_mem->GetPointer()); | 102 | SharedMem* mem = reinterpret_cast<SharedMem*>(shared_mem->GetPointer()); |
| 79 | 103 | ||
| 80 | PadState state = VideoCore::g_emu_window->GetPadState(); | 104 | if (is_device_reload_pending.exchange(false)) |
| 105 | LoadInputDevices(); | ||
| 106 | |||
| 107 | PadState state; | ||
| 108 | using namespace Settings::NativeButton; | ||
| 109 | state.a.Assign(buttons[A - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 110 | state.b.Assign(buttons[B - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 111 | state.x.Assign(buttons[X - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 112 | state.y.Assign(buttons[Y - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 113 | state.right.Assign(buttons[Right - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 114 | state.left.Assign(buttons[Left - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 115 | state.up.Assign(buttons[Up - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 116 | state.down.Assign(buttons[Down - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 117 | state.l.Assign(buttons[L - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 118 | state.r.Assign(buttons[R - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 119 | state.start.Assign(buttons[Start - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 120 | state.select.Assign(buttons[Select - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 81 | 121 | ||
| 82 | // Get current circle pad position and update circle pad direction | 122 | // Get current circle pad position and update circle pad direction |
| 83 | s16 circle_pad_x, circle_pad_y; | 123 | float circle_pad_x_f, circle_pad_y_f; |
| 84 | std::tie(circle_pad_x, circle_pad_y) = VideoCore::g_emu_window->GetCirclePadState(); | 124 | std::tie(circle_pad_x_f, circle_pad_y_f) = circle_pad->GetStatus(); |
| 125 | constexpr int MAX_CIRCLEPAD_POS = 0x9C; // Max value for a circle pad position | ||
| 126 | s16 circle_pad_x = static_cast<s16>(circle_pad_x_f * MAX_CIRCLEPAD_POS); | ||
| 127 | s16 circle_pad_y = static_cast<s16>(circle_pad_y_f * MAX_CIRCLEPAD_POS); | ||
| 85 | state.hex |= GetCirclePadDirectionState(circle_pad_x, circle_pad_y).hex; | 128 | state.hex |= GetCirclePadDirectionState(circle_pad_x, circle_pad_y).hex; |
| 86 | 129 | ||
| 87 | mem->pad.current_state.hex = state.hex; | 130 | mem->pad.current_state.hex = state.hex; |
| @@ -313,6 +356,8 @@ void Init() { | |||
| 313 | AddService(new HID_U_Interface); | 356 | AddService(new HID_U_Interface); |
| 314 | AddService(new HID_SPVR_Interface); | 357 | AddService(new HID_SPVR_Interface); |
| 315 | 358 | ||
| 359 | is_device_reload_pending.store(true); | ||
| 360 | |||
| 316 | using Kernel::MemoryPermission; | 361 | using Kernel::MemoryPermission; |
| 317 | shared_mem = | 362 | shared_mem = |
| 318 | SharedMemory::Create(nullptr, 0x1000, MemoryPermission::ReadWrite, MemoryPermission::Read, | 363 | SharedMemory::Create(nullptr, 0x1000, MemoryPermission::ReadWrite, MemoryPermission::Read, |
| @@ -350,6 +395,11 @@ void Shutdown() { | |||
| 350 | event_accelerometer = nullptr; | 395 | event_accelerometer = nullptr; |
| 351 | event_gyroscope = nullptr; | 396 | event_gyroscope = nullptr; |
| 352 | event_debug_pad = nullptr; | 397 | event_debug_pad = nullptr; |
| 398 | UnloadInputDevices(); | ||
| 399 | } | ||
| 400 | |||
| 401 | void ReloadInputDevices() { | ||
| 402 | is_device_reload_pending.store(true); | ||
| 353 | } | 403 | } |
| 354 | 404 | ||
| 355 | } // namespace HID | 405 | } // namespace HID |
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index c7f4ee138..b505cdcd5 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h | |||
| @@ -39,13 +39,6 @@ struct PadState { | |||
| 39 | BitField<10, 1, u32> x; | 39 | BitField<10, 1, u32> x; |
| 40 | BitField<11, 1, u32> y; | 40 | BitField<11, 1, u32> y; |
| 41 | 41 | ||
| 42 | BitField<14, 1, u32> zl; | ||
| 43 | BitField<15, 1, u32> zr; | ||
| 44 | |||
| 45 | BitField<24, 1, u32> c_right; | ||
| 46 | BitField<25, 1, u32> c_left; | ||
| 47 | BitField<26, 1, u32> c_up; | ||
| 48 | BitField<27, 1, u32> c_down; | ||
| 49 | BitField<28, 1, u32> circle_right; | 42 | BitField<28, 1, u32> circle_right; |
| 50 | BitField<29, 1, u32> circle_left; | 43 | BitField<29, 1, u32> circle_left; |
| 51 | BitField<30, 1, u32> circle_up; | 44 | BitField<30, 1, u32> circle_up; |
| @@ -183,33 +176,6 @@ ASSERT_REG_POSITION(touch.index_reset_ticks, 0x2A); | |||
| 183 | #undef ASSERT_REG_POSITION | 176 | #undef ASSERT_REG_POSITION |
| 184 | #endif // !defined(_MSC_VER) | 177 | #endif // !defined(_MSC_VER) |
| 185 | 178 | ||
| 186 | // Pre-defined PadStates for single button presses | ||
| 187 | const PadState PAD_NONE = {{0}}; | ||
| 188 | const PadState PAD_A = {{1u << 0}}; | ||
| 189 | const PadState PAD_B = {{1u << 1}}; | ||
| 190 | const PadState PAD_SELECT = {{1u << 2}}; | ||
| 191 | const PadState PAD_START = {{1u << 3}}; | ||
| 192 | const PadState PAD_RIGHT = {{1u << 4}}; | ||
| 193 | const PadState PAD_LEFT = {{1u << 5}}; | ||
| 194 | const PadState PAD_UP = {{1u << 6}}; | ||
| 195 | const PadState PAD_DOWN = {{1u << 7}}; | ||
| 196 | const PadState PAD_R = {{1u << 8}}; | ||
| 197 | const PadState PAD_L = {{1u << 9}}; | ||
| 198 | const PadState PAD_X = {{1u << 10}}; | ||
| 199 | const PadState PAD_Y = {{1u << 11}}; | ||
| 200 | |||
| 201 | const PadState PAD_ZL = {{1u << 14}}; | ||
| 202 | const PadState PAD_ZR = {{1u << 15}}; | ||
| 203 | |||
| 204 | const PadState PAD_C_RIGHT = {{1u << 24}}; | ||
| 205 | const PadState PAD_C_LEFT = {{1u << 25}}; | ||
| 206 | const PadState PAD_C_UP = {{1u << 26}}; | ||
| 207 | const PadState PAD_C_DOWN = {{1u << 27}}; | ||
| 208 | const PadState PAD_CIRCLE_RIGHT = {{1u << 28}}; | ||
| 209 | const PadState PAD_CIRCLE_LEFT = {{1u << 29}}; | ||
| 210 | const PadState PAD_CIRCLE_UP = {{1u << 30}}; | ||
| 211 | const PadState PAD_CIRCLE_DOWN = {{1u << 31}}; | ||
| 212 | |||
| 213 | /** | 179 | /** |
| 214 | * HID::GetIPCHandles service function | 180 | * HID::GetIPCHandles service function |
| 215 | * Inputs: | 181 | * Inputs: |
| @@ -297,5 +263,8 @@ void Init(); | |||
| 297 | 263 | ||
| 298 | /// Shutdown HID service | 264 | /// Shutdown HID service |
| 299 | void Shutdown(); | 265 | void Shutdown(); |
| 266 | |||
| 267 | /// Reload input devices. Used when input configuration changed | ||
| 268 | void ReloadInputDevices(); | ||
| 300 | } | 269 | } |
| 301 | } | 270 | } |
diff --git a/src/core/hle/service/ptm/ptm.cpp b/src/core/hle/service/ptm/ptm.cpp index 8ff808fd9..e373ed47a 100644 --- a/src/core/hle/service/ptm/ptm.cpp +++ b/src/core/hle/service/ptm/ptm.cpp | |||
| @@ -92,8 +92,7 @@ void GetSoftwareClosedFlag(Service::Interface* self) { | |||
| 92 | LOG_WARNING(Service_PTM, "(STUBBED) called"); | 92 | LOG_WARNING(Service_PTM, "(STUBBED) called"); |
| 93 | } | 93 | } |
| 94 | 94 | ||
| 95 | void CheckNew3DS(Service::Interface* self) { | 95 | void CheckNew3DS(IPC::RequestBuilder& rb) { |
| 96 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 97 | const bool is_new_3ds = Settings::values.is_new_3ds; | 96 | const bool is_new_3ds = Settings::values.is_new_3ds; |
| 98 | 97 | ||
| 99 | if (is_new_3ds) { | 98 | if (is_new_3ds) { |
| @@ -101,12 +100,17 @@ void CheckNew3DS(Service::Interface* self) { | |||
| 101 | "settings. Citra does not fully support New 3DS emulation yet!"); | 100 | "settings. Citra does not fully support New 3DS emulation yet!"); |
| 102 | } | 101 | } |
| 103 | 102 | ||
| 104 | cmd_buff[1] = RESULT_SUCCESS.raw; | 103 | rb.Push(RESULT_SUCCESS); |
| 105 | cmd_buff[2] = is_new_3ds ? 1 : 0; | 104 | rb.Push(is_new_3ds); |
| 106 | 105 | ||
| 107 | LOG_WARNING(Service_PTM, "(STUBBED) called isNew3DS = 0x%08x", static_cast<u32>(is_new_3ds)); | 106 | LOG_WARNING(Service_PTM, "(STUBBED) called isNew3DS = 0x%08x", static_cast<u32>(is_new_3ds)); |
| 108 | } | 107 | } |
| 109 | 108 | ||
| 109 | void CheckNew3DS(Service::Interface* self) { | ||
| 110 | IPC::RequestBuilder rb(Kernel::GetCommandBuffer(), 0x40A, 0, 0); // 0x040A0000 | ||
| 111 | CheckNew3DS(rb); | ||
| 112 | } | ||
| 113 | |||
| 110 | void Init() { | 114 | void Init() { |
| 111 | AddService(new PTM_Gets); | 115 | AddService(new PTM_Gets); |
| 112 | AddService(new PTM_Play); | 116 | AddService(new PTM_Play); |
| @@ -134,9 +138,9 @@ void Init() { | |||
| 134 | ASSERT_MSG(archive_result.Succeeded(), "Could not open the PTM SharedExtSaveData archive!"); | 138 | ASSERT_MSG(archive_result.Succeeded(), "Could not open the PTM SharedExtSaveData archive!"); |
| 135 | 139 | ||
| 136 | FileSys::Path gamecoin_path("/gamecoin.dat"); | 140 | FileSys::Path gamecoin_path("/gamecoin.dat"); |
| 141 | Service::FS::CreateFileInArchive(*archive_result, gamecoin_path, sizeof(GameCoin)); | ||
| 137 | FileSys::Mode open_mode = {}; | 142 | FileSys::Mode open_mode = {}; |
| 138 | open_mode.write_flag.Assign(1); | 143 | open_mode.write_flag.Assign(1); |
| 139 | open_mode.create_flag.Assign(1); | ||
| 140 | // Open the file and write the default gamecoin information | 144 | // Open the file and write the default gamecoin information |
| 141 | auto gamecoin_result = | 145 | auto gamecoin_result = |
| 142 | Service::FS::OpenFileFromArchive(*archive_result, gamecoin_path, open_mode); | 146 | Service::FS::OpenFileFromArchive(*archive_result, gamecoin_path, open_mode); |
diff --git a/src/core/hle/service/ptm/ptm.h b/src/core/hle/service/ptm/ptm.h index a1a628012..683fb445b 100644 --- a/src/core/hle/service/ptm/ptm.h +++ b/src/core/hle/service/ptm/ptm.h | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include "common/common_types.h" | 7 | #include "common/common_types.h" |
| 8 | #include "core/hle/ipc_helpers.h" | ||
| 8 | 9 | ||
| 9 | namespace Service { | 10 | namespace Service { |
| 10 | 11 | ||
| @@ -97,6 +98,7 @@ void GetSoftwareClosedFlag(Interface* self); | |||
| 97 | * 2: u8 output: 0 = Old3DS, 1 = New3DS. | 98 | * 2: u8 output: 0 = Old3DS, 1 = New3DS. |
| 98 | */ | 99 | */ |
| 99 | void CheckNew3DS(Interface* self); | 100 | void CheckNew3DS(Interface* self); |
| 101 | void CheckNew3DS(IPC::RequestBuilder& rb); | ||
| 100 | 102 | ||
| 101 | /// Initialize the PTM service | 103 | /// Initialize the PTM service |
| 102 | void Init(); | 104 | void Init(); |
diff --git a/src/core/hle/service/soc_u.cpp b/src/core/hle/service/soc_u.cpp index dcc5c3c90..530614e6f 100644 --- a/src/core/hle/service/soc_u.cpp +++ b/src/core/hle/service/soc_u.cpp | |||
| @@ -362,18 +362,18 @@ static void Socket(Interface* self) { | |||
| 362 | return; | 362 | return; |
| 363 | } | 363 | } |
| 364 | 364 | ||
| 365 | u32 socket_handle = static_cast<u32>(::socket(domain, type, protocol)); | 365 | u32 ret = static_cast<u32>(::socket(domain, type, protocol)); |
| 366 | 366 | ||
| 367 | if ((s32)socket_handle != SOCKET_ERROR_VALUE) | 367 | if ((s32)ret != SOCKET_ERROR_VALUE) |
| 368 | open_sockets[socket_handle] = {socket_handle, true}; | 368 | open_sockets[ret] = {ret, true}; |
| 369 | 369 | ||
| 370 | int result = 0; | 370 | int result = 0; |
| 371 | if ((s32)socket_handle == SOCKET_ERROR_VALUE) | 371 | if ((s32)ret == SOCKET_ERROR_VALUE) |
| 372 | result = TranslateError(GET_ERRNO); | 372 | ret = TranslateError(GET_ERRNO); |
| 373 | 373 | ||
| 374 | cmd_buffer[0] = IPC::MakeHeader(2, 2, 0); | 374 | cmd_buffer[0] = IPC::MakeHeader(2, 2, 0); |
| 375 | cmd_buffer[1] = result; | 375 | cmd_buffer[1] = result; |
| 376 | cmd_buffer[2] = socket_handle; | 376 | cmd_buffer[2] = ret; |
| 377 | } | 377 | } |
| 378 | 378 | ||
| 379 | static void Bind(Interface* self) { | 379 | static void Bind(Interface* self) { |
| @@ -393,15 +393,15 @@ static void Bind(Interface* self) { | |||
| 393 | 393 | ||
| 394 | sockaddr sock_addr = CTRSockAddr::ToPlatform(ctr_sock_addr); | 394 | sockaddr sock_addr = CTRSockAddr::ToPlatform(ctr_sock_addr); |
| 395 | 395 | ||
| 396 | int res = ::bind(socket_handle, &sock_addr, std::max<u32>(sizeof(sock_addr), len)); | 396 | int ret = ::bind(socket_handle, &sock_addr, std::max<u32>(sizeof(sock_addr), len)); |
| 397 | 397 | ||
| 398 | int result = 0; | 398 | int result = 0; |
| 399 | if (res != 0) | 399 | if (ret != 0) |
| 400 | result = TranslateError(GET_ERRNO); | 400 | ret = TranslateError(GET_ERRNO); |
| 401 | 401 | ||
| 402 | cmd_buffer[0] = IPC::MakeHeader(5, 2, 0); | 402 | cmd_buffer[0] = IPC::MakeHeader(5, 2, 0); |
| 403 | cmd_buffer[1] = result; | 403 | cmd_buffer[1] = result; |
| 404 | cmd_buffer[2] = res; | 404 | cmd_buffer[2] = ret; |
| 405 | } | 405 | } |
| 406 | 406 | ||
| 407 | static void Fcntl(Interface* self) { | 407 | static void Fcntl(Interface* self) { |
| @@ -426,8 +426,7 @@ static void Fcntl(Interface* self) { | |||
| 426 | #else | 426 | #else |
| 427 | int ret = ::fcntl(socket_handle, F_GETFL, 0); | 427 | int ret = ::fcntl(socket_handle, F_GETFL, 0); |
| 428 | if (ret == SOCKET_ERROR_VALUE) { | 428 | if (ret == SOCKET_ERROR_VALUE) { |
| 429 | result = TranslateError(GET_ERRNO); | 429 | posix_ret = TranslateError(GET_ERRNO); |
| 430 | posix_ret = -1; | ||
| 431 | return; | 430 | return; |
| 432 | } | 431 | } |
| 433 | posix_ret = 0; | 432 | posix_ret = 0; |
| @@ -439,8 +438,7 @@ static void Fcntl(Interface* self) { | |||
| 439 | unsigned long tmp = (ctr_arg & 4 /* O_NONBLOCK */) ? 1 : 0; | 438 | unsigned long tmp = (ctr_arg & 4 /* O_NONBLOCK */) ? 1 : 0; |
| 440 | int ret = ioctlsocket(socket_handle, FIONBIO, &tmp); | 439 | int ret = ioctlsocket(socket_handle, FIONBIO, &tmp); |
| 441 | if (ret == SOCKET_ERROR_VALUE) { | 440 | if (ret == SOCKET_ERROR_VALUE) { |
| 442 | result = TranslateError(GET_ERRNO); | 441 | posix_ret = TranslateError(GET_ERRNO); |
| 443 | posix_ret = -1; | ||
| 444 | return; | 442 | return; |
| 445 | } | 443 | } |
| 446 | auto iter = open_sockets.find(socket_handle); | 444 | auto iter = open_sockets.find(socket_handle); |
| @@ -449,8 +447,7 @@ static void Fcntl(Interface* self) { | |||
| 449 | #else | 447 | #else |
| 450 | int flags = ::fcntl(socket_handle, F_GETFL, 0); | 448 | int flags = ::fcntl(socket_handle, F_GETFL, 0); |
| 451 | if (flags == SOCKET_ERROR_VALUE) { | 449 | if (flags == SOCKET_ERROR_VALUE) { |
| 452 | result = TranslateError(GET_ERRNO); | 450 | posix_ret = TranslateError(GET_ERRNO); |
| 453 | posix_ret = -1; | ||
| 454 | return; | 451 | return; |
| 455 | } | 452 | } |
| 456 | 453 | ||
| @@ -460,15 +457,13 @@ static void Fcntl(Interface* self) { | |||
| 460 | 457 | ||
| 461 | int ret = ::fcntl(socket_handle, F_SETFL, flags); | 458 | int ret = ::fcntl(socket_handle, F_SETFL, flags); |
| 462 | if (ret == SOCKET_ERROR_VALUE) { | 459 | if (ret == SOCKET_ERROR_VALUE) { |
| 463 | result = TranslateError(GET_ERRNO); | 460 | posix_ret = TranslateError(GET_ERRNO); |
| 464 | posix_ret = -1; | ||
| 465 | return; | 461 | return; |
| 466 | } | 462 | } |
| 467 | #endif | 463 | #endif |
| 468 | } else { | 464 | } else { |
| 469 | LOG_ERROR(Service_SOC, "Unsupported command (%d) in fcntl call", ctr_cmd); | 465 | LOG_ERROR(Service_SOC, "Unsupported command (%d) in fcntl call", ctr_cmd); |
| 470 | result = TranslateError(EINVAL); // TODO: Find the correct error | 466 | posix_ret = TranslateError(EINVAL); // TODO: Find the correct error |
| 471 | posix_ret = -1; | ||
| 472 | return; | 467 | return; |
| 473 | } | 468 | } |
| 474 | } | 469 | } |
| @@ -481,7 +476,7 @@ static void Listen(Interface* self) { | |||
| 481 | int ret = ::listen(socket_handle, backlog); | 476 | int ret = ::listen(socket_handle, backlog); |
| 482 | int result = 0; | 477 | int result = 0; |
| 483 | if (ret != 0) | 478 | if (ret != 0) |
| 484 | result = TranslateError(GET_ERRNO); | 479 | ret = TranslateError(GET_ERRNO); |
| 485 | 480 | ||
| 486 | cmd_buffer[0] = IPC::MakeHeader(3, 2, 0); | 481 | cmd_buffer[0] = IPC::MakeHeader(3, 2, 0); |
| 487 | cmd_buffer[1] = result; | 482 | cmd_buffer[1] = result; |
| @@ -504,7 +499,7 @@ static void Accept(Interface* self) { | |||
| 504 | 499 | ||
| 505 | int result = 0; | 500 | int result = 0; |
| 506 | if ((s32)ret == SOCKET_ERROR_VALUE) { | 501 | if ((s32)ret == SOCKET_ERROR_VALUE) { |
| 507 | result = TranslateError(GET_ERRNO); | 502 | ret = TranslateError(GET_ERRNO); |
| 508 | } else { | 503 | } else { |
| 509 | CTRSockAddr ctr_addr = CTRSockAddr::FromPlatform(addr); | 504 | CTRSockAddr ctr_addr = CTRSockAddr::FromPlatform(addr); |
| 510 | Memory::WriteBlock(cmd_buffer[0x104 >> 2], &ctr_addr, sizeof(ctr_addr)); | 505 | Memory::WriteBlock(cmd_buffer[0x104 >> 2], &ctr_addr, sizeof(ctr_addr)); |
| @@ -545,7 +540,7 @@ static void Close(Interface* self) { | |||
| 545 | 540 | ||
| 546 | int result = 0; | 541 | int result = 0; |
| 547 | if (ret != 0) | 542 | if (ret != 0) |
| 548 | result = TranslateError(GET_ERRNO); | 543 | ret = TranslateError(GET_ERRNO); |
| 549 | 544 | ||
| 550 | cmd_buffer[2] = ret; | 545 | cmd_buffer[2] = ret; |
| 551 | cmd_buffer[1] = result; | 546 | cmd_buffer[1] = result; |
| @@ -589,7 +584,7 @@ static void SendTo(Interface* self) { | |||
| 589 | 584 | ||
| 590 | int result = 0; | 585 | int result = 0; |
| 591 | if (ret == SOCKET_ERROR_VALUE) | 586 | if (ret == SOCKET_ERROR_VALUE) |
| 592 | result = TranslateError(GET_ERRNO); | 587 | ret = TranslateError(GET_ERRNO); |
| 593 | 588 | ||
| 594 | cmd_buffer[2] = ret; | 589 | cmd_buffer[2] = ret; |
| 595 | cmd_buffer[1] = result; | 590 | cmd_buffer[1] = result; |
| @@ -638,7 +633,7 @@ static void RecvFrom(Interface* self) { | |||
| 638 | int result = 0; | 633 | int result = 0; |
| 639 | int total_received = ret; | 634 | int total_received = ret; |
| 640 | if (ret == SOCKET_ERROR_VALUE) { | 635 | if (ret == SOCKET_ERROR_VALUE) { |
| 641 | result = TranslateError(GET_ERRNO); | 636 | ret = TranslateError(GET_ERRNO); |
| 642 | total_received = 0; | 637 | total_received = 0; |
| 643 | } else { | 638 | } else { |
| 644 | // Write only the data we received to avoid overwriting parts of the buffer with zeros | 639 | // Write only the data we received to avoid overwriting parts of the buffer with zeros |
| @@ -673,7 +668,7 @@ static void Poll(Interface* self) { | |||
| 673 | std::vector<pollfd> platform_pollfd(nfds); | 668 | std::vector<pollfd> platform_pollfd(nfds); |
| 674 | std::transform(ctr_fds.begin(), ctr_fds.end(), platform_pollfd.begin(), CTRPollFD::ToPlatform); | 669 | std::transform(ctr_fds.begin(), ctr_fds.end(), platform_pollfd.begin(), CTRPollFD::ToPlatform); |
| 675 | 670 | ||
| 676 | const int ret = ::poll(platform_pollfd.data(), nfds, timeout); | 671 | int ret = ::poll(platform_pollfd.data(), nfds, timeout); |
| 677 | 672 | ||
| 678 | // Now update the output pollfd structure | 673 | // Now update the output pollfd structure |
| 679 | std::transform(platform_pollfd.begin(), platform_pollfd.end(), ctr_fds.begin(), | 674 | std::transform(platform_pollfd.begin(), platform_pollfd.end(), ctr_fds.begin(), |
| @@ -683,7 +678,7 @@ static void Poll(Interface* self) { | |||
| 683 | 678 | ||
| 684 | int result = 0; | 679 | int result = 0; |
| 685 | if (ret == SOCKET_ERROR_VALUE) | 680 | if (ret == SOCKET_ERROR_VALUE) |
| 686 | result = TranslateError(GET_ERRNO); | 681 | ret = TranslateError(GET_ERRNO); |
| 687 | 682 | ||
| 688 | cmd_buffer[1] = result; | 683 | cmd_buffer[1] = result; |
| 689 | cmd_buffer[2] = ret; | 684 | cmd_buffer[2] = ret; |
| @@ -710,7 +705,7 @@ static void GetSockName(Interface* self) { | |||
| 710 | 705 | ||
| 711 | int result = 0; | 706 | int result = 0; |
| 712 | if (ret != 0) | 707 | if (ret != 0) |
| 713 | result = TranslateError(GET_ERRNO); | 708 | ret = TranslateError(GET_ERRNO); |
| 714 | 709 | ||
| 715 | cmd_buffer[2] = ret; | 710 | cmd_buffer[2] = ret; |
| 716 | cmd_buffer[1] = result; | 711 | cmd_buffer[1] = result; |
| @@ -724,7 +719,7 @@ static void Shutdown(Interface* self) { | |||
| 724 | int ret = ::shutdown(socket_handle, how); | 719 | int ret = ::shutdown(socket_handle, how); |
| 725 | int result = 0; | 720 | int result = 0; |
| 726 | if (ret != 0) | 721 | if (ret != 0) |
| 727 | result = TranslateError(GET_ERRNO); | 722 | ret = TranslateError(GET_ERRNO); |
| 728 | cmd_buffer[2] = ret; | 723 | cmd_buffer[2] = ret; |
| 729 | cmd_buffer[1] = result; | 724 | cmd_buffer[1] = result; |
| 730 | } | 725 | } |
| @@ -750,7 +745,7 @@ static void GetPeerName(Interface* self) { | |||
| 750 | 745 | ||
| 751 | int result = 0; | 746 | int result = 0; |
| 752 | if (ret != 0) | 747 | if (ret != 0) |
| 753 | result = TranslateError(GET_ERRNO); | 748 | ret = TranslateError(GET_ERRNO); |
| 754 | 749 | ||
| 755 | cmd_buffer[2] = ret; | 750 | cmd_buffer[2] = ret; |
| 756 | cmd_buffer[1] = result; | 751 | cmd_buffer[1] = result; |
| @@ -777,7 +772,7 @@ static void Connect(Interface* self) { | |||
| 777 | int ret = ::connect(socket_handle, &input_addr, sizeof(input_addr)); | 772 | int ret = ::connect(socket_handle, &input_addr, sizeof(input_addr)); |
| 778 | int result = 0; | 773 | int result = 0; |
| 779 | if (ret != 0) | 774 | if (ret != 0) |
| 780 | result = TranslateError(GET_ERRNO); | 775 | ret = TranslateError(GET_ERRNO); |
| 781 | 776 | ||
| 782 | cmd_buffer[0] = IPC::MakeHeader(6, 2, 0); | 777 | cmd_buffer[0] = IPC::MakeHeader(6, 2, 0); |
| 783 | cmd_buffer[1] = result; | 778 | cmd_buffer[1] = result; |
| @@ -815,7 +810,7 @@ static void GetSockOpt(Interface* self) { | |||
| 815 | int optname = TranslateSockOpt(cmd_buffer[3]); | 810 | int optname = TranslateSockOpt(cmd_buffer[3]); |
| 816 | socklen_t optlen = (socklen_t)cmd_buffer[4]; | 811 | socklen_t optlen = (socklen_t)cmd_buffer[4]; |
| 817 | 812 | ||
| 818 | int ret = -1; | 813 | int ret = 0; |
| 819 | int err = 0; | 814 | int err = 0; |
| 820 | 815 | ||
| 821 | if (optname < 0) { | 816 | if (optname < 0) { |
| @@ -830,9 +825,8 @@ static void GetSockOpt(Interface* self) { | |||
| 830 | // >> 2 = convert to u32 offset instead of byte offset (cmd_buffer = u32*) | 825 | // >> 2 = convert to u32 offset instead of byte offset (cmd_buffer = u32*) |
| 831 | char* optval = reinterpret_cast<char*>(Memory::GetPointer(cmd_buffer[0x104 >> 2])); | 826 | char* optval = reinterpret_cast<char*>(Memory::GetPointer(cmd_buffer[0x104 >> 2])); |
| 832 | 827 | ||
| 833 | ret = ::getsockopt(socket_handle, level, optname, optval, &optlen); | 828 | err = ::getsockopt(socket_handle, level, optname, optval, &optlen); |
| 834 | err = 0; | 829 | if (err == SOCKET_ERROR_VALUE) { |
| 835 | if (ret == SOCKET_ERROR_VALUE) { | ||
| 836 | err = TranslateError(GET_ERRNO); | 830 | err = TranslateError(GET_ERRNO); |
| 837 | } | 831 | } |
| 838 | } | 832 | } |
| @@ -849,7 +843,7 @@ static void SetSockOpt(Interface* self) { | |||
| 849 | u32 level = cmd_buffer[2]; | 843 | u32 level = cmd_buffer[2]; |
| 850 | int optname = TranslateSockOpt(cmd_buffer[3]); | 844 | int optname = TranslateSockOpt(cmd_buffer[3]); |
| 851 | 845 | ||
| 852 | int ret = -1; | 846 | int ret = 0; |
| 853 | int err = 0; | 847 | int err = 0; |
| 854 | 848 | ||
| 855 | if (optname < 0) { | 849 | if (optname < 0) { |
| @@ -862,9 +856,8 @@ static void SetSockOpt(Interface* self) { | |||
| 862 | socklen_t optlen = static_cast<socklen_t>(cmd_buffer[4]); | 856 | socklen_t optlen = static_cast<socklen_t>(cmd_buffer[4]); |
| 863 | const char* optval = reinterpret_cast<const char*>(Memory::GetPointer(cmd_buffer[8])); | 857 | const char* optval = reinterpret_cast<const char*>(Memory::GetPointer(cmd_buffer[8])); |
| 864 | 858 | ||
| 865 | ret = static_cast<u32>(::setsockopt(socket_handle, level, optname, optval, optlen)); | 859 | err = static_cast<u32>(::setsockopt(socket_handle, level, optname, optval, optlen)); |
| 866 | err = 0; | 860 | if (err == SOCKET_ERROR_VALUE) { |
| 867 | if (ret == SOCKET_ERROR_VALUE) { | ||
| 868 | err = TranslateError(GET_ERRNO); | 861 | err = TranslateError(GET_ERRNO); |
| 869 | } | 862 | } |
| 870 | } | 863 | } |
diff --git a/src/core/hle/service/y2r_u.cpp b/src/core/hle/service/y2r_u.cpp index 907d9c8fa..c0837d49d 100644 --- a/src/core/hle/service/y2r_u.cpp +++ b/src/core/hle/service/y2r_u.cpp | |||
| @@ -189,11 +189,9 @@ static void SetSpacialDithering(Interface* self) { | |||
| 189 | * 2 : u8, 0 = Disabled, 1 = Enabled | 189 | * 2 : u8, 0 = Disabled, 1 = Enabled |
| 190 | */ | 190 | */ |
| 191 | static void GetSpacialDithering(Interface* self) { | 191 | static void GetSpacialDithering(Interface* self) { |
| 192 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 192 | IPC::RequestBuilder rb(Kernel::GetCommandBuffer(), 0xA, 2, 0); |
| 193 | 193 | rb.Push(RESULT_SUCCESS); | |
| 194 | cmd_buff[0] = IPC::MakeHeader(0xA, 2, 0); | 194 | rb.Push(spacial_dithering_enabled != 0); |
| 195 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 196 | cmd_buff[2] = spacial_dithering_enabled; | ||
| 197 | 195 | ||
| 198 | LOG_WARNING(Service_Y2R, "(STUBBED) called"); | 196 | LOG_WARNING(Service_Y2R, "(STUBBED) called"); |
| 199 | } | 197 | } |
diff --git a/src/core/hle/shared_page.cpp b/src/core/hle/shared_page.cpp index d0d92487d..5978ccdd4 100644 --- a/src/core/hle/shared_page.cpp +++ b/src/core/hle/shared_page.cpp | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | #include <cstring> | 6 | #include <cstring> |
| 7 | #include <ctime> | 7 | #include <ctime> |
| 8 | #include "core/core_timing.h" | 8 | #include "core/core_timing.h" |
| 9 | #include "core/hle/service/ptm/ptm.h" | ||
| 9 | #include "core/hle/shared_page.h" | 10 | #include "core/hle/shared_page.h" |
| 10 | 11 | ||
| 11 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 12 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| @@ -73,6 +74,12 @@ void Init() { | |||
| 73 | // Some games wait until this value becomes 0x1, before asking running_hw | 74 | // Some games wait until this value becomes 0x1, before asking running_hw |
| 74 | shared_page.unknown_value = 0x1; | 75 | shared_page.unknown_value = 0x1; |
| 75 | 76 | ||
| 77 | // Set to a completely full battery | ||
| 78 | shared_page.battery_state.charge_level.Assign( | ||
| 79 | static_cast<u8>(Service::PTM::ChargeLevels::CompletelyFull)); | ||
| 80 | shared_page.battery_state.is_adapter_connected.Assign(1); | ||
| 81 | shared_page.battery_state.is_charging.Assign(1); | ||
| 82 | |||
| 76 | update_time_event = | 83 | update_time_event = |
| 77 | CoreTiming::RegisterEvent("SharedPage::UpdateTimeCallback", UpdateTimeCallback); | 84 | CoreTiming::RegisterEvent("SharedPage::UpdateTimeCallback", UpdateTimeCallback); |
| 78 | CoreTiming::ScheduleEvent(0, update_time_event); | 85 | CoreTiming::ScheduleEvent(0, update_time_event); |
diff --git a/src/core/hle/shared_page.h b/src/core/hle/shared_page.h index 106e47efc..864695ae1 100644 --- a/src/core/hle/shared_page.h +++ b/src/core/hle/shared_page.h | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | * write access, according to 3dbrew; this is not emulated) | 10 | * write access, according to 3dbrew; this is not emulated) |
| 11 | */ | 11 | */ |
| 12 | 12 | ||
| 13 | #include "common/bit_field.h" | ||
| 13 | #include "common/common_funcs.h" | 14 | #include "common/common_funcs.h" |
| 14 | #include "common/common_types.h" | 15 | #include "common/common_types.h" |
| 15 | #include "common/swap.h" | 16 | #include "common/swap.h" |
| @@ -29,6 +30,13 @@ struct DateTime { | |||
| 29 | }; | 30 | }; |
| 30 | static_assert(sizeof(DateTime) == 0x20, "Datetime size is wrong"); | 31 | static_assert(sizeof(DateTime) == 0x20, "Datetime size is wrong"); |
| 31 | 32 | ||
| 33 | union BatteryState { | ||
| 34 | u8 raw; | ||
| 35 | BitField<0, 1, u8> is_adapter_connected; | ||
| 36 | BitField<1, 1, u8> is_charging; | ||
| 37 | BitField<2, 3, u8> charge_level; | ||
| 38 | }; | ||
| 39 | |||
| 32 | struct SharedPageDef { | 40 | struct SharedPageDef { |
| 33 | // Most of these names are taken from the 3dbrew page linked above. | 41 | // Most of these names are taken from the 3dbrew page linked above. |
| 34 | u32_le date_time_counter; // 0 | 42 | u32_le date_time_counter; // 0 |
| @@ -44,7 +52,7 @@ struct SharedPageDef { | |||
| 44 | INSERT_PADDING_BYTES(0x80 - 0x68); // 68 | 52 | INSERT_PADDING_BYTES(0x80 - 0x68); // 68 |
| 45 | float_le sliderstate_3d; // 80 | 53 | float_le sliderstate_3d; // 80 |
| 46 | u8 ledstate_3d; // 84 | 54 | u8 ledstate_3d; // 84 |
| 47 | INSERT_PADDING_BYTES(1); // 85 | 55 | BatteryState battery_state; // 85 |
| 48 | u8 unknown_value; // 86 | 56 | u8 unknown_value; // 86 |
| 49 | INSERT_PADDING_BYTES(0xA0 - 0x87); // 87 | 57 | INSERT_PADDING_BYTES(0xA0 - 0x87); // 87 |
| 50 | u64_le menu_title_id; // A0 | 58 | u64_le menu_title_id; // A0 |
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index 1baa80671..2db823c61 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp | |||
| @@ -467,8 +467,8 @@ static void Break(u8 break_reason) { | |||
| 467 | } | 467 | } |
| 468 | 468 | ||
| 469 | /// Used to output a message on a debug hardware unit - does nothing on a retail unit | 469 | /// Used to output a message on a debug hardware unit - does nothing on a retail unit |
| 470 | static void OutputDebugString(const char* string) { | 470 | static void OutputDebugString(const char* string, int len) { |
| 471 | LOG_DEBUG(Debug_Emulated, "%s", string); | 471 | LOG_DEBUG(Debug_Emulated, "%.*s", len, string); |
| 472 | } | 472 | } |
| 473 | 473 | ||
| 474 | /// Get resource limit | 474 | /// Get resource limit |
| @@ -556,11 +556,21 @@ static ResultCode CreateThread(Kernel::Handle* out_handle, s32 priority, u32 ent | |||
| 556 | break; | 556 | break; |
| 557 | } | 557 | } |
| 558 | 558 | ||
| 559 | if (processor_id == THREADPROCESSORID_1 || processor_id == THREADPROCESSORID_ALL || | 559 | if (processor_id == THREADPROCESSORID_ALL) { |
| 560 | (processor_id == THREADPROCESSORID_DEFAULT && | 560 | LOG_INFO(Kernel_SVC, |
| 561 | Kernel::g_current_process->ideal_processor == THREADPROCESSORID_1)) { | 561 | "Newly created thread is allowed to be run in any Core, unimplemented."); |
| 562 | LOG_WARNING(Kernel_SVC, | 562 | } |
| 563 | "Newly created thread is allowed to be run in the SysCore, unimplemented."); | 563 | |
| 564 | if (processor_id == THREADPROCESSORID_DEFAULT && | ||
| 565 | Kernel::g_current_process->ideal_processor == THREADPROCESSORID_1) { | ||
| 566 | LOG_WARNING( | ||
| 567 | Kernel_SVC, | ||
| 568 | "Newly created thread is allowed to be run in the SysCore (Core1), unimplemented."); | ||
| 569 | } | ||
| 570 | |||
| 571 | if (processor_id == THREADPROCESSORID_1) { | ||
| 572 | LOG_ERROR(Kernel_SVC, | ||
| 573 | "Newly created thread must run in the SysCore (Core1), unimplemented."); | ||
| 564 | } | 574 | } |
| 565 | 575 | ||
| 566 | CASCADE_RESULT(SharedPtr<Thread> thread, Kernel::Thread::Create(name, entry_point, priority, | 576 | CASCADE_RESULT(SharedPtr<Thread> thread, Kernel::Thread::Create(name, entry_point, priority, |
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp index 147bf8591..be719d74c 100644 --- a/src/core/loader/loader.cpp +++ b/src/core/loader/loader.cpp | |||
| @@ -139,7 +139,7 @@ std::unique_ptr<AppLoader> GetLoader(const std::string& filename) { | |||
| 139 | type = filename_type; | 139 | type = filename_type; |
| 140 | } | 140 | } |
| 141 | 141 | ||
| 142 | LOG_INFO(Loader, "Loading file %s as %s...", filename.c_str(), GetFileTypeString(type)); | 142 | LOG_DEBUG(Loader, "Loading file %s as %s...", filename.c_str(), GetFileTypeString(type)); |
| 143 | 143 | ||
| 144 | return GetFileLoader(std::move(file), type, filename_filename, filename); | 144 | return GetFileLoader(std::move(file), type, filename_filename, filename); |
| 145 | } | 145 | } |
diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp index 98b8259d9..1a4e3efa8 100644 --- a/src/core/loader/ncch.cpp +++ b/src/core/loader/ncch.cpp | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <algorithm> | 5 | #include <algorithm> |
| 6 | #include <cinttypes> | ||
| 6 | #include <cstring> | 7 | #include <cstring> |
| 7 | #include <memory> | 8 | #include <memory> |
| 8 | #include "common/logging/log.h" | 9 | #include "common/logging/log.h" |
| @@ -253,7 +254,7 @@ ResultStatus AppLoader_NCCH::LoadExeFS() { | |||
| 253 | 254 | ||
| 254 | // Skip NCSD header and load first NCCH (NCSD is just a container of NCCH files)... | 255 | // Skip NCSD header and load first NCCH (NCSD is just a container of NCCH files)... |
| 255 | if (MakeMagic('N', 'C', 'S', 'D') == ncch_header.magic) { | 256 | if (MakeMagic('N', 'C', 'S', 'D') == ncch_header.magic) { |
| 256 | LOG_WARNING(Loader, "Only loading the first (bootable) NCCH within the NCSD file!"); | 257 | LOG_DEBUG(Loader, "Only loading the first (bootable) NCCH within the NCSD file!"); |
| 257 | ncch_offset = 0x4000; | 258 | ncch_offset = 0x4000; |
| 258 | file.Seek(ncch_offset, SEEK_SET); | 259 | file.Seek(ncch_offset, SEEK_SET); |
| 259 | file.ReadBytes(&ncch_header, sizeof(NCCH_Header)); | 260 | file.ReadBytes(&ncch_header, sizeof(NCCH_Header)); |
| @@ -277,8 +278,8 @@ ResultStatus AppLoader_NCCH::LoadExeFS() { | |||
| 277 | priority = exheader_header.arm11_system_local_caps.priority; | 278 | priority = exheader_header.arm11_system_local_caps.priority; |
| 278 | resource_limit_category = exheader_header.arm11_system_local_caps.resource_limit_category; | 279 | resource_limit_category = exheader_header.arm11_system_local_caps.resource_limit_category; |
| 279 | 280 | ||
| 280 | LOG_INFO(Loader, "Name: %s", exheader_header.codeset_info.name); | 281 | LOG_DEBUG(Loader, "Name: %s", exheader_header.codeset_info.name); |
| 281 | LOG_INFO(Loader, "Program ID: %016llX", ncch_header.program_id); | 282 | LOG_DEBUG(Loader, "Program ID: %016" PRIX64, ncch_header.program_id); |
| 282 | LOG_DEBUG(Loader, "Code compressed: %s", is_compressed ? "yes" : "no"); | 283 | LOG_DEBUG(Loader, "Code compressed: %s", is_compressed ? "yes" : "no"); |
| 283 | LOG_DEBUG(Loader, "Entry point: 0x%08X", entry_point); | 284 | LOG_DEBUG(Loader, "Entry point: 0x%08X", entry_point); |
| 284 | LOG_DEBUG(Loader, "Code size: 0x%08X", code_size); | 285 | LOG_DEBUG(Loader, "Code size: 0x%08X", code_size); |
| @@ -336,6 +337,8 @@ ResultStatus AppLoader_NCCH::Load() { | |||
| 336 | if (result != ResultStatus::Success) | 337 | if (result != ResultStatus::Success) |
| 337 | return result; | 338 | return result; |
| 338 | 339 | ||
| 340 | LOG_INFO(Loader, "Program ID: %016" PRIX64, ncch_header.program_id); | ||
| 341 | |||
| 339 | is_loaded = true; // Set state to loaded | 342 | is_loaded = true; // Set state to loaded |
| 340 | 343 | ||
| 341 | result = LoadExec(); // Load the executable into memory for booting | 344 | result = LoadExec(); // Load the executable into memory for booting |
diff --git a/src/core/settings.cpp b/src/core/settings.cpp index 3a32b70aa..a598f9f2f 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #include "audio_core/audio_core.h" | 5 | #include "audio_core/audio_core.h" |
| 6 | #include "core/gdbstub/gdbstub.h" | 6 | #include "core/gdbstub/gdbstub.h" |
| 7 | #include "core/hle/service/hid/hid.h" | ||
| 7 | #include "settings.h" | 8 | #include "settings.h" |
| 8 | #include "video_core/video_core.h" | 9 | #include "video_core/video_core.h" |
| 9 | 10 | ||
| @@ -29,6 +30,8 @@ void Apply() { | |||
| 29 | 30 | ||
| 30 | AudioCore::SelectSink(values.sink_id); | 31 | AudioCore::SelectSink(values.sink_id); |
| 31 | AudioCore::EnableStretching(values.enable_audio_stretching); | 32 | AudioCore::EnableStretching(values.enable_audio_stretching); |
| 33 | |||
| 34 | Service::HID::ReloadInputDevices(); | ||
| 32 | } | 35 | } |
| 33 | 36 | ||
| 34 | } // namespace | 37 | } // namespace |
diff --git a/src/core/settings.h b/src/core/settings.h index b6c75531f..03c64c94c 100644 --- a/src/core/settings.h +++ b/src/core/settings.h | |||
| @@ -15,67 +15,70 @@ enum class LayoutOption { | |||
| 15 | Default, | 15 | Default, |
| 16 | SingleScreen, | 16 | SingleScreen, |
| 17 | LargeScreen, | 17 | LargeScreen, |
| 18 | Custom, | ||
| 19 | }; | 18 | }; |
| 20 | 19 | ||
| 21 | namespace NativeInput { | 20 | namespace NativeButton { |
| 22 | |||
| 23 | enum Values { | 21 | enum Values { |
| 24 | // directly mapped keys | ||
| 25 | A, | 22 | A, |
| 26 | B, | 23 | B, |
| 27 | X, | 24 | X, |
| 28 | Y, | 25 | Y, |
| 26 | Up, | ||
| 27 | Down, | ||
| 28 | Left, | ||
| 29 | Right, | ||
| 29 | L, | 30 | L, |
| 30 | R, | 31 | R, |
| 32 | Start, | ||
| 33 | Select, | ||
| 34 | |||
| 31 | ZL, | 35 | ZL, |
| 32 | ZR, | 36 | ZR, |
| 33 | START, | 37 | |
| 34 | SELECT, | 38 | Home, |
| 35 | HOME, | 39 | |
| 36 | DUP, | 40 | NumButtons, |
| 37 | DDOWN, | ||
| 38 | DLEFT, | ||
| 39 | DRIGHT, | ||
| 40 | CUP, | ||
| 41 | CDOWN, | ||
| 42 | CLEFT, | ||
| 43 | CRIGHT, | ||
| 44 | |||
| 45 | // indirectly mapped keys | ||
| 46 | CIRCLE_UP, | ||
| 47 | CIRCLE_DOWN, | ||
| 48 | CIRCLE_LEFT, | ||
| 49 | CIRCLE_RIGHT, | ||
| 50 | CIRCLE_MODIFIER, | ||
| 51 | |||
| 52 | NUM_INPUTS | ||
| 53 | }; | 41 | }; |
| 54 | 42 | ||
| 55 | static const std::array<const char*, NUM_INPUTS> Mapping = {{ | 43 | constexpr int BUTTON_HID_BEGIN = A; |
| 56 | // directly mapped keys | 44 | constexpr int BUTTON_IR_BEGIN = ZL; |
| 57 | "pad_a", "pad_b", "pad_x", "pad_y", "pad_l", "pad_r", "pad_zl", "pad_zr", "pad_start", | 45 | constexpr int BUTTON_NS_BEGIN = Home; |
| 58 | "pad_select", "pad_home", "pad_dup", "pad_ddown", "pad_dleft", "pad_dright", "pad_cup", | 46 | |
| 59 | "pad_cdown", "pad_cleft", "pad_cright", | 47 | constexpr int BUTTON_HID_END = BUTTON_IR_BEGIN; |
| 48 | constexpr int BUTTON_IR_END = BUTTON_NS_BEGIN; | ||
| 49 | constexpr int BUTTON_NS_END = NumButtons; | ||
| 50 | |||
| 51 | constexpr int NUM_BUTTONS_HID = BUTTON_HID_END - BUTTON_HID_BEGIN; | ||
| 52 | constexpr int NUM_BUTTONS_IR = BUTTON_IR_END - BUTTON_IR_BEGIN; | ||
| 53 | constexpr int NUM_BUTTONS_NS = BUTTON_NS_END - BUTTON_NS_BEGIN; | ||
| 60 | 54 | ||
| 61 | // indirectly mapped keys | 55 | static const std::array<const char*, NumButtons> mapping = {{ |
| 62 | "pad_circle_up", "pad_circle_down", "pad_circle_left", "pad_circle_right", | 56 | "button_a", "button_b", "button_x", "button_y", "button_up", "button_down", "button_left", |
| 63 | "pad_circle_modifier", | 57 | "button_right", "button_l", "button_r", "button_start", "button_select", "button_zl", |
| 58 | "button_zr", "button_home", | ||
| 64 | }}; | 59 | }}; |
| 65 | static const std::array<Values, NUM_INPUTS> All = {{ | 60 | } // namespace NativeButton |
| 66 | A, B, X, Y, L, R, ZL, ZR, | 61 | |
| 67 | START, SELECT, HOME, DUP, DDOWN, DLEFT, DRIGHT, CUP, | 62 | namespace NativeAnalog { |
| 68 | CDOWN, CLEFT, CRIGHT, CIRCLE_UP, CIRCLE_DOWN, CIRCLE_LEFT, CIRCLE_RIGHT, CIRCLE_MODIFIER, | 63 | enum Values { |
| 64 | CirclePad, | ||
| 65 | CStick, | ||
| 66 | |||
| 67 | NumAnalogs, | ||
| 68 | }; | ||
| 69 | |||
| 70 | static const std::array<const char*, NumAnalogs> mapping = {{ | ||
| 71 | "circle_pad", "c_stick", | ||
| 69 | }}; | 72 | }}; |
| 70 | } | 73 | } // namespace NumAnalog |
| 71 | 74 | ||
| 72 | struct Values { | 75 | struct Values { |
| 73 | // CheckNew3DS | 76 | // CheckNew3DS |
| 74 | bool is_new_3ds; | 77 | bool is_new_3ds; |
| 75 | 78 | ||
| 76 | // Controls | 79 | // Controls |
| 77 | std::array<int, NativeInput::NUM_INPUTS> input_mappings; | 80 | std::array<std::string, NativeButton::NumButtons> buttons; |
| 78 | float pad_circle_modifier_scale; | 81 | std::array<std::string, NativeAnalog::NumAnalogs> analogs; |
| 79 | 82 | ||
| 80 | // Core | 83 | // Core |
| 81 | bool use_cpu_jit; | 84 | bool use_cpu_jit; |
| @@ -95,6 +98,15 @@ struct Values { | |||
| 95 | 98 | ||
| 96 | LayoutOption layout_option; | 99 | LayoutOption layout_option; |
| 97 | bool swap_screen; | 100 | bool swap_screen; |
| 101 | bool custom_layout; | ||
| 102 | u16 custom_top_left; | ||
| 103 | u16 custom_top_top; | ||
| 104 | u16 custom_top_right; | ||
| 105 | u16 custom_top_bottom; | ||
| 106 | u16 custom_bottom_left; | ||
| 107 | u16 custom_bottom_top; | ||
| 108 | u16 custom_bottom_right; | ||
| 109 | u16 custom_bottom_bottom; | ||
| 98 | 110 | ||
| 99 | float bg_red; | 111 | float bg_red; |
| 100 | float bg_green; | 112 | float bg_green; |
diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt new file mode 100644 index 000000000..cfe5caaa3 --- /dev/null +++ b/src/input_common/CMakeLists.txt | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | set(SRCS | ||
| 2 | analog_from_button.cpp | ||
| 3 | keyboard.cpp | ||
| 4 | main.cpp | ||
| 5 | ) | ||
| 6 | |||
| 7 | set(HEADERS | ||
| 8 | analog_from_button.h | ||
| 9 | keyboard.h | ||
| 10 | main.h | ||
| 11 | ) | ||
| 12 | |||
| 13 | if(SDL2_FOUND) | ||
| 14 | set(SRCS ${SRCS} sdl/sdl.cpp) | ||
| 15 | set(HEADERS ${HEADERS} sdl/sdl.h) | ||
| 16 | include_directories(${SDL2_INCLUDE_DIR}) | ||
| 17 | endif() | ||
| 18 | |||
| 19 | create_directory_groups(${SRCS} ${HEADERS}) | ||
| 20 | |||
| 21 | add_library(input_common STATIC ${SRCS} ${HEADERS}) | ||
| 22 | target_link_libraries(input_common common core) | ||
| 23 | |||
| 24 | if(SDL2_FOUND) | ||
| 25 | target_link_libraries(input_common ${SDL2_LIBRARY}) | ||
| 26 | set_property(TARGET input_common APPEND PROPERTY COMPILE_DEFINITIONS HAVE_SDL2) | ||
| 27 | endif() | ||
diff --git a/src/input_common/analog_from_button.cpp b/src/input_common/analog_from_button.cpp new file mode 100755 index 000000000..e1a260762 --- /dev/null +++ b/src/input_common/analog_from_button.cpp | |||
| @@ -0,0 +1,58 @@ | |||
| 1 | // Copyright 2017 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "input_common/analog_from_button.h" | ||
| 6 | |||
| 7 | namespace InputCommon { | ||
| 8 | |||
| 9 | class Analog final : public Input::AnalogDevice { | ||
| 10 | public: | ||
| 11 | using Button = std::unique_ptr<Input::ButtonDevice>; | ||
| 12 | |||
| 13 | Analog(Button up_, Button down_, Button left_, Button right_, Button modifier_, | ||
| 14 | float modifier_scale_) | ||
| 15 | : up(std::move(up_)), down(std::move(down_)), left(std::move(left_)), | ||
| 16 | right(std::move(right_)), modifier(std::move(modifier_)), | ||
| 17 | modifier_scale(modifier_scale_) {} | ||
| 18 | |||
| 19 | std::tuple<float, float> GetStatus() const override { | ||
| 20 | constexpr float SQRT_HALF = 0.707106781f; | ||
| 21 | int x = 0, y = 0; | ||
| 22 | |||
| 23 | if (right->GetStatus()) | ||
| 24 | ++x; | ||
| 25 | if (left->GetStatus()) | ||
| 26 | --x; | ||
| 27 | if (up->GetStatus()) | ||
| 28 | ++y; | ||
| 29 | if (down->GetStatus()) | ||
| 30 | --y; | ||
| 31 | |||
| 32 | float coef = modifier->GetStatus() ? modifier_scale : 1.0f; | ||
| 33 | return std::make_tuple(x * coef * (y == 0 ? 1.0f : SQRT_HALF), | ||
| 34 | y * coef * (x == 0 ? 1.0f : SQRT_HALF)); | ||
| 35 | } | ||
| 36 | |||
| 37 | private: | ||
| 38 | Button up; | ||
| 39 | Button down; | ||
| 40 | Button left; | ||
| 41 | Button right; | ||
| 42 | Button modifier; | ||
| 43 | float modifier_scale; | ||
| 44 | }; | ||
| 45 | |||
| 46 | std::unique_ptr<Input::AnalogDevice> AnalogFromButton::Create(const Common::ParamPackage& params) { | ||
| 47 | const std::string null_engine = Common::ParamPackage{{"engine", "null"}}.Serialize(); | ||
| 48 | auto up = Input::CreateDevice<Input::ButtonDevice>(params.Get("up", null_engine)); | ||
| 49 | auto down = Input::CreateDevice<Input::ButtonDevice>(params.Get("down", null_engine)); | ||
| 50 | auto left = Input::CreateDevice<Input::ButtonDevice>(params.Get("left", null_engine)); | ||
| 51 | auto right = Input::CreateDevice<Input::ButtonDevice>(params.Get("right", null_engine)); | ||
| 52 | auto modifier = Input::CreateDevice<Input::ButtonDevice>(params.Get("modifier", null_engine)); | ||
| 53 | auto modifier_scale = params.Get("modifier_scale", 0.5f); | ||
| 54 | return std::make_unique<Analog>(std::move(up), std::move(down), std::move(left), | ||
| 55 | std::move(right), std::move(modifier), modifier_scale); | ||
| 56 | } | ||
| 57 | |||
| 58 | } // namespace InputCommon | ||
diff --git a/src/input_common/analog_from_button.h b/src/input_common/analog_from_button.h new file mode 100755 index 000000000..bbd583dd9 --- /dev/null +++ b/src/input_common/analog_from_button.h | |||
| @@ -0,0 +1,31 @@ | |||
| 1 | // Copyright 2017 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <memory> | ||
| 8 | #include "core/frontend/input.h" | ||
| 9 | |||
| 10 | namespace InputCommon { | ||
| 11 | |||
| 12 | /** | ||
| 13 | * An analog device factory that takes direction button devices and combines them into a analog | ||
| 14 | * device. | ||
| 15 | */ | ||
| 16 | class AnalogFromButton final : public Input::Factory<Input::AnalogDevice> { | ||
| 17 | public: | ||
| 18 | /** | ||
| 19 | * Creates an analog device from direction button devices | ||
| 20 | * @param params contains parameters for creating the device: | ||
| 21 | * - "up": a serialized ParamPackage for creating a button device for up direction | ||
| 22 | * - "down": a serialized ParamPackage for creating a button device for down direction | ||
| 23 | * - "left": a serialized ParamPackage for creating a button device for left direction | ||
| 24 | * - "right": a serialized ParamPackage for creating a button device for right direction | ||
| 25 | * - "modifier": a serialized ParamPackage for creating a button device as the modifier | ||
| 26 | * - "modifier_scale": a float for the multiplier the modifier gives to the position | ||
| 27 | */ | ||
| 28 | std::unique_ptr<Input::AnalogDevice> Create(const Common::ParamPackage& params) override; | ||
| 29 | }; | ||
| 30 | |||
| 31 | } // namespace InputCommon | ||
diff --git a/src/input_common/keyboard.cpp b/src/input_common/keyboard.cpp new file mode 100644 index 000000000..0f0d10f23 --- /dev/null +++ b/src/input_common/keyboard.cpp | |||
| @@ -0,0 +1,93 @@ | |||
| 1 | // Copyright 2017 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <atomic> | ||
| 6 | #include <list> | ||
| 7 | #include <mutex> | ||
| 8 | #include "input_common/keyboard.h" | ||
| 9 | |||
| 10 | namespace InputCommon { | ||
| 11 | |||
| 12 | class KeyButton final : public Input::ButtonDevice { | ||
| 13 | public: | ||
| 14 | explicit KeyButton(std::shared_ptr<KeyButtonList> key_button_list_) | ||
| 15 | : key_button_list(key_button_list_) {} | ||
| 16 | |||
| 17 | ~KeyButton(); | ||
| 18 | |||
| 19 | bool GetStatus() const override { | ||
| 20 | return status.load(); | ||
| 21 | } | ||
| 22 | |||
| 23 | friend class KeyButtonList; | ||
| 24 | |||
| 25 | private: | ||
| 26 | std::shared_ptr<KeyButtonList> key_button_list; | ||
| 27 | std::atomic<bool> status{false}; | ||
| 28 | }; | ||
| 29 | |||
| 30 | struct KeyButtonPair { | ||
| 31 | int key_code; | ||
| 32 | KeyButton* key_button; | ||
| 33 | }; | ||
| 34 | |||
| 35 | class KeyButtonList { | ||
| 36 | public: | ||
| 37 | void AddKeyButton(int key_code, KeyButton* key_button) { | ||
| 38 | std::lock_guard<std::mutex> guard(mutex); | ||
| 39 | list.push_back(KeyButtonPair{key_code, key_button}); | ||
| 40 | } | ||
| 41 | |||
| 42 | void RemoveKeyButton(const KeyButton* key_button) { | ||
| 43 | std::lock_guard<std::mutex> guard(mutex); | ||
| 44 | list.remove_if( | ||
| 45 | [key_button](const KeyButtonPair& pair) { return pair.key_button == key_button; }); | ||
| 46 | } | ||
| 47 | |||
| 48 | void ChangeKeyStatus(int key_code, bool pressed) { | ||
| 49 | std::lock_guard<std::mutex> guard(mutex); | ||
| 50 | for (const KeyButtonPair& pair : list) { | ||
| 51 | if (pair.key_code == key_code) | ||
| 52 | pair.key_button->status.store(pressed); | ||
| 53 | } | ||
| 54 | } | ||
| 55 | |||
| 56 | void ChangeAllKeyStatus(bool pressed) { | ||
| 57 | std::lock_guard<std::mutex> guard(mutex); | ||
| 58 | for (const KeyButtonPair& pair : list) { | ||
| 59 | pair.key_button->status.store(pressed); | ||
| 60 | } | ||
| 61 | } | ||
| 62 | |||
| 63 | private: | ||
| 64 | std::mutex mutex; | ||
| 65 | std::list<KeyButtonPair> list; | ||
| 66 | }; | ||
| 67 | |||
| 68 | Keyboard::Keyboard() : key_button_list{std::make_shared<KeyButtonList>()} {} | ||
| 69 | |||
| 70 | KeyButton::~KeyButton() { | ||
| 71 | key_button_list->RemoveKeyButton(this); | ||
| 72 | } | ||
| 73 | |||
| 74 | std::unique_ptr<Input::ButtonDevice> Keyboard::Create(const Common::ParamPackage& params) { | ||
| 75 | int key_code = params.Get("code", 0); | ||
| 76 | std::unique_ptr<KeyButton> button = std::make_unique<KeyButton>(key_button_list); | ||
| 77 | key_button_list->AddKeyButton(key_code, button.get()); | ||
| 78 | return std::move(button); | ||
| 79 | } | ||
| 80 | |||
| 81 | void Keyboard::PressKey(int key_code) { | ||
| 82 | key_button_list->ChangeKeyStatus(key_code, true); | ||
| 83 | } | ||
| 84 | |||
| 85 | void Keyboard::ReleaseKey(int key_code) { | ||
| 86 | key_button_list->ChangeKeyStatus(key_code, false); | ||
| 87 | } | ||
| 88 | |||
| 89 | void Keyboard::ReleaseAllKeys() { | ||
| 90 | key_button_list->ChangeAllKeyStatus(false); | ||
| 91 | } | ||
| 92 | |||
| 93 | } // namespace InputCommon | ||
diff --git a/src/input_common/keyboard.h b/src/input_common/keyboard.h new file mode 100644 index 000000000..861950472 --- /dev/null +++ b/src/input_common/keyboard.h | |||
| @@ -0,0 +1,47 @@ | |||
| 1 | // Copyright 2017 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <memory> | ||
| 8 | #include "core/frontend/input.h" | ||
| 9 | |||
| 10 | namespace InputCommon { | ||
| 11 | |||
| 12 | class KeyButtonList; | ||
| 13 | |||
| 14 | /** | ||
| 15 | * A button device factory representing a keyboard. It receives keyboard events and forward them | ||
| 16 | * to all button devices it created. | ||
| 17 | */ | ||
| 18 | class Keyboard final : public Input::Factory<Input::ButtonDevice> { | ||
| 19 | public: | ||
| 20 | Keyboard(); | ||
| 21 | |||
| 22 | /** | ||
| 23 | * Creates a button device from a keyboard key | ||
| 24 | * @param params contains parameters for creating the device: | ||
| 25 | * - "code": the code of the key to bind with the button | ||
| 26 | */ | ||
| 27 | std::unique_ptr<Input::ButtonDevice> Create(const Common::ParamPackage& params) override; | ||
| 28 | |||
| 29 | /** | ||
| 30 | * Sets the status of all buttons bound with the key to pressed | ||
| 31 | * @param key_code the code of the key to press | ||
| 32 | */ | ||
| 33 | void PressKey(int key_code); | ||
| 34 | |||
| 35 | /** | ||
| 36 | * Sets the status of all buttons bound with the key to released | ||
| 37 | * @param key_code the code of the key to release | ||
| 38 | */ | ||
| 39 | void ReleaseKey(int key_code); | ||
| 40 | |||
| 41 | void ReleaseAllKeys(); | ||
| 42 | |||
| 43 | private: | ||
| 44 | std::shared_ptr<KeyButtonList> key_button_list; | ||
| 45 | }; | ||
| 46 | |||
| 47 | } // namespace InputCommon | ||
diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp new file mode 100644 index 000000000..699f41e6b --- /dev/null +++ b/src/input_common/main.cpp | |||
| @@ -0,0 +1,63 @@ | |||
| 1 | // Copyright 2017 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <memory> | ||
| 6 | #include "common/param_package.h" | ||
| 7 | #include "input_common/analog_from_button.h" | ||
| 8 | #include "input_common/keyboard.h" | ||
| 9 | #include "input_common/main.h" | ||
| 10 | #ifdef HAVE_SDL2 | ||
| 11 | #include "input_common/sdl/sdl.h" | ||
| 12 | #endif | ||
| 13 | |||
| 14 | namespace InputCommon { | ||
| 15 | |||
| 16 | static std::shared_ptr<Keyboard> keyboard; | ||
| 17 | |||
| 18 | void Init() { | ||
| 19 | keyboard = std::make_shared<InputCommon::Keyboard>(); | ||
| 20 | Input::RegisterFactory<Input::ButtonDevice>("keyboard", keyboard); | ||
| 21 | Input::RegisterFactory<Input::AnalogDevice>("analog_from_button", | ||
| 22 | std::make_shared<InputCommon::AnalogFromButton>()); | ||
| 23 | #ifdef HAVE_SDL2 | ||
| 24 | SDL::Init(); | ||
| 25 | #endif | ||
| 26 | } | ||
| 27 | |||
| 28 | void Shutdown() { | ||
| 29 | Input::UnregisterFactory<Input::ButtonDevice>("keyboard"); | ||
| 30 | keyboard.reset(); | ||
| 31 | Input::UnregisterFactory<Input::AnalogDevice>("analog_from_button"); | ||
| 32 | |||
| 33 | #ifdef HAVE_SDL2 | ||
| 34 | SDL::Shutdown(); | ||
| 35 | #endif | ||
| 36 | } | ||
| 37 | |||
| 38 | Keyboard* GetKeyboard() { | ||
| 39 | return keyboard.get(); | ||
| 40 | } | ||
| 41 | |||
| 42 | std::string GenerateKeyboardParam(int key_code) { | ||
| 43 | Common::ParamPackage param{ | ||
| 44 | {"engine", "keyboard"}, {"code", std::to_string(key_code)}, | ||
| 45 | }; | ||
| 46 | return param.Serialize(); | ||
| 47 | } | ||
| 48 | |||
| 49 | std::string GenerateAnalogParamFromKeys(int key_up, int key_down, int key_left, int key_right, | ||
| 50 | int key_modifier, float modifier_scale) { | ||
| 51 | Common::ParamPackage circle_pad_param{ | ||
| 52 | {"engine", "analog_from_button"}, | ||
| 53 | {"up", GenerateKeyboardParam(key_up)}, | ||
| 54 | {"down", GenerateKeyboardParam(key_down)}, | ||
| 55 | {"left", GenerateKeyboardParam(key_left)}, | ||
| 56 | {"right", GenerateKeyboardParam(key_right)}, | ||
| 57 | {"modifier", GenerateKeyboardParam(key_modifier)}, | ||
| 58 | {"modifier_scale", std::to_string(modifier_scale)}, | ||
| 59 | }; | ||
| 60 | return circle_pad_param.Serialize(); | ||
| 61 | } | ||
| 62 | |||
| 63 | } // namespace InputCommon | ||
diff --git a/src/input_common/main.h b/src/input_common/main.h new file mode 100644 index 000000000..140bbd014 --- /dev/null +++ b/src/input_common/main.h | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | // Copyright 2017 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <string> | ||
| 8 | |||
| 9 | namespace InputCommon { | ||
| 10 | |||
| 11 | /// Initializes and registers all built-in input device factories. | ||
| 12 | void Init(); | ||
| 13 | |||
| 14 | /// Unresisters all build-in input device factories and shut them down. | ||
| 15 | void Shutdown(); | ||
| 16 | |||
| 17 | class Keyboard; | ||
| 18 | |||
| 19 | /// Gets the keyboard button device factory. | ||
| 20 | Keyboard* GetKeyboard(); | ||
| 21 | |||
| 22 | /// Generates a serialized param package for creating a keyboard button device | ||
| 23 | std::string GenerateKeyboardParam(int key_code); | ||
| 24 | |||
| 25 | /// Generates a serialized param package for creating an analog device taking input from keyboard | ||
| 26 | std::string GenerateAnalogParamFromKeys(int key_up, int key_down, int key_left, int key_right, | ||
| 27 | int key_modifier, float modifier_scale); | ||
| 28 | |||
| 29 | } // namespace InputCommon | ||
diff --git a/src/input_common/sdl/sdl.cpp b/src/input_common/sdl/sdl.cpp new file mode 100644 index 000000000..ae0206909 --- /dev/null +++ b/src/input_common/sdl/sdl.cpp | |||
| @@ -0,0 +1,202 @@ | |||
| 1 | // Copyright 2017 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <cmath> | ||
| 6 | #include <memory> | ||
| 7 | #include <string> | ||
| 8 | #include <tuple> | ||
| 9 | #include <unordered_map> | ||
| 10 | #include <SDL.h> | ||
| 11 | #include "common/math_util.h" | ||
| 12 | #include "input_common/sdl/sdl.h" | ||
| 13 | |||
| 14 | namespace InputCommon { | ||
| 15 | |||
| 16 | namespace SDL { | ||
| 17 | |||
| 18 | class SDLJoystick; | ||
| 19 | class SDLButtonFactory; | ||
| 20 | class SDLAnalogFactory; | ||
| 21 | static std::unordered_map<int, std::weak_ptr<SDLJoystick>> joystick_list; | ||
| 22 | static std::shared_ptr<SDLButtonFactory> button_factory; | ||
| 23 | static std::shared_ptr<SDLAnalogFactory> analog_factory; | ||
| 24 | |||
| 25 | static bool initialized = false; | ||
| 26 | |||
| 27 | class SDLJoystick { | ||
| 28 | public: | ||
| 29 | explicit SDLJoystick(int joystick_index) | ||
| 30 | : joystick{SDL_JoystickOpen(joystick_index), SDL_JoystickClose} { | ||
| 31 | if (!joystick) { | ||
| 32 | LOG_ERROR(Input, "failed to open joystick %d", joystick_index); | ||
| 33 | } | ||
| 34 | } | ||
| 35 | |||
| 36 | bool GetButton(int button) const { | ||
| 37 | if (!joystick) | ||
| 38 | return {}; | ||
| 39 | SDL_JoystickUpdate(); | ||
| 40 | return SDL_JoystickGetButton(joystick.get(), button) == 1; | ||
| 41 | } | ||
| 42 | |||
| 43 | std::tuple<float, float> GetAnalog(int axis_x, int axis_y) const { | ||
| 44 | if (!joystick) | ||
| 45 | return {}; | ||
| 46 | SDL_JoystickUpdate(); | ||
| 47 | float x = SDL_JoystickGetAxis(joystick.get(), axis_x) / 32767.0f; | ||
| 48 | float y = SDL_JoystickGetAxis(joystick.get(), axis_y) / 32767.0f; | ||
| 49 | y = -y; // 3DS uses an y-axis inverse from SDL | ||
| 50 | |||
| 51 | // Make sure the coordinates are in the unit circle, | ||
| 52 | // otherwise normalize it. | ||
| 53 | float r = x * x + y * y; | ||
| 54 | if (r > 1.0f) { | ||
| 55 | r = std::sqrt(r); | ||
| 56 | x /= r; | ||
| 57 | y /= r; | ||
| 58 | } | ||
| 59 | |||
| 60 | return std::make_tuple(x, y); | ||
| 61 | } | ||
| 62 | |||
| 63 | bool GetHatDirection(int hat, Uint8 direction) const { | ||
| 64 | return (SDL_JoystickGetHat(joystick.get(), hat) & direction) != 0; | ||
| 65 | } | ||
| 66 | |||
| 67 | private: | ||
| 68 | std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)> joystick; | ||
| 69 | }; | ||
| 70 | |||
| 71 | class SDLButton final : public Input::ButtonDevice { | ||
| 72 | public: | ||
| 73 | explicit SDLButton(std::shared_ptr<SDLJoystick> joystick_, int button_) | ||
| 74 | : joystick(joystick_), button(button_) {} | ||
| 75 | |||
| 76 | bool GetStatus() const override { | ||
| 77 | return joystick->GetButton(button); | ||
| 78 | } | ||
| 79 | |||
| 80 | private: | ||
| 81 | std::shared_ptr<SDLJoystick> joystick; | ||
| 82 | int button; | ||
| 83 | }; | ||
| 84 | |||
| 85 | class SDLDirectionButton final : public Input::ButtonDevice { | ||
| 86 | public: | ||
| 87 | explicit SDLDirectionButton(std::shared_ptr<SDLJoystick> joystick_, int hat_, Uint8 direction_) | ||
| 88 | : joystick(joystick_), hat(hat_), direction(direction_) {} | ||
| 89 | |||
| 90 | bool GetStatus() const override { | ||
| 91 | return joystick->GetHatDirection(hat, direction); | ||
| 92 | } | ||
| 93 | |||
| 94 | private: | ||
| 95 | std::shared_ptr<SDLJoystick> joystick; | ||
| 96 | int hat; | ||
| 97 | Uint8 direction; | ||
| 98 | }; | ||
| 99 | |||
| 100 | class SDLAnalog final : public Input::AnalogDevice { | ||
| 101 | public: | ||
| 102 | SDLAnalog(std::shared_ptr<SDLJoystick> joystick_, int axis_x_, int axis_y_) | ||
| 103 | : joystick(joystick_), axis_x(axis_x_), axis_y(axis_y_) {} | ||
| 104 | |||
| 105 | std::tuple<float, float> GetStatus() const override { | ||
| 106 | return joystick->GetAnalog(axis_x, axis_y); | ||
| 107 | } | ||
| 108 | |||
| 109 | private: | ||
| 110 | std::shared_ptr<SDLJoystick> joystick; | ||
| 111 | int axis_x; | ||
| 112 | int axis_y; | ||
| 113 | }; | ||
| 114 | |||
| 115 | static std::shared_ptr<SDLJoystick> GetJoystick(int joystick_index) { | ||
| 116 | std::shared_ptr<SDLJoystick> joystick = joystick_list[joystick_index].lock(); | ||
| 117 | if (!joystick) { | ||
| 118 | joystick = std::make_shared<SDLJoystick>(joystick_index); | ||
| 119 | joystick_list[joystick_index] = joystick; | ||
| 120 | } | ||
| 121 | return joystick; | ||
| 122 | } | ||
| 123 | |||
| 124 | /// A button device factory that creates button devices from SDL joystick | ||
| 125 | class SDLButtonFactory final : public Input::Factory<Input::ButtonDevice> { | ||
| 126 | public: | ||
| 127 | /** | ||
| 128 | * Creates a button device from a joystick button | ||
| 129 | * @param params contains parameters for creating the device: | ||
| 130 | * - "joystick": the index of the joystick to bind | ||
| 131 | * - "button"(optional): the index of the button to bind | ||
| 132 | * - "hat"(optional): the index of the hat to bind as direction buttons | ||
| 133 | * - "direction"(only used for hat): the direction name of the hat to bind. Can be "up", | ||
| 134 | * "down", "left" or "right" | ||
| 135 | */ | ||
| 136 | std::unique_ptr<Input::ButtonDevice> Create(const Common::ParamPackage& params) override { | ||
| 137 | const int joystick_index = params.Get("joystick", 0); | ||
| 138 | |||
| 139 | if (params.Has("hat")) { | ||
| 140 | const int hat = params.Get("hat", 0); | ||
| 141 | const std::string direction_name = params.Get("direction", ""); | ||
| 142 | Uint8 direction; | ||
| 143 | if (direction_name == "up") { | ||
| 144 | direction = SDL_HAT_UP; | ||
| 145 | } else if (direction_name == "down") { | ||
| 146 | direction = SDL_HAT_DOWN; | ||
| 147 | } else if (direction_name == "left") { | ||
| 148 | direction = SDL_HAT_LEFT; | ||
| 149 | } else if (direction_name == "right") { | ||
| 150 | direction = SDL_HAT_RIGHT; | ||
| 151 | } else { | ||
| 152 | direction = 0; | ||
| 153 | } | ||
| 154 | return std::make_unique<SDLDirectionButton>(GetJoystick(joystick_index), hat, | ||
| 155 | direction); | ||
| 156 | } | ||
| 157 | |||
| 158 | const int button = params.Get("button", 0); | ||
| 159 | return std::make_unique<SDLButton>(GetJoystick(joystick_index), button); | ||
| 160 | } | ||
| 161 | }; | ||
| 162 | |||
| 163 | /// An analog device factory that creates analog devices from SDL joystick | ||
| 164 | class SDLAnalogFactory final : public Input::Factory<Input::AnalogDevice> { | ||
| 165 | public: | ||
| 166 | /** | ||
| 167 | * Creates analog device from joystick axes | ||
| 168 | * @param params contains parameters for creating the device: | ||
| 169 | * - "joystick": the index of the joystick to bind | ||
| 170 | * - "axis_x": the index of the axis to be bind as x-axis | ||
| 171 | * - "axis_y": the index of the axis to be bind as y-axis | ||
| 172 | */ | ||
| 173 | std::unique_ptr<Input::AnalogDevice> Create(const Common::ParamPackage& params) override { | ||
| 174 | const int joystick_index = params.Get("joystick", 0); | ||
| 175 | const int axis_x = params.Get("axis_x", 0); | ||
| 176 | const int axis_y = params.Get("axis_y", 1); | ||
| 177 | return std::make_unique<SDLAnalog>(GetJoystick(joystick_index), axis_x, axis_y); | ||
| 178 | } | ||
| 179 | }; | ||
| 180 | |||
| 181 | void Init() { | ||
| 182 | if (SDL_Init(SDL_INIT_JOYSTICK) < 0) { | ||
| 183 | LOG_CRITICAL(Input, "SDL_Init(SDL_INIT_JOYSTICK) failed with: %s", SDL_GetError()); | ||
| 184 | } else { | ||
| 185 | using namespace Input; | ||
| 186 | RegisterFactory<ButtonDevice>("sdl", std::make_shared<SDLButtonFactory>()); | ||
| 187 | RegisterFactory<AnalogDevice>("sdl", std::make_shared<SDLAnalogFactory>()); | ||
| 188 | initialized = true; | ||
| 189 | } | ||
| 190 | } | ||
| 191 | |||
| 192 | void Shutdown() { | ||
| 193 | if (initialized) { | ||
| 194 | using namespace Input; | ||
| 195 | UnregisterFactory<ButtonDevice>("sdl"); | ||
| 196 | UnregisterFactory<AnalogDevice>("sdl"); | ||
| 197 | SDL_QuitSubSystem(SDL_INIT_JOYSTICK); | ||
| 198 | } | ||
| 199 | } | ||
| 200 | |||
| 201 | } // namespace SDL | ||
| 202 | } // namespace InputCommon | ||
diff --git a/src/input_common/sdl/sdl.h b/src/input_common/sdl/sdl.h new file mode 100644 index 000000000..3e72debcc --- /dev/null +++ b/src/input_common/sdl/sdl.h | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | // Copyright 2017 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/frontend/input.h" | ||
| 8 | |||
| 9 | namespace InputCommon { | ||
| 10 | namespace SDL { | ||
| 11 | |||
| 12 | /// Initializes and registers SDL device factories | ||
| 13 | void Init(); | ||
| 14 | |||
| 15 | /// Unresisters SDL device factories and shut them down. | ||
| 16 | void Shutdown(); | ||
| 17 | |||
| 18 | } // namespace SDL | ||
| 19 | } // namespace InputCommon | ||
diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index b47156ca4..d1144ba77 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | set(SRCS | 1 | set(SRCS |
| 2 | glad.cpp | 2 | glad.cpp |
| 3 | tests.cpp | 3 | tests.cpp |
| 4 | common/param_package.cpp | ||
| 4 | core/file_sys/path_parser.cpp | 5 | core/file_sys/path_parser.cpp |
| 5 | ) | 6 | ) |
| 6 | 7 | ||
diff --git a/src/tests/common/param_package.cpp b/src/tests/common/param_package.cpp new file mode 100644 index 000000000..efec2cc86 --- /dev/null +++ b/src/tests/common/param_package.cpp | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | // Copyright 2017 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <catch.hpp> | ||
| 6 | #include <math.h> | ||
| 7 | #include "common/param_package.h" | ||
| 8 | |||
| 9 | namespace Common { | ||
| 10 | |||
| 11 | TEST_CASE("ParamPackage", "[common]") { | ||
| 12 | ParamPackage original{ | ||
| 13 | {"abc", "xyz"}, {"def", "42"}, {"jkl", "$$:1:$2$,3"}, | ||
| 14 | }; | ||
| 15 | original.Set("ghi", 3.14f); | ||
| 16 | ParamPackage copy(original.Serialize()); | ||
| 17 | REQUIRE(copy.Get("abc", "") == "xyz"); | ||
| 18 | REQUIRE(copy.Get("def", 0) == 42); | ||
| 19 | REQUIRE(std::abs(copy.Get("ghi", 0.0f) - 3.14f) < 0.01f); | ||
| 20 | REQUIRE(copy.Get("jkl", "") == "$$:1:$2$,3"); | ||
| 21 | REQUIRE(copy.Get("mno", "uvw") == "uvw"); | ||
| 22 | REQUIRE(copy.Get("abc", 42) == 42); | ||
| 23 | } | ||
| 24 | |||
| 25 | } // namespace Common | ||
diff --git a/src/video_core/regs_framebuffer.h b/src/video_core/regs_framebuffer.h index 366782080..9ddc79243 100644 --- a/src/video_core/regs_framebuffer.h +++ b/src/video_core/regs_framebuffer.h | |||
| @@ -89,8 +89,8 @@ struct FramebufferRegs { | |||
| 89 | }; | 89 | }; |
| 90 | 90 | ||
| 91 | union { | 91 | union { |
| 92 | BitField<0, 8, BlendEquation> blend_equation_rgb; | 92 | BitField<0, 3, BlendEquation> blend_equation_rgb; |
| 93 | BitField<8, 8, BlendEquation> blend_equation_a; | 93 | BitField<8, 3, BlendEquation> blend_equation_a; |
| 94 | 94 | ||
| 95 | BitField<16, 4, BlendFactor> factor_source_rgb; | 95 | BitField<16, 4, BlendFactor> factor_source_rgb; |
| 96 | BitField<20, 4, BlendFactor> factor_dest_rgb; | 96 | BitField<20, 4, BlendFactor> factor_dest_rgb; |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index 0818a87b3..456443e86 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | #include "common/vector_math.h" | 17 | #include "common/vector_math.h" |
| 18 | #include "core/frontend/emu_window.h" | 18 | #include "core/frontend/emu_window.h" |
| 19 | #include "core/memory.h" | 19 | #include "core/memory.h" |
| 20 | #include "core/settings.h" | ||
| 20 | #include "video_core/pica_state.h" | 21 | #include "video_core/pica_state.h" |
| 21 | #include "video_core/renderer_opengl/gl_rasterizer_cache.h" | 22 | #include "video_core/renderer_opengl/gl_rasterizer_cache.h" |
| 22 | #include "video_core/renderer_opengl/gl_state.h" | 23 | #include "video_core/renderer_opengl/gl_state.h" |