Compare commits

...

384 Commits

Author SHA1 Message Date
german77
5ba7b11ba4 yuzu: Implement basic controller navigation 2021-12-02 15:17:44 -06:00
Narr the Reg
46e3ed5a48 Merge pull request #7472 from Morph1984/post-kraken-cleanup
core: hid: Post kraken cleanup
2021-11-29 21:10:02 -06:00
Narr the Reg
e4492a9a82 input_common: Fix error with thread name 2021-11-29 22:03:47 -05:00
Morph
5deecd714b input_interpreter: Make use of NpadButton instead of a u64
Allows us to be more explicit with the representation of button states and use the provided bit manipulation operators
2021-11-29 19:21:51 -05:00
Morph
322339a5fd npad: Return NpadButton in GetAndResetPressState
We were previously truncating this to a u32 as there were no known buttons that used the full 64 bits of this type. Fix this now that we know they are used.
2021-11-29 19:21:51 -05:00
Morph
bfac21fca1 core: hid: hid_types: Add "All" to NpadButton
This represents a bitmask for all pressed buttons
2021-11-29 19:21:51 -05:00
Morph
b86fcf7c31 qt_controller: Make use of (Enable/Disable)AllControllerConfiguration
This also moves the use of DisableConfiguration to the destructor.
2021-11-29 19:21:50 -05:00
bunnei
051e63c9a1 Merge pull request #7466 from vonchenplus/add_miss_pixel_format_mapping
Add missing pixel format mapping
2021-11-29 15:19:15 -08:00
Morph
940375dfbb core: hid: hid_core: Add (Enable/DIsable)AllControllerConfiguration 2021-11-29 17:59:58 -05:00
Morph
410df5446e general: Fix handheld typo 2021-11-29 17:22:59 -05:00
Morph
04f48f0120 core: hid: Mark constructors as explicit 2021-11-29 17:20:15 -05:00
Morph
b9b28c0457 core: hid: Cleanup and amend documentation 2021-11-29 17:20:14 -05:00
Morph
614702488f Merge pull request #7465 from german77/no_input
qt_controller: Fix input when the controller applet is ignored
2021-11-29 07:25:36 -05:00
Feng Chen
524a9baa7e Add missing pixel format mapping 2021-11-29 12:39:37 +08:00
german77
dcc4685557 qt_controller: Fix input when the controller applet is ignored 2021-11-28 21:03:42 -06:00
Fernando S
3031223153 Merge pull request #7396 from FernandoS27/blit-this-mf
TextureCache: Eliminate format deduction as full depth conversion has been supported.
2021-11-28 12:16:31 +01:00
Fernando Sahmkow
5a3463bc2b Texture Cache: Secure insertions against deletions. 2021-11-28 10:53:27 +01:00
bunnei
11a9bff36d Merge pull request #7438 from german77/homebrew2
Core: Stub services and functions needed for checkpoint
2021-11-28 00:54:48 -08:00
bunnei
be56587ad7 Merge pull request #7451 from german77/debug_controller
settings: Add debug setting to enable all controllers
2021-11-28 00:54:29 -08:00
Narr the Reg
54f007efc6 core/ns: Implement GetReadOnlyApplicationControlDataInterface
Used in checkpoint homebrew
2021-11-27 20:30:16 -06:00
Narr the Reg
50d8e753c5 core/pdm: Stub QueryPlayStatisticsByApplicationIdAndUserAccountId
Used in checkpoint homebrew
2021-11-27 20:30:16 -06:00
german77
51df96b7c0 settings: Add debug setting to enable all controllers 2021-11-27 20:24:37 -06:00
Narr the Reg
f966c05a74 core/hid: Stub GetUniquePadsFromNpad
Used in checkpoint homebrew
2021-11-27 09:03:10 -06:00
Fernando S
564f105277 Merge pull request #7255 from german77/kraken
Project Kraken: Input rewrite
2021-11-27 11:52:08 +01:00
Fernando Sahmkow
ecefc932e6 Texture Cache: Redesigning the blitting system (again). 2021-11-27 11:22:16 +01:00
german77
182cd9004f config: Remove vibration configuration 2021-11-26 19:31:04 -06:00
german77
a4a0638bc8 applet/controller: Enable configuring mode while the applet is open 2021-11-26 18:55:28 -06:00
bunnei
157985f556 Merge pull request #7431 from liushuyu/fix-linux-decoding
video_core/codecs: fix multiple decoding issues on Linux
2021-11-26 15:38:40 -08:00
Narr the Reg
639402850a input_common: Fully implement UDP controllers 2021-11-26 15:46:36 -06:00
Fernando Sahmkow
1624f307d0 Texture Cache: Further fix regressions. 2021-11-26 17:03:48 +01:00
bunnei
50a19b07d1 Merge pull request #7440 from lioncash/fmt
CMakeLists: Update fmt to 8.0.1
2021-11-25 20:58:49 -08:00
Lioncash
5303161aa1 CMakeLists: Update fmt to 8.0.1
Ensures that we're using the latest version of fmt.
2021-11-25 23:08:45 -05:00
bunnei
06ad463ec8 Merge pull request #7330 from MightyCreak/simplify-theme-selection
Replace "Light" theme by "Default"
2021-11-25 01:52:48 -08:00
Narr the Reg
23bf2e3bb6 service/hid: Finish converting LIFO objects and address some nits 2021-11-24 20:30:29 -06:00
german77
e64ee99f00 yuzu: Fix TAS from rebase 2021-11-24 20:30:29 -06:00
german77
746c85b560 input_common: Move button names to the frontend 2021-11-24 20:30:28 -06:00
german77
c4760489a0 input_common: Fix SDL controller with inverted axis 2021-11-24 20:30:28 -06:00
german77
922aa9410a bootmanager: Use cross-platform keyboard input 2021-11-24 20:30:28 -06:00
german77
42949738f2 kraken: Address comments from review
Fix compiler bug
2021-11-24 20:30:28 -06:00
german77
f4e5f89e6f core/hid: Improve accuary of mouse implementation 2021-11-24 20:30:28 -06:00
german77
654d76e79e core/hid: Fully implement native mouse 2021-11-24 20:30:28 -06:00
german77
bca299e8e0 input_common: Allow keyboard to be backwards compatible 2021-11-24 20:30:28 -06:00
german77
b673857d7d core/hid: Improve accuracy of the keyboard implementation 2021-11-24 20:30:28 -06:00
german77
7fcfe24a3e core/hid: Fix keyboard alignment 2021-11-24 20:30:28 -06:00
german77
71f9b90dd9 core/hid: Remove usage of native types, fix a couple of errors with motion 2021-11-24 20:30:28 -06:00
german77
a17550be98 settings: Remove includes of core.h 2021-11-24 20:30:27 -06:00
german77
e7eee36d52 service/hid: Remove includes of core.h and settings.h 2021-11-24 20:30:27 -06:00
Levi Behunin
690013b342 UI nits
Set top margin to 6 on Right Stick, LeftStick, Face Buttons, D-Pad.
Change property on Input Device QComboBox from minimumSize to minimumContentsLength.
2021-11-24 20:30:27 -06:00
german77
b21fcd9527 service/hid: Add support for new controllers 2021-11-24 20:30:27 -06:00
german77
d14e74132c settings: Fix controller preview not displaying the correct controller 2021-11-24 20:30:27 -06:00
german77
5d0f3540c4 core/hid: Rename NpadType to NpadStyleIndex 2021-11-24 20:30:27 -06:00
german77
84c58666a4 config: Cleanup and documentation 2021-11-24 20:30:27 -06:00
german77
c35af8d1c0 input_common: Fix motion from 3 axis 2021-11-24 20:30:27 -06:00
german77
157e0b85fd core/hid: Prevent Emulated controller from flapping with multiple inputs devices 2021-11-24 20:30:27 -06:00
german77
136eb9c4c2 core/hid: Fully emulate motion from button 2021-11-24 20:30:27 -06:00
german77
77fa4d4bf6 second commit lion review 2021-11-24 20:30:26 -06:00
german77
730f078302 settings: Fix Debug controller type options 2021-11-24 20:30:26 -06:00
german77
2b1b0c2a30 kraken: Address comments from review
start lion review
2021-11-24 20:30:26 -06:00
german77
61d9eb9f69 input_common: Revert deleted TAS functions 2021-11-24 20:30:26 -06:00
german77
5f69fdbfcc core/hid: Explain better what a temporary value does 2021-11-24 20:30:26 -06:00
german77
d8e3f2b10b input_common: Fix GC adapter initialization
Fix GC controller
2021-11-24 20:30:26 -06:00
german77
2d3a63b289 core/hid: Update structs to 13.1.0 2021-11-24 20:30:26 -06:00
german77
c085e54316 core/hid: Add TAS input 2021-11-24 20:30:26 -06:00
german77
1d71d4b874 input_common: Fix UDP uuid 2021-11-24 20:30:26 -06:00
german77
7348e205d9 input_common: Add multiple vibration curves 2021-11-24 20:30:26 -06:00
german77
064ddacf49 core/hid: Rework battery mappings 2021-11-24 20:30:26 -06:00
german77
c6c32daf40 input_common: Add manual update options to input devices 2021-11-24 20:30:26 -06:00
german77
f01dac3bf9 service/hid: Fix memory allocated incorrectly 2021-11-24 20:30:25 -06:00
german77
464c4d26ac settings: Fix mouse and keyboard mappings 2021-11-24 20:30:25 -06:00
german77
cc651c7c99 web_applet: Replace HIDButton with NpadButton 2021-11-24 20:30:25 -06:00
german77
b564f024f0 Morph review first wave 2021-11-24 20:30:25 -06:00
german77
e2e5f1beaf service/hid: Match shared memory closer to HW 2021-11-24 20:30:25 -06:00
german77
21819da8cd yuzu: Fix loading input profiles 2021-11-24 20:30:25 -06:00
german77
b5e72de753 kraken: Address comments from review
review fixes
2021-11-24 20:30:25 -06:00
german77
95cf66b655 service/hid: Use ring buffer for gestures 2021-11-24 20:30:25 -06:00
german77
85052b8662 service/hid: Fix gesture input 2021-11-24 20:30:25 -06:00
german77
af55dd1935 configuration: Migrate controller settings to emulated controller 2021-11-24 20:30:25 -06:00
german77
c3ff0a8ac0 core/hid: Fix rumble too strong at 1% 2021-11-24 20:30:24 -06:00
german77
601ac43495 core/hid: Only signal when needed 2021-11-24 20:30:24 -06:00
german77
4d308fd0b4 hid: Fix controller connection/disconnection 2021-11-24 20:30:24 -06:00
german77
72e5920240 core/hid: Documment some files 2021-11-24 20:30:24 -06:00
german77
e0da5c1bbc kraken: Fix errors from rebase and format files 2021-11-24 20:30:24 -06:00
german77
06a5ef5874 core/hid: Add output devices 2021-11-24 20:30:24 -06:00
german77
e14ae06391 core: Update input interpreter 2021-11-24 20:30:24 -06:00
german77
1b82d5bb4f yuzu: Update overlay applet 2021-11-24 20:30:24 -06:00
german77
510c7d2953 core/frontend: Update applets 2021-11-24 20:30:24 -06:00
german77
dd62a0187d core: Remove frontend/input 2021-11-24 20:30:24 -06:00
german77
c87ad2d0d6 service/hid: Rewrite npad to use ring lifo and the emulated controller 2021-11-24 20:30:24 -06:00
german77
a2ad5762e6 service/hid: Update console sixaxis to the emulated console 2021-11-24 20:30:24 -06:00
german77
800a66d25a service/hid: Update mouse and keyboard to use ring lifo and the emulated device 2021-11-24 20:30:24 -06:00
german77
afe2d667d9 service/hid: Update touch and gestures to use ring lifo and the emulated console 2021-11-24 20:30:24 -06:00
german77
072559dede service/hid: Update debug pad, xpad, stubbed and controller base to use ring lifo and the emulated controller 2021-11-24 20:30:23 -06:00
german77
dbe0301102 service/hid: Use remove duplicated code, update names 2021-11-24 20:30:23 -06:00
german77
db08721dcc service/hid: Create ring LIFO 2021-11-24 20:30:23 -06:00
german77
8fff6d6c67 Qt_applets: Use new input 2021-11-24 20:30:23 -06:00
german77
6e2c84042d settings: Cleanup settings 2021-11-24 20:30:23 -06:00
german77
456397ed39 debugger/controller: Remove TAS 2021-11-24 20:30:23 -06:00
german77
173a6b1e57 core/emu_window: Remove touch input 2021-11-24 20:30:23 -06:00
german77
c405a19b73 yuzu: Update frontend 2021-11-24 20:30:23 -06:00
german77
967cca10ff core: Register HID 2021-11-24 20:30:23 -06:00
german77
c3f54ff232 core/hid: Add emulated controllers 2021-11-24 20:30:23 -06:00
german77
14b949a0da yuzu_cmd: Use new input 2021-11-24 20:30:23 -06:00
german77
737d305f63 yuzu: Use new input on main and bootmanager 2021-11-24 20:30:23 -06:00
german77
29ae42f3e2 input_common: Rewrite main and add the new drivers 2021-11-24 20:30:23 -06:00
german77
6d108f0dcb input_common: Remove obsolete files 2021-11-24 20:30:23 -06:00
german77
59b995a9e5 input_common: Rewrite SDL 2021-11-24 20:30:23 -06:00
german77
10241886dd input_common: Rewrite udp client 2021-11-24 20:30:22 -06:00
german77
dc3ab9e110 input_common: Rewrite tas input 2021-11-24 20:30:22 -06:00
german77
395e9a449d input_common: Rewrite gc_adapter 2021-11-24 20:30:22 -06:00
german77
fa8e23b842 input_common: Rewrite touch 2021-11-24 20:30:22 -06:00
german77
00834b84dd input_common: Rewrite mouse 2021-11-24 20:30:22 -06:00
german77
5a785ed794 input_common: Rewrite keyboard 2021-11-24 20:30:22 -06:00
german77
4c6f2c2547 input_common: Move touch and analog from button. Move udp protocol 2021-11-24 20:30:22 -06:00
german77
854c933716 input_common: Create input poller and mapping 2021-11-24 20:30:22 -06:00
german77
ea7b1fbc67 input_common: Create input_engine 2021-11-24 20:30:22 -06:00
german77
449576df93 core/hid: Move motion_input, create input converter and hid_types 2021-11-24 20:30:22 -06:00
german77
bf71d18af9 core/hid: Move input_interpreter to hid 2021-11-24 20:30:22 -06:00
german77
ad5142ac2c common: Rewrite and move core/frontend/input.h to common 2021-11-24 20:30:21 -06:00
Adam Heinermann
f078d3d212 Refactor menu states and shortcuts in GMainWindow. (#7419)
Refactor menu states and shortcuts in GMainWindow.

- Removed "Start", since it was always disabled unless it was "Continue"
which has now been moved to "Pause".
- Allow hotkeys to be used while in fullscreen.
- Removed the load amiibo hotkey.
2021-11-24 21:27:25 -05:00
liushuyu
60928cf8cd video_core/codec: address comments 2021-11-24 18:06:38 -07:00
liushuyu
72aa418b0b video_core/codecs: fix multiple decoding issues on Linux ...
* when someone installed Intel video drivers on an AMD system, the
  decoder will select the Intel VA-API decoding driver and yuzu will
  crash due to incorrect driver selection; the fix will check if the
  currently about-to-use driver is loaded in the kernel
* when using NVIDIA driver on Linux with a ffmpeg that does not have
  CUDA capability enabled, the decoder will crash; the fix simply
  making the decoder prefers the VDPAU driver over CUDA on Linux
2021-11-24 17:23:57 -07:00
bunnei
cd6cf0422d Merge pull request #7404 from Kewlan/per-game-framerate-cap
configure_general: Allow framerate cap to be used in custom game configs
2021-11-24 02:36:30 -08:00
bunnei
daecbd3a7f Merge pull request #7394 from Morph1984/svc-SetMemoryPermission
kernel: svc: Implement SetProcessMemoryPermission
2021-11-22 14:06:09 -08:00
Fernando Sahmkow
08674aee87 Texture Cache: Fix issue with blitting 3D textures. 2021-11-22 06:07:21 +01:00
Mai M
ee76b546d4 Merge pull request #7406 from heinermann/tas_menu
Added TAS controls to the menu under Tools
2021-11-21 23:17:07 -05:00
Mai M
be238fb26a Merge pull request #7407 from jam1garner/ic-ivau-instruction
Add InstructionCacheOperationRaised handler for 'ic ivau' instruction
2021-11-21 23:16:36 -05:00
jam1garner
4d9c9e567e arm: dynarmic: Cleanup icache op handling 2021-11-21 22:44:13 -05:00
jam1garner
c8a67a725d arm: dynarmic: Implement icache op handling for 'ic iallu' instruction 2021-11-21 21:18:56 -05:00
jam1garner
84eb3e7d02 arm: dynarmic: Implement icache op handling for 'ic ivau' instruction 2021-11-21 21:10:14 -05:00
Adam Heinermann
097de2febc const fixes 2021-11-21 18:07:37 -08:00
Adam Heinermann
b7a938e817 Apply clang format 2021-11-21 18:02:08 -08:00
Adam Heinermann
f90d980837 Added TAS controls to the menu under Tools 2021-11-21 17:28:47 -08:00
Fernando Sahmkow
1e474fb9d1 Texture Cache: Correct conversion shaders. 2021-11-22 00:21:42 +01:00
Fernando Sahmkow
0902119302 Texture Cache: Always copy on NVIDIA. 2021-11-22 00:06:56 +01:00
Fernando Sahmkow
8532849439 TextureCache: Simplify blitting of D24S8 formats and fix bugs. 2021-11-22 00:00:01 +01:00
Fernando Sahmkow
d7f4434bd5 VulkanTexturECache: Use reinterpret on D32_S8 formats. 2021-11-21 21:09:49 +01:00
Fernando Sahmkow
b96caf200d HostShaders: Fix D24S8 convertion shaders. 2021-11-21 21:04:04 +01:00
Kewlan
8e3371a5c5 configure_general: Allow framerate cap to be used in custom game configs 2021-11-21 16:57:00 +01:00
bunnei
d20f91da11 Merge pull request #7395 from Morph1984/resolve-comments
general: Resolve comments in PR #7368
2021-11-21 02:42:24 -08:00
bunnei
5082712b4e Merge pull request #7389 from ameerj/screenshot-1x
Fix screenshot dimensions when at 1x scale
2021-11-21 02:31:32 -08:00
bunnei
ba5210675a Merge pull request #7359 from heinermann/kthread_crash
Fix crash on exit due to static scoped dummy threads
2021-11-20 23:59:58 -08:00
bunnei
fc34749778 Merge pull request #7393 from Morph1984/pm-ams-get-pid
service: pm: Implement AtmosphereGetProcessId
2021-11-20 22:08:25 -08:00
Fernando Sahmkow
779f4ac72d TextureCache: Eliminate format deduction as full depth conversion has been supported. 2021-11-21 05:37:01 +01:00
Morph
5cf93c1346 kernel: svc: Move all IsValid functions to an anonymous namespace 2021-11-20 22:49:13 -05:00
Morph
2726d705f8 kernel: svc: Implement SetProcessMemoryPermission
- Used by Skyline modding framework
2021-11-20 22:18:56 -05:00
Morph
281437c811 kernel: KPageTable: Rename SetCodeMemoryPermission to SetProcessMemoryPermission 2021-11-20 22:18:56 -05:00
Morph
a41c6dafea vk_texture_cache: Mark VkBufferUsageFlags as static constexpr 2021-11-20 21:49:37 -05:00
Morph
095bc88428 vk_blit_image: Consolidate CreatePipelineTargetEx functions 2021-11-20 21:18:37 -05:00
Morph
9173f07a51 service: pm: Implement AtmosphereGetProcessId
- Used by Skyline modding framework
2021-11-20 20:56:29 -05:00
Morph
3dc38d185b service: pm: Add all relevant result codes 2021-11-20 20:56:28 -05:00
bunnei
ea6fa044f3 Merge pull request #7368 from FernandoS27/vulkan-conv
Fix ART Blit detection regression and add D24S8 <-> RGBA8 conv to Vulkan
2021-11-20 16:51:13 -08:00
Morph
40cd0bb97b service: pm: Rename title id to program id 2021-11-20 19:39:26 -05:00
ameerj
fe1f06c856 Fix screenshot dimensions when at 1x scale
This was regressed by ART.
Prior to ART, the screenshots were saved at the title's framebuffer resolution. A misunderstanding of the existing logic led to screenshot dimensions becoming dependent on the host render window size.

This changes the behavior to match how it was prior to ART at 1x, with screenshots now always being the title's framebuffer dimensions scaled by the resolution scaling factor.
2021-11-20 17:50:24 -05:00
Fernando Sahmkow
da2fe81905 TextureCache: Refactor and fix linux compiling. 2021-11-20 14:46:19 +01:00
Fernando Sahmkow
4ca6e9a9e2 TextureCache: Assure full conversions on depth/stencil write shaders. 2021-11-20 06:17:01 +01:00
Fernando Sahmkow
0857f82913 TextureCache: Implement buffer copies on Vulkan. 2021-11-20 06:15:29 +01:00
bunnei
c3e1ffc44b Merge pull request #7294 from vonchenplus/fix_image_update_error_when_width_too_small
Fix image update/download error when width too small
2021-11-19 15:56:27 -08:00
Fernando Sahmkow
e02cff2f69 TextureCache: Add R16G16 to D24S8 converter. 2021-11-20 00:02:12 +01:00
Fernando Sahmkow
1d5e6a51d7 TextureCache: Add B10G11R11 to D24S8 converter. 2021-11-19 23:22:44 +01:00
Fernando Sahmkow
6f896d1fae TextureCache: Further fixes on resolve algorithm. 2021-11-19 23:02:04 +01:00
bunnei
b44fbf6cdd Merge pull request #7369 from Morph1984/amd-fsr-statusbar
main: Shorten AMD FSR status bar text
2021-11-19 01:20:27 -08:00
bunnei
d2e009f355 Merge pull request #7273 from fpdotmonkey/submodule-checkout-command-on-new-line
Move the cmake submodule checkout command to a new line
2021-11-19 01:19:50 -08:00
bunnei
a69813948f Merge pull request #7342 from goldenx86/patch-3
Replace keys error pop up
2021-11-19 01:17:18 -08:00
bunnei
c45af76ea0 Merge pull request #7357 from Morph1984/s8_uint
video_core: Implement S8_UINT format
2021-11-19 01:16:49 -08:00
Fernando Sahmkow
b805c7bf05 TextureCache: Implement additional D24S8 convertions. 2021-11-19 06:27:44 +01:00
Fernando Sahmkow
0ff228405f TextureCache: force same image format when resolving an image. 2021-11-19 05:46:57 +01:00
Morph
bc5ed1aa1b main: Fix default AA name
By default, no AA is applied, not FXAA
2021-11-18 23:22:32 -05:00
Morph
a237fb5f75 configure_graphics_ui: AMD's -> AMD
AMD officially markets FSR as AMD FidelityFX™️ Super Resolution
2021-11-18 23:17:16 -05:00
Morph
c76163b611 main: Shorten AMD FSR status bar text
AMD'S FIDELITYFX SR -> FSR
2021-11-18 23:17:16 -05:00
Fernando Sahmkow
b130f648d7 TextureCache: Fix regression caused by ART and improve blit detection algorithm to be smarter. 2021-11-19 03:17:54 +01:00
Fernando Sahmkow
2ec7fcecb7 Vulkan: implement D24S8 <-> RGBA8 convertions. 2021-11-19 03:17:02 +01:00
bunnei
0bc46fedd6 Merge pull request #7349 from ameerj/ogl-convert-image
gl_texture_cache: Implement pixel format conversions for copies
2021-11-18 11:30:47 -08:00
bunnei
a100f5d5d4 Merge pull request #7353 from v1993/no-more-epilepsy
Prevent window flickering when holding Esc
2021-11-18 11:26:28 -08:00
Morph
dc61b7045b renderer_vulkan: Implement S8_UINT stencil format
It should be noted that on Windows, only nvidia gpus support this format natively as of this commit.
2021-11-18 00:05:51 -05:00
Ameer J
66fed9ecbd Merge pull request #7348 from Morph1984/ci-disable-submodule-fetch
ci: Don't fetch submodules when fetching PRs
2021-11-17 23:58:34 -05:00
ameerj
f7e155d8b9 gl_texture_cache: Round format conversion PBO to next power of 2 2021-11-17 23:49:44 -05:00
bunnei
2054013edb Merge pull request #7355 from german77/hotkey_spam
hotkeys: Don't allow hotkeys to spam
2021-11-17 18:16:17 -08:00
Adam Heinermann
d8a783a368 Fix crash on exit due to static scoped dummy threads 2021-11-17 15:29:25 -08:00
Morph
6dd6dc046c renderer_opengl: Implement S8_UINT stencil format 2021-11-17 15:05:07 -05:00
Morph
2348eb41f3 video_core: Add S8_UINT stencil format 2021-11-17 15:04:38 -05:00
german77
311324e231 hotkeys: Don't allow hotkeys to spam 2021-11-17 10:42:20 -06:00
Valeri
f7e0a37753 Prevent window flickering when holding Esc
Reported on discord by Levlight. Don't try to exit fullscreen if it's already off.
2021-11-17 18:07:47 +03:00
Feng Chen
894cc9d876 Fix image update/download error when width too small 2021-11-17 12:21:17 +08:00
ameerj
20ed7ba441 texture_cache: Use pixel format conversion when supported by the runtime 2021-11-16 22:32:46 -05:00
ameerj
50c3d53076 gl_texture_cache: Make FormatConversionPass more generic
This allows the usage of the FormatConversionPass to be applied to more than the previously used BGR conversion scenarios.
2021-11-16 22:32:11 -05:00
ameerj
35ca6274f4 gl_texture_cache: Rename BGRCopyPass to FormatConversionPass 2021-11-16 22:31:58 -05:00
Morph
16aa49d138 ci: Don't fetch submodules when fetching PRs 2021-11-16 22:26:54 -05:00
bunnei
71313509f7 Merge pull request #7219 from FernandoS27/aristotles-right-testicle
Project A.R.T. Advanced Rendering Techniques
2021-11-16 18:52:11 -08:00
Morph
3154773c00 Merge pull request #7347 from lioncash/catch
CMakeLists: Update catch to 2.13.7
2021-11-16 21:26:11 -05:00
Fernando Sahmkow
1c8a3d8d29 TextureCache: Fix Automatic Anisotropic. 2021-11-17 03:15:08 +01:00
Lioncash
6e57c519e2 CMakeLists: Update catch to 2.13.7
Keeps the testing libraries up to date.
2021-11-16 20:04:25 -05:00
FernandoS27
1128cc35b9 TextureCache: OGL query device memory if possible. 2021-11-17 01:45:50 +01:00
Fernando Sahmkow
978f598ff6 TextureCache: Fix OGL cleaning 2021-11-17 00:59:46 +01:00
Fernando Sahmkow
282e04bffb TextureCache: Add automatic anisotropic filtering and refactor code. 2021-11-16 23:14:51 +01:00
Fernando Sahmkow
5230378709 TextureCache: Make a better Anisotropic setter. 2021-11-16 22:11:33 +01:00
Fernando Sahmkow
6c97ab571a Texture Cache: revert Image changes. 2021-11-16 22:11:33 +01:00
Fernando Sahmkow
6f98690963 ShaderCache: Better fix for Shuffling gl_FragCoord 2021-11-16 22:11:33 +01:00
FernandoS27
d46a71e786 HostShader: fix Gaussian filter. 2021-11-16 22:11:33 +01:00
FernandoS27
de1c8c5c2c Texture Cahe/Shader decompiler: Resize PointSize on rescaling, refactor and make reaper more agressive on 4Gb GPUs. 2021-11-16 22:11:33 +01:00
ameerj
917b2466ad texture_cache: Refactor Render Target scaling function 2021-11-16 22:11:33 +01:00
ameerj
9fc1fa1b0d gl_resource_manager: Ensure non EXT_framebuffer objects are created 2021-11-16 22:11:33 +01:00
FernandoS27
099b0b3167 Texture Cache: Fix memory usage on ScaleDown. 2021-11-16 22:11:33 +01:00
FernandoS27
9189aacfe2 OpenGL: Fix viewport/Scissor scaling on downscaling. 2021-11-16 22:11:33 +01:00
FernandoS27
c97c46747d Vulkan: fix regression. 2021-11-16 22:11:33 +01:00
ameerj
87abab71ff host_shaders: Misc copyright/style changes 2021-11-16 22:11:33 +01:00
ameerj
864f2e0b81 configure_graphics.ui: Cleanup scaling options and fix duplicate name warning 2021-11-16 22:11:33 +01:00
ameerj
99124b7261 FSR: Fix GCC build errors 2021-11-16 22:11:33 +01:00
Marshall Mohror
bb03675485 Vulkan: Reimplement FSR constant generation functions to avoid GCC warnings 2021-11-16 22:11:33 +01:00
ameerj
47369faaab vk_blit_screen: Fix AA destruction order 2021-11-16 22:11:32 +01:00
Marshall Mohror
dcc5b4f6b0 Presentation: Only use FP16 in scaling shaders on supported devices in Vulkan 2021-11-16 22:11:32 +01:00
ameerj
a39e867c73 renderer_vulkan/blit_image: Use generic color state on Depth to Color blits
Fixes Bayonetta 2 on AMD
2021-11-16 22:11:32 +01:00
ameerj
282a4501d9 vk_texture_cache: Refactor 3D scaling helpers 2021-11-16 22:11:32 +01:00
ameerj
93c9eb196f gl_rasterizer: Fix ScissorTest and Clear when scaling 2021-11-16 22:11:32 +01:00
ameerj
172d4f1e3b gl_texture_cache: Simplify scaling procedures 2021-11-16 22:11:32 +01:00
Fernando Sahmkow
5c6fa88935 OpenGlTextureCache: Fix state invalidation on rescaling. 2021-11-16 22:11:32 +01:00
Fernando Sahmkow
c5dbd93adb VulkanBufferCache: Avoid adding barriers between multiple copies. 2021-11-16 22:11:32 +01:00
Fernando Sahmkow
99547d2656 HostShader: Fix gaussian and add attribution. 2021-11-16 22:11:32 +01:00
Fernando Sahmkow
a96c9c803b Yuzu UI: Add button for Anti Alias 2021-11-16 22:11:32 +01:00
Fernando Sahmkow
21a8ba0437 Vulkan: Fix FXAA in AMD. 2021-11-16 22:11:32 +01:00
Fernando Sahmkow
6cdfaee7b4 Texture Cache: Fix blitting. 2021-11-16 22:11:32 +01:00
FernandoS27
e6f1ed08fb Vulkan: Implement FXAA 2021-11-16 22:11:32 +01:00
Marshall Mohror
056894f07a OpenGL: fix FXAA with scaling 2021-11-16 22:11:32 +01:00
Marshall Mohror
48cf376462 OpenGL: Implement FXAA 2021-11-16 22:11:32 +01:00
Marshall Mohror
74e39ed6ee Frontend: Add anti-aliasing method setting 2021-11-16 22:11:32 +01:00
Marshall Mohror
510caeefb3 Settings: Add anti-aliasing method setting 2021-11-16 22:11:32 +01:00
FernandoS27
2eff80b47f QtGUI: Add buttton to toggle the filter. 2021-11-16 22:11:32 +01:00
FernandoS27
9e065b9c7d VideoCore: Add gaussian filtering. 2021-11-16 22:11:32 +01:00
FernandoS27
bf01b7993d TextureCache: Improve Reaper. 2021-11-16 22:11:32 +01:00
FernandoS27
bb3e95133d Vulkan: fix waiting on semaphore. 2021-11-16 22:11:32 +01:00
Marshall Mohror
916b882ea8 Update scaleforce to use FP16 2021-11-16 22:11:32 +01:00
FernandoS27
e7fc60406e VideoCore: Add more rescaling option. 2021-11-16 22:11:31 +01:00
FernandoS27
d37d10e7a7 TextureCache: fix rescaling in aliases and overlap joins. 2021-11-16 22:11:31 +01:00
Marshall Mohror
7506ac4118 Presentation: Fix turning FSR on and off in settings 2021-11-16 22:11:31 +01:00
Fernando Sahmkow
4ad22c7d2b Video Core: fix building for GCC. 2021-11-16 22:11:31 +01:00
FernandoS27
826a350e2b Vulkan Rasterizer: Fix clears on integer textures. 2021-11-16 22:11:31 +01:00
FernandoS27
150bc45401 Texture cache: fix Intel with rescaler. 2021-11-16 22:11:31 +01:00
FernandoS27
f3ff8bdc0e TextureCache: Fix blitting filter in Vulkan and correct viewport/scissor calculation when downscaling. 2021-11-16 22:11:31 +01:00
Fernando Sahmkow
3b61de74e6 Texture Cache: fix memory managment and optimize scaled downloads, uploads. 2021-11-16 22:11:31 +01:00
Fernando Sahmkow
c2ca55c9d5 Texture Cache: ease the requirements of textures being blacklisted. 2021-11-16 22:11:31 +01:00
Fernando Sahmkow
50b4c774cb Vulkan: Fix Blit Depth Stencil 2021-11-16 22:11:31 +01:00
Fernando Sahmkow
425ab9ef4b Texture Cache: Fix downscaling and correct memory comsumption. 2021-11-16 22:11:31 +01:00
Fernando Sahmkow
b60966041c Presentation: add Nearest Neighbor filter. 2021-11-16 22:11:31 +01:00
ameerj
77b0812d69 externals: Add only included ffx-fsr headers
The submodule adds a lot of unneeded bloat due its addition of samples that contain large media files that are difficult to compress.
2021-11-16 22:11:31 +01:00
Marshall Mohror
37cb0377ae vulkan: Implement FidelityFX Super Resolution 2021-11-16 22:11:31 +01:00
FernandoS27
d4f5193bd3 Texture Cache: Rescale conversions between depth and color 2021-11-16 22:11:31 +01:00
Fernando Sahmkow
ef1dc42635 Texture cache: Fix memory consumption and ignore rating when a depth texture is rendered. 2021-11-16 22:11:31 +01:00
ameerj
618de4e787 vulkan: Fix rescaling push constant usage 2021-11-16 22:11:31 +01:00
Fernando Sahmkow
b7ccc58f23 Texture Cahe: Fix downscaling on SMO. 2021-11-16 22:11:31 +01:00
ameerj
0f14c9379e texture_cache_base: Remove unused function declarations 2021-11-16 22:11:31 +01:00
ameerj
ca1db63116 yuzu: Fix build errors 2021-11-16 22:11:31 +01:00
ameerj
ebf36f23dd vk_texture_cache: Use 3D to scale images when blit is unsupported 2021-11-16 22:11:31 +01:00
ameerj
4de584005f texture_cache: Fix infinitely recursive ImageCanRescale check 2021-11-16 22:11:31 +01:00
ameerj
b1ae935f11 vk_texture_cache: Fix BlitScale of non-2D images 2021-11-16 22:11:31 +01:00
ameerj
abd07e4158 video_core: Refactor resolution scale function 2021-11-16 22:11:31 +01:00
ameerj
b14f2c7c82 texture_cache: Fix image resolves when src/dst are not both scaled 2021-11-16 22:11:30 +01:00
lat9nq
49c0c7efd2 yuzu_cmd: Read resolution_setup and scaling_filter from config
Also adds descriptions and the settings to the default config.
2021-11-16 22:11:30 +01:00
lat9nq
1c93476a80 video_core,yuzu: Move UpdateRescalingInfo call to video_core
This only needs to happen once per game boot, so we can just call it
during CreateGPU and be done with it, avoiding the need to call it in
the frontends.
2021-11-16 22:11:30 +01:00
ameerj
3233fa5dc8 gl_texture_cache: Disable scissor test when scaling textures
Fixes a bug on BOTW where some objects were no longer being rendered after blitting
2021-11-16 22:11:30 +01:00
ameerj
89a7e566c7 vk_texture_cache: Fix unsupported blit format error checking 2021-11-16 22:11:30 +01:00
ameerj
f8339cd703 vk_texture_cache: Fix early returns on unsupported scales 2021-11-16 22:11:30 +01:00
ameerj
31478c6c1b video_core: Misc resolution scaling related refactoring 2021-11-16 22:11:30 +01:00
ameerj
88ef04dbaf texture_cache: Refactor scaled image size calculation 2021-11-16 22:11:30 +01:00
Fernando Sahmkow
237a43004f Texture Cache: Fix calculations when scaling. 2021-11-16 22:11:30 +01:00
ameerj
e0a3830855 gl_texture_cache: Fix BGR pbo size for scaled textures 2021-11-16 22:11:30 +01:00
ameerj
581ea90062 rescaling_pass: Fix IR errors when unscalable texture types are encountered 2021-11-16 22:11:30 +01:00
Fernando Sahmkow
ea82bd4b7e Texture Cache: Fix Rescaling on Multisample 2021-11-16 22:11:30 +01:00
Fernando Sahmkow
19ca0c9ab5 TextureCache: Base fixes on rescaling. 2021-11-16 22:11:30 +01:00
ameerj
99eec162da rescaling_pass: Logic simplification and minor style cleanup 2021-11-16 22:11:30 +01:00
ameerj
276565973f rescaling_pass: Scale ImageFetch offset if it exists
Plus some code deduplication
2021-11-16 22:11:30 +01:00
ameerj
dd66384451 rescaling_pass: Enable PatchImageQueryDimensions on fragment stages 2021-11-16 22:11:30 +01:00
ameerj
36f261edef vk_texture_cache: Simplify scaled image management 2021-11-16 22:11:30 +01:00
ameerj
8183142cd4 gl_texture_cache: Fix scaling backup logic 2021-11-16 22:11:30 +01:00
ameerj
122ddeb7ff vk_rasterizer: Fix scaling on Y_NEGATE 2021-11-16 22:11:30 +01:00
ameerj
16017ac450 vk_texture_cache: Use nearest neighbor scaling when available 2021-11-16 22:11:30 +01:00
ameerj
27af298e78 gl_texture_cache: Fix depth and integer format scaling blits 2021-11-16 22:11:30 +01:00
ameerj
b027fac794 gl_texture_cache/rescaling_pass: minor cleanup 2021-11-16 22:11:30 +01:00
ameerj
c8a971be91 vk_texture_cache: Minor cleanup 2021-11-16 22:11:30 +01:00
ameerj
edb5844240 rescaling_pass: Fix and simplify shuffle/fragcoord pass 2021-11-16 22:11:30 +01:00
Fernando Sahmkow
b3a9c8f108 Shader: Don't rescale FragCoord if used by Shuffle 2021-11-16 22:11:30 +01:00
ameerj
6000fe69a4 image_info: Mark MSAA textures as non-rescalable
Blitting or resolving multisampled images requires the dimensions of the src and dst to be equal for valid usage, making them difficult for resolution scaling using the current implementation.
2021-11-16 22:11:30 +01:00
ameerj
80f8d4989e bootmanager: Fix screenshot resolution factor usage
Fixes screenshots at non integer scaling
2021-11-16 22:11:30 +01:00
ameerj
fcf2b2c78a gl_texture_cache: Simplify scaling
We don't need to reconstruct new textures every time we ScaleUp/ScaleDown. We can scale up once, and revert to the original texture whenever scaling down.
Fixes memory leaks due to glDeleteTextures being deferred for later handling on some drivers
2021-11-16 22:11:29 +01:00
ameerj
ae8d19d17e Renderers: Unify post processing filter shaders 2021-11-16 22:11:29 +01:00
ameerj
29710f3250 gl_texture_cache: fix scaling on upload 2021-11-16 22:11:29 +01:00
Fernando Sahmkow
a6b88e85bf Renderer: Implement Bicubic and ScaleForce filters. 2021-11-16 22:11:29 +01:00
Fernando Sahmkow
c5bbbf3902 Texture Cache: fix scaling on upload and stop scaling on base resolution. 2021-11-16 22:11:29 +01:00
ameerj
68e038404c shader, video_core: Fix GCC build errors 2021-11-16 22:11:29 +01:00
ameerj
65781f88f8 emit_spirv: Fix RescalingLayout alignment 2021-11-16 22:11:29 +01:00
Fernando Sahmkow
d7c9792169 TextureCache: Fix Buffer Views Scaling. 2021-11-16 22:11:29 +01:00
Fernando Sahmkow
dfa8291526 RescalingPass: Agregate pixels on texelFetch while on Fragment Shader 2021-11-16 22:11:29 +01:00
Fernando Sahmkow
4b1393a691 Texture Cache: Correctly fix Blits Rescaling. 2021-11-16 22:11:29 +01:00
Fernando Sahmkow
8f78444de3 shader: Fix TextureSize check on rescaling. 2021-11-16 22:11:29 +01:00
ameerj
ed675cfd8c texture_cache: Disable dst_image scaling in BlitImage
Fixes scaling in Super Mario Party
2021-11-16 22:11:29 +01:00
ameerj
dc28284437 emit_spirv: Fix RescalingLayout alignment 2021-11-16 22:11:29 +01:00
ReinUsesLisp
e66d5b88a6 shader: Properly scale image reads and add GL SPIR-V support
Thanks for everything!
2021-11-16 22:11:29 +01:00
ReinUsesLisp
fc9bb3c3fe shader: Properly blacklist and scale image loads 2021-11-16 22:11:29 +01:00
ReinUsesLisp
c7a1cbad44 texture_cache: Add getter to query if image view is rescaled 2021-11-16 22:11:29 +01:00
ReinUsesLisp
526e47f148 vk_rasterizer: Minor style change 2021-11-16 22:11:29 +01:00
ReinUsesLisp
c9238555f7 gl_texture_cache: Fix scaling blits 2021-11-16 22:11:29 +01:00
ReinUsesLisp
cfeb161c7e glsl/glasm: Pass and use scaling parameters in shaders 2021-11-16 22:11:29 +01:00
ReinUsesLisp
4a512d6827 gl_rasterizer: Properly scale viewports and scissors 2021-11-16 22:11:29 +01:00
ameerj
05d98d9bbf gl_texture_cache: Fix multi layered texture Scale 2021-11-16 22:11:29 +01:00
ameerj
b6060873ce gl_compute_pipeline: Add downscale factor to shader uniforms 2021-11-16 22:11:29 +01:00
ameerj
9bc7b04ca5 gl_rasterizer: Fix rescale dirty state checking 2021-11-16 22:11:29 +01:00
ameerj
f086c82e1f gl_graphics_pipeline: Add downscale factor to shader uniforms 2021-11-16 22:11:28 +01:00
ReinUsesLisp
2182d25750 texture_cache: Fix blacklists on compute 2021-11-16 22:11:28 +01:00
ReinUsesLisp
56ccda1d99 texture_cache: Simplify image view queries and blacklisting 2021-11-16 22:11:28 +01:00
Fernando Sahmkow
48d81506a3 Vulkan: Fix downscaling Blit. 2021-11-16 22:11:28 +01:00
Fernando Sahmkow
07c564f38b Texture Cache: Implement Rating System. 2021-11-16 22:11:28 +01:00
Fernando Sahmkow
cee7eba64e OpenGL: set linear mag filter when blitting a downscaled image. 2021-11-16 22:11:28 +01:00
Fernando Sahmkow
117f8ee7a4 Vulkan: Fix AA when rescaling. 2021-11-16 22:11:28 +01:00
Fernando Sahmkow
0e8cf38f39 Texture Cache: Implement Blacklisting. 2021-11-16 22:11:28 +01:00
Morph
138d9d7eff main: Add resolution scale label in the status bar
Shows the resolution scale as "Scale: {}x" in the status bar, where {} is a floating point value representing the current resolution scaling factor.
2021-11-16 22:11:28 +01:00
ReinUsesLisp
d2388dd0d0 vulkan: Implement rescaling shader patching 2021-11-16 22:11:28 +01:00
ReinUsesLisp
dc72d4d4f5 vk_texture_cache: Properly scale blit source images 2021-11-16 22:11:28 +01:00
ReinUsesLisp
baf0993d5c vk_graphics_pipeline: Use Shader::NumDescriptors when possible 2021-11-16 22:11:28 +01:00
ReinUsesLisp
6f3a41abe2 opengl: Use Shader::NumDescriptors when possible 2021-11-16 22:11:28 +01:00
ReinUsesLisp
656adee630 spirv: Implement rescaling patching 2021-11-16 22:11:28 +01:00
ReinUsesLisp
01379c5e3c shader/rescaling_pass: Patch more instructions 2021-11-16 22:11:28 +01:00
ReinUsesLisp
c15332c44f shader: Add IsTextureScaled opcode 2021-11-16 22:11:28 +01:00
ReinUsesLisp
74efa57c1b texture_cache: Add image getters 2021-11-16 22:11:28 +01:00
ReinUsesLisp
c892359d1b shader: Add copy constructor to instructions 2021-11-16 22:11:28 +01:00
ReinUsesLisp
95761cc6a7 shader: Add integer division opcodes 2021-11-16 22:11:28 +01:00
ReinUsesLisp
43aa695a04 common/settings: Remove unused scaling options 2021-11-16 22:11:28 +01:00
ReinUsesLisp
e580299467 shader: Fix rescaling pass 2021-11-16 22:11:28 +01:00
ameerj
fad2c92a39 gl_texture_cache: Simplify rescaling 2021-11-16 22:11:28 +01:00
ameerj
d5143c83a9 texture_cache: Fix typo in aliased image rescaling 2021-11-16 22:11:28 +01:00
ReinUsesLisp
0fb4b84383 vk_texture_cache: Simplify and optimize scaling blits 2021-11-16 22:11:28 +01:00
ReinUsesLisp
520c4a44f6 vk_texture_cache: Fix scaling blit validation errors 2021-11-16 22:11:28 +01:00
ReinUsesLisp
1672e9ba09 shader: Fix resolution scaling pass 2021-11-16 22:11:27 +01:00
ReinUsesLisp
fb924ea85c shader: Add resolution down factor opcode 2021-11-16 22:11:27 +01:00
ameerj
fddf372c68 gl_texture_cache: Implement ScaleDown 2021-11-16 22:11:27 +01:00
ameerj
0a6c895af7 gl_texture_cache: Rescale fixes for multi-layered textures 2021-11-16 22:11:27 +01:00
Fernando Sahmkow
dfc65cd0a3 Texture Cache: Implement Rescaling on Aliases and Blits. 2021-11-16 22:11:27 +01:00
ReinUsesLisp
d464b122d5 Fix blits with mips 2021-11-16 22:11:27 +01:00
ReinUsesLisp
973f8f1d08 Fix blits 2021-11-16 22:11:27 +01:00
ameerj
de66a69ed4 renderer_gl: Resolution scaling fixes 2021-11-16 22:11:27 +01:00
Fernando Sahmkow
8704c93913 TextureCache: Fix rescaling of ImageCopies 2021-11-16 22:11:27 +01:00
Fernando Sahmkow
778700ff9d TextureCache: Modify Viewports/Scissors according to Rescale. 2021-11-16 22:11:27 +01:00
Fernando Sahmkow
71ca84d829 Settings: eliminate rescaling_factor. 2021-11-16 22:11:27 +01:00
Fernando Sahmkow
84f2aea896 Texture Cache: More rescaling fixes. 2021-11-16 22:11:27 +01:00
ameerj
10e5065a5c gl_texture_cache: WIP texture rescale 2021-11-16 22:11:27 +01:00
Fernando Sahmkow
ba18047e8d Texture Cache: Implement Vulkan UpScaling & DownScaling 2021-11-16 22:11:27 +01:00
Fernando Sahmkow
360e897ccd ShaderDecompiler: Add initial support for rescaling. 2021-11-16 22:11:27 +01:00
Fernando Sahmkow
37ef9c9130 Settings: Add resolution scaling to settings. 2021-11-16 22:11:27 +01:00
Fernando Sahmkow
22f4b290b6 VideoCore: Initial Setup for the Resolution Scaler. 2021-11-16 22:11:27 +01:00
Matías Locatti
ffb79afd29 Replace keys error pop up
Fight me.
2021-11-16 03:53:28 -03:00
Fernando S
720970c4c1 Merge pull request #7326 from ameerj/vp8
codecs: Implement VP8 video decoding support
2021-11-14 23:03:56 +01:00
Romain Failliot
2e5866147e Replace "Light" theme by "Default"
This reflects the current behavior: Light = System default. If your
system is set to dark theme, then Light = Dark, which is a bit confusing
for the end user.

In this PR, I propose to change "Light" with "Default". This way, the
user has "Default" and "Default Colorful", which will apply the system
theme. Now that the Flatpak respects the system theme, I think this
makes much more sense.

I also simplified the theme update. Before the code was branching
between the default theme and the others, but I think we can have
something simpler by forcing the default theme if no theme is defined in
the settings, or if the selected theme doesn't exist. And if there's an
error, tell the theme name in the error message.
2021-11-14 08:52:55 -05:00
bunnei
30442d8a89 Merge pull request #7260 from vonchenplus/spirv_support_legacy_attribute_v2
shader: Spirv support legacy attribute v2
2021-11-14 02:07:45 -08:00
bunnei
7f256392a1 Merge pull request #7305 from Morph1984/ci
ci: Print traceback on patch merge failure
2021-11-14 02:07:04 -08:00
bunnei
0eacc362dd Merge pull request #7272 from behunin/the-courteous-logger
Logging: Impl refactor
2021-11-13 00:03:54 -08:00
ameerj
c50f170597 codes: Rename ComposeFrameHeader to ComposeFrame
These functions were composing the entire frame, not just the headers. Rename to more accurately describe them.
2021-11-12 23:52:19 -05:00
ameerj
1994edfeb6 CMake: Enable VP8 ffmpeg decoders 2021-11-12 23:52:19 -05:00
ameerj
d35391b9f4 vp8: Implement header composition
Enables frame decoding with FFmpeg
2021-11-12 23:52:18 -05:00
ameerj
b39b33b1fe codecs: Add VP8 codec class 2021-11-12 19:49:45 -05:00
Mai M
852858c2cb Merge pull request #7320 from OatmealDome/homebrew-capabilities
program_metadata: Add default ThreadInfo capability
2021-11-11 00:26:59 -05:00
OatmealDome
50acc0da20 program_metadata: Add default ThreadInfo kernel capability 2021-11-10 22:01:05 -05:00
Fernando S
bdabd17c76 Merge pull request #7303 from Morph1984/swkbd-confirm-skip-textcheck
applets/swkbd: Skip text checking if the text has been confirmed
2021-11-10 13:42:11 +01:00
Morph
3af2117c88 applets/swkbd: Fix text check message encoding
The text check message can be encoded in UTF-8.
2021-11-08 14:57:53 -05:00
Morph
84934693cf ci: Print traceback on patch merge failure 2021-11-08 13:36:05 -05:00
Morph
1af499c15b applets/swkbd: Skip text checking if the text has been confirmed
Confirm means that the text has already been checked by the application to be correct, but is asking the user for confirmation.
The confirmation text itself seems to be corrupted though, this needs to be investigated.

Fixes the software keyboard in Famicom Detective Club: The Missing Heir
2021-11-08 13:05:50 -05:00
Narr the Reg
ced1302975 service/pctl: Stub EndFreeCommunication
- Used by Just Dance 2022
2021-11-05 12:16:19 -04:00
Feng Chen
70d51f72ec vulkan_device: Add missing vulkan image format R5G6B5 in GetFormatProperties
- Used by Dragon Quest Builders
2021-11-05 10:31:40 -04:00
Morph
3a71ff44f8 Merge pull request #7279 from Morph1984/system-get-program-id
general: Get the current process program id directly from the system
2021-11-04 20:34:20 -04:00
Morph
2ceb514a39 Merge pull request #7289 from ameerj/perf-stat-shutdown
core: Reorder perf_stats destruction order on Shutdown
2021-11-04 20:34:09 -04:00
ameerj
0cf78a34ba core: Reorder perf_stats destruction order on Shutdown
Avoids the gpu_core using perf_stats after it's been freed.
2021-11-04 20:19:58 -04:00
Fernando S
3ceefc64f1 Merge pull request #7287 from Morph1984/stub-aoc
service: aoc: Stub more 13.x functions used by Animal Crossing
2021-11-05 00:26:10 +01:00
Morph
a6e6a5ac38 general: Get the current process program id directly from the system
This allows us to avoid including KProcess' header file in files that only need to get the current process' program id.
2021-11-04 16:59:39 -04:00
Morph
64275dfbf4 general: Rename GetTitleID to GetProgramID 2021-11-04 16:57:16 -04:00
bunnei
f178a8ef0c Merge pull request #7282 from ameerj/core-includes
core: Reduce unused header includes
2021-11-04 13:56:10 -07:00
Morph
21c1316503 service: aoc: Stub NotifyUnmountAddOnContent
Used by Animal Crossing: New Horizons v2.0.0 DLC
2021-11-04 16:50:08 -04:00
Morph
ef427e4cb0 service: aoc: Stub NotifyMountAddOnContent and NotifyMountAddOnContent
Used by Animal Crossing: New Horizons v2.0.0 DLC
2021-11-04 16:48:47 -04:00
bunnei
b92c4abc96 Merge pull request #7285 from german77/acc
service/acc: Rename Unknown160 to InitializeApplicationInfoV2
2021-11-04 10:45:53 -07:00
german77
bee6b71553 service/acc: Rename Unknown160 to InitializeApplicationInfoV2 2021-11-04 10:10:58 -06:00
Fernando S
35aa153d6c Merge pull request #7283 from Morph1984/stub-160
service: acc: Stub acc:u0 '160'
2021-11-04 16:25:32 +01:00
Morph
f2988ecabc service: acc: Stub acc:u0 '160'
- Used by Animal Crossing: New Horizons v2.0.0

Since the name is currently unknown, '160' is used as a placeholder.
2021-11-04 02:57:13 -04:00
Feng Chen
f2a4204245 Simply legacy attribute implement 2021-11-04 09:26:16 +08:00
Fletcher Porter
2b3d66fe69 Move the cmake submodule checkout command to a new line
Presently, if you forget to initialize the git submodules before
running cmake, there'll be a helpful message that reminds you to do so.
However, on narrow terminals (e.g. 80 wide) there's a word wrap that
includes a new line in the middle of the git command, precluding easy
copy-paste.  This moves the entire git command to its own line to avoid
such tragedies.

Before:

```
CMake Error at CMakeLists.txt:59 (message):
  Git submodule externals/inih/inih not found.  Please run: git submodule
  update --init --recursive
```

After:

```
CMake Error at CMakeLists.txt:59 (message):
  Git submodule externals/inih/inih not found.  Please run:

  git submodule update --init --recursive
```
2021-11-02 00:01:39 -07:00
Levi Behunin
d6b5f64484 Refactor Logging Impl
Loop on stop_token and remove final_entry in Entry.
Move Backend thread out of Impl Constructor to its own function.
Add Start function for backend thread.
Use stop token in PopWait and check if entry filename is nullptr before logging.
2021-11-01 18:36:27 -06:00
vonchenplus
49f9a44235 Support gl_FogFragCoord attribute 2021-10-31 23:34:17 +08:00
vonchenplus
36c21ff6cb Support gl_BackSecondaryColor attribute 2021-10-26 23:14:40 +08:00
vonchenplus
92bebecf46 Support gl_FrontSecondaryColor attribute 2021-10-26 23:09:44 +08:00
vonchenplus
b04c7b6343 Support gl_BackColor attribute 2021-10-26 23:01:57 +08:00
333 changed files with 25311 additions and 12566 deletions

View File

@@ -25,7 +25,7 @@ def check_individual(repo_id, pr_id):
def merge_pr(pn, ref):
print("Matched PR# %s" % pn)
print(subprocess.check_output(["git", "fetch", "https://%sdev.azure.com/%s/_git/%s" % (user, org, repo), ref, "-f"]))
print(subprocess.check_output(["git", "fetch", "https://%sdev.azure.com/%s/_git/%s" % (user, org, repo), ref, "-f", "--no-recurse-submodules"]))
print(subprocess.check_output(["git", "merge", "--squash", 'origin/' + ref.replace('refs/heads/','')]))
print(subprocess.check_output(["git", "commit", "-m\"Merge %s PR %s\"" % (tagline, pn)]))

View File

@@ -1,7 +1,7 @@
# Download all pull requests as patches that match a specific label
# Usage: python download-patches-by-label.py <Label to Match> <Root Path Folder to DL to>
import requests, sys, json, urllib3.request, shutil, subprocess, os
import requests, sys, json, urllib3.request, shutil, subprocess, os, traceback
tagline = sys.argv[2]
@@ -25,7 +25,7 @@ def do_page(page):
if (check_individual(pr["labels"])):
pn = pr["number"]
print("Matched PR# %s" % pn)
print(subprocess.check_output(["git", "fetch", "https://github.com/yuzu-emu/yuzu.git", "pull/%s/head:pr-%s" % (pn, pn), "-f"]))
print(subprocess.check_output(["git", "fetch", "https://github.com/yuzu-emu/yuzu.git", "pull/%s/head:pr-%s" % (pn, pn), "-f", "--no-recurse-submodules"]))
print(subprocess.check_output(["git", "merge", "--squash", "pr-%s" % pn]))
print(subprocess.check_output(["git", "commit", "-m\"Merge %s PR %s\"" % (tagline, pn)]))
@@ -33,4 +33,5 @@ try:
for i in range(1,30):
do_page(i)
except:
traceback.print_exc(file=sys.stdout)
sys.exit(-1)

View File

@@ -57,7 +57,7 @@ function(check_submodules_present)
string(REGEX REPLACE "path *= *" "" module ${module})
if (NOT EXISTS "${PROJECT_SOURCE_DIR}/${module}/.git")
message(FATAL_ERROR "Git submodule ${module} not found. "
"Please run: git submodule update --init --recursive")
"Please run: \ngit submodule update --init --recursive")
endif()
endforeach()
endfunction()
@@ -166,8 +166,8 @@ macro(yuzu_find_packages)
# Capitalization matters here. We need the naming to match the generated paths from Conan
set(REQUIRED_LIBS
# Cmake Pkg Prefix Version Conan Pkg
"Catch2 2.13 catch2/2.13.0"
"fmt 8.0 fmt/8.0.0"
"Catch2 2.13.7 catch2/2.13.7"
"fmt 8.0.1 fmt/8.0.1"
"lz4 1.8 lz4/1.9.2"
"nlohmann_json 3.8 nlohmann_json/3.8.0"
"ZLIB 1.2 zlib/1.2.11"
@@ -600,6 +600,7 @@ if (YUZU_USE_BUNDLED_FFMPEG)
${LIBVA_LIBRARIES})
set(FFmpeg_HWACCEL_FLAGS
--enable-hwaccel=h264_vaapi
--enable-hwaccel=vp8_vaapi
--enable-hwaccel=vp9_vaapi
--enable-libdrm)
list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS
@@ -620,6 +621,7 @@ if (YUZU_USE_BUNDLED_FFMPEG)
--enable-ffnvcodec
--enable-nvdec
--enable-hwaccel=h264_nvdec
--enable-hwaccel=vp8_nvdec
--enable-hwaccel=vp9_nvdec
--extra-cflags=-I${CUDA_INCLUDE_DIRS}
)
@@ -670,6 +672,7 @@ if (YUZU_USE_BUNDLED_FFMPEG)
--disable-postproc
--disable-swresample
--enable-decoder=h264
--enable-decoder=vp8
--enable-decoder=vp9
--cc="${CMAKE_C_COMPILER}"
--cxx="${CMAKE_CXX_COMPILER}"

2656
externals/FidelityFX-FSR/ffx-fsr/ffx_a.h vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

19
externals/FidelityFX-FSR/license.txt vendored Normal file
View File

@@ -0,0 +1,19 @@
Copyright (c) 2021 Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -73,6 +73,7 @@ add_library(common STATIC
hex_util.h
host_memory.cpp
host_memory.h
input.h
intrusive_red_black_tree.h
literals.h
logging/backend.cpp

View File

@@ -7,6 +7,7 @@
#include <bit>
#include <climits>
#include <cstddef>
#include <type_traits>
#include "common/common_types.h"
@@ -44,4 +45,10 @@ template <typename T>
return static_cast<u32>(log2_f + static_cast<u64>((value ^ (1ULL << log2_f)) != 0ULL));
}
template <typename T>
requires std::is_integral_v<T>
[[nodiscard]] T NextPow2(T value) {
return static_cast<T>(1ULL << ((8U * sizeof(T)) - std::countl_zero(value - 1U)));
}
} // namespace Common

372
src/common/input.h Normal file
View File

@@ -0,0 +1,372 @@
// Copyright 2017 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <functional>
#include <memory>
#include <string>
#include <unordered_map>
#include <utility>
#include "common/logging/log.h"
#include "common/param_package.h"
#include "common/uuid.h"
namespace Common::Input {
// Type of data that is expected to recieve or send
enum class InputType {
None,
Battery,
Button,
Stick,
Analog,
Trigger,
Motion,
Touch,
Color,
Vibration,
Nfc,
Ir,
};
// Internal battery charge level
enum class BatteryLevel : u32 {
None,
Empty,
Critical,
Low,
Medium,
Full,
Charging,
};
enum class PollingMode {
// Constant polling of buttons, analogs and motion data
Active,
// Only update on button change, digital analogs
Pasive,
// Enable near field communication polling
NFC,
// Enable infrared camera polling
IR,
};
// Vibration reply from the controller
enum class VibrationError {
None,
NotSupported,
Disabled,
Unknown,
};
// Polling mode reply from the controller
enum class PollingError {
None,
NotSupported,
Unknown,
};
// Hint for amplification curve to be used
enum class VibrationAmplificationType {
Linear,
Exponential,
};
// Analog properties for calibration
struct AnalogProperties {
// Anything below this value will be detected as zero
float deadzone{};
// Anyting above this values will be detected as one
float range{1.0f};
// Minimum value to be detected as active
float threshold{0.5f};
// Drift correction applied to the raw data
float offset{};
// Invert direction of the sensor data
bool inverted{};
};
// Single analog sensor data
struct AnalogStatus {
float value{};
float raw_value{};
AnalogProperties properties{};
};
// Button data
struct ButtonStatus {
Common::UUID uuid{};
bool value{};
bool inverted{};
bool toggle{};
bool locked{};
};
// Internal battery data
using BatteryStatus = BatteryLevel;
// Analog and digital joystick data
struct StickStatus {
Common::UUID uuid{};
AnalogStatus x{};
AnalogStatus y{};
bool left{};
bool right{};
bool up{};
bool down{};
};
// Analog and digital trigger data
struct TriggerStatus {
Common::UUID uuid{};
AnalogStatus analog{};
ButtonStatus pressed{};
};
// 3D vector representing motion input
struct MotionSensor {
AnalogStatus x{};
AnalogStatus y{};
AnalogStatus z{};
};
// Motion data used to calculate controller orientation
struct MotionStatus {
// Gyroscope vector measurement in radians/s.
MotionSensor gyro{};
// Acceleration vector measurement in G force
MotionSensor accel{};
// Time since last measurement in microseconds
u64 delta_timestamp{};
// Request to update after reading the value
bool force_update{};
};
// Data of a single point on a touch screen
struct TouchStatus {
ButtonStatus pressed{};
AnalogStatus x{};
AnalogStatus y{};
int id{};
};
// Physical controller color in RGB format
struct BodyColorStatus {
u32 body{};
u32 buttons{};
};
// HD rumble data
struct VibrationStatus {
f32 low_amplitude{};
f32 low_frequency{};
f32 high_amplitude{};
f32 high_frequency{};
VibrationAmplificationType type;
};
// Physical controller LED pattern
struct LedStatus {
bool led_1{};
bool led_2{};
bool led_3{};
bool led_4{};
};
// List of buttons to be passed to Qt that can be translated
enum class ButtonNames {
Undefined,
Invalid,
// This will display the engine name instead of the button name
Engine,
// This will display the button by value instead of the button name
Value,
ButtonLeft,
ButtonRight,
ButtonDown,
ButtonUp,
TriggerZ,
TriggerR,
TriggerL,
ButtonA,
ButtonB,
ButtonX,
ButtonY,
ButtonStart,
// DS4 button names
L1,
L2,
L3,
R1,
R2,
R3,
Circle,
Cross,
Square,
Triangle,
Share,
Options,
};
// Callback data consisting of an input type and the equivalent data status
struct CallbackStatus {
InputType type{InputType::None};
ButtonStatus button_status{};
StickStatus stick_status{};
AnalogStatus analog_status{};
TriggerStatus trigger_status{};
MotionStatus motion_status{};
TouchStatus touch_status{};
BodyColorStatus color_status{};
BatteryStatus battery_status{};
VibrationStatus vibration_status{};
};
// Triggered once every input change
struct InputCallback {
std::function<void(CallbackStatus)> on_change;
};
/// An abstract class template for an input device (a button, an analog input, etc.).
class InputDevice {
public:
virtual ~InputDevice() = default;
// Request input device to update if necessary
virtual void SoftUpdate() {
return;
}
// Force input device to update data regardless of the current state
virtual void ForceUpdate() {
return;
}
// Sets the function to be triggered when input changes
void SetCallback(InputCallback callback_) {
callback = std::move(callback_);
}
// Triggers the function set in the callback
void TriggerOnChange(CallbackStatus status) {
if (callback.on_change) {
callback.on_change(status);
}
}
private:
InputCallback callback;
};
/// An abstract class template for an output device (rumble, LED pattern, polling mode).
class OutputDevice {
public:
virtual ~OutputDevice() = default;
virtual void SetLED([[maybe_unused]] LedStatus led_status) {
return;
}
virtual VibrationError SetVibration([[maybe_unused]] VibrationStatus vibration_status) {
return VibrationError::NotSupported;
}
virtual PollingError SetPollingMode([[maybe_unused]] PollingMode polling_mode) {
return PollingError::NotSupported;
}
};
/// An abstract class template for a factory that can create input devices.
template <typename InputDeviceType>
class Factory {
public:
virtual ~Factory() = default;
virtual std::unique_ptr<InputDeviceType> Create(const Common::ParamPackage&) = 0;
};
namespace Impl {
template <typename InputDeviceType>
using FactoryListType = std::unordered_map<std::string, std::shared_ptr<Factory<InputDeviceType>>>;
template <typename InputDeviceType>
struct FactoryList {
static FactoryListType<InputDeviceType> list;
};
template <typename InputDeviceType>
FactoryListType<InputDeviceType> FactoryList<InputDeviceType>::list;
} // namespace Impl
/**
* Registers an input device factory.
* @tparam InputDeviceType the type of input devices the factory can create
* @param name the name of the factory. Will be used to match the "engine" parameter when creating
* a device
* @param factory the factory object to register
*/
template <typename InputDeviceType>
void RegisterFactory(const std::string& name, std::shared_ptr<Factory<InputDeviceType>> factory) {
auto pair = std::make_pair(name, std::move(factory));
if (!Impl::FactoryList<InputDeviceType>::list.insert(std::move(pair)).second) {
LOG_ERROR(Input, "Factory '{}' already registered", name);
}
}
/**
* Unregisters an input device factory.
* @tparam InputDeviceType the type of input devices the factory can create
* @param name the name of the factory to unregister
*/
template <typename InputDeviceType>
void UnregisterFactory(const std::string& name) {
if (Impl::FactoryList<InputDeviceType>::list.erase(name) == 0) {
LOG_ERROR(Input, "Factory '{}' not registered", name);
}
}
/**
* Create an input device from given paramters.
* @tparam InputDeviceType the type of input devices to create
* @param params a serialized ParamPackage string that contains all parameters for creating the
* device
*/
template <typename InputDeviceType>
std::unique_ptr<InputDeviceType> CreateDeviceFromString(const std::string& params) {
const Common::ParamPackage package(params);
const std::string engine = package.Get("engine", "null");
const auto& factory_list = Impl::FactoryList<InputDeviceType>::list;
const auto pair = factory_list.find(engine);
if (pair == factory_list.end()) {
if (engine != "null") {
LOG_ERROR(Input, "Unknown engine name: {}", engine);
}
return std::make_unique<InputDeviceType>();
}
return pair->second->Create(package);
}
/**
* Create an input device from given paramters.
* @tparam InputDeviceType the type of input devices to create
* @param A ParamPackage that contains all parameters for creating the device
*/
template <typename InputDeviceType>
std::unique_ptr<InputDeviceType> CreateDevice(const Common::ParamPackage package) {
const std::string engine = package.Get("engine", "null");
const auto& factory_list = Impl::FactoryList<InputDeviceType>::list;
const auto pair = factory_list.find(engine);
if (pair == factory_list.end()) {
if (engine != "null") {
LOG_ERROR(Input, "Unknown engine name: {}", engine);
}
return std::make_unique<InputDeviceType>();
}
return pair->second->Create(package);
}
} // namespace Common::Input

View File

@@ -6,6 +6,7 @@
#include <chrono>
#include <climits>
#include <exception>
#include <stop_token>
#include <thread>
#include <vector>
@@ -186,6 +187,10 @@ public:
initialization_in_progress_suppress_logging = false;
}
static void Start() {
instance->StartBackendThread();
}
Impl(const Impl&) = delete;
Impl& operator=(const Impl&) = delete;
@@ -201,7 +206,7 @@ public:
}
void PushEntry(Class log_class, Level log_level, const char* filename, unsigned int line_num,
const char* function, std::string message) {
const char* function, std::string&& message) {
if (!filter.CheckMessage(log_class, log_level))
return;
const Entry& entry =
@@ -211,40 +216,41 @@ public:
private:
Impl(const std::filesystem::path& file_backend_filename, const Filter& filter_)
: filter{filter_}, file_backend{file_backend_filename}, backend_thread{std::thread([this] {
Common::SetCurrentThreadName("yuzu:Log");
Entry entry;
const auto write_logs = [this, &entry]() {
ForEachBackend([&entry](Backend& backend) { backend.Write(entry); });
};
while (true) {
entry = message_queue.PopWait();
if (entry.final_entry) {
break;
}
write_logs();
}
// Drain the logging queue. Only writes out up to MAX_LOGS_TO_WRITE to prevent a
// case where a system is repeatedly spamming logs even on close.
int max_logs_to_write = filter.IsDebug() ? INT_MAX : 100;
while (max_logs_to_write-- && message_queue.Pop(entry)) {
write_logs();
}
})} {}
: filter{filter_}, file_backend{file_backend_filename} {}
~Impl() {
StopBackendThread();
}
void StartBackendThread() {
backend_thread = std::thread([this] {
Common::SetCurrentThreadName("yuzu:Log");
Entry entry;
const auto write_logs = [this, &entry]() {
ForEachBackend([&entry](Backend& backend) { backend.Write(entry); });
};
while (!stop.stop_requested()) {
entry = message_queue.PopWait(stop.get_token());
if (entry.filename != nullptr) {
write_logs();
}
}
// Drain the logging queue. Only writes out up to MAX_LOGS_TO_WRITE to prevent a
// case where a system is repeatedly spamming logs even on close.
int max_logs_to_write = filter.IsDebug() ? INT_MAX : 100;
while (max_logs_to_write-- && message_queue.Pop(entry)) {
write_logs();
}
});
}
void StopBackendThread() {
Entry stop_entry{};
stop_entry.final_entry = true;
message_queue.Push(stop_entry);
stop.request_stop();
backend_thread.join();
}
Entry CreateEntry(Class log_class, Level log_level, const char* filename, unsigned int line_nr,
const char* function, std::string message) const {
const char* function, std::string&& message) const {
using std::chrono::duration_cast;
using std::chrono::microseconds;
using std::chrono::steady_clock;
@@ -257,7 +263,6 @@ private:
.line_num = line_nr,
.function = function,
.message = std::move(message),
.final_entry = false,
};
}
@@ -278,8 +283,9 @@ private:
ColorConsoleBackend color_console_backend{};
FileBackend file_backend;
std::stop_source stop;
std::thread backend_thread;
MPSCQueue<Entry> message_queue{};
MPSCQueue<Entry, true> message_queue{};
std::chrono::steady_clock::time_point time_origin{std::chrono::steady_clock::now()};
};
} // namespace
@@ -288,6 +294,10 @@ void Initialize() {
Impl::Initialize();
}
void Start() {
Impl::Start();
}
void DisableLoggingInTests() {
initialization_in_progress_suppress_logging = true;
}

View File

@@ -14,6 +14,8 @@ class Filter;
/// Initializes the logging system. This should be the first thing called in main.
void Initialize();
void Start();
void DisableLoggingInTests();
/**

View File

@@ -22,7 +22,6 @@ struct Entry {
unsigned int line_num = 0;
std::string function;
std::string message;
bool final_entry = false;
};
} // namespace Common::Log

View File

@@ -48,8 +48,8 @@ struct Rectangle {
}
[[nodiscard]] Rectangle<T> Scale(const float s) const {
return Rectangle{left, top, static_cast<T>(left + GetWidth() * s),
static_cast<T>(top + GetHeight() * s)};
return Rectangle{left, top, static_cast<T>(static_cast<float>(left + GetWidth()) * s),
static_cast<T>(static_cast<float>(top + GetHeight()) * s)};
}
};

View File

@@ -47,7 +47,9 @@ void LogSettings() {
log_setting("System_TimeZoneIndex", values.time_zone_index.GetValue());
log_setting("Core_UseMultiCore", values.use_multi_core.GetValue());
log_setting("CPU_Accuracy", values.cpu_accuracy.GetValue());
log_setting("Renderer_UseResolutionFactor", values.resolution_factor.GetValue());
log_setting("Renderer_UseResolutionScaling", values.resolution_setup.GetValue());
log_setting("Renderer_ScalingFilter", values.scaling_filter.GetValue());
log_setting("Renderer_AntiAliasing", values.anti_aliasing.GetValue());
log_setting("Renderer_UseSpeedLimit", values.use_speed_limit.GetValue());
log_setting("Renderer_SpeedLimit", values.speed_limit.GetValue());
log_setting("Renderer_UseDiskShaderCache", values.use_disk_shader_cache.GetValue());
@@ -105,6 +107,55 @@ float Volume() {
return values.volume.GetValue() / 100.0f;
}
void UpdateRescalingInfo() {
const auto setup = values.resolution_setup.GetValue();
auto& info = values.resolution_info;
info.downscale = false;
switch (setup) {
case ResolutionSetup::Res1_2X:
info.up_scale = 1;
info.down_shift = 1;
info.downscale = true;
break;
case ResolutionSetup::Res3_4X:
info.up_scale = 3;
info.down_shift = 2;
info.downscale = true;
break;
case ResolutionSetup::Res1X:
info.up_scale = 1;
info.down_shift = 0;
break;
case ResolutionSetup::Res2X:
info.up_scale = 2;
info.down_shift = 0;
break;
case ResolutionSetup::Res3X:
info.up_scale = 3;
info.down_shift = 0;
break;
case ResolutionSetup::Res4X:
info.up_scale = 4;
info.down_shift = 0;
break;
case ResolutionSetup::Res5X:
info.up_scale = 5;
info.down_shift = 0;
break;
case ResolutionSetup::Res6X:
info.up_scale = 6;
info.down_shift = 0;
break;
default:
UNREACHABLE();
info.up_scale = 1;
info.down_shift = 0;
}
info.up_factor = static_cast<f32>(info.up_scale) / (1U << info.down_shift);
info.down_factor = static_cast<f32>(1U << info.down_shift) / info.up_scale;
info.active = info.up_scale != 1 || info.down_shift != 0;
}
void RestoreGlobalState(bool is_powered_on) {
// If a game is running, DO NOT restore the global settings state
if (is_powered_on) {
@@ -132,6 +183,7 @@ void RestoreGlobalState(bool is_powered_on) {
values.max_anisotropy.SetGlobal(true);
values.use_speed_limit.SetGlobal(true);
values.speed_limit.SetGlobal(true);
values.fps_cap.SetGlobal(true);
values.use_disk_shader_cache.SetGlobal(true);
values.gpu_accuracy.SetGlobal(true);
values.use_asynchronous_gpu_emulation.SetGlobal(true);

View File

@@ -6,7 +6,6 @@
#include <algorithm>
#include <array>
#include <atomic>
#include <map>
#include <optional>
#include <string>
@@ -52,6 +51,56 @@ enum class NvdecEmulation : u32 {
GPU = 2,
};
enum class ResolutionSetup : u32 {
Res1_2X = 0,
Res3_4X = 1,
Res1X = 2,
Res2X = 3,
Res3X = 4,
Res4X = 5,
Res5X = 6,
Res6X = 7,
};
enum class ScalingFilter : u32 {
NearestNeighbor = 0,
Bilinear = 1,
Bicubic = 2,
Gaussian = 3,
ScaleForce = 4,
Fsr = 5,
LastFilter = Fsr,
};
enum class AntiAliasing : u32 {
None = 0,
Fxaa = 1,
LastAA = Fxaa,
};
struct ResolutionScalingInfo {
u32 up_scale{1};
u32 down_shift{0};
f32 up_factor{1.0f};
f32 down_factor{1.0f};
bool active{};
bool downscale{};
s32 ScaleUp(s32 value) const {
if (value == 0) {
return 0;
}
return std::max((value * static_cast<s32>(up_scale)) >> static_cast<s32>(down_shift), 1);
}
u32 ScaleUp(u32 value) const {
if (value == 0U) {
return 0U;
}
return std::max((value * up_scale) >> down_shift, 1U);
}
};
/** The BasicSetting class is a simple resource manager. It defines a label and default value
* alongside the actual value of the setting for simpler and less-error prone use with frontend
* configurations. Setting a default value and label is required, though subclasses may deviate from
@@ -451,7 +500,10 @@ struct Values {
"disable_shader_loop_safety_checks"};
Setting<int> vulkan_device{0, "vulkan_device"};
Setting<u16> resolution_factor{1, "resolution_factor"};
ResolutionScalingInfo resolution_info{};
Setting<ResolutionSetup> resolution_setup{ResolutionSetup::Res1X, "resolution_setup"};
Setting<ScalingFilter> scaling_filter{ScalingFilter::Bilinear, "scaling_filter"};
Setting<AntiAliasing> anti_aliasing{AntiAliasing::None, "anti_aliasing"};
// *nix platforms may have issues with the borderless windowed fullscreen mode.
// Default to exclusive fullscreen on these platforms for now.
RangedSetting<FullscreenMode> fullscreen_mode{
@@ -462,7 +514,7 @@ struct Values {
#endif
FullscreenMode::Borderless, FullscreenMode::Exclusive, "fullscreen_mode"};
RangedSetting<int> aspect_ratio{0, 0, 3, "aspect_ratio"};
RangedSetting<int> max_anisotropy{0, 0, 4, "max_anisotropy"};
RangedSetting<int> max_anisotropy{0, 0, 5, "max_anisotropy"};
Setting<bool> use_speed_limit{true, "use_speed_limit"};
RangedSetting<u16> speed_limit{100, 0, 9999, "speed_limit"};
Setting<bool> use_disk_shader_cache{true, "use_disk_shader_cache"};
@@ -472,7 +524,7 @@ struct Values {
Setting<NvdecEmulation> nvdec_emulation{NvdecEmulation::GPU, "nvdec_emulation"};
Setting<bool> accelerate_astc{true, "accelerate_astc"};
Setting<bool> use_vsync{true, "use_vsync"};
BasicRangedSetting<u16> fps_cap{1000, 1, 1000, "fps_cap"};
RangedSetting<u16> fps_cap{1000, 1, 1000, "fps_cap"};
BasicSetting<bool> disable_fps_limit{false, "disable_fps_limit"};
RangedSetting<ShaderBackend> shader_backend{ShaderBackend::GLASM, ShaderBackend::GLSL,
ShaderBackend::SPIRV, "shader_backend"};
@@ -507,25 +559,19 @@ struct Values {
Setting<bool> enable_accurate_vibrations{false, "enable_accurate_vibrations"};
Setting<bool> motion_enabled{true, "motion_enabled"};
BasicSetting<std::string> motion_device{"engine:motion_emu,update_period:100,sensitivity:0.01",
"motion_device"};
BasicSetting<std::string> udp_input_servers{"127.0.0.1:26760", "udp_input_servers"};
BasicSetting<bool> enable_udp_controller{false, "enable_udp_controller"};
BasicSetting<bool> pause_tas_on_load{true, "pause_tas_on_load"};
BasicSetting<bool> tas_enable{false, "tas_enable"};
BasicSetting<bool> tas_loop{false, "tas_loop"};
BasicSetting<bool> tas_swap_controllers{true, "tas_swap_controllers"};
BasicSetting<bool> mouse_panning{false, "mouse_panning"};
BasicRangedSetting<u8> mouse_panning_sensitivity{10, 1, 100, "mouse_panning_sensitivity"};
BasicSetting<bool> mouse_enabled{false, "mouse_enabled"};
std::string mouse_device;
MouseButtonsRaw mouse_buttons;
BasicSetting<bool> emulate_analog_keyboard{false, "emulate_analog_keyboard"};
BasicSetting<bool> keyboard_enabled{false, "keyboard_enabled"};
KeyboardKeysRaw keyboard_keys;
KeyboardModsRaw keyboard_mods;
BasicSetting<bool> debug_pad_enabled{false, "debug_pad_enabled"};
ButtonsRaw debug_pad_buttons;
@@ -533,14 +579,11 @@ struct Values {
TouchscreenInput touchscreen;
BasicSetting<bool> use_touch_from_button{false, "use_touch_from_button"};
BasicSetting<std::string> touch_device{"min_x:100,min_y:50,max_x:1800,max_y:850",
"touch_device"};
BasicSetting<int> touch_from_button_map_index{0, "touch_from_button_map"};
std::vector<TouchFromButtonMap> touch_from_button_maps;
std::atomic_bool is_device_reload_pending{true};
// Data Storage
BasicSetting<bool> use_virtual_sd{true, "use_virtual_sd"};
BasicSetting<bool> gamecard_inserted{false, "gamecard_inserted"};
@@ -561,6 +604,7 @@ struct Values {
BasicSetting<bool> extended_logging{false, "extended_logging"};
BasicSetting<bool> use_debug_asserts{false, "use_debug_asserts"};
BasicSetting<bool> use_auto_stub{false, "use_auto_stub"};
BasicSetting<bool> enable_all_controllers{false, "enable_all_controllers"};
// Miscellaneous
BasicSetting<std::string> log_filter{"*:Info", "log_filter"};
@@ -595,6 +639,8 @@ std::string GetTimeZoneString();
void LogSettings();
void UpdateRescalingInfo();
// Restore the global state of all applicable settings in the Values struct
void RestoreGlobalState(bool is_powered_on);

View File

@@ -62,11 +62,22 @@ enum Values : int {
constexpr int STICK_HID_BEGIN = LStick;
constexpr int STICK_HID_END = NumAnalogs;
constexpr int NUM_STICKS_HID = NumAnalogs;
extern const std::array<const char*, NumAnalogs> mapping;
} // namespace NativeAnalog
namespace NativeTrigger {
enum Values : int {
LTrigger,
RTrigger,
NumTriggers,
};
constexpr int TRIGGER_HID_BEGIN = LTrigger;
constexpr int TRIGGER_HID_END = NumTriggers;
} // namespace NativeTrigger
namespace NativeVibration {
enum Values : int {
LeftVibrationDevice,
@@ -115,10 +126,20 @@ constexpr int NUM_MOUSE_HID = NumMouseButtons;
extern const std::array<const char*, NumMouseButtons> mapping;
} // namespace NativeMouseButton
namespace NativeMouseWheel {
enum Values {
X,
Y,
NumMouseWheels,
};
extern const std::array<const char*, NumMouseWheels> mapping;
} // namespace NativeMouseWheel
namespace NativeKeyboard {
enum Keys {
None,
Error,
A = 4,
B,
@@ -156,22 +177,22 @@ enum Keys {
N8,
N9,
N0,
Enter,
Return,
Escape,
Backspace,
Tab,
Space,
Minus,
Equal,
LeftBrace,
RightBrace,
Backslash,
Plus,
OpenBracket,
CloseBracket,
Pipe,
Tilde,
Semicolon,
Apostrophe,
Grave,
Quote,
Backquote,
Comma,
Dot,
Period,
Slash,
CapsLockKey,
@@ -188,7 +209,7 @@ enum Keys {
F11,
F12,
SystemRequest,
PrintScreen,
ScrollLockKey,
Pause,
Insert,
@@ -257,8 +278,18 @@ enum Keys {
ScrollLockActive,
KPComma,
KPLeftParenthesis,
KPRightParenthesis,
Ro = 0x87,
KatakanaHiragana,
Yen,
Henkan,
Muhenkan,
NumPadCommaPc98,
HangulEnglish = 0x90,
Hanja,
KatakanaKey,
HiraganaKey,
ZenkakuHankaku,
LeftControlKey = 0xE0,
LeftShiftKey,
@@ -307,6 +338,8 @@ enum Modifiers {
CapsLock,
ScrollLock,
NumLock,
Katakana,
Hiragana,
NumKeyboardMods,
};
@@ -324,11 +357,6 @@ constexpr int NUM_KEYBOARD_MODS_HID = NumKeyboardMods;
using AnalogsRaw = std::array<std::string, NativeAnalog::NumAnalogs>;
using ButtonsRaw = std::array<std::string, NativeButton::NumButtons>;
using MotionsRaw = std::array<std::string, NativeMotion::NumMotions>;
using VibrationsRaw = std::array<std::string, NativeVibration::NumVibrations>;
using MouseButtonsRaw = std::array<std::string, NativeMouseButton::NumMouseButtons>;
using KeyboardKeysRaw = std::array<std::string, NativeKeyboard::NumKeyboardKeys>;
using KeyboardModsRaw = std::array<std::string, NativeKeyboard::NumKeyboardMods>;
constexpr u32 JOYCON_BODY_NEON_RED = 0xFF3C28;
constexpr u32 JOYCON_BUTTONS_NEON_RED = 0x1E0A0A;
@@ -342,6 +370,11 @@ enum class ControllerType {
RightJoycon,
Handheld,
GameCube,
Pokeball,
NES,
SNES,
N64,
SegaGenesis,
};
struct PlayerInput {
@@ -349,7 +382,6 @@ struct PlayerInput {
ControllerType controller_type;
ButtonsRaw buttons;
AnalogsRaw analogs;
VibrationsRaw vibrations;
MotionsRaw motions;
bool vibration_enabled;

View File

@@ -132,11 +132,23 @@ add_library(core STATIC
frontend/emu_window.h
frontend/framebuffer_layout.cpp
frontend/framebuffer_layout.h
frontend/input_interpreter.cpp
frontend/input_interpreter.h
frontend/input.h
hardware_interrupt_manager.cpp
hardware_interrupt_manager.h
hid/emulated_console.cpp
hid/emulated_console.h
hid/emulated_controller.cpp
hid/emulated_controller.h
hid/emulated_devices.cpp
hid/emulated_devices.h
hid/hid_core.cpp
hid/hid_core.h
hid/hid_types.h
hid/input_converter.cpp
hid/input_converter.h
hid/input_interpreter.cpp
hid/input_interpreter.h
hid/motion_input.cpp
hid/motion_input.h
hle/api_version.h
hle/ipc.h
hle/ipc_helpers.h
@@ -402,6 +414,7 @@ add_library(core STATIC
hle/service/hid/hid.h
hle/service/hid/irs.cpp
hle/service/hid/irs.h
hle/service/hid/ring_lifo.h
hle/service/hid/xcd.cpp
hle/service/hid/xcd.h
hle/service/hid/errors.h
@@ -466,6 +479,8 @@ add_library(core STATIC
hle/service/ns/language.h
hle/service/ns/ns.cpp
hle/service/ns/ns.h
hle/service/ns/pdm_qry.cpp
hle/service/ns/pdm_qry.h
hle/service/ns/pl_u.cpp
hle/service/ns/pl_u.h
hle/service/nvdrv/devices/nvdevice.h

View File

@@ -86,6 +86,26 @@ public:
num_instructions, MemoryReadCode(pc));
}
void InstructionCacheOperationRaised(Dynarmic::A64::InstructionCacheOperation op,
VAddr value) override {
switch (op) {
case Dynarmic::A64::InstructionCacheOperation::InvalidateByVAToPoU: {
static constexpr u64 ICACHE_LINE_SIZE = 64;
const u64 cache_line_start = value & ~(ICACHE_LINE_SIZE - 1);
parent.InvalidateCacheRange(cache_line_start, ICACHE_LINE_SIZE);
break;
}
case Dynarmic::A64::InstructionCacheOperation::InvalidateAllToPoU:
parent.ClearInstructionCache();
break;
case Dynarmic::A64::InstructionCacheOperation::InvalidateAllToPoUInnerSharable:
default:
LOG_DEBUG(Core_ARM, "Unprocesseed instruction cache operation: {}", op);
break;
}
}
void ExceptionRaised(u64 pc, Dynarmic::A64::Exception exception) override {
switch (exception) {
case Dynarmic::A64::Exception::WaitForInterrupt:

View File

@@ -27,6 +27,7 @@
#include "core/file_sys/vfs_concat.h"
#include "core/file_sys/vfs_real.h"
#include "core/hardware_interrupt_manager.h"
#include "core/hid/hid_core.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_scheduler.h"
#include "core/hle/kernel/kernel.h"
@@ -126,7 +127,7 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
struct System::Impl {
explicit Impl(System& system)
: kernel{system}, fs_controller{system}, memory{system},
: kernel{system}, fs_controller{system}, memory{system}, hid_core{},
cpu_manager{system}, reporter{system}, applet_manager{system}, time_manager{system} {}
SystemResultStatus Run() {
@@ -324,8 +325,8 @@ struct System::Impl {
time_manager.Shutdown();
core_timing.Shutdown();
app_loader.reset();
perf_stats.reset();
gpu_core.reset();
perf_stats.reset();
kernel.Shutdown();
memory.Reset();
applet_manager.ClearAll();
@@ -349,7 +350,7 @@ struct System::Impl {
}
Service::Glue::ApplicationLaunchProperty launch{};
launch.title_id = process.GetTitleID();
launch.title_id = process.GetProgramID();
FileSys::PatchManager pm{launch.title_id, fs_controller, *content_provider};
launch.version = pm.GetGameVersion().value_or(0);
@@ -391,6 +392,7 @@ struct System::Impl {
std::unique_ptr<Hardware::InterruptManager> interrupt_manager;
std::unique_ptr<Core::DeviceMemory> device_memory;
Core::Memory::Memory memory;
Core::HID::HIDCore hid_core;
CpuManager cpu_manager;
std::atomic_bool is_powered_on{};
bool exit_lock = false;
@@ -615,6 +617,14 @@ const Kernel::KernelCore& System::Kernel() const {
return impl->kernel;
}
HID::HIDCore& System::HIDCore() {
return impl->hid_core;
}
const HID::HIDCore& System::HIDCore() const {
return impl->hid_core;
}
Timing::CoreTiming& System::CoreTiming() {
return impl->core_timing;
}
@@ -639,6 +649,10 @@ const Core::SpeedLimiter& System::SpeedLimiter() const {
return impl->speed_limiter;
}
u64 System::GetCurrentProcessProgramID() const {
return impl->kernel.CurrentProcess()->GetProgramID();
}
Loader::ResultStatus System::GetGameName(std::string& out) const {
return impl->GetGameName(out);
}
@@ -821,8 +835,6 @@ void System::ApplySettings() {
if (IsPoweredOn()) {
Renderer().RefreshBaseSettings();
}
Service::HID::ReloadInputDevices();
}
} // namespace Core

View File

@@ -89,6 +89,10 @@ namespace Core::Hardware {
class InterruptManager;
}
namespace Core::HID {
class HIDCore;
}
namespace Core {
class ARM_Interface;
@@ -285,6 +289,12 @@ public:
/// Provides a constant reference to the kernel instance.
[[nodiscard]] const Kernel::KernelCore& Kernel() const;
/// Gets a mutable reference to the HID interface.
[[nodiscard]] HID::HIDCore& HIDCore();
/// Gets an immutable reference to the HID interface.
[[nodiscard]] const HID::HIDCore& HIDCore() const;
/// Provides a reference to the internal PerfStats instance.
[[nodiscard]] Core::PerfStats& GetPerfStats();
@@ -297,6 +307,8 @@ public:
/// Provides a constant reference to the speed limiter
[[nodiscard]] const Core::SpeedLimiter& SpeedLimiter() const;
[[nodiscard]] u64 GetCurrentProcessProgramID() const;
/// Gets the name of the current game
[[nodiscard]] Loader::ResultStatus GetGameName(std::string& out) const;

View File

@@ -53,13 +53,16 @@ Loader::ResultStatus ProgramMetadata::Load(VirtualFile file) {
}
/*static*/ ProgramMetadata ProgramMetadata::GetDefault() {
// Allow use of cores 0~3 and thread priorities 1~63.
constexpr u32 default_thread_info_capability = 0x30007F7;
ProgramMetadata result;
result.LoadManual(
true /*is_64_bit*/, FileSys::ProgramAddressSpaceType::Is39Bit /*address_space*/,
0x2c /*main_thread_prio*/, 0 /*main_thread_core*/, 0x00100000 /*main_thread_stack_size*/,
0 /*title_id*/, 0xFFFFFFFFFFFFFFFF /*filesystem_permissions*/,
0x1FE00000 /*system_resource_size*/, {} /*capabilities*/);
0x1FE00000 /*system_resource_size*/, {default_thread_info_capability} /*capabilities*/);
return result;
}

View File

@@ -9,7 +9,6 @@
#include "core/core.h"
#include "core/file_sys/savedata_factory.h"
#include "core/file_sys/vfs.h"
#include "core/hle/kernel/k_process.h"
namespace FileSys {
@@ -143,7 +142,7 @@ std::string SaveDataFactory::GetFullPath(Core::System& system, SaveDataSpaceId s
// be interpreted as the title id of the current process.
if (type == SaveDataType::SaveData || type == SaveDataType::DeviceSaveData) {
if (title_id == 0) {
title_id = system.CurrentProcess()->GetTitleID();
title_id = system.GetCurrentProcessProgramID();
}
}

View File

@@ -5,16 +5,15 @@
#include "common/assert.h"
#include "common/logging/log.h"
#include "core/frontend/applets/controller.h"
#include "core/hle/service/hid/controllers/npad.h"
#include "core/hle/service/hid/hid.h"
#include "core/hle/service/sm/sm.h"
#include "core/hid/emulated_controller.h"
#include "core/hid/hid_core.h"
#include "core/hid/hid_types.h"
namespace Core::Frontend {
ControllerApplet::~ControllerApplet() = default;
DefaultControllerApplet::DefaultControllerApplet(Service::SM::ServiceManager& service_manager_)
: service_manager{service_manager_} {}
DefaultControllerApplet::DefaultControllerApplet(HID::HIDCore& hid_core_) : hid_core{hid_core_} {}
DefaultControllerApplet::~DefaultControllerApplet() = default;
@@ -22,24 +21,20 @@ void DefaultControllerApplet::ReconfigureControllers(std::function<void()> callb
const ControllerParameters& parameters) const {
LOG_INFO(Service_HID, "called, deducing the best configuration based on the given parameters!");
auto& npad =
service_manager.GetService<Service::HID::Hid>("hid")
->GetAppletResource()
->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad);
auto& players = Settings::values.players.GetValue();
const std::size_t min_supported_players =
parameters.enable_single_mode ? 1 : parameters.min_players;
// Disconnect Handheld first.
npad.DisconnectNpadAtIndex(8);
auto* handheld = hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld);
handheld->Disconnect();
// Deduce the best configuration based on the input parameters.
for (std::size_t index = 0; index < players.size() - 2; ++index) {
for (std::size_t index = 0; index < hid_core.available_controllers - 2; ++index) {
auto* controller = hid_core.GetEmulatedControllerByIndex(index);
// First, disconnect all controllers regardless of the value of keep_controllers_connected.
// This makes it easy to connect the desired controllers.
npad.DisconnectNpadAtIndex(index);
controller->Disconnect();
// Only connect the minimum number of required players.
if (index >= min_supported_players) {
@@ -49,27 +44,27 @@ void DefaultControllerApplet::ReconfigureControllers(std::function<void()> callb
// Connect controllers based on the following priority list from highest to lowest priority:
// Pro Controller -> Dual Joycons -> Left Joycon/Right Joycon -> Handheld
if (parameters.allow_pro_controller) {
npad.AddNewControllerAt(
npad.MapSettingsTypeToNPad(Settings::ControllerType::ProController), index);
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController);
controller->Connect();
} else if (parameters.allow_dual_joycons) {
npad.AddNewControllerAt(
npad.MapSettingsTypeToNPad(Settings::ControllerType::DualJoyconDetached), index);
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconDual);
controller->Connect();
} else if (parameters.allow_left_joycon && parameters.allow_right_joycon) {
// Assign left joycons to even player indices and right joycons to odd player indices.
// We do this since Captain Toad Treasure Tracker expects a left joycon for Player 1 and
// a right Joycon for Player 2 in 2 Player Assist mode.
if (index % 2 == 0) {
npad.AddNewControllerAt(
npad.MapSettingsTypeToNPad(Settings::ControllerType::LeftJoycon), index);
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconLeft);
controller->Connect();
} else {
npad.AddNewControllerAt(
npad.MapSettingsTypeToNPad(Settings::ControllerType::RightJoycon), index);
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconRight);
controller->Connect();
}
} else if (index == 0 && parameters.enable_single_mode && parameters.allow_handheld &&
!Settings::values.use_docked_mode.GetValue()) {
// We should *never* reach here under any normal circumstances.
npad.AddNewControllerAt(npad.MapSettingsTypeToNPad(Settings::ControllerType::Handheld),
index);
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Handheld);
controller->Connect();
} else {
UNREACHABLE_MSG("Unable to add a new controller based on the given parameters!");
}

View File

@@ -8,8 +8,8 @@
#include "common/common_types.h"
namespace Service::SM {
class ServiceManager;
namespace Core::HID {
class HIDCore;
}
namespace Core::Frontend {
@@ -44,14 +44,14 @@ public:
class DefaultControllerApplet final : public ControllerApplet {
public:
explicit DefaultControllerApplet(Service::SM::ServiceManager& service_manager_);
explicit DefaultControllerApplet(HID::HIDCore& hid_core_);
~DefaultControllerApplet() override;
void ReconfigureControllers(std::function<void()> callback,
const ControllerParameters& parameters) const override;
private:
Service::SM::ServiceManager& service_manager;
HID::HIDCore& hid_core;
};
} // namespace Core::Frontend

View File

@@ -16,7 +16,8 @@ DefaultSoftwareKeyboardApplet::~DefaultSoftwareKeyboardApplet() = default;
void DefaultSoftwareKeyboardApplet::InitializeKeyboard(
bool is_inline, KeyboardInitializeParameters initialize_parameters,
std::function<void(Service::AM::Applets::SwkbdResult, std::u16string)> submit_normal_callback_,
std::function<void(Service::AM::Applets::SwkbdResult, std::u16string, bool)>
submit_normal_callback_,
std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)>
submit_inline_callback_) {
if (is_inline) {
@@ -128,7 +129,7 @@ void DefaultSoftwareKeyboardApplet::ExitKeyboard() const {
}
void DefaultSoftwareKeyboardApplet::SubmitNormalText(std::u16string text) const {
submit_normal_callback(Service::AM::Applets::SwkbdResult::Ok, text);
submit_normal_callback(Service::AM::Applets::SwkbdResult::Ok, text, true);
}
void DefaultSoftwareKeyboardApplet::SubmitInlineText(std::u16string_view text) const {

View File

@@ -57,7 +57,7 @@ public:
virtual void InitializeKeyboard(
bool is_inline, KeyboardInitializeParameters initialize_parameters,
std::function<void(Service::AM::Applets::SwkbdResult, std::u16string)>
std::function<void(Service::AM::Applets::SwkbdResult, std::u16string, bool)>
submit_normal_callback_,
std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)>
submit_inline_callback_) = 0;
@@ -82,7 +82,7 @@ public:
void InitializeKeyboard(
bool is_inline, KeyboardInitializeParameters initialize_parameters,
std::function<void(Service::AM::Applets::SwkbdResult, std::u16string)>
std::function<void(Service::AM::Applets::SwkbdResult, std::u16string, bool)>
submit_normal_callback_,
std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)>
submit_inline_callback_) override;
@@ -106,7 +106,7 @@ private:
KeyboardInitializeParameters parameters;
mutable std::function<void(Service::AM::Applets::SwkbdResult, std::u16string)>
mutable std::function<void(Service::AM::Applets::SwkbdResult, std::u16string, bool)>
submit_normal_callback;
mutable std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)>
submit_inline_callback;

View File

@@ -3,66 +3,31 @@
// Refer to the license.txt file included.
#include <mutex>
#include "common/settings.h"
#include "core/frontend/emu_window.h"
#include "core/frontend/input.h"
namespace Core::Frontend {
GraphicsContext::~GraphicsContext() = default;
class EmuWindow::TouchState : public Input::Factory<Input::TouchDevice>,
public std::enable_shared_from_this<TouchState> {
public:
std::unique_ptr<Input::TouchDevice> Create(const Common::ParamPackage&) override {
return std::make_unique<Device>(shared_from_this());
}
std::mutex mutex;
Input::TouchStatus status;
private:
class Device : public Input::TouchDevice {
public:
explicit Device(std::weak_ptr<TouchState>&& touch_state_) : touch_state(touch_state_) {}
Input::TouchStatus GetStatus() const override {
if (auto state = touch_state.lock()) {
std::lock_guard guard{state->mutex};
return state->status;
}
return {};
}
private:
std::weak_ptr<TouchState> touch_state;
};
};
EmuWindow::EmuWindow() {
// TODO: Find a better place to set this.
config.min_client_area_size =
std::make_pair(Layout::MinimumSize::Width, Layout::MinimumSize::Height);
active_config = config;
touch_state = std::make_shared<TouchState>();
Input::RegisterFactory<Input::TouchDevice>("emu_window", touch_state);
}
EmuWindow::~EmuWindow() {
Input::UnregisterFactory<Input::TouchDevice>("emu_window");
}
EmuWindow::~EmuWindow() {}
/**
* Check if the given x/y coordinates are within the touchpad specified by the framebuffer layout
* @param layout FramebufferLayout object describing the framebuffer size and screen positions
* @param framebuffer_x Framebuffer x-coordinate to check
* @param framebuffer_y Framebuffer y-coordinate to check
* @return True if the coordinates are within the touchpad, otherwise false
*/
static bool IsWithinTouchscreen(const Layout::FramebufferLayout& layout, u32 framebuffer_x,
u32 framebuffer_y) {
return (framebuffer_y >= layout.screen.top && framebuffer_y < layout.screen.bottom &&
framebuffer_x >= layout.screen.left && framebuffer_x < layout.screen.right);
std::pair<f32, f32> EmuWindow::MapToTouchScreen(u32 framebuffer_x, u32 framebuffer_y) const {
std::tie(framebuffer_x, framebuffer_y) = ClipToTouchScreen(framebuffer_x, framebuffer_y);
const float x =
static_cast<float>(framebuffer_x - framebuffer_layout.screen.left) /
static_cast<float>(framebuffer_layout.screen.right - framebuffer_layout.screen.left);
const float y =
static_cast<float>(framebuffer_y - framebuffer_layout.screen.top) /
static_cast<float>(framebuffer_layout.screen.bottom - framebuffer_layout.screen.top);
return std::make_pair(x, y);
}
std::pair<u32, u32> EmuWindow::ClipToTouchScreen(u32 new_x, u32 new_y) const {
@@ -75,49 +40,6 @@ std::pair<u32, u32> EmuWindow::ClipToTouchScreen(u32 new_x, u32 new_y) const {
return std::make_pair(new_x, new_y);
}
void EmuWindow::TouchPressed(u32 framebuffer_x, u32 framebuffer_y, size_t id) {
if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y)) {
return;
}
if (id >= touch_state->status.size()) {
return;
}
std::lock_guard guard{touch_state->mutex};
const float x =
static_cast<float>(framebuffer_x - framebuffer_layout.screen.left) /
static_cast<float>(framebuffer_layout.screen.right - framebuffer_layout.screen.left);
const float y =
static_cast<float>(framebuffer_y - framebuffer_layout.screen.top) /
static_cast<float>(framebuffer_layout.screen.bottom - framebuffer_layout.screen.top);
touch_state->status[id] = std::make_tuple(x, y, true);
}
void EmuWindow::TouchReleased(size_t id) {
if (id >= touch_state->status.size()) {
return;
}
std::lock_guard guard{touch_state->mutex};
touch_state->status[id] = std::make_tuple(0.0f, 0.0f, false);
}
void EmuWindow::TouchMoved(u32 framebuffer_x, u32 framebuffer_y, size_t id) {
if (id >= touch_state->status.size()) {
return;
}
if (!std::get<2>(touch_state->status[id])) {
return;
}
if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y)) {
std::tie(framebuffer_x, framebuffer_y) = ClipToTouchScreen(framebuffer_x, framebuffer_y);
}
TouchPressed(framebuffer_x, framebuffer_y, id);
}
void EmuWindow::UpdateCurrentFramebufferLayout(u32 width, u32 height) {
NotifyFramebufferLayoutChanged(Layout::DefaultFrameLayout(width, height));
}

View File

@@ -112,28 +112,6 @@ public:
/// Returns if window is shown (not minimized)
virtual bool IsShown() const = 0;
/**
* Signal that a touch pressed event has occurred (e.g. mouse click pressed)
* @param framebuffer_x Framebuffer x-coordinate that was pressed
* @param framebuffer_y Framebuffer y-coordinate that was pressed
* @param id Touch event ID
*/
void TouchPressed(u32 framebuffer_x, u32 framebuffer_y, size_t id);
/**
* Signal that a touch released event has occurred (e.g. mouse click released)
* @param id Touch event ID
*/
void TouchReleased(size_t id);
/**
* Signal that a touch movement event has occurred (e.g. mouse was moved over the emu window)
* @param framebuffer_x Framebuffer x-coordinate
* @param framebuffer_y Framebuffer y-coordinate
* @param id Touch event ID
*/
void TouchMoved(u32 framebuffer_x, u32 framebuffer_y, size_t id);
/**
* Returns currently active configuration.
* @note Accesses to the returned object need not be consistent because it may be modified in
@@ -212,6 +190,11 @@ protected:
client_area_height = size.second;
}
/**
* Converts a screen postion into the equivalent touchscreen position.
*/
std::pair<f32, f32> MapToTouchScreen(u32 framebuffer_x, u32 framebuffer_y) const;
WindowSystemInfo window_info;
private:
@@ -237,9 +220,6 @@ private:
WindowConfig config; ///< Internal configuration (changes pending for being applied in
/// ProcessConfigurationChanges)
WindowConfig active_config; ///< Internal active configuration
class TouchState;
std::shared_ptr<TouchState> touch_state;
};
} // namespace Core::Frontend

View File

@@ -25,7 +25,12 @@ FramebufferLayout DefaultFrameLayout(u32 width, u32 height) {
ASSERT(height > 0);
// The drawing code needs at least somewhat valid values for both screens
// so just calculate them both even if the other isn't showing.
FramebufferLayout res{width, height, false, {}};
FramebufferLayout res{
.width = width,
.height = height,
.screen = {},
.is_srgb = false,
};
const float window_aspect_ratio = static_cast<float>(height) / static_cast<float>(width);
const float emulation_aspect_ratio = EmulationAspectRatio(
@@ -44,16 +49,13 @@ FramebufferLayout DefaultFrameLayout(u32 width, u32 height) {
return res;
}
FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale) {
u32 width, height;
FramebufferLayout FrameLayoutFromResolutionScale(f32 res_scale) {
const bool is_docked = Settings::values.use_docked_mode.GetValue();
const u32 screen_width = is_docked ? ScreenDocked::Width : ScreenUndocked::Width;
const u32 screen_height = is_docked ? ScreenDocked::Height : ScreenUndocked::Height;
if (Settings::values.use_docked_mode.GetValue()) {
width = ScreenDocked::Width * res_scale;
height = ScreenDocked::Height * res_scale;
} else {
width = ScreenUndocked::Width * res_scale;
height = ScreenUndocked::Height * res_scale;
}
const u32 width = static_cast<u32>(static_cast<f32>(screen_width) * res_scale);
const u32 height = static_cast<u32>(static_cast<f32>(screen_height) * res_scale);
return DefaultFrameLayout(width, height);
}

View File

@@ -35,17 +35,8 @@ enum class AspectRatio {
struct FramebufferLayout {
u32 width{ScreenUndocked::Width};
u32 height{ScreenUndocked::Height};
bool is_srgb{};
Common::Rectangle<u32> screen;
/**
* Returns the ration of pixel size of the screen, compared to the native size of the undocked
* Switch screen.
*/
float GetScalingRatio() const {
return static_cast<float>(screen.GetWidth()) / ScreenUndocked::Width;
}
bool is_srgb{};
};
/**
@@ -60,7 +51,7 @@ FramebufferLayout DefaultFrameLayout(u32 width, u32 height);
* Convenience method to get frame layout by resolution scale
* @param res_scale resolution scale factor
*/
FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale);
FramebufferLayout FrameLayoutFromResolutionScale(f32 res_scale);
/**
* Convenience method to determine emulation aspect ratio

View File

@@ -1,217 +0,0 @@
// Copyright 2017 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <functional>
#include <memory>
#include <string>
#include <tuple>
#include <unordered_map>
#include <utility>
#include "common/logging/log.h"
#include "common/param_package.h"
#include "common/quaternion.h"
#include "common/vector_math.h"
namespace Input {
enum class AnalogDirection : u8 {
RIGHT,
LEFT,
UP,
DOWN,
};
struct AnalogProperties {
float deadzone;
float range;
float threshold;
};
template <typename StatusType>
struct InputCallback {
std::function<void(StatusType)> on_change;
};
/// An abstract class template for an input device (a button, an analog input, etc.).
template <typename StatusType>
class InputDevice {
public:
virtual ~InputDevice() = default;
virtual StatusType GetStatus() const {
return {};
}
virtual StatusType GetRawStatus() const {
return GetStatus();
}
virtual AnalogProperties GetAnalogProperties() const {
return {};
}
virtual bool GetAnalogDirectionStatus([[maybe_unused]] AnalogDirection direction) const {
return {};
}
virtual bool SetRumblePlay([[maybe_unused]] f32 amp_low, [[maybe_unused]] f32 freq_low,
[[maybe_unused]] f32 amp_high,
[[maybe_unused]] f32 freq_high) const {
return {};
}
void SetCallback(InputCallback<StatusType> callback_) {
callback = std::move(callback_);
}
void TriggerOnChange() {
if (callback.on_change) {
callback.on_change(GetStatus());
}
}
private:
InputCallback<StatusType> callback;
};
/// An abstract class template for a factory that can create input devices.
template <typename InputDeviceType>
class Factory {
public:
virtual ~Factory() = default;
virtual std::unique_ptr<InputDeviceType> Create(const Common::ParamPackage&) = 0;
};
namespace Impl {
template <typename InputDeviceType>
using FactoryListType = std::unordered_map<std::string, std::shared_ptr<Factory<InputDeviceType>>>;
template <typename InputDeviceType>
struct FactoryList {
static FactoryListType<InputDeviceType> list;
};
template <typename InputDeviceType>
FactoryListType<InputDeviceType> FactoryList<InputDeviceType>::list;
} // namespace Impl
/**
* Registers an input device factory.
* @tparam InputDeviceType the type of input devices the factory can create
* @param name the name of the factory. Will be used to match the "engine" parameter when creating
* a device
* @param factory the factory object to register
*/
template <typename InputDeviceType>
void RegisterFactory(const std::string& name, std::shared_ptr<Factory<InputDeviceType>> factory) {
auto pair = std::make_pair(name, std::move(factory));
if (!Impl::FactoryList<InputDeviceType>::list.insert(std::move(pair)).second) {
LOG_ERROR(Input, "Factory '{}' already registered", name);
}
}
/**
* Unregisters an input device factory.
* @tparam InputDeviceType the type of input devices the factory can create
* @param name the name of the factory to unregister
*/
template <typename InputDeviceType>
void UnregisterFactory(const std::string& name) {
if (Impl::FactoryList<InputDeviceType>::list.erase(name) == 0) {
LOG_ERROR(Input, "Factory '{}' not registered", name);
}
}
/**
* Create an input device from given paramters.
* @tparam InputDeviceType the type of input devices to create
* @param params a serialized ParamPackage string contains all parameters for creating the device
*/
template <typename InputDeviceType>
std::unique_ptr<InputDeviceType> CreateDevice(const std::string& params) {
const Common::ParamPackage package(params);
const std::string engine = package.Get("engine", "null");
const auto& factory_list = Impl::FactoryList<InputDeviceType>::list;
const auto pair = factory_list.find(engine);
if (pair == factory_list.end()) {
if (engine != "null") {
LOG_ERROR(Input, "Unknown engine name: {}", engine);
}
return std::make_unique<InputDeviceType>();
}
return pair->second->Create(package);
}
/**
* A button device is an input device that returns bool as status.
* true for pressed; false for released.
*/
using ButtonDevice = InputDevice<bool>;
/**
* An analog device is an input device that returns a tuple of x and y coordinates as status. The
* coordinates are within the unit circle. x+ is defined as right direction, and y+ is defined as up
* direction
*/
using AnalogDevice = InputDevice<std::tuple<float, float>>;
/**
* A vibration device is an input device that returns an unsigned byte as status.
* It represents whether the vibration device supports vibration or not.
* If the status returns 1, it supports vibration. Otherwise, it does not support vibration.
*/
using VibrationDevice = InputDevice<u8>;
/**
* A motion status is an object that returns a tuple of accelerometer state vector,
* gyroscope state vector, rotation state vector, orientation state matrix and quaterion state
* vector.
*
* For both 3D vectors:
* x+ is the same direction as RIGHT on D-pad.
* y+ is normal to the touch screen, pointing outward.
* z+ is the same direction as UP on D-pad.
*
* For accelerometer state vector
* Units: g (gravitational acceleration)
*
* For gyroscope state vector:
* Orientation is determined by right-hand rule.
* Units: deg/sec
*
* For rotation state vector
* Units: rotations
*
* For orientation state matrix
* x vector
* y vector
* z vector
*
* For quaternion state vector
* xyz vector
* w float
*/
using MotionStatus = std::tuple<Common::Vec3<float>, Common::Vec3<float>, Common::Vec3<float>,
std::array<Common::Vec3f, 3>, Common::Quaternion<f32>>;
/**
* A motion device is an input device that returns a motion status object
*/
using MotionDevice = InputDevice<MotionStatus>;
/**
* A touch status is an object that returns an array of 16 tuple elements of two floats and a bool.
* The floats are x and y coordinates in the range 0.0 - 1.0, and the bool indicates whether it is
* pressed.
*/
using TouchStatus = std::array<std::tuple<float, float, bool>, 16>;
/**
* A touch device is an input device that returns a touch status object
*/
using TouchDevice = InputDevice<TouchStatus>;
/**
* A mouse device is an input device that returns a tuple of two floats and four ints.
* The first two floats are X and Y device coordinates of the mouse (from 0-1).
* The s32s are the mouse wheel.
*/
using MouseDevice = InputDevice<std::tuple<float, float, s32, s32>>;
} // namespace Input

View File

@@ -0,0 +1,229 @@
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included
#include "common/settings.h"
#include "core/hid/emulated_console.h"
#include "core/hid/input_converter.h"
namespace Core::HID {
EmulatedConsole::EmulatedConsole() = default;
EmulatedConsole::~EmulatedConsole() = default;
void EmulatedConsole::ReloadFromSettings() {
// Using first motion device from player 1. No need to assign any unique config at the moment
const auto& player = Settings::values.players.GetValue()[0];
motion_params = Common::ParamPackage(player.motions[0]);
ReloadInput();
}
void EmulatedConsole::SetTouchParams() {
// TODO(german77): Support any number of fingers
std::size_t index = 0;
// Hardcode mouse, touchscreen and cemuhook parameters
if (!Settings::values.mouse_enabled) {
// We can't use mouse as touch if native mouse is enabled
touch_params[index++] = Common::ParamPackage{"engine:mouse,axis_x:10,axis_y:11,button:0"};
}
touch_params[index++] = Common::ParamPackage{"engine:touch,axis_x:0,axis_y:1,button:0"};
touch_params[index++] = Common::ParamPackage{"engine:touch,axis_x:2,axis_y:3,button:1"};
touch_params[index++] =
Common::ParamPackage{"engine:cemuhookudp,axis_x:17,axis_y:18,button:65536"};
touch_params[index++] =
Common::ParamPackage{"engine:cemuhookudp,axis_x:19,axis_y:20,button:131072"};
const auto button_index =
static_cast<u64>(Settings::values.touch_from_button_map_index.GetValue());
const auto& touch_buttons = Settings::values.touch_from_button_maps[button_index].buttons;
// Map the rest of the fingers from touch from button configuration
for (const auto& config_entry : touch_buttons) {
if (index >= touch_params.size()) {
continue;
}
Common::ParamPackage params{config_entry};
Common::ParamPackage touch_button_params;
const int x = params.Get("x", 0);
const int y = params.Get("y", 0);
params.Erase("x");
params.Erase("y");
touch_button_params.Set("engine", "touch_from_button");
touch_button_params.Set("button", params.Serialize());
touch_button_params.Set("x", x);
touch_button_params.Set("y", y);
touch_button_params.Set("touch_id", static_cast<int>(index));
touch_params[index] = touch_button_params;
index++;
}
}
void EmulatedConsole::ReloadInput() {
// If you load any device here add the equivalent to the UnloadInput() function
SetTouchParams();
motion_devices = Common::Input::CreateDevice<Common::Input::InputDevice>(motion_params);
if (motion_devices) {
Common::Input::InputCallback motion_callback{
[this](Common::Input::CallbackStatus callback) { SetMotion(callback); }};
motion_devices->SetCallback(motion_callback);
}
// Unique index for identifying touch device source
std::size_t index = 0;
for (auto& touch_device : touch_devices) {
touch_device = Common::Input::CreateDevice<Common::Input::InputDevice>(touch_params[index]);
if (!touch_device) {
continue;
}
Common::Input::InputCallback touch_callback{
[this, index](Common::Input::CallbackStatus callback) { SetTouch(callback, index); }};
touch_device->SetCallback(touch_callback);
index++;
}
}
void EmulatedConsole::UnloadInput() {
motion_devices.reset();
for (auto& touch : touch_devices) {
touch.reset();
}
}
void EmulatedConsole::EnableConfiguration() {
is_configuring = true;
SaveCurrentConfig();
}
void EmulatedConsole::DisableConfiguration() {
is_configuring = false;
}
bool EmulatedConsole::IsConfiguring() const {
return is_configuring;
}
void EmulatedConsole::SaveCurrentConfig() {
if (!is_configuring) {
return;
}
}
void EmulatedConsole::RestoreConfig() {
if (!is_configuring) {
return;
}
ReloadFromSettings();
}
Common::ParamPackage EmulatedConsole::GetMotionParam() const {
return motion_params;
}
void EmulatedConsole::SetMotionParam(Common::ParamPackage param) {
motion_params = param;
ReloadInput();
}
void EmulatedConsole::SetMotion(Common::Input::CallbackStatus callback) {
std::lock_guard lock{mutex};
auto& raw_status = console.motion_values.raw_status;
auto& emulated = console.motion_values.emulated;
raw_status = TransformToMotion(callback);
emulated.SetAcceleration(Common::Vec3f{
raw_status.accel.x.value,
raw_status.accel.y.value,
raw_status.accel.z.value,
});
emulated.SetGyroscope(Common::Vec3f{
raw_status.gyro.x.value,
raw_status.gyro.y.value,
raw_status.gyro.z.value,
});
emulated.UpdateRotation(raw_status.delta_timestamp);
emulated.UpdateOrientation(raw_status.delta_timestamp);
if (is_configuring) {
TriggerOnChange(ConsoleTriggerType::Motion);
return;
}
auto& motion = console.motion_state;
motion.accel = emulated.GetAcceleration();
motion.gyro = emulated.GetGyroscope();
motion.rotation = emulated.GetGyroscope();
motion.orientation = emulated.GetOrientation();
motion.quaternion = emulated.GetQuaternion();
motion.is_at_rest = !emulated.IsMoving(motion_sensitivity);
TriggerOnChange(ConsoleTriggerType::Motion);
}
void EmulatedConsole::SetTouch(Common::Input::CallbackStatus callback,
[[maybe_unused]] std::size_t index) {
if (index >= console.touch_values.size()) {
return;
}
std::lock_guard lock{mutex};
console.touch_values[index] = TransformToTouch(callback);
if (is_configuring) {
TriggerOnChange(ConsoleTriggerType::Touch);
return;
}
// TODO(german77): Remap touch id in sequential order
console.touch_state[index] = {
.position = {console.touch_values[index].x.value, console.touch_values[index].y.value},
.id = static_cast<u32>(console.touch_values[index].id),
.pressed = console.touch_values[index].pressed.value,
};
TriggerOnChange(ConsoleTriggerType::Touch);
}
ConsoleMotionValues EmulatedConsole::GetMotionValues() const {
return console.motion_values;
}
TouchValues EmulatedConsole::GetTouchValues() const {
return console.touch_values;
}
ConsoleMotion EmulatedConsole::GetMotion() const {
return console.motion_state;
}
TouchFingerState EmulatedConsole::GetTouch() const {
return console.touch_state;
}
void EmulatedConsole::TriggerOnChange(ConsoleTriggerType type) {
for (const auto& poller_pair : callback_list) {
const ConsoleUpdateCallback& poller = poller_pair.second;
if (poller.on_change) {
poller.on_change(type);
}
}
}
int EmulatedConsole::SetCallback(ConsoleUpdateCallback update_callback) {
std::lock_guard lock{mutex};
callback_list.insert_or_assign(last_callback_key, update_callback);
return last_callback_key++;
}
void EmulatedConsole::DeleteCallback(int key) {
std::lock_guard lock{mutex};
const auto& iterator = callback_list.find(key);
if (iterator == callback_list.end()) {
LOG_ERROR(Input, "Tried to delete non-existent callback {}", key);
return;
}
callback_list.erase(iterator);
}
} // namespace Core::HID

View File

@@ -0,0 +1,190 @@
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <array>
#include <functional>
#include <memory>
#include <mutex>
#include <unordered_map>
#include "common/common_types.h"
#include "common/input.h"
#include "common/param_package.h"
#include "common/point.h"
#include "common/quaternion.h"
#include "common/vector_math.h"
#include "core/hid/hid_types.h"
#include "core/hid/motion_input.h"
namespace Core::HID {
struct ConsoleMotionInfo {
Common::Input::MotionStatus raw_status{};
MotionInput emulated{};
};
using ConsoleMotionDevices = std::unique_ptr<Common::Input::InputDevice>;
using TouchDevices = std::array<std::unique_ptr<Common::Input::InputDevice>, 16>;
using ConsoleMotionParams = Common::ParamPackage;
using TouchParams = std::array<Common::ParamPackage, 16>;
using ConsoleMotionValues = ConsoleMotionInfo;
using TouchValues = std::array<Common::Input::TouchStatus, 16>;
struct TouchFinger {
u64 last_touch{};
Common::Point<float> position{};
u32 id{};
TouchAttribute attribute{};
bool pressed{};
};
// Contains all motion related data that is used on the services
struct ConsoleMotion {
Common::Vec3f accel{};
Common::Vec3f gyro{};
Common::Vec3f rotation{};
std::array<Common::Vec3f, 3> orientation{};
Common::Quaternion<f32> quaternion{};
bool is_at_rest{};
};
using TouchFingerState = std::array<TouchFinger, 16>;
struct ConsoleStatus {
// Data from input_common
ConsoleMotionValues motion_values{};
TouchValues touch_values{};
// Data for HID services
ConsoleMotion motion_state{};
TouchFingerState touch_state{};
};
enum class ConsoleTriggerType {
Motion,
Touch,
All,
};
struct ConsoleUpdateCallback {
std::function<void(ConsoleTriggerType)> on_change;
};
class EmulatedConsole {
public:
/**
* Contains all input data within the emulated switch console tablet such as touch and motion
*/
explicit EmulatedConsole();
~EmulatedConsole();
YUZU_NON_COPYABLE(EmulatedConsole);
YUZU_NON_MOVEABLE(EmulatedConsole);
/// Removes all callbacks created from input devices
void UnloadInput();
/**
* Sets the emulated console into configuring mode
* This prevents the modification of the HID state of the emulated console by input commands
*/
void EnableConfiguration();
/// Returns the emulated console into normal mode, allowing the modification of the HID state
void DisableConfiguration();
/// Returns true if the emulated console is in configuring mode
bool IsConfiguring() const;
/// Reload all input devices
void ReloadInput();
/// Overrides current mapped devices with the stored configuration and reloads all input devices
void ReloadFromSettings();
/// Saves the current mapped configuration
void SaveCurrentConfig();
/// Reverts any mapped changes made that weren't saved
void RestoreConfig();
// Returns the current mapped motion device
Common::ParamPackage GetMotionParam() const;
/**
* Updates the current mapped motion device
* @param param ParamPackage with controller data to be mapped
*/
void SetMotionParam(Common::ParamPackage param);
/// Returns the latest status of motion input from the console with parameters
ConsoleMotionValues GetMotionValues() const;
/// Returns the latest status of touch input from the console with parameters
TouchValues GetTouchValues() const;
/// Returns the latest status of motion input from the console
ConsoleMotion GetMotion() const;
/// Returns the latest status of touch input from the console
TouchFingerState GetTouch() const;
/**
* Adds a callback to the list of events
* @param update_callback A ConsoleUpdateCallback that will be triggered
* @return an unique key corresponding to the callback index in the list
*/
int SetCallback(ConsoleUpdateCallback update_callback);
/**
* Removes a callback from the list stopping any future events to this object
* @param key Key corresponding to the callback index in the list
*/
void DeleteCallback(int key);
private:
/// Creates and stores the touch params
void SetTouchParams();
/**
* Updates the motion status of the console
* @param callback A CallbackStatus containing gyro and accelerometer data
*/
void SetMotion(Common::Input::CallbackStatus callback);
/**
* Updates the touch status of the console
* @param callback A CallbackStatus containing the touch position
* @param index Finger ID to be updated
*/
void SetTouch(Common::Input::CallbackStatus callback, std::size_t index);
/**
* Triggers a callback that something has changed on the console status
* @param type Input type of the event to trigger
*/
void TriggerOnChange(ConsoleTriggerType type);
bool is_configuring{false};
f32 motion_sensitivity{0.01f};
ConsoleMotionParams motion_params;
TouchParams touch_params;
ConsoleMotionDevices motion_devices;
TouchDevices touch_devices;
mutable std::mutex mutex;
std::unordered_map<int, ConsoleUpdateCallback> callback_list;
int last_callback_key = 0;
// Stores the current status of all console input
ConsoleStatus console;
};
} // namespace Core::HID

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,394 @@
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <array>
#include <functional>
#include <memory>
#include <mutex>
#include <unordered_map>
#include "common/common_types.h"
#include "common/input.h"
#include "common/param_package.h"
#include "common/point.h"
#include "common/quaternion.h"
#include "common/settings.h"
#include "common/vector_math.h"
#include "core/hid/hid_types.h"
#include "core/hid/motion_input.h"
namespace Core::HID {
const std::size_t max_emulated_controllers = 2;
struct ControllerMotionInfo {
Common::Input::MotionStatus raw_status{};
MotionInput emulated{};
};
using ButtonDevices =
std::array<std::unique_ptr<Common::Input::InputDevice>, Settings::NativeButton::NumButtons>;
using StickDevices =
std::array<std::unique_ptr<Common::Input::InputDevice>, Settings::NativeAnalog::NumAnalogs>;
using ControllerMotionDevices =
std::array<std::unique_ptr<Common::Input::InputDevice>, Settings::NativeMotion::NumMotions>;
using TriggerDevices =
std::array<std::unique_ptr<Common::Input::InputDevice>, Settings::NativeTrigger::NumTriggers>;
using BatteryDevices =
std::array<std::unique_ptr<Common::Input::InputDevice>, max_emulated_controllers>;
using OutputDevices =
std::array<std::unique_ptr<Common::Input::OutputDevice>, max_emulated_controllers>;
using ButtonParams = std::array<Common::ParamPackage, Settings::NativeButton::NumButtons>;
using StickParams = std::array<Common::ParamPackage, Settings::NativeAnalog::NumAnalogs>;
using ControllerMotionParams = std::array<Common::ParamPackage, Settings::NativeMotion::NumMotions>;
using TriggerParams = std::array<Common::ParamPackage, Settings::NativeTrigger::NumTriggers>;
using BatteryParams = std::array<Common::ParamPackage, max_emulated_controllers>;
using OutputParams = std::array<Common::ParamPackage, max_emulated_controllers>;
using ButtonValues = std::array<Common::Input::ButtonStatus, Settings::NativeButton::NumButtons>;
using SticksValues = std::array<Common::Input::StickStatus, Settings::NativeAnalog::NumAnalogs>;
using TriggerValues =
std::array<Common::Input::TriggerStatus, Settings::NativeTrigger::NumTriggers>;
using ControllerMotionValues = std::array<ControllerMotionInfo, Settings::NativeMotion::NumMotions>;
using ColorValues = std::array<Common::Input::BodyColorStatus, max_emulated_controllers>;
using BatteryValues = std::array<Common::Input::BatteryStatus, max_emulated_controllers>;
using VibrationValues = std::array<Common::Input::VibrationStatus, max_emulated_controllers>;
struct AnalogSticks {
AnalogStickState left{};
AnalogStickState right{};
};
struct ControllerColors {
NpadControllerColor fullkey{};
NpadControllerColor left{};
NpadControllerColor right{};
};
struct BatteryLevelState {
NpadPowerInfo dual{};
NpadPowerInfo left{};
NpadPowerInfo right{};
};
struct ControllerMotion {
Common::Vec3f accel{};
Common::Vec3f gyro{};
Common::Vec3f rotation{};
std::array<Common::Vec3f, 3> orientation{};
bool is_at_rest{};
};
enum EmulatedDeviceIndex : u8 {
LeftIndex,
RightIndex,
DualIndex,
AllDevices,
};
using MotionState = std::array<ControllerMotion, 2>;
struct ControllerStatus {
// Data from input_common
ButtonValues button_values{};
SticksValues stick_values{};
ControllerMotionValues motion_values{};
TriggerValues trigger_values{};
ColorValues color_values{};
BatteryValues battery_values{};
VibrationValues vibration_values{};
// Data for HID serices
NpadButtonState npad_button_state{};
DebugPadButton debug_pad_button_state{};
AnalogSticks analog_stick_state{};
MotionState motion_state{};
NpadGcTriggerState gc_trigger_state{};
ControllerColors colors_state{};
BatteryLevelState battery_state{};
};
enum class ControllerTriggerType {
Button,
Stick,
Trigger,
Motion,
Color,
Battery,
Vibration,
Connected,
Disconnected,
Type,
All,
};
struct ControllerUpdateCallback {
std::function<void(ControllerTriggerType)> on_change;
bool is_npad_service;
};
class EmulatedController {
public:
/**
* Contains all input data (buttons, joysticks, vibration, and motion) within this controller.
* @param npad_id_type npad id type for this specific controller
*/
explicit EmulatedController(NpadIdType npad_id_type_);
~EmulatedController();
YUZU_NON_COPYABLE(EmulatedController);
YUZU_NON_MOVEABLE(EmulatedController);
/// Converts the controller type from settings to npad type
static NpadStyleIndex MapSettingsTypeToNPad(Settings::ControllerType type);
/// Converts npad type to the equivalent of controller type from settings
static Settings::ControllerType MapNPadToSettingsType(NpadStyleIndex type);
/// Gets the NpadIdType for this controller
NpadIdType GetNpadIdType() const;
/// Sets the NpadStyleIndex for this controller
void SetNpadStyleIndex(NpadStyleIndex npad_type_);
/**
* Gets the NpadStyleIndex for this controller
* @param get_temporary_value If true tmp_npad_type will be returned
* @return NpadStyleIndex set on the controller
*/
NpadStyleIndex GetNpadStyleIndex(bool get_temporary_value = false) const;
/// Sets the connected status to true
void Connect();
/// Sets the connected status to false
void Disconnect();
/**
* Is the emulated connected
* @param get_temporary_value If true tmp_is_connected will be returned
* @return true if the controller has the connected status
*/
bool IsConnected(bool get_temporary_value = false) const;
/// Returns true if vibration is enabled
bool IsVibrationEnabled() const;
/// Removes all callbacks created from input devices
void UnloadInput();
/**
* Sets the emulated controller into configuring mode
* This prevents the modification of the HID state of the emulated controller by input commands
*/
void EnableConfiguration();
/// Returns the emulated controller into normal mode, allowing the modification of the HID state
void DisableConfiguration();
/// Returns true if the emulated controller is in configuring mode
bool IsConfiguring() const;
/// Reload all input devices
void ReloadInput();
/// Overrides current mapped devices with the stored configuration and reloads all input devices
void ReloadFromSettings();
/// Saves the current mapped configuration
void SaveCurrentConfig();
/// Reverts any mapped changes made that weren't saved
void RestoreConfig();
/// Returns a vector of mapped devices from the mapped button and stick parameters
std::vector<Common::ParamPackage> GetMappedDevices(EmulatedDeviceIndex device_index) const;
// Returns the current mapped button device
Common::ParamPackage GetButtonParam(std::size_t index) const;
// Returns the current mapped stick device
Common::ParamPackage GetStickParam(std::size_t index) const;
// Returns the current mapped motion device
Common::ParamPackage GetMotionParam(std::size_t index) const;
/**
* Updates the current mapped button device
* @param param ParamPackage with controller data to be mapped
*/
void SetButtonParam(std::size_t index, Common::ParamPackage param);
/**
* Updates the current mapped stick device
* @param param ParamPackage with controller data to be mapped
*/
void SetStickParam(std::size_t index, Common::ParamPackage param);
/**
* Updates the current mapped motion device
* @param param ParamPackage with controller data to be mapped
*/
void SetMotionParam(std::size_t index, Common::ParamPackage param);
/// Returns the latest button status from the controller with parameters
ButtonValues GetButtonsValues() const;
/// Returns the latest analog stick status from the controller with parameters
SticksValues GetSticksValues() const;
/// Returns the latest trigger status from the controller with parameters
TriggerValues GetTriggersValues() const;
/// Returns the latest motion status from the controller with parameters
ControllerMotionValues GetMotionValues() const;
/// Returns the latest color status from the controller with parameters
ColorValues GetColorsValues() const;
/// Returns the latest battery status from the controller with parameters
BatteryValues GetBatteryValues() const;
/// Returns the latest status of button input for the npad service
NpadButtonState GetNpadButtons() const;
/// Returns the latest status of button input for the debug pad service
DebugPadButton GetDebugPadButtons() const;
/// Returns the latest status of stick input from the mouse
AnalogSticks GetSticks() const;
/// Returns the latest status of trigger input from the mouse
NpadGcTriggerState GetTriggers() const;
/// Returns the latest status of motion input from the mouse
MotionState GetMotions() const;
/// Returns the latest color value from the controller
ControllerColors GetColors() const;
/// Returns the latest battery status from the controller
BatteryLevelState GetBattery() const;
/**
* Sends a specific vibration to the output device
* @return returns true if vibration had no errors
*/
bool SetVibration(std::size_t device_index, VibrationValue vibration);
/**
* Sends a small vibration to the output device
* @return returns true if SetVibration was successfull
*/
bool TestVibration(std::size_t device_index);
/// Returns the led pattern corresponding to this emulated controller
LedPattern GetLedPattern() const;
/// Asks the output device to change the player led pattern
void SetLedPattern();
/**
* Adds a callback to the list of events
* @param update_callback A ConsoleUpdateCallback that will be triggered
* @return an unique key corresponding to the callback index in the list
*/
int SetCallback(ControllerUpdateCallback update_callback);
/**
* Removes a callback from the list stopping any future events to this object
* @param key Key corresponding to the callback index in the list
*/
void DeleteCallback(int key);
private:
/// creates input devices from params
void LoadDevices();
/// Set the params for TAS devices
void LoadTASParams();
/**
* Updates the button status of the controller
* @param callback A CallbackStatus containing the button status
* @param index Button ID of the to be updated
*/
void SetButton(Common::Input::CallbackStatus callback, std::size_t index, Common::UUID uuid);
/**
* Updates the analog stick status of the controller
* @param callback A CallbackStatus containing the analog stick status
* @param index stick ID of the to be updated
*/
void SetStick(Common::Input::CallbackStatus callback, std::size_t index, Common::UUID uuid);
/**
* Updates the trigger status of the controller
* @param callback A CallbackStatus containing the trigger status
* @param index trigger ID of the to be updated
*/
void SetTrigger(Common::Input::CallbackStatus callback, std::size_t index, Common::UUID uuid);
/**
* Updates the motion status of the controller
* @param callback A CallbackStatus containing gyro and accelerometer data
* @param index motion ID of the to be updated
*/
void SetMotion(Common::Input::CallbackStatus callback, std::size_t index);
/**
* Updates the battery status of the controller
* @param callback A CallbackStatus containing the battery status
* @param index Button ID of the to be updated
*/
void SetBattery(Common::Input::CallbackStatus callback, std::size_t index);
/**
* Triggers a callback that something has changed on the controller status
* @param type Input type of the event to trigger
* @param is_service_update indicates if this event should only be sent to HID services
*/
void TriggerOnChange(ControllerTriggerType type, bool is_service_update);
NpadIdType npad_id_type;
NpadStyleIndex npad_type{NpadStyleIndex::None};
bool is_connected{false};
bool is_configuring{false};
f32 motion_sensitivity{0.01f};
bool force_update_motion{false};
// Temporary values to avoid doing changes while the controller is in configuring mode
NpadStyleIndex tmp_npad_type{NpadStyleIndex::None};
bool tmp_is_connected{false};
ButtonParams button_params;
StickParams stick_params;
ControllerMotionParams motion_params;
TriggerParams trigger_params;
BatteryParams battery_params;
OutputParams output_params;
ButtonDevices button_devices;
StickDevices stick_devices;
ControllerMotionDevices motion_devices;
TriggerDevices trigger_devices;
BatteryDevices battery_devices;
OutputDevices output_devices;
// TAS related variables
ButtonParams tas_button_params;
StickParams tas_stick_params;
ButtonDevices tas_button_devices;
StickDevices tas_stick_devices;
mutable std::mutex mutex;
std::unordered_map<int, ControllerUpdateCallback> callback_list;
int last_callback_key = 0;
// Stores the current status of all controller input
ControllerStatus controller;
};
} // namespace Core::HID

View File

@@ -0,0 +1,451 @@
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included
#include <algorithm>
#include <fmt/format.h>
#include "core/hid/emulated_devices.h"
#include "core/hid/input_converter.h"
namespace Core::HID {
EmulatedDevices::EmulatedDevices() = default;
EmulatedDevices::~EmulatedDevices() = default;
void EmulatedDevices::ReloadFromSettings() {
ReloadInput();
}
void EmulatedDevices::ReloadInput() {
// If you load any device here add the equivalent to the UnloadInput() function
std::size_t key_index = 0;
for (auto& mouse_device : mouse_button_devices) {
Common::ParamPackage mouse_params;
mouse_params.Set("engine", "mouse");
mouse_params.Set("button", static_cast<int>(key_index));
mouse_device = Common::Input::CreateDevice<Common::Input::InputDevice>(mouse_params);
key_index++;
}
mouse_stick_device = Common::Input::CreateDeviceFromString<Common::Input::InputDevice>(
"engine:mouse,axis_x:0,axis_y:1");
// First two axis are reserved for mouse position
key_index = 2;
for (auto& mouse_device : mouse_analog_devices) {
Common::ParamPackage mouse_params;
mouse_params.Set("engine", "mouse");
mouse_params.Set("axis", static_cast<int>(key_index));
mouse_device = Common::Input::CreateDevice<Common::Input::InputDevice>(mouse_params);
key_index++;
}
key_index = 0;
for (auto& keyboard_device : keyboard_devices) {
// Keyboard keys are only mapped on port 1, pad 0
Common::ParamPackage keyboard_params;
keyboard_params.Set("engine", "keyboard");
keyboard_params.Set("button", static_cast<int>(key_index));
keyboard_params.Set("port", 1);
keyboard_params.Set("pad", 0);
keyboard_device = Common::Input::CreateDevice<Common::Input::InputDevice>(keyboard_params);
key_index++;
}
key_index = 0;
for (auto& keyboard_device : keyboard_modifier_devices) {
// Keyboard moddifiers are only mapped on port 1, pad 1
Common::ParamPackage keyboard_params;
keyboard_params.Set("engine", "keyboard");
keyboard_params.Set("button", static_cast<int>(key_index));
keyboard_params.Set("port", 1);
keyboard_params.Set("pad", 1);
keyboard_device = Common::Input::CreateDevice<Common::Input::InputDevice>(keyboard_params);
key_index++;
}
for (std::size_t index = 0; index < mouse_button_devices.size(); ++index) {
if (!mouse_button_devices[index]) {
continue;
}
Common::Input::InputCallback button_callback{
[this, index](Common::Input::CallbackStatus callback) {
SetMouseButton(callback, index);
}};
mouse_button_devices[index]->SetCallback(button_callback);
}
for (std::size_t index = 0; index < mouse_analog_devices.size(); ++index) {
if (!mouse_analog_devices[index]) {
continue;
}
Common::Input::InputCallback button_callback{
[this, index](Common::Input::CallbackStatus callback) {
SetMouseAnalog(callback, index);
}};
mouse_analog_devices[index]->SetCallback(button_callback);
}
if (mouse_stick_device) {
Common::Input::InputCallback button_callback{
[this](Common::Input::CallbackStatus callback) { SetMouseStick(callback); }};
mouse_stick_device->SetCallback(button_callback);
}
for (std::size_t index = 0; index < keyboard_devices.size(); ++index) {
if (!keyboard_devices[index]) {
continue;
}
Common::Input::InputCallback button_callback{
[this, index](Common::Input::CallbackStatus callback) {
SetKeyboardButton(callback, index);
}};
keyboard_devices[index]->SetCallback(button_callback);
}
for (std::size_t index = 0; index < keyboard_modifier_devices.size(); ++index) {
if (!keyboard_modifier_devices[index]) {
continue;
}
Common::Input::InputCallback button_callback{
[this, index](Common::Input::CallbackStatus callback) {
SetKeyboardModifier(callback, index);
}};
keyboard_modifier_devices[index]->SetCallback(button_callback);
}
}
void EmulatedDevices::UnloadInput() {
for (auto& button : mouse_button_devices) {
button.reset();
}
for (auto& analog : mouse_analog_devices) {
analog.reset();
}
mouse_stick_device.reset();
for (auto& button : keyboard_devices) {
button.reset();
}
for (auto& button : keyboard_modifier_devices) {
button.reset();
}
}
void EmulatedDevices::EnableConfiguration() {
is_configuring = true;
SaveCurrentConfig();
}
void EmulatedDevices::DisableConfiguration() {
is_configuring = false;
}
bool EmulatedDevices::IsConfiguring() const {
return is_configuring;
}
void EmulatedDevices::SaveCurrentConfig() {
if (!is_configuring) {
return;
}
}
void EmulatedDevices::RestoreConfig() {
if (!is_configuring) {
return;
}
ReloadFromSettings();
}
void EmulatedDevices::SetKeyboardButton(Common::Input::CallbackStatus callback, std::size_t index) {
if (index >= device_status.keyboard_values.size()) {
return;
}
std::lock_guard lock{mutex};
bool value_changed = false;
const auto new_status = TransformToButton(callback);
auto& current_status = device_status.keyboard_values[index];
current_status.toggle = new_status.toggle;
// Update button status with current status
if (!current_status.toggle) {
current_status.locked = false;
if (current_status.value != new_status.value) {
current_status.value = new_status.value;
value_changed = true;
}
} else {
// Toggle button and lock status
if (new_status.value && !current_status.locked) {
current_status.locked = true;
current_status.value = !current_status.value;
value_changed = true;
}
// Unlock button, ready for next press
if (!new_status.value && current_status.locked) {
current_status.locked = false;
}
}
if (!value_changed) {
return;
}
if (is_configuring) {
TriggerOnChange(DeviceTriggerType::Keyboard);
return;
}
// Index should be converted from NativeKeyboard to KeyboardKeyIndex
UpdateKey(index, current_status.value);
TriggerOnChange(DeviceTriggerType::Keyboard);
}
void EmulatedDevices::UpdateKey(std::size_t key_index, bool status) {
constexpr std::size_t KEYS_PER_BYTE = 8;
auto& entry = device_status.keyboard_state.key[key_index / KEYS_PER_BYTE];
const u8 mask = static_cast<u8>(1 << (key_index % KEYS_PER_BYTE));
if (status) {
entry = entry | mask;
} else {
entry = static_cast<u8>(entry & ~mask);
}
}
void EmulatedDevices::SetKeyboardModifier(Common::Input::CallbackStatus callback,
std::size_t index) {
if (index >= device_status.keyboard_moddifier_values.size()) {
return;
}
std::lock_guard lock{mutex};
bool value_changed = false;
const auto new_status = TransformToButton(callback);
auto& current_status = device_status.keyboard_moddifier_values[index];
current_status.toggle = new_status.toggle;
// Update button status with current
if (!current_status.toggle) {
current_status.locked = false;
if (current_status.value != new_status.value) {
current_status.value = new_status.value;
value_changed = true;
}
} else {
// Toggle button and lock status
if (new_status.value && !current_status.locked) {
current_status.locked = true;
current_status.value = !current_status.value;
value_changed = true;
}
// Unlock button ready for next press
if (!new_status.value && current_status.locked) {
current_status.locked = false;
}
}
if (!value_changed) {
return;
}
if (is_configuring) {
TriggerOnChange(DeviceTriggerType::KeyboardModdifier);
return;
}
switch (index) {
case Settings::NativeKeyboard::LeftControl:
case Settings::NativeKeyboard::RightControl:
device_status.keyboard_moddifier_state.control.Assign(current_status.value);
break;
case Settings::NativeKeyboard::LeftShift:
case Settings::NativeKeyboard::RightShift:
device_status.keyboard_moddifier_state.shift.Assign(current_status.value);
break;
case Settings::NativeKeyboard::LeftAlt:
device_status.keyboard_moddifier_state.left_alt.Assign(current_status.value);
break;
case Settings::NativeKeyboard::RightAlt:
device_status.keyboard_moddifier_state.right_alt.Assign(current_status.value);
break;
case Settings::NativeKeyboard::CapsLock:
device_status.keyboard_moddifier_state.caps_lock.Assign(current_status.value);
break;
case Settings::NativeKeyboard::ScrollLock:
device_status.keyboard_moddifier_state.scroll_lock.Assign(current_status.value);
break;
case Settings::NativeKeyboard::NumLock:
device_status.keyboard_moddifier_state.num_lock.Assign(current_status.value);
break;
}
TriggerOnChange(DeviceTriggerType::KeyboardModdifier);
}
void EmulatedDevices::SetMouseButton(Common::Input::CallbackStatus callback, std::size_t index) {
if (index >= device_status.mouse_button_values.size()) {
return;
}
std::lock_guard lock{mutex};
bool value_changed = false;
const auto new_status = TransformToButton(callback);
auto& current_status = device_status.mouse_button_values[index];
current_status.toggle = new_status.toggle;
// Update button status with current
if (!current_status.toggle) {
current_status.locked = false;
if (current_status.value != new_status.value) {
current_status.value = new_status.value;
value_changed = true;
}
} else {
// Toggle button and lock status
if (new_status.value && !current_status.locked) {
current_status.locked = true;
current_status.value = !current_status.value;
value_changed = true;
}
// Unlock button ready for next press
if (!new_status.value && current_status.locked) {
current_status.locked = false;
}
}
if (!value_changed) {
return;
}
if (is_configuring) {
TriggerOnChange(DeviceTriggerType::Mouse);
return;
}
switch (index) {
case Settings::NativeMouseButton::Left:
device_status.mouse_button_state.left.Assign(current_status.value);
break;
case Settings::NativeMouseButton::Right:
device_status.mouse_button_state.right.Assign(current_status.value);
break;
case Settings::NativeMouseButton::Middle:
device_status.mouse_button_state.middle.Assign(current_status.value);
break;
case Settings::NativeMouseButton::Forward:
device_status.mouse_button_state.forward.Assign(current_status.value);
break;
case Settings::NativeMouseButton::Back:
device_status.mouse_button_state.back.Assign(current_status.value);
break;
}
TriggerOnChange(DeviceTriggerType::Mouse);
}
void EmulatedDevices::SetMouseAnalog(Common::Input::CallbackStatus callback, std::size_t index) {
if (index >= device_status.mouse_analog_values.size()) {
return;
}
std::lock_guard lock{mutex};
const auto analog_value = TransformToAnalog(callback);
device_status.mouse_analog_values[index] = analog_value;
if (is_configuring) {
device_status.mouse_position_state = {};
TriggerOnChange(DeviceTriggerType::Mouse);
return;
}
switch (index) {
case Settings::NativeMouseWheel::X:
device_status.mouse_wheel_state.x = static_cast<s32>(analog_value.value);
break;
case Settings::NativeMouseWheel::Y:
device_status.mouse_wheel_state.y = static_cast<s32>(analog_value.value);
break;
}
TriggerOnChange(DeviceTriggerType::Mouse);
}
void EmulatedDevices::SetMouseStick(Common::Input::CallbackStatus callback) {
std::lock_guard lock{mutex};
const auto touch_value = TransformToTouch(callback);
device_status.mouse_stick_value = touch_value;
if (is_configuring) {
device_status.mouse_position_state = {};
TriggerOnChange(DeviceTriggerType::Mouse);
return;
}
device_status.mouse_position_state.x = touch_value.x.value;
device_status.mouse_position_state.y = touch_value.y.value;
TriggerOnChange(DeviceTriggerType::Mouse);
}
KeyboardValues EmulatedDevices::GetKeyboardValues() const {
return device_status.keyboard_values;
}
KeyboardModifierValues EmulatedDevices::GetKeyboardModdifierValues() const {
return device_status.keyboard_moddifier_values;
}
MouseButtonValues EmulatedDevices::GetMouseButtonsValues() const {
return device_status.mouse_button_values;
}
KeyboardKey EmulatedDevices::GetKeyboard() const {
return device_status.keyboard_state;
}
KeyboardModifier EmulatedDevices::GetKeyboardModifier() const {
return device_status.keyboard_moddifier_state;
}
MouseButton EmulatedDevices::GetMouseButtons() const {
return device_status.mouse_button_state;
}
MousePosition EmulatedDevices::GetMousePosition() const {
return device_status.mouse_position_state;
}
AnalogStickState EmulatedDevices::GetMouseWheel() const {
return device_status.mouse_wheel_state;
}
void EmulatedDevices::TriggerOnChange(DeviceTriggerType type) {
for (const auto& poller_pair : callback_list) {
const InterfaceUpdateCallback& poller = poller_pair.second;
if (poller.on_change) {
poller.on_change(type);
}
}
}
int EmulatedDevices::SetCallback(InterfaceUpdateCallback update_callback) {
std::lock_guard lock{mutex};
callback_list.insert_or_assign(last_callback_key, update_callback);
return last_callback_key++;
}
void EmulatedDevices::DeleteCallback(int key) {
std::lock_guard lock{mutex};
const auto& iterator = callback_list.find(key);
if (iterator == callback_list.end()) {
LOG_ERROR(Input, "Tried to delete non-existent callback {}", key);
return;
}
callback_list.erase(iterator);
}
} // namespace Core::HID

View File

@@ -0,0 +1,211 @@
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <array>
#include <functional>
#include <memory>
#include <mutex>
#include <unordered_map>
#include "common/common_types.h"
#include "common/input.h"
#include "common/param_package.h"
#include "common/settings.h"
#include "core/hid/hid_types.h"
namespace Core::HID {
using KeyboardDevices = std::array<std::unique_ptr<Common::Input::InputDevice>,
Settings::NativeKeyboard::NumKeyboardKeys>;
using KeyboardModifierDevices = std::array<std::unique_ptr<Common::Input::InputDevice>,
Settings::NativeKeyboard::NumKeyboardMods>;
using MouseButtonDevices = std::array<std::unique_ptr<Common::Input::InputDevice>,
Settings::NativeMouseButton::NumMouseButtons>;
using MouseAnalogDevices = std::array<std::unique_ptr<Common::Input::InputDevice>,
Settings::NativeMouseWheel::NumMouseWheels>;
using MouseStickDevice = std::unique_ptr<Common::Input::InputDevice>;
using MouseButtonParams =
std::array<Common::ParamPackage, Settings::NativeMouseButton::NumMouseButtons>;
using KeyboardValues =
std::array<Common::Input::ButtonStatus, Settings::NativeKeyboard::NumKeyboardKeys>;
using KeyboardModifierValues =
std::array<Common::Input::ButtonStatus, Settings::NativeKeyboard::NumKeyboardMods>;
using MouseButtonValues =
std::array<Common::Input::ButtonStatus, Settings::NativeMouseButton::NumMouseButtons>;
using MouseAnalogValues =
std::array<Common::Input::AnalogStatus, Settings::NativeMouseWheel::NumMouseWheels>;
using MouseStickValue = Common::Input::TouchStatus;
struct MousePosition {
f32 x;
f32 y;
};
struct DeviceStatus {
// Data from input_common
KeyboardValues keyboard_values{};
KeyboardModifierValues keyboard_moddifier_values{};
MouseButtonValues mouse_button_values{};
MouseAnalogValues mouse_analog_values{};
MouseStickValue mouse_stick_value{};
// Data for HID serices
KeyboardKey keyboard_state{};
KeyboardModifier keyboard_moddifier_state{};
MouseButton mouse_button_state{};
MousePosition mouse_position_state{};
AnalogStickState mouse_wheel_state{};
};
enum class DeviceTriggerType {
Keyboard,
KeyboardModdifier,
Mouse,
};
struct InterfaceUpdateCallback {
std::function<void(DeviceTriggerType)> on_change;
};
class EmulatedDevices {
public:
/**
* Contains all input data related to external devices that aren't necesarily a controller
* This includes devices such as the keyboard or mouse
*/
explicit EmulatedDevices();
~EmulatedDevices();
YUZU_NON_COPYABLE(EmulatedDevices);
YUZU_NON_MOVEABLE(EmulatedDevices);
/// Removes all callbacks created from input devices
void UnloadInput();
/**
* Sets the emulated devices into configuring mode
* This prevents the modification of the HID state of the emulated devices by input commands
*/
void EnableConfiguration();
/// Returns the emulated devices into normal mode, allowing the modification of the HID state
void DisableConfiguration();
/// Returns true if the emulated device is in configuring mode
bool IsConfiguring() const;
/// Reload all input devices
void ReloadInput();
/// Overrides current mapped devices with the stored configuration and reloads all input devices
void ReloadFromSettings();
/// Saves the current mapped configuration
void SaveCurrentConfig();
/// Reverts any mapped changes made that weren't saved
void RestoreConfig();
/// Returns the latest status of button input from the keyboard with parameters
KeyboardValues GetKeyboardValues() const;
/// Returns the latest status of button input from the keyboard modifiers with parameters
KeyboardModifierValues GetKeyboardModdifierValues() const;
/// Returns the latest status of button input from the mouse with parameters
MouseButtonValues GetMouseButtonsValues() const;
/// Returns the latest status of button input from the keyboard
KeyboardKey GetKeyboard() const;
/// Returns the latest status of button input from the keyboard modifiers
KeyboardModifier GetKeyboardModifier() const;
/// Returns the latest status of button input from the mouse
MouseButton GetMouseButtons() const;
/// Returns the latest mouse coordinates
MousePosition GetMousePosition() const;
/// Returns the latest mouse wheel change
AnalogStickState GetMouseWheel() const;
/**
* Adds a callback to the list of events
* @param update_callback InterfaceUpdateCallback that will be triggered
* @return an unique key corresponding to the callback index in the list
*/
int SetCallback(InterfaceUpdateCallback update_callback);
/**
* Removes a callback from the list stopping any future events to this object
* @param key Key corresponding to the callback index in the list
*/
void DeleteCallback(int key);
private:
/// Helps assigning a value to keyboard_state
void UpdateKey(std::size_t key_index, bool status);
/**
* Updates the touch status of the keyboard device
* @param callback A CallbackStatus containing the key status
* @param index key ID to be updated
*/
void SetKeyboardButton(Common::Input::CallbackStatus callback, std::size_t index);
/**
* Updates the keyboard status of the keyboard device
* @param callback A CallbackStatus containing the modifier key status
* @param index modifier key ID to be updated
*/
void SetKeyboardModifier(Common::Input::CallbackStatus callback, std::size_t index);
/**
* Updates the mouse button status of the mouse device
* @param callback A CallbackStatus containing the button status
* @param index Button ID to be updated
*/
void SetMouseButton(Common::Input::CallbackStatus callback, std::size_t index);
/**
* Updates the mouse wheel status of the mouse device
* @param callback A CallbackStatus containing the wheel status
* @param index wheel ID to be updated
*/
void SetMouseAnalog(Common::Input::CallbackStatus callback, std::size_t index);
/**
* Updates the mouse position status of the mouse device
* @param callback A CallbackStatus containing the position status
* @param index stick ID to be updated
*/
void SetMouseStick(Common::Input::CallbackStatus callback);
/**
* Triggers a callback that something has changed on the device status
* @param type Input type of the event to trigger
*/
void TriggerOnChange(DeviceTriggerType type);
bool is_configuring{false};
KeyboardDevices keyboard_devices;
KeyboardModifierDevices keyboard_modifier_devices;
MouseButtonDevices mouse_button_devices;
MouseAnalogDevices mouse_analog_devices;
MouseStickDevice mouse_stick_device;
mutable std::mutex mutex;
std::unordered_map<int, InterfaceUpdateCallback> callback_list;
int last_callback_key = 0;
// Stores the current status of all external device input
DeviceStatus device_status;
};
} // namespace Core::HID

194
src/core/hid/hid_core.cpp Normal file
View File

@@ -0,0 +1,194 @@
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/assert.h"
#include "core/hid/emulated_console.h"
#include "core/hid/emulated_controller.h"
#include "core/hid/emulated_devices.h"
#include "core/hid/hid_core.h"
namespace Core::HID {
HIDCore::HIDCore()
: player_1{std::make_unique<EmulatedController>(NpadIdType::Player1)},
player_2{std::make_unique<EmulatedController>(NpadIdType::Player2)},
player_3{std::make_unique<EmulatedController>(NpadIdType::Player3)},
player_4{std::make_unique<EmulatedController>(NpadIdType::Player4)},
player_5{std::make_unique<EmulatedController>(NpadIdType::Player5)},
player_6{std::make_unique<EmulatedController>(NpadIdType::Player6)},
player_7{std::make_unique<EmulatedController>(NpadIdType::Player7)},
player_8{std::make_unique<EmulatedController>(NpadIdType::Player8)},
other{std::make_unique<EmulatedController>(NpadIdType::Other)},
handheld{std::make_unique<EmulatedController>(NpadIdType::Handheld)},
console{std::make_unique<EmulatedConsole>()}, devices{std::make_unique<EmulatedDevices>()} {}
HIDCore::~HIDCore() = default;
EmulatedController* HIDCore::GetEmulatedController(NpadIdType npad_id_type) {
switch (npad_id_type) {
case NpadIdType::Player1:
return player_1.get();
case NpadIdType::Player2:
return player_2.get();
case NpadIdType::Player3:
return player_3.get();
case NpadIdType::Player4:
return player_4.get();
case NpadIdType::Player5:
return player_5.get();
case NpadIdType::Player6:
return player_6.get();
case NpadIdType::Player7:
return player_7.get();
case NpadIdType::Player8:
return player_8.get();
case NpadIdType::Other:
return other.get();
case NpadIdType::Handheld:
return handheld.get();
case NpadIdType::Invalid:
default:
UNREACHABLE_MSG("Invalid NpadIdType={}", npad_id_type);
return nullptr;
}
}
const EmulatedController* HIDCore::GetEmulatedController(NpadIdType npad_id_type) const {
switch (npad_id_type) {
case NpadIdType::Player1:
return player_1.get();
case NpadIdType::Player2:
return player_2.get();
case NpadIdType::Player3:
return player_3.get();
case NpadIdType::Player4:
return player_4.get();
case NpadIdType::Player5:
return player_5.get();
case NpadIdType::Player6:
return player_6.get();
case NpadIdType::Player7:
return player_7.get();
case NpadIdType::Player8:
return player_8.get();
case NpadIdType::Other:
return other.get();
case NpadIdType::Handheld:
return handheld.get();
case NpadIdType::Invalid:
default:
UNREACHABLE_MSG("Invalid NpadIdType={}", npad_id_type);
return nullptr;
}
}
EmulatedConsole* HIDCore::GetEmulatedConsole() {
return console.get();
}
const EmulatedConsole* HIDCore::GetEmulatedConsole() const {
return console.get();
}
EmulatedDevices* HIDCore::GetEmulatedDevices() {
return devices.get();
}
const EmulatedDevices* HIDCore::GetEmulatedDevices() const {
return devices.get();
}
EmulatedController* HIDCore::GetEmulatedControllerByIndex(std::size_t index) {
return GetEmulatedController(IndexToNpadIdType(index));
}
const EmulatedController* HIDCore::GetEmulatedControllerByIndex(std::size_t index) const {
return GetEmulatedController(IndexToNpadIdType(index));
}
void HIDCore::SetSupportedStyleTag(NpadStyleTag style_tag) {
supported_style_tag.raw = style_tag.raw;
}
NpadStyleTag HIDCore::GetSupportedStyleTag() const {
return supported_style_tag;
}
s8 HIDCore::GetPlayerCount() const {
s8 active_players = 0;
for (std::size_t player_index = 0; player_index < available_controllers - 2; ++player_index) {
const auto* const controller = GetEmulatedControllerByIndex(player_index);
if (controller->IsConnected()) {
active_players++;
}
}
return active_players;
}
NpadIdType HIDCore::GetFirstNpadId() const {
for (std::size_t player_index = 0; player_index < available_controllers; ++player_index) {
const auto* const controller = GetEmulatedControllerByIndex(player_index);
if (controller->IsConnected()) {
return controller->GetNpadIdType();
}
}
return NpadIdType::Player1;
}
void HIDCore::EnableAllControllerConfiguration() {
player_1->EnableConfiguration();
player_2->EnableConfiguration();
player_3->EnableConfiguration();
player_4->EnableConfiguration();
player_5->EnableConfiguration();
player_6->EnableConfiguration();
player_7->EnableConfiguration();
player_8->EnableConfiguration();
other->EnableConfiguration();
handheld->EnableConfiguration();
}
void HIDCore::DisableAllControllerConfiguration() {
player_1->DisableConfiguration();
player_2->DisableConfiguration();
player_3->DisableConfiguration();
player_4->DisableConfiguration();
player_5->DisableConfiguration();
player_6->DisableConfiguration();
player_7->DisableConfiguration();
player_8->DisableConfiguration();
other->DisableConfiguration();
handheld->DisableConfiguration();
}
void HIDCore::ReloadInputDevices() {
player_1->ReloadFromSettings();
player_2->ReloadFromSettings();
player_3->ReloadFromSettings();
player_4->ReloadFromSettings();
player_5->ReloadFromSettings();
player_6->ReloadFromSettings();
player_7->ReloadFromSettings();
player_8->ReloadFromSettings();
other->ReloadFromSettings();
handheld->ReloadFromSettings();
console->ReloadFromSettings();
devices->ReloadFromSettings();
}
void HIDCore::UnloadInputDevices() {
player_1->UnloadInput();
player_2->UnloadInput();
player_3->UnloadInput();
player_4->UnloadInput();
player_5->UnloadInput();
player_6->UnloadInput();
player_7->UnloadInput();
player_8->UnloadInput();
other->UnloadInput();
handheld->UnloadInput();
console->UnloadInput();
devices->UnloadInput();
}
} // namespace Core::HID

79
src/core/hid/hid_core.h Normal file
View File

@@ -0,0 +1,79 @@
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <memory>
#include "core/hid/hid_types.h"
namespace Core::HID {
class EmulatedConsole;
class EmulatedController;
class EmulatedDevices;
} // namespace Core::HID
namespace Core::HID {
class HIDCore {
public:
explicit HIDCore();
~HIDCore();
YUZU_NON_COPYABLE(HIDCore);
YUZU_NON_MOVEABLE(HIDCore);
EmulatedController* GetEmulatedController(NpadIdType npad_id_type);
const EmulatedController* GetEmulatedController(NpadIdType npad_id_type) const;
EmulatedController* GetEmulatedControllerByIndex(std::size_t index);
const EmulatedController* GetEmulatedControllerByIndex(std::size_t index) const;
EmulatedConsole* GetEmulatedConsole();
const EmulatedConsole* GetEmulatedConsole() const;
EmulatedDevices* GetEmulatedDevices();
const EmulatedDevices* GetEmulatedDevices() const;
void SetSupportedStyleTag(NpadStyleTag style_tag);
NpadStyleTag GetSupportedStyleTag() const;
/// Counts the connected players from P1-P8
s8 GetPlayerCount() const;
/// Returns the first connected npad id
NpadIdType GetFirstNpadId() const;
/// Sets all emulated controllers into configuring mode.
void EnableAllControllerConfiguration();
/// Sets all emulated controllers into normal mode.
void DisableAllControllerConfiguration();
/// Reloads all input devices from settings
void ReloadInputDevices();
/// Removes all callbacks from input common
void UnloadInputDevices();
/// Number of emulated controllers
static constexpr std::size_t available_controllers{10};
private:
std::unique_ptr<EmulatedController> player_1;
std::unique_ptr<EmulatedController> player_2;
std::unique_ptr<EmulatedController> player_3;
std::unique_ptr<EmulatedController> player_4;
std::unique_ptr<EmulatedController> player_5;
std::unique_ptr<EmulatedController> player_6;
std::unique_ptr<EmulatedController> player_7;
std::unique_ptr<EmulatedController> player_8;
std::unique_ptr<EmulatedController> other;
std::unique_ptr<EmulatedController> handheld;
std::unique_ptr<EmulatedConsole> console;
std::unique_ptr<EmulatedDevices> devices;
NpadStyleTag supported_style_tag;
};
} // namespace Core::HID

633
src/core/hid/hid_types.h Normal file
View File

@@ -0,0 +1,633 @@
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "common/bit_field.h"
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/point.h"
#include "common/uuid.h"
namespace Core::HID {
enum class DeviceIndex : u8 {
Left = 0,
Right = 1,
None = 2,
MaxDeviceIndex = 3,
};
// This is nn::hid::NpadButton
enum class NpadButton : u64 {
None = 0,
A = 1U << 0,
B = 1U << 1,
X = 1U << 2,
Y = 1U << 3,
StickL = 1U << 4,
StickR = 1U << 5,
L = 1U << 6,
R = 1U << 7,
ZL = 1U << 8,
ZR = 1U << 9,
Plus = 1U << 10,
Minus = 1U << 11,
Left = 1U << 12,
Up = 1U << 13,
Right = 1U << 14,
Down = 1U << 15,
StickLLeft = 1U << 16,
StickLUp = 1U << 17,
StickLRight = 1U << 18,
StickLDown = 1U << 19,
StickRLeft = 1U << 20,
StickRUp = 1U << 21,
StickRRight = 1U << 22,
StickRDown = 1U << 23,
LeftSL = 1U << 24,
LeftSR = 1U << 25,
RightSL = 1U << 26,
RightSR = 1U << 27,
Palma = 1U << 28,
Verification = 1U << 29,
HandheldLeftB = 1U << 30,
LagonCLeft = 1U << 31,
LagonCUp = 1ULL << 32,
LagonCRight = 1ULL << 33,
LagonCDown = 1ULL << 34,
All = 0xFFFFFFFFFFFFFFFFULL,
};
DECLARE_ENUM_FLAG_OPERATORS(NpadButton);
enum class KeyboardKeyIndex : u32 {
A = 4,
B = 5,
C = 6,
D = 7,
E = 8,
F = 9,
G = 10,
H = 11,
I = 12,
J = 13,
K = 14,
L = 15,
M = 16,
N = 17,
O = 18,
P = 19,
Q = 20,
R = 21,
S = 22,
T = 23,
U = 24,
V = 25,
W = 26,
X = 27,
Y = 28,
Z = 29,
D1 = 30,
D2 = 31,
D3 = 32,
D4 = 33,
D5 = 34,
D6 = 35,
D7 = 36,
D8 = 37,
D9 = 38,
D0 = 39,
Return = 40,
Escape = 41,
Backspace = 42,
Tab = 43,
Space = 44,
Minus = 45,
Plus = 46,
OpenBracket = 47,
CloseBracket = 48,
Pipe = 49,
Tilde = 50,
Semicolon = 51,
Quote = 52,
Backquote = 53,
Comma = 54,
Period = 55,
Slash = 56,
CapsLock = 57,
F1 = 58,
F2 = 59,
F3 = 60,
F4 = 61,
F5 = 62,
F6 = 63,
F7 = 64,
F8 = 65,
F9 = 66,
F10 = 67,
F11 = 68,
F12 = 69,
PrintScreen = 70,
ScrollLock = 71,
Pause = 72,
Insert = 73,
Home = 74,
PageUp = 75,
Delete = 76,
End = 77,
PageDown = 78,
RightArrow = 79,
LeftArrow = 80,
DownArrow = 81,
UpArrow = 82,
NumLock = 83,
NumPadDivide = 84,
NumPadMultiply = 85,
NumPadSubtract = 86,
NumPadAdd = 87,
NumPadEnter = 88,
NumPad1 = 89,
NumPad2 = 90,
NumPad3 = 91,
NumPad4 = 92,
NumPad5 = 93,
NumPad6 = 94,
NumPad7 = 95,
NumPad8 = 96,
NumPad9 = 97,
NumPad0 = 98,
NumPadDot = 99,
Backslash = 100,
Application = 101,
Power = 102,
NumPadEquals = 103,
F13 = 104,
F14 = 105,
F15 = 106,
F16 = 107,
F17 = 108,
F18 = 109,
F19 = 110,
F20 = 111,
F21 = 112,
F22 = 113,
F23 = 114,
F24 = 115,
NumPadComma = 133,
Ro = 135,
KatakanaHiragana = 136,
Yen = 137,
Henkan = 138,
Muhenkan = 139,
NumPadCommaPc98 = 140,
HangulEnglish = 144,
Hanja = 145,
Katakana = 146,
Hiragana = 147,
ZenkakuHankaku = 148,
LeftControl = 224,
LeftShift = 225,
LeftAlt = 226,
LeftGui = 227,
RightControl = 228,
RightShift = 229,
RightAlt = 230,
RightGui = 231,
};
// This is nn::hid::NpadIdType
enum class NpadIdType : u32 {
Player1 = 0x0,
Player2 = 0x1,
Player3 = 0x2,
Player4 = 0x3,
Player5 = 0x4,
Player6 = 0x5,
Player7 = 0x6,
Player8 = 0x7,
Other = 0x10,
Handheld = 0x20,
Invalid = 0xFFFFFFFF,
};
// This is nn::hid::NpadStyleIndex
enum class NpadStyleIndex : u8 {
None = 0,
ProController = 3,
Handheld = 4,
HandheldNES = 4,
JoyconDual = 5,
JoyconLeft = 6,
JoyconRight = 7,
GameCube = 8,
Pokeball = 9,
NES = 10,
SNES = 12,
N64 = 13,
SegaGenesis = 14,
SystemExt = 32,
System = 33,
MaxNpadType = 34,
};
// This is nn::hid::NpadStyleSet
enum class NpadStyleSet : u32 {
None = 0,
Fullkey = 1U << 0,
Handheld = 1U << 1,
JoyDual = 1U << 2,
JoyLeft = 1U << 3,
JoyRight = 1U << 4,
Gc = 1U << 5,
Palma = 1U << 6,
Lark = 1U << 7,
HandheldLark = 1U << 8,
Lucia = 1U << 9,
Lagoon = 1U << 10,
Lager = 1U << 11,
SystemExt = 1U << 29,
System = 1U << 30,
};
static_assert(sizeof(NpadStyleSet) == 4, "NpadStyleSet is an invalid size");
// This is nn::hid::VibrationDevicePosition
enum class VibrationDevicePosition : u32 {
None = 0,
Left = 1,
Right = 2,
};
// This is nn::hid::VibrationDeviceType
enum class VibrationDeviceType : u32 {
Unknown = 0,
LinearResonantActuator = 1,
GcErm = 2,
};
// This is nn::hid::VibrationGcErmCommand
enum class VibrationGcErmCommand : u64 {
Stop = 0,
Start = 1,
StopHard = 2,
};
// This is nn::hid::NpadStyleTag
struct NpadStyleTag {
union {
NpadStyleSet raw{};
BitField<0, 1, u32> fullkey;
BitField<1, 1, u32> handheld;
BitField<2, 1, u32> joycon_dual;
BitField<3, 1, u32> joycon_left;
BitField<4, 1, u32> joycon_right;
BitField<5, 1, u32> gamecube;
BitField<6, 1, u32> palma;
BitField<7, 1, u32> lark;
BitField<8, 1, u32> handheld_lark;
BitField<9, 1, u32> lucia;
BitField<10, 1, u32> lagoon;
BitField<11, 1, u32> lager;
BitField<29, 1, u32> system_ext;
BitField<30, 1, u32> system;
};
};
static_assert(sizeof(NpadStyleTag) == 4, "NpadStyleTag is an invalid size");
// This is nn::hid::TouchAttribute
struct TouchAttribute {
union {
u32 raw{};
BitField<0, 1, u32> start_touch;
BitField<1, 1, u32> end_touch;
};
};
static_assert(sizeof(TouchAttribute) == 0x4, "TouchAttribute is an invalid size");
// This is nn::hid::TouchState
struct TouchState {
u64 delta_time;
TouchAttribute attribute;
u32 finger;
Common::Point<u32> position;
u32 diameter_x;
u32 diameter_y;
u32 rotation_angle;
};
static_assert(sizeof(TouchState) == 0x28, "Touchstate is an invalid size");
// This is nn::hid::NpadControllerColor
struct NpadControllerColor {
u32 body;
u32 button;
};
static_assert(sizeof(NpadControllerColor) == 8, "NpadControllerColor is an invalid size");
// This is nn::hid::AnalogStickState
struct AnalogStickState {
s32 x;
s32 y;
};
static_assert(sizeof(AnalogStickState) == 8, "AnalogStickState is an invalid size");
// This is nn::hid::server::NpadGcTriggerState
struct NpadGcTriggerState {
s64 sampling_number{};
s32 left{};
s32 right{};
};
static_assert(sizeof(NpadGcTriggerState) == 0x10, "NpadGcTriggerState is an invalid size");
// This is nn::hid::system::NpadBatteryLevel
using NpadBatteryLevel = u32;
static_assert(sizeof(NpadBatteryLevel) == 0x4, "NpadBatteryLevel is an invalid size");
// This is nn::hid::system::NpadPowerInfo
struct NpadPowerInfo {
bool is_powered;
bool is_charging;
INSERT_PADDING_BYTES(0x6);
NpadBatteryLevel battery_level;
};
static_assert(sizeof(NpadPowerInfo) == 0xC, "NpadPowerInfo is an invalid size");
struct LedPattern {
explicit LedPattern(u64 light1, u64 light2, u64 light3, u64 light4) {
position1.Assign(light1);
position2.Assign(light2);
position3.Assign(light3);
position4.Assign(light4);
}
union {
u64 raw{};
BitField<0, 1, u64> position1;
BitField<1, 1, u64> position2;
BitField<2, 1, u64> position3;
BitField<3, 1, u64> position4;
};
};
struct NpadButtonState {
union {
NpadButton raw{};
// Buttons
BitField<0, 1, u64> a;
BitField<1, 1, u64> b;
BitField<2, 1, u64> x;
BitField<3, 1, u64> y;
BitField<4, 1, u64> stick_l;
BitField<5, 1, u64> stick_r;
BitField<6, 1, u64> l;
BitField<7, 1, u64> r;
BitField<8, 1, u64> zl;
BitField<9, 1, u64> zr;
BitField<10, 1, u64> plus;
BitField<11, 1, u64> minus;
// D-Pad
BitField<12, 1, u64> left;
BitField<13, 1, u64> up;
BitField<14, 1, u64> right;
BitField<15, 1, u64> down;
// Left JoyStick
BitField<16, 1, u64> stick_l_left;
BitField<17, 1, u64> stick_l_up;
BitField<18, 1, u64> stick_l_right;
BitField<19, 1, u64> stick_l_down;
// Right JoyStick
BitField<20, 1, u64> stick_r_left;
BitField<21, 1, u64> stick_r_up;
BitField<22, 1, u64> stick_r_right;
BitField<23, 1, u64> stick_r_down;
BitField<24, 1, u64> left_sl;
BitField<25, 1, u64> left_sr;
BitField<26, 1, u64> right_sl;
BitField<27, 1, u64> right_sr;
BitField<28, 1, u64> palma;
BitField<29, 1, u64> verification;
BitField<30, 1, u64> handheld_left_b;
BitField<31, 1, u64> lagon_c_left;
BitField<32, 1, u64> lagon_c_up;
BitField<33, 1, u64> lagon_c_right;
BitField<34, 1, u64> lagon_c_down;
};
};
static_assert(sizeof(NpadButtonState) == 0x8, "NpadButtonState has incorrect size.");
// This is nn::hid::DebugPadButton
struct DebugPadButton {
union {
u32 raw{};
BitField<0, 1, u32> a;
BitField<1, 1, u32> b;
BitField<2, 1, u32> x;
BitField<3, 1, u32> y;
BitField<4, 1, u32> l;
BitField<5, 1, u32> r;
BitField<6, 1, u32> zl;
BitField<7, 1, u32> zr;
BitField<8, 1, u32> plus;
BitField<9, 1, u32> minus;
BitField<10, 1, u32> d_left;
BitField<11, 1, u32> d_up;
BitField<12, 1, u32> d_right;
BitField<13, 1, u32> d_down;
};
};
static_assert(sizeof(DebugPadButton) == 0x4, "DebugPadButton is an invalid size");
// This is nn::hid::ConsoleSixAxisSensorHandle
struct ConsoleSixAxisSensorHandle {
u8 unknown_1;
u8 unknown_2;
INSERT_PADDING_BYTES_NOINIT(2);
};
static_assert(sizeof(ConsoleSixAxisSensorHandle) == 4,
"ConsoleSixAxisSensorHandle is an invalid size");
// This is nn::hid::SixAxisSensorHandle
struct SixAxisSensorHandle {
NpadStyleIndex npad_type;
u8 npad_id;
DeviceIndex device_index;
INSERT_PADDING_BYTES_NOINIT(1);
};
static_assert(sizeof(SixAxisSensorHandle) == 4, "SixAxisSensorHandle is an invalid size");
struct SixAxisSensorFusionParameters {
f32 parameter1;
f32 parameter2;
};
static_assert(sizeof(SixAxisSensorFusionParameters) == 8,
"SixAxisSensorFusionParameters is an invalid size");
// This is nn::hid::VibrationDeviceHandle
struct VibrationDeviceHandle {
NpadStyleIndex npad_type;
u8 npad_id;
DeviceIndex device_index;
INSERT_PADDING_BYTES_NOINIT(1);
};
static_assert(sizeof(VibrationDeviceHandle) == 4, "SixAxisSensorHandle is an invalid size");
// This is nn::hid::VibrationValue
struct VibrationValue {
f32 low_amplitude;
f32 low_frequency;
f32 high_amplitude;
f32 high_frequency;
};
static_assert(sizeof(VibrationValue) == 0x10, "VibrationValue has incorrect size.");
// This is nn::hid::VibrationDeviceInfo
struct VibrationDeviceInfo {
VibrationDeviceType type{};
VibrationDevicePosition position{};
};
static_assert(sizeof(VibrationDeviceInfo) == 0x8, "VibrationDeviceInfo has incorrect size.");
// This is nn::hid::KeyboardModifier
struct KeyboardModifier {
union {
u32 raw{};
BitField<0, 1, u32> control;
BitField<1, 1, u32> shift;
BitField<2, 1, u32> left_alt;
BitField<3, 1, u32> right_alt;
BitField<4, 1, u32> gui;
BitField<8, 1, u32> caps_lock;
BitField<9, 1, u32> scroll_lock;
BitField<10, 1, u32> num_lock;
BitField<11, 1, u32> katakana;
BitField<12, 1, u32> hiragana;
};
};
static_assert(sizeof(KeyboardModifier) == 0x4, "KeyboardModifier is an invalid size");
// This is nn::hid::KeyboardAttribute
struct KeyboardAttribute {
union {
u32 raw{};
BitField<0, 1, u32> is_connected;
};
};
static_assert(sizeof(KeyboardAttribute) == 0x4, "KeyboardAttribute is an invalid size");
// This is nn::hid::KeyboardKey
struct KeyboardKey {
// This should be a 256 bit flag
std::array<u8, 32> key;
};
static_assert(sizeof(KeyboardKey) == 0x20, "KeyboardKey is an invalid size");
// This is nn::hid::MouseButton
struct MouseButton {
union {
u32_le raw{};
BitField<0, 1, u32> left;
BitField<1, 1, u32> right;
BitField<2, 1, u32> middle;
BitField<3, 1, u32> forward;
BitField<4, 1, u32> back;
};
};
static_assert(sizeof(MouseButton) == 0x4, "MouseButton is an invalid size");
// This is nn::hid::MouseAttribute
struct MouseAttribute {
union {
u32 raw{};
BitField<0, 1, u32> transferable;
BitField<1, 1, u32> is_connected;
};
};
static_assert(sizeof(MouseAttribute) == 0x4, "MouseAttribute is an invalid size");
// This is nn::hid::detail::MouseState
struct MouseState {
s64 sampling_number;
s32 x;
s32 y;
s32 delta_x;
s32 delta_y;
// Axis Order in HW is switched for the wheel
s32 delta_wheel_y;
s32 delta_wheel_x;
MouseButton button;
MouseAttribute attribute;
};
static_assert(sizeof(MouseState) == 0x28, "MouseState is an invalid size");
/// Converts a NpadIdType to an array index.
constexpr size_t NpadIdTypeToIndex(NpadIdType npad_id_type) {
switch (npad_id_type) {
case NpadIdType::Player1:
return 0;
case NpadIdType::Player2:
return 1;
case NpadIdType::Player3:
return 2;
case NpadIdType::Player4:
return 3;
case NpadIdType::Player5:
return 4;
case NpadIdType::Player6:
return 5;
case NpadIdType::Player7:
return 6;
case NpadIdType::Player8:
return 7;
case NpadIdType::Handheld:
return 8;
case NpadIdType::Other:
return 9;
default:
return 0;
}
}
/// Converts an array index to a NpadIdType
constexpr NpadIdType IndexToNpadIdType(size_t index) {
switch (index) {
case 0:
return NpadIdType::Player1;
case 1:
return NpadIdType::Player2;
case 2:
return NpadIdType::Player3;
case 3:
return NpadIdType::Player4;
case 4:
return NpadIdType::Player5;
case 5:
return NpadIdType::Player6;
case 6:
return NpadIdType::Player7;
case 7:
return NpadIdType::Player8;
case 8:
return NpadIdType::Handheld;
case 9:
return NpadIdType::Other;
default:
return NpadIdType::Invalid;
}
}
} // namespace Core::HID

View File

@@ -0,0 +1,383 @@
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included
#include <random>
#include "common/input.h"
#include "core/hid/input_converter.h"
namespace Core::HID {
Common::Input::BatteryStatus TransformToBattery(const Common::Input::CallbackStatus& callback) {
Common::Input::BatteryStatus battery{Common::Input::BatteryStatus::None};
switch (callback.type) {
case Common::Input::InputType::Analog:
case Common::Input::InputType::Trigger: {
const auto value = TransformToTrigger(callback).analog.value;
battery = Common::Input::BatteryLevel::Empty;
if (value > 0.2f) {
battery = Common::Input::BatteryLevel::Critical;
}
if (value > 0.4f) {
battery = Common::Input::BatteryLevel::Low;
}
if (value > 0.6f) {
battery = Common::Input::BatteryLevel::Medium;
}
if (value > 0.8f) {
battery = Common::Input::BatteryLevel::Full;
}
if (value >= 1.0f) {
battery = Common::Input::BatteryLevel::Charging;
}
break;
}
case Common::Input::InputType::Button:
battery = callback.button_status.value ? Common::Input::BatteryLevel::Charging
: Common::Input::BatteryLevel::Critical;
break;
case Common::Input::InputType::Battery:
battery = callback.battery_status;
break;
default:
LOG_ERROR(Input, "Conversion from type {} to battery not implemented", callback.type);
break;
}
return battery;
}
Common::Input::ButtonStatus TransformToButton(const Common::Input::CallbackStatus& callback) {
Common::Input::ButtonStatus status{};
switch (callback.type) {
case Common::Input::InputType::Analog:
case Common::Input::InputType::Trigger:
status.value = TransformToTrigger(callback).pressed.value;
break;
case Common::Input::InputType::Button:
status = callback.button_status;
break;
default:
LOG_ERROR(Input, "Conversion from type {} to button not implemented", callback.type);
break;
}
if (status.inverted) {
status.value = !status.value;
}
return status;
}
Common::Input::MotionStatus TransformToMotion(const Common::Input::CallbackStatus& callback) {
Common::Input::MotionStatus status{};
switch (callback.type) {
case Common::Input::InputType::Button: {
Common::Input::AnalogProperties properties{
.deadzone = 0.0f,
.range = 1.0f,
.offset = 0.0f,
};
status.delta_timestamp = 5000;
status.force_update = true;
status.accel.x = {
.value = 0.0f,
.raw_value = 0.0f,
.properties = properties,
};
status.accel.y = {
.value = 0.0f,
.raw_value = 0.0f,
.properties = properties,
};
status.accel.z = {
.value = 0.0f,
.raw_value = -1.0f,
.properties = properties,
};
status.gyro.x = {
.value = 0.0f,
.raw_value = 0.0f,
.properties = properties,
};
status.gyro.y = {
.value = 0.0f,
.raw_value = 0.0f,
.properties = properties,
};
status.gyro.z = {
.value = 0.0f,
.raw_value = 0.0f,
.properties = properties,
};
if (TransformToButton(callback).value) {
std::random_device device;
std::mt19937 gen(device());
std::uniform_int_distribution<s16> distribution(-1000, 1000);
status.accel.x.raw_value = static_cast<f32>(distribution(gen)) * 0.001f;
status.accel.y.raw_value = static_cast<f32>(distribution(gen)) * 0.001f;
status.accel.z.raw_value = static_cast<f32>(distribution(gen)) * 0.001f;
status.gyro.x.raw_value = static_cast<f32>(distribution(gen)) * 0.001f;
status.gyro.y.raw_value = static_cast<f32>(distribution(gen)) * 0.001f;
status.gyro.z.raw_value = static_cast<f32>(distribution(gen)) * 0.001f;
}
break;
}
case Common::Input::InputType::Motion:
status = callback.motion_status;
break;
default:
LOG_ERROR(Input, "Conversion from type {} to motion not implemented", callback.type);
break;
}
SanitizeAnalog(status.accel.x, false);
SanitizeAnalog(status.accel.y, false);
SanitizeAnalog(status.accel.z, false);
SanitizeAnalog(status.gyro.x, false);
SanitizeAnalog(status.gyro.y, false);
SanitizeAnalog(status.gyro.z, false);
return status;
}
Common::Input::StickStatus TransformToStick(const Common::Input::CallbackStatus& callback) {
Common::Input::StickStatus status{};
switch (callback.type) {
case Common::Input::InputType::Stick:
status = callback.stick_status;
break;
default:
LOG_ERROR(Input, "Conversion from type {} to stick not implemented", callback.type);
break;
}
SanitizeStick(status.x, status.y, true);
const auto& properties_x = status.x.properties;
const auto& properties_y = status.y.properties;
const float x = status.x.value;
const float y = status.y.value;
// Set directional buttons
status.right = x > properties_x.threshold;
status.left = x < -properties_x.threshold;
status.up = y > properties_y.threshold;
status.down = y < -properties_y.threshold;
return status;
}
Common::Input::TouchStatus TransformToTouch(const Common::Input::CallbackStatus& callback) {
Common::Input::TouchStatus status{};
switch (callback.type) {
case Common::Input::InputType::Touch:
status = callback.touch_status;
break;
case Common::Input::InputType::Stick:
status.x = callback.stick_status.x;
status.y = callback.stick_status.y;
break;
default:
LOG_ERROR(Input, "Conversion from type {} to touch not implemented", callback.type);
break;
}
SanitizeAnalog(status.x, true);
SanitizeAnalog(status.y, true);
float& x = status.x.value;
float& y = status.y.value;
// Adjust if value is inverted
x = status.x.properties.inverted ? 1.0f + x : x;
y = status.y.properties.inverted ? 1.0f + y : y;
// clamp value
x = std::clamp(x, 0.0f, 1.0f);
y = std::clamp(y, 0.0f, 1.0f);
if (status.pressed.inverted) {
status.pressed.value = !status.pressed.value;
}
return status;
}
Common::Input::TriggerStatus TransformToTrigger(const Common::Input::CallbackStatus& callback) {
Common::Input::TriggerStatus status{};
float& raw_value = status.analog.raw_value;
bool calculate_button_value = true;
switch (callback.type) {
case Common::Input::InputType::Analog:
status.analog.properties = callback.analog_status.properties;
raw_value = callback.analog_status.raw_value;
break;
case Common::Input::InputType::Button:
status.analog.properties.range = 1.0f;
status.analog.properties.inverted = callback.button_status.inverted;
raw_value = callback.button_status.value ? 1.0f : 0.0f;
break;
case Common::Input::InputType::Trigger:
status = callback.trigger_status;
calculate_button_value = false;
break;
default:
LOG_ERROR(Input, "Conversion from type {} to trigger not implemented", callback.type);
break;
}
SanitizeAnalog(status.analog, true);
const auto& properties = status.analog.properties;
float& value = status.analog.value;
// Set button status
if (calculate_button_value) {
status.pressed.value = value > properties.threshold;
}
// Adjust if value is inverted
value = properties.inverted ? 1.0f + value : value;
// clamp value
value = std::clamp(value, 0.0f, 1.0f);
return status;
}
Common::Input::AnalogStatus TransformToAnalog(const Common::Input::CallbackStatus& callback) {
Common::Input::AnalogStatus status{};
switch (callback.type) {
case Common::Input::InputType::Analog:
status.properties = callback.analog_status.properties;
status.raw_value = callback.analog_status.raw_value;
break;
default:
LOG_ERROR(Input, "Conversion from type {} to analog not implemented", callback.type);
break;
}
SanitizeAnalog(status, false);
// Adjust if value is inverted
status.value = status.properties.inverted ? -status.value : status.value;
return status;
}
void SanitizeAnalog(Common::Input::AnalogStatus& analog, bool clamp_value) {
const auto& properties = analog.properties;
float& raw_value = analog.raw_value;
float& value = analog.value;
if (!std::isnormal(raw_value)) {
raw_value = 0;
}
// Apply center offset
raw_value -= properties.offset;
// Set initial values to be formated
value = raw_value;
// Calculate vector size
const float r = std::abs(value);
// Return zero if value is smaller than the deadzone
if (r <= properties.deadzone || properties.deadzone == 1.0f) {
analog.value = 0;
return;
}
// Adjust range of value
const float deadzone_factor =
1.0f / r * (r - properties.deadzone) / (1.0f - properties.deadzone);
value = value * deadzone_factor / properties.range;
// Invert direction if needed
if (properties.inverted) {
value = -value;
}
// Clamp value
if (clamp_value) {
value = std::clamp(value, -1.0f, 1.0f);
}
}
void SanitizeStick(Common::Input::AnalogStatus& analog_x, Common::Input::AnalogStatus& analog_y,
bool clamp_value) {
const auto& properties_x = analog_x.properties;
const auto& properties_y = analog_y.properties;
float& raw_x = analog_x.raw_value;
float& raw_y = analog_y.raw_value;
float& x = analog_x.value;
float& y = analog_y.value;
if (!std::isnormal(raw_x)) {
raw_x = 0;
}
if (!std::isnormal(raw_y)) {
raw_y = 0;
}
// Apply center offset
raw_x += properties_x.offset;
raw_y += properties_y.offset;
// Apply X scale correction from offset
if (std::abs(properties_x.offset) < 0.5f) {
if (raw_x > 0) {
raw_x /= 1 + properties_x.offset;
} else {
raw_x /= 1 - properties_x.offset;
}
}
// Apply Y scale correction from offset
if (std::abs(properties_y.offset) < 0.5f) {
if (raw_y > 0) {
raw_y /= 1 + properties_y.offset;
} else {
raw_y /= 1 - properties_y.offset;
}
}
// Invert direction if needed
raw_x = properties_x.inverted ? -raw_x : raw_x;
raw_y = properties_y.inverted ? -raw_y : raw_y;
// Set initial values to be formated
x = raw_x;
y = raw_y;
// Calculate vector size
float r = x * x + y * y;
r = std::sqrt(r);
// TODO(German77): Use deadzone and range of both axis
// Return zero if values are smaller than the deadzone
if (r <= properties_x.deadzone || properties_x.deadzone >= 1.0f) {
x = 0;
y = 0;
return;
}
// Adjust range of joystick
const float deadzone_factor =
1.0f / r * (r - properties_x.deadzone) / (1.0f - properties_x.deadzone);
x = x * deadzone_factor / properties_x.range;
y = y * deadzone_factor / properties_x.range;
r = r * deadzone_factor / properties_x.range;
// Normalize joystick
if (clamp_value && r > 1.0f) {
x /= r;
y /= r;
}
}
} // namespace Core::HID

View File

@@ -0,0 +1,96 @@
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included
#pragma once
namespace Common::Input {
struct CallbackStatus;
enum class BatteryLevel : u32;
using BatteryStatus = BatteryLevel;
struct AnalogStatus;
struct ButtonStatus;
struct MotionStatus;
struct StickStatus;
struct TouchStatus;
struct TriggerStatus;
}; // namespace Common::Input
namespace Core::HID {
/**
* Converts raw input data into a valid battery status.
*
* @param callback Supported callbacks: Analog, Battery, Trigger.
* @return A valid BatteryStatus object.
*/
Common::Input::BatteryStatus TransformToBattery(const Common::Input::CallbackStatus& callback);
/**
* Converts raw input data into a valid button status. Applies invert properties to the output.
*
* @param callback Supported callbacks: Analog, Button, Trigger.
* @return A valid TouchStatus object.
*/
Common::Input::ButtonStatus TransformToButton(const Common::Input::CallbackStatus& callback);
/**
* Converts raw input data into a valid motion status.
*
* @param callback Supported callbacks: Motion.
* @return A valid TouchStatus object.
*/
Common::Input::MotionStatus TransformToMotion(const Common::Input::CallbackStatus& callback);
/**
* Converts raw input data into a valid stick status. Applies offset, deadzone, range and invert
* properties to the output.
*
* @param callback Supported callbacks: Stick.
* @return A valid StickStatus object.
*/
Common::Input::StickStatus TransformToStick(const Common::Input::CallbackStatus& callback);
/**
* Converts raw input data into a valid touch status.
*
* @param callback Supported callbacks: Touch.
* @return A valid TouchStatus object.
*/
Common::Input::TouchStatus TransformToTouch(const Common::Input::CallbackStatus& callback);
/**
* Converts raw input data into a valid trigger status. Applies offset, deadzone, range and
* invert properties to the output. Button status uses the threshold property if necessary.
*
* @param callback Supported callbacks: Analog, Button, Trigger.
* @return A valid TriggerStatus object.
*/
Common::Input::TriggerStatus TransformToTrigger(const Common::Input::CallbackStatus& callback);
/**
* Converts raw input data into a valid analog status. Applies offset, deadzone, range and
* invert properties to the output.
*
* @param callback Supported callbacks: Analog.
* @return A valid AnalogStatus object.
*/
Common::Input::AnalogStatus TransformToAnalog(const Common::Input::CallbackStatus& callback);
/**
* Converts raw analog data into a valid analog value
* @param analog An analog object containing raw data and properties
* @param clamp_value determines if the value needs to be clamped between -1.0f and 1.0f.
*/
void SanitizeAnalog(Common::Input::AnalogStatus& analog, bool clamp_value);
/**
* Converts raw stick data into a valid stick value
* @param analog_x raw analog data and properties for the x-axis
* @param analog_y raw analog data and properties for the y-axis
* @param clamp_value bool that determines if the value needs to be clamped into the unit circle.
*/
void SanitizeStick(Common::Input::AnalogStatus& analog_x, Common::Input::AnalogStatus& analog_y,
bool clamp_value);
} // namespace Core::HID

View File

@@ -3,7 +3,8 @@
// Refer to the license.txt file included.
#include "core/core.h"
#include "core/frontend/input_interpreter.h"
#include "core/hid/hid_types.h"
#include "core/hid/input_interpreter.h"
#include "core/hle/service/hid/controllers/npad.h"
#include "core/hle/service/hid/hid.h"
#include "core/hle/service/sm/sm.h"
@@ -19,7 +20,7 @@ InputInterpreter::InputInterpreter(Core::System& system)
InputInterpreter::~InputInterpreter() = default;
void InputInterpreter::PollInput() {
const u32 button_state = npad.GetAndResetPressState();
const auto button_state = npad.GetAndResetPressState();
previous_index = current_index;
current_index = (current_index + 1) % button_states.size();
@@ -31,32 +32,30 @@ void InputInterpreter::ResetButtonStates() {
previous_index = 0;
current_index = 0;
button_states[0] = 0xFFFFFFFF;
button_states[0] = Core::HID::NpadButton::All;
for (std::size_t i = 1; i < button_states.size(); ++i) {
button_states[i] = 0;
button_states[i] = Core::HID::NpadButton::None;
}
}
bool InputInterpreter::IsButtonPressed(HIDButton button) const {
return (button_states[current_index] & (1U << static_cast<u8>(button))) != 0;
bool InputInterpreter::IsButtonPressed(Core::HID::NpadButton button) const {
return True(button_states[current_index] & button);
}
bool InputInterpreter::IsButtonPressedOnce(HIDButton button) const {
const bool current_press =
(button_states[current_index] & (1U << static_cast<u8>(button))) != 0;
const bool previous_press =
(button_states[previous_index] & (1U << static_cast<u8>(button))) != 0;
bool InputInterpreter::IsButtonPressedOnce(Core::HID::NpadButton button) const {
const bool current_press = True(button_states[current_index] & button);
const bool previous_press = True(button_states[previous_index] & button);
return current_press && !previous_press;
}
bool InputInterpreter::IsButtonHeld(HIDButton button) const {
u32 held_buttons{button_states[0]};
bool InputInterpreter::IsButtonHeld(Core::HID::NpadButton button) const {
Core::HID::NpadButton held_buttons{button_states[0]};
for (std::size_t i = 1; i < button_states.size(); ++i) {
held_buttons &= button_states[i];
}
return (held_buttons & (1U << static_cast<u8>(button))) != 0;
return True(held_buttons & button);
}

View File

@@ -12,46 +12,14 @@ namespace Core {
class System;
}
namespace Core::HID {
enum class NpadButton : u64;
}
namespace Service::HID {
class Controller_NPad;
}
enum class HIDButton : u8 {
A,
B,
X,
Y,
LStick,
RStick,
L,
R,
ZL,
ZR,
Plus,
Minus,
DLeft,
DUp,
DRight,
DDown,
LStickLeft,
LStickUp,
LStickRight,
LStickDown,
RStickLeft,
RStickUp,
RStickRight,
RStickDown,
LeftSL,
LeftSR,
RightSL,
RightSR,
};
/**
* The InputInterpreter class interfaces with HID to retrieve button press states.
* Input is intended to be polled every 50ms so that a button is considered to be
@@ -76,7 +44,7 @@ public:
*
* @returns True when the button is pressed.
*/
[[nodiscard]] bool IsButtonPressed(HIDButton button) const;
[[nodiscard]] bool IsButtonPressed(Core::HID::NpadButton button) const;
/**
* Checks whether any of the buttons in the parameter list is pressed.
@@ -85,7 +53,7 @@ public:
*
* @returns True when at least one of the buttons is pressed.
*/
template <HIDButton... T>
template <Core::HID::NpadButton... T>
[[nodiscard]] bool IsAnyButtonPressed() {
return (IsButtonPressed(T) || ...);
}
@@ -98,7 +66,7 @@ public:
*
* @returns True when the button is pressed once.
*/
[[nodiscard]] bool IsButtonPressedOnce(HIDButton button) const;
[[nodiscard]] bool IsButtonPressedOnce(Core::HID::NpadButton button) const;
/**
* Checks whether any of the buttons in the parameter list is pressed once.
@@ -107,7 +75,7 @@ public:
*
* @returns True when at least one of the buttons is pressed once.
*/
template <HIDButton... T>
template <Core::HID::NpadButton... T>
[[nodiscard]] bool IsAnyButtonPressedOnce() const {
return (IsButtonPressedOnce(T) || ...);
}
@@ -119,7 +87,7 @@ public:
*
* @returns True when the button is held down.
*/
[[nodiscard]] bool IsButtonHeld(HIDButton button) const;
[[nodiscard]] bool IsButtonHeld(Core::HID::NpadButton button) const;
/**
* Checks whether any of the buttons in the parameter list is held down.
@@ -128,7 +96,7 @@ public:
*
* @returns True when at least one of the buttons is held down.
*/
template <HIDButton... T>
template <Core::HID::NpadButton... T>
[[nodiscard]] bool IsAnyButtonHeld() const {
return (IsButtonHeld(T) || ...);
}
@@ -137,7 +105,7 @@ private:
Service::HID::Controller_NPad& npad;
/// Stores 9 consecutive button states polled from HID.
std::array<u32, 9> button_states{};
std::array<Core::HID::NpadButton, 9> button_states{};
std::size_t previous_index{};
std::size_t current_index{};

View File

@@ -2,13 +2,21 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included
#include <random>
#include "common/math_util.h"
#include "input_common/motion_input.h"
#include "core/hid/motion_input.h"
namespace InputCommon {
namespace Core::HID {
MotionInput::MotionInput(f32 new_kp, f32 new_ki, f32 new_kd) : kp(new_kp), ki(new_ki), kd(new_kd) {}
MotionInput::MotionInput() {
// Initialize PID constants with default values
SetPID(0.3f, 0.005f, 0.0f);
}
void MotionInput::SetPID(f32 new_kp, f32 new_ki, f32 new_kd) {
kp = new_kp;
ki = new_ki;
kd = new_kd;
}
void MotionInput::SetAcceleration(const Common::Vec3f& acceleration) {
accel = acceleration;
@@ -65,6 +73,8 @@ void MotionInput::UpdateRotation(u64 elapsed_time) {
rotations += gyro * sample_period;
}
// Based on Madgwick's implementation of Mayhony's AHRS algorithm.
// https://github.com/xioTechnologies/Open-Source-AHRS-With-x-IMU/blob/master/x-IMU%20IMU%20and%20AHRS%20Algorithms/x-IMU%20IMU%20and%20AHRS%20Algorithms/AHRS/MahonyAHRS.cs
void MotionInput::UpdateOrientation(u64 elapsed_time) {
if (!IsCalibrated(0.1f)) {
ResetOrientation();
@@ -190,43 +200,6 @@ Common::Vec3f MotionInput::GetRotations() const {
return rotations;
}
Input::MotionStatus MotionInput::GetMotion() const {
const Common::Vec3f gyroscope = GetGyroscope();
const Common::Vec3f accelerometer = GetAcceleration();
const Common::Vec3f rotation = GetRotations();
const std::array<Common::Vec3f, 3> orientation = GetOrientation();
const Common::Quaternion<f32> quaternion = GetQuaternion();
return {accelerometer, gyroscope, rotation, orientation, quaternion};
}
Input::MotionStatus MotionInput::GetRandomMotion(int accel_magnitude, int gyro_magnitude) const {
std::random_device device;
std::mt19937 gen(device());
std::uniform_int_distribution<s16> distribution(-1000, 1000);
const Common::Vec3f gyroscope{
static_cast<f32>(distribution(gen)) * 0.001f,
static_cast<f32>(distribution(gen)) * 0.001f,
static_cast<f32>(distribution(gen)) * 0.001f,
};
const Common::Vec3f accelerometer{
static_cast<f32>(distribution(gen)) * 0.001f,
static_cast<f32>(distribution(gen)) * 0.001f,
static_cast<f32>(distribution(gen)) * 0.001f,
};
constexpr Common::Vec3f rotation;
constexpr std::array orientation{
Common::Vec3f{1.0f, 0.0f, 0.0f},
Common::Vec3f{0.0f, 1.0f, 0.0f},
Common::Vec3f{0.0f, 0.0f, 1.0f},
};
constexpr Common::Quaternion<f32> quaternion{
{0.0f, 0.0f, 0.0f},
1.0f,
};
return {accelerometer * accel_magnitude, gyroscope * gyro_magnitude, rotation, orientation,
quaternion};
}
void MotionInput::ResetOrientation() {
if (!reset_enabled || only_accelerometer) {
return;
@@ -304,4 +277,4 @@ void MotionInput::SetOrientationFromAccelerometer() {
quat = quat.Normalized();
}
}
} // namespace InputCommon
} // namespace Core::HID

View File

@@ -7,13 +7,12 @@
#include "common/common_types.h"
#include "common/quaternion.h"
#include "common/vector_math.h"
#include "core/frontend/input.h"
namespace InputCommon {
namespace Core::HID {
class MotionInput {
public:
explicit MotionInput(f32 new_kp, f32 new_ki, f32 new_kd);
explicit MotionInput();
MotionInput(const MotionInput&) = default;
MotionInput& operator=(const MotionInput&) = default;
@@ -21,6 +20,7 @@ public:
MotionInput(MotionInput&&) = default;
MotionInput& operator=(MotionInput&&) = default;
void SetPID(f32 new_kp, f32 new_ki, f32 new_kd);
void SetAcceleration(const Common::Vec3f& acceleration);
void SetGyroscope(const Common::Vec3f& gyroscope);
void SetQuaternion(const Common::Quaternion<f32>& quaternion);
@@ -38,9 +38,6 @@ public:
[[nodiscard]] Common::Vec3f GetGyroscope() const;
[[nodiscard]] Common::Vec3f GetRotations() const;
[[nodiscard]] Common::Quaternion<f32> GetQuaternion() const;
[[nodiscard]] Input::MotionStatus GetMotion() const;
[[nodiscard]] Input::MotionStatus GetRandomMotion(int accel_magnitude,
int gyro_magnitude) const;
[[nodiscard]] bool IsMoving(f32 sensitivity) const;
[[nodiscard]] bool IsCalibrated(f32 sensitivity) const;
@@ -59,16 +56,32 @@ private:
Common::Vec3f integral_error;
Common::Vec3f derivative_error;
// Quaternion containing the device orientation
Common::Quaternion<f32> quat{{0.0f, 0.0f, -1.0f}, 0.0f};
// Number of full rotations in each axis
Common::Vec3f rotations;
// Acceleration vector measurement in G force
Common::Vec3f accel;
// Gyroscope vector measurement in radians/s.
Common::Vec3f gyro;
// Vector to be substracted from gyro measurements
Common::Vec3f gyro_drift;
// Minimum gyro amplitude to detect if the device is moving
f32 gyro_threshold = 0.0f;
// Number of invalid sequential data
u32 reset_counter = 0;
// If the provided data is invalid the device will be autocalibrated
bool reset_enabled = true;
// Use accelerometer values to calculate position
bool only_accelerometer = true;
};
} // namespace InputCommon
} // namespace Core::HID

View File

@@ -685,8 +685,8 @@ ResultCode KPageTable::UnmapPages(VAddr addr, KPageLinkedList& page_linked_list,
return ResultSuccess;
}
ResultCode KPageTable::SetCodeMemoryPermission(VAddr addr, std::size_t size,
KMemoryPermission perm) {
ResultCode KPageTable::SetProcessMemoryPermission(VAddr addr, std::size_t size,
KMemoryPermission perm) {
std::lock_guard lock{page_table_lock};

View File

@@ -41,7 +41,7 @@ public:
ResultCode MapPages(VAddr addr, KPageLinkedList& page_linked_list, KMemoryState state,
KMemoryPermission perm);
ResultCode UnmapPages(VAddr addr, KPageLinkedList& page_linked_list, KMemoryState state);
ResultCode SetCodeMemoryPermission(VAddr addr, std::size_t size, KMemoryPermission perm);
ResultCode SetProcessMemoryPermission(VAddr addr, std::size_t size, KMemoryPermission perm);
KMemoryInfo QueryInfo(VAddr addr);
ResultCode ReserveTransferMemory(VAddr addr, std::size_t size, KMemoryPermission perm);
ResultCode ResetTransferMemory(VAddr addr, std::size_t size);

View File

@@ -528,7 +528,7 @@ void KProcess::LoadModule(CodeSet code_set, VAddr base_addr) {
std::lock_guard lock{HLE::g_hle_lock};
const auto ReprotectSegment = [&](const CodeSet::Segment& segment,
KMemoryPermission permission) {
page_table->SetCodeMemoryPermission(segment.addr + base_addr, segment.size, permission);
page_table->SetProcessMemoryPermission(segment.addr + base_addr, segment.size, permission);
};
kernel.System().Memory().WriteBlock(*this, base_addr, code_set.memory.data(),

View File

@@ -154,8 +154,8 @@ public:
return process_id;
}
/// Gets the title ID corresponding to this process.
u64 GetTitleID() const {
/// Gets the program ID corresponding to this process.
u64 GetProgramID() const {
return program_id;
}

View File

@@ -300,15 +300,16 @@ struct KernelCore::Impl {
// Gets the dummy KThread for the caller, allocating a new one if this is the first time
KThread* GetHostDummyThread() {
auto make_thread = [this]() {
std::unique_ptr<KThread> thread = std::make_unique<KThread>(system.Kernel());
std::lock_guard lk(dummy_thread_lock);
auto& thread = dummy_threads.emplace_back(std::make_unique<KThread>(system.Kernel()));
KAutoObject::Create(thread.get());
ASSERT(KThread::InitializeDummyThread(thread.get()).IsSuccess());
thread->SetName(fmt::format("DummyThread:{}", GetHostThreadId()));
return thread;
return thread.get();
};
thread_local auto thread = make_thread();
return thread.get();
thread_local KThread* saved_thread = make_thread();
return saved_thread;
}
/// Registers a CPU core thread by allocating a host thread ID for it
@@ -695,6 +696,12 @@ struct KernelCore::Impl {
return port;
}
std::mutex server_ports_lock;
std::mutex server_sessions_lock;
std::mutex registered_objects_lock;
std::mutex registered_in_use_objects_lock;
std::mutex dummy_thread_lock;
std::atomic<u32> next_object_id{0};
std::atomic<u64> next_kernel_process_id{KProcess::InitialKIPIDMin};
std::atomic<u64> next_user_process_id{KProcess::ProcessIDMin};
@@ -725,10 +732,6 @@ struct KernelCore::Impl {
std::unordered_set<KServerSession*> server_sessions;
std::unordered_set<KAutoObject*> registered_objects;
std::unordered_set<KAutoObject*> registered_in_use_objects;
std::mutex server_ports_lock;
std::mutex server_sessions_lock;
std::mutex registered_objects_lock;
std::mutex registered_in_use_objects_lock;
std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor;
std::vector<Kernel::PhysicalCore> cores;
@@ -753,6 +756,9 @@ struct KernelCore::Impl {
std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES> interrupts{};
std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{};
// Specifically tracked to be automatically destroyed with kernel
std::vector<std::unique_ptr<KThread>> dummy_threads;
bool is_multicore{};
bool is_phantom_mode_for_singlecore{};
u32 single_core_thread_id{};

View File

@@ -768,7 +768,7 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, Handle
return ResultSuccess;
case GetInfoType::TitleId:
*result = process->GetTitleID();
*result = process->GetProgramID();
return ResultSuccess;
case GetInfoType::UserExceptionContextAddr:
@@ -1169,6 +1169,8 @@ static u32 GetCurrentProcessorNumber32(Core::System& system) {
return GetCurrentProcessorNumber(system);
}
namespace {
constexpr bool IsValidSharedMemoryPermission(Svc::MemoryPermission perm) {
switch (perm) {
case Svc::MemoryPermission::Read:
@@ -1179,10 +1181,24 @@ constexpr bool IsValidSharedMemoryPermission(Svc::MemoryPermission perm) {
}
}
constexpr bool IsValidRemoteSharedMemoryPermission(Svc::MemoryPermission perm) {
[[maybe_unused]] constexpr bool IsValidRemoteSharedMemoryPermission(Svc::MemoryPermission perm) {
return IsValidSharedMemoryPermission(perm) || perm == Svc::MemoryPermission::DontCare;
}
constexpr bool IsValidProcessMemoryPermission(Svc::MemoryPermission perm) {
switch (perm) {
case Svc::MemoryPermission::None:
case Svc::MemoryPermission::Read:
case Svc::MemoryPermission::ReadWrite:
case Svc::MemoryPermission::ReadExecute:
return true;
default:
return false;
}
}
} // Anonymous namespace
static ResultCode MapSharedMemory(Core::System& system, Handle shmem_handle, VAddr address,
u64 size, Svc::MemoryPermission map_perm) {
LOG_TRACE(Kernel_SVC,
@@ -1262,6 +1278,34 @@ static ResultCode UnmapSharedMemory32(Core::System& system, Handle shmem_handle,
return UnmapSharedMemory(system, shmem_handle, address, size);
}
static ResultCode SetProcessMemoryPermission(Core::System& system, Handle process_handle,
VAddr address, u64 size, Svc::MemoryPermission perm) {
LOG_TRACE(Kernel_SVC,
"called, process_handle=0x{:X}, addr=0x{:X}, size=0x{:X}, permissions=0x{:08X}",
process_handle, address, size, perm);
// Validate the address/size.
R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress);
R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize);
R_UNLESS(size > 0, ResultInvalidSize);
R_UNLESS((address < address + size), ResultInvalidCurrentMemory);
// Validate the memory permission.
R_UNLESS(IsValidProcessMemoryPermission(perm), ResultInvalidNewMemoryPermission);
// Get the process from its handle.
KScopedAutoObject process =
system.CurrentProcess()->GetHandleTable().GetObject<KProcess>(process_handle);
R_UNLESS(process.IsNotNull(), ResultInvalidHandle);
// Validate that the address is in range.
auto& page_table = process->PageTable();
R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory);
// Set the memory permission.
return page_table.SetProcessMemoryPermission(address, size, ConvertToKMemoryPermission(perm));
}
static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_address,
VAddr page_info_address, Handle process_handle,
VAddr address) {
@@ -1459,10 +1503,14 @@ static void ExitProcess32(Core::System& system) {
ExitProcess(system);
}
static constexpr bool IsValidVirtualCoreId(int32_t core_id) {
namespace {
constexpr bool IsValidVirtualCoreId(int32_t core_id) {
return (0 <= core_id && core_id < static_cast<int32_t>(Core::Hardware::NUM_CPU_CORES));
}
} // Anonymous namespace
/// Creates a new thread
static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr entry_point, u64 arg,
VAddr stack_bottom, u32 priority, s32 core_id) {
@@ -1846,7 +1894,9 @@ static ResultCode ResetSignal32(Core::System& system, Handle handle) {
return ResetSignal(system, handle);
}
static constexpr bool IsValidTransferMemoryPermission(MemoryPermission perm) {
namespace {
constexpr bool IsValidTransferMemoryPermission(MemoryPermission perm) {
switch (perm) {
case MemoryPermission::None:
case MemoryPermission::Read:
@@ -1857,6 +1907,8 @@ static constexpr bool IsValidTransferMemoryPermission(MemoryPermission perm) {
}
}
} // Anonymous namespace
/// Creates a TransferMemory object
static ResultCode CreateTransferMemory(Core::System& system, Handle* out, VAddr address, u64 size,
MemoryPermission map_perm) {
@@ -2588,7 +2640,7 @@ static const FunctionDef SVC_Table_64[] = {
{0x70, nullptr, "CreatePort"},
{0x71, nullptr, "ManageNamedPort"},
{0x72, nullptr, "ConnectToPort"},
{0x73, nullptr, "SetProcessMemoryPermission"},
{0x73, SvcWrap64<SetProcessMemoryPermission>, "SetProcessMemoryPermission"},
{0x74, nullptr, "MapProcessMemory"},
{0x75, nullptr, "UnmapProcessMemory"},
{0x76, SvcWrap64<QueryProcessMemory>, "QueryProcessMemory"},

View File

@@ -16,7 +16,6 @@
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/patch_manager.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/service/acc/acc.h"
#include "core/hle/service/acc/acc_aa.h"
@@ -759,9 +758,8 @@ ResultCode Module::Interface::InitializeApplicationInfoBase() {
// TODO(ogniK): This should be changed to reflect the target process for when we have multiple
// processes emulated. As we don't actually have pid support we should assume we're just using
// our own process
const auto& current_process = system.Kernel().CurrentProcess();
const auto launch_property =
system.GetARPManager().GetLaunchProperty(current_process->GetTitleID());
system.GetARPManager().GetLaunchProperty(system.GetCurrentProcessProgramID());
if (launch_property.Failed()) {
LOG_ERROR(Service_ACC, "Failed to get launch property");
@@ -805,7 +803,7 @@ void Module::Interface::IsUserAccountSwitchLocked(Kernel::HLERequestContext& ctx
bool is_locked = false;
if (res != Loader::ResultStatus::Success) {
const FileSys::PatchManager pm{system.CurrentProcess()->GetTitleID(),
const FileSys::PatchManager pm{system.GetCurrentProcessProgramID(),
system.GetFileSystemController(),
system.GetContentProvider()};
const auto nacp_unique = pm.GetControlMetadata().first;
@@ -824,6 +822,13 @@ void Module::Interface::IsUserAccountSwitchLocked(Kernel::HLERequestContext& ctx
rb.Push(is_locked);
}
void Module::Interface::InitializeApplicationInfoV2(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_ACC, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void Module::Interface::GetProfileEditor(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
Common::UUID user_id = rp.PopRaw<Common::UUID>();

View File

@@ -33,6 +33,7 @@ public:
void IsUserRegistrationRequestPermitted(Kernel::HLERequestContext& ctx);
void TrySelectUserWithoutInteraction(Kernel::HLERequestContext& ctx);
void IsUserAccountSwitchLocked(Kernel::HLERequestContext& ctx);
void InitializeApplicationInfoV2(Kernel::HLERequestContext& ctx);
void GetProfileEditor(Kernel::HLERequestContext& ctx);
void ListQualifiedUsers(Kernel::HLERequestContext& ctx);
void LoadOpenContext(Kernel::HLERequestContext& ctx);

View File

@@ -34,6 +34,7 @@ ACC_U0::ACC_U0(std::shared_ptr<Module> module_, std::shared_ptr<ProfileManager>
{140, &ACC_U0::InitializeApplicationInfoRestricted, "InitializeApplicationInfoRestricted"}, // 6.0.0+
{141, &ACC_U0::ListQualifiedUsers, "ListQualifiedUsers"}, // 6.0.0+
{150, &ACC_U0::IsUserAccountSwitchLocked, "IsUserAccountSwitchLocked"}, // 6.0.0+
{160, &ACC_U0::InitializeApplicationInfoV2, "InitializeApplicationInfoV2"},
};
// clang-format on

View File

@@ -15,7 +15,6 @@
#include "core/file_sys/savedata_factory.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/k_event.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_transfer_memory.h"
#include "core/hle/service/acc/profile_manager.h"
#include "core/hle/service/am/am.h"
@@ -798,15 +797,11 @@ void ICommonStateGetter::GetDefaultDisplayResolution(Kernel::HLERequestContext&
rb.Push(ResultSuccess);
if (Settings::values.use_docked_mode.GetValue()) {
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth) *
static_cast<u32>(Settings::values.resolution_factor.GetValue()));
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight) *
static_cast<u32>(Settings::values.resolution_factor.GetValue()));
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth));
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight));
} else {
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth) *
static_cast<u32>(Settings::values.resolution_factor.GetValue()));
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight) *
static_cast<u32>(Settings::values.resolution_factor.GetValue()));
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth));
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight));
}
}
@@ -1429,7 +1424,7 @@ void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) {
u64 build_id{};
std::memcpy(&build_id, build_id_full.data(), sizeof(u64));
auto data = backend->GetLaunchParameter({system.CurrentProcess()->GetTitleID(), build_id});
auto data = backend->GetLaunchParameter({system.GetCurrentProcessProgramID(), build_id});
if (data.has_value()) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
@@ -1481,7 +1476,7 @@ void IApplicationFunctions::EnsureSaveData(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called, uid={:016X}{:016X}", user_id[1], user_id[0]);
FileSys::SaveDataAttribute attribute{};
attribute.title_id = system.CurrentProcess()->GetTitleID();
attribute.title_id = system.GetCurrentProcessProgramID();
attribute.user_id = user_id;
attribute.type = FileSys::SaveDataType::SaveData;
const auto res = system.GetFileSystemController().CreateSaveData(
@@ -1511,7 +1506,7 @@ void IApplicationFunctions::GetDisplayVersion(Kernel::HLERequestContext& ctx) {
std::array<u8, 0x10> version_string{};
const auto res = [this] {
const auto title_id = system.CurrentProcess()->GetTitleID();
const auto title_id = system.GetCurrentProcessProgramID();
const FileSys::PatchManager pm{title_id, system.GetFileSystemController(),
system.GetContentProvider()};
@@ -1548,7 +1543,7 @@ void IApplicationFunctions::GetDesiredLanguage(Kernel::HLERequestContext& ctx) {
u32 supported_languages = 0;
const auto res = [this] {
const auto title_id = system.CurrentProcess()->GetTitleID();
const auto title_id = system.GetCurrentProcessProgramID();
const FileSys::PatchManager pm{title_id, system.GetFileSystemController(),
system.GetContentProvider()};
@@ -1656,7 +1651,7 @@ void IApplicationFunctions::ExtendSaveData(Kernel::HLERequestContext& ctx) {
static_cast<u8>(type), user_id[1], user_id[0], new_normal_size, new_journal_size);
system.GetFileSystemController().WriteSaveDataSize(
type, system.CurrentProcess()->GetTitleID(), user_id, {new_normal_size, new_journal_size});
type, system.GetCurrentProcessProgramID(), user_id, {new_normal_size, new_journal_size});
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
@@ -1680,7 +1675,7 @@ void IApplicationFunctions::GetSaveDataSize(Kernel::HLERequestContext& ctx) {
user_id[0]);
const auto size = system.GetFileSystemController().ReadSaveDataSize(
type, system.CurrentProcess()->GetTitleID(), user_id);
type, system.GetCurrentProcessProgramID(), user_id);
IPC::ResponseBuilder rb{ctx, 6};
rb.Push(ResultSuccess);

View File

@@ -10,6 +10,9 @@
#include "common/string_util.h"
#include "core/core.h"
#include "core/frontend/applets/controller.h"
#include "core/hid/emulated_controller.h"
#include "core/hid/hid_core.h"
#include "core/hid/hid_types.h"
#include "core/hle/result.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applets/applet_controller.h"
@@ -25,7 +28,7 @@ namespace Service::AM::Applets {
static Core::Frontend::ControllerParameters ConvertToFrontendParameters(
ControllerSupportArgPrivate private_arg, ControllerSupportArgHeader header, bool enable_text,
std::vector<IdentificationColor> identification_colors, std::vector<ExplainText> text) {
HID::Controller_NPad::NpadStyleSet npad_style_set;
Core::HID::NpadStyleTag npad_style_set;
npad_style_set.raw = private_arg.style_set;
return {
@@ -243,19 +246,11 @@ void Controller::Execute() {
void Controller::ConfigurationComplete() {
ControllerSupportResultInfo result_info{};
const auto& players = Settings::values.players.GetValue();
// If enable_single_mode is enabled, player_count is 1 regardless of any other parameters.
// Otherwise, only count connected players from P1-P8.
result_info.player_count =
is_single_mode
? 1
: static_cast<s8>(std::count_if(players.begin(), players.end() - 2,
[](const auto& player) { return player.connected; }));
result_info.player_count = is_single_mode ? 1 : system.HIDCore().GetPlayerCount();
result_info.selected_id = HID::Controller_NPad::IndexToNPad(std::distance(
players.begin(), std::find_if(players.begin(), players.end(),
[](const auto& player) { return player.connected; })));
result_info.selected_id = static_cast<u32>(system.HIDCore().GetFirstNpadId());
result_info.result = 0;

View File

@@ -16,6 +16,10 @@ namespace Core {
class System;
}
namespace Core::HID {
enum class NpadStyleSet : u32;
}
namespace Service::AM::Applets {
using IdentificationColor = std::array<u8, 4>;
@@ -52,7 +56,7 @@ struct ControllerSupportArgPrivate {
bool flag_1{};
ControllerSupportMode mode{};
ControllerSupportCaller caller{};
u32 style_set{};
Core::HID::NpadStyleSet style_set{};
u32 joy_hold_type{};
};
static_assert(sizeof(ControllerSupportArgPrivate) == 0x14,

View File

@@ -9,7 +9,6 @@
#include "common/string_util.h"
#include "core/core.h"
#include "core/frontend/applets/error.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applets/applet_error.h"
#include "core/reporter.h"
@@ -167,7 +166,7 @@ void Error::Execute() {
}
const auto callback = [this] { DisplayCompleted(); };
const auto title_id = system.CurrentProcess()->GetTitleID();
const auto title_id = system.GetCurrentProcessProgramID();
const auto& reporter{system.GetReporter()};
switch (mode) {

View File

@@ -7,7 +7,6 @@
#include "common/logging/log.h"
#include "core/core.h"
#include "core/frontend/applets/general_frontend.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/result.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applets/applet_general_backend.h"
@@ -187,7 +186,7 @@ void PhotoViewer::Execute() {
const auto callback = [this] { ViewFinished(); };
switch (mode) {
case PhotoViewerAppletMode::CurrentApp:
frontend.ShowPhotosForApplication(system.CurrentProcess()->GetTitleID(), callback);
frontend.ShowPhotosForApplication(system.GetCurrentProcessProgramID(), callback);
break;
case PhotoViewerAppletMode::AllApps:
frontend.ShowAllPhotos(callback);

View File

@@ -109,13 +109,18 @@ void SoftwareKeyboard::Execute() {
ShowNormalKeyboard();
}
void SoftwareKeyboard::SubmitTextNormal(SwkbdResult result, std::u16string submitted_text) {
void SoftwareKeyboard::SubmitTextNormal(SwkbdResult result, std::u16string submitted_text,
bool confirmed) {
if (complete) {
return;
}
if (swkbd_config_common.use_text_check && result == SwkbdResult::Ok) {
SubmitForTextCheck(submitted_text);
if (confirmed) {
SubmitNormalOutputAndExit(result, submitted_text);
} else {
SubmitForTextCheck(submitted_text);
}
} else {
SubmitNormalOutputAndExit(result, submitted_text);
}
@@ -273,13 +278,21 @@ void SoftwareKeyboard::ProcessTextCheck() {
std::memcpy(&swkbd_text_check, text_check_data.data(), sizeof(SwkbdTextCheck));
std::u16string text_check_message =
swkbd_text_check.text_check_result == SwkbdTextCheckResult::Failure ||
swkbd_text_check.text_check_result == SwkbdTextCheckResult::Confirm
? Common::UTF16StringFromFixedZeroTerminatedBuffer(
swkbd_text_check.text_check_message.data(),
swkbd_text_check.text_check_message.size())
: u"";
std::u16string text_check_message = [this, &swkbd_text_check]() -> std::u16string {
if (swkbd_text_check.text_check_result == SwkbdTextCheckResult::Failure ||
swkbd_text_check.text_check_result == SwkbdTextCheckResult::Confirm) {
return swkbd_config_common.use_utf8
? Common::UTF8ToUTF16(Common::StringFromFixedZeroTerminatedBuffer(
reinterpret_cast<const char*>(
swkbd_text_check.text_check_message.data()),
swkbd_text_check.text_check_message.size() * sizeof(char16_t)))
: Common::UTF16StringFromFixedZeroTerminatedBuffer(
swkbd_text_check.text_check_message.data(),
swkbd_text_check.text_check_message.size());
} else {
return u"";
}
}();
LOG_INFO(Service_AM, "\nTextCheckResult: {}\nTextCheckMessage: {}",
GetTextCheckResultName(swkbd_text_check.text_check_result),
@@ -583,11 +596,12 @@ void SoftwareKeyboard::InitializeFrontendKeyboard() {
.disable_cancel_button{disable_cancel_button},
};
frontend.InitializeKeyboard(false, std::move(initialize_parameters),
[this](SwkbdResult result, std::u16string submitted_text) {
SubmitTextNormal(result, submitted_text);
},
{});
frontend.InitializeKeyboard(
false, std::move(initialize_parameters),
[this](SwkbdResult result, std::u16string submitted_text, bool confirmed) {
SubmitTextNormal(result, submitted_text, confirmed);
},
{});
}
}

View File

@@ -36,8 +36,9 @@ public:
*
* @param result SwkbdResult enum
* @param submitted_text UTF-16 encoded string
* @param confirmed Whether the text has been confirmed after TextCheckResult::Confirm
*/
void SubmitTextNormal(SwkbdResult result, std::u16string submitted_text);
void SubmitTextNormal(SwkbdResult result, std::u16string submitted_text, bool confirmed);
/**
* Submits the input text to the application.

View File

@@ -18,7 +18,6 @@
#include "core/file_sys/system_archive/system_archive.h"
#include "core/file_sys/vfs_vector.h"
#include "core/frontend/applets/web_browser.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/result.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applets/applet_web_browser.h"
@@ -395,7 +394,7 @@ void WebBrowser::InitializeOffline() {
switch (document_kind) {
case DocumentKind::OfflineHtmlPage:
default:
title_id = system.CurrentProcess()->GetTitleID();
title_id = system.GetCurrentProcessProgramID();
nca_type = FileSys::ContentRecordType::HtmlDocument;
additional_paths = "html-document";
break;

View File

@@ -231,7 +231,7 @@ void AppletManager::SetDefaultAppletFrontendSet() {
void AppletManager::SetDefaultAppletsIfMissing() {
if (frontend.controller == nullptr) {
frontend.controller =
std::make_unique<Core::Frontend::DefaultControllerApplet>(system.ServiceManager());
std::make_unique<Core::Frontend::DefaultControllerApplet>(system.HIDCore());
}
if (frontend.error == nullptr) {

View File

@@ -17,7 +17,6 @@
#include "core/file_sys/registered_cache.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/k_event.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/service/aoc/aoc_u.h"
#include "core/loader/loader.h"
@@ -123,9 +122,14 @@ AOC_U::AOC_U(Core::System& system_)
{8, &AOC_U::GetAddOnContentListChangedEvent, "GetAddOnContentListChangedEvent"},
{9, nullptr, "GetAddOnContentLostErrorCode"},
{10, &AOC_U::GetAddOnContentListChangedEventWithProcessId, "GetAddOnContentListChangedEventWithProcessId"},
{11, &AOC_U::NotifyMountAddOnContent, "NotifyMountAddOnContent"},
{12, &AOC_U::NotifyUnmountAddOnContent, "NotifyUnmountAddOnContent"},
{13, nullptr, "IsAddOnContentMountedForDebug"},
{50, &AOC_U::CheckAddOnContentMountStatus, "CheckAddOnContentMountStatus"},
{100, &AOC_U::CreateEcPurchasedEventManager, "CreateEcPurchasedEventManager"},
{101, &AOC_U::CreatePermanentEcPurchasedEventManager, "CreatePermanentEcPurchasedEventManager"},
{110, nullptr, "CreateContentsServiceManager"},
{200, nullptr, "SetRequiredAddOnContentsOnContentsAvailabilityTransition"},
};
// clang-format on
@@ -152,7 +156,7 @@ void AOC_U::CountAddOnContent(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
const auto current = system.CurrentProcess()->GetTitleID();
const auto current = system.GetCurrentProcessProgramID();
const auto& disabled = Settings::values.disabled_addons[current];
if (std::find(disabled.begin(), disabled.end(), "DLC") != disabled.end()) {
@@ -179,7 +183,7 @@ void AOC_U::ListAddOnContent(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_AOC, "called with offset={}, count={}, process_id={}", offset, count,
process_id);
const auto current = system.CurrentProcess()->GetTitleID();
const auto current = system.GetCurrentProcessProgramID();
std::vector<u32> out;
const auto& disabled = Settings::values.disabled_addons[current];
@@ -225,7 +229,7 @@ void AOC_U::GetAddOnContentBaseId(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
const auto title_id = system.CurrentProcess()->GetTitleID();
const auto title_id = system.GetCurrentProcessProgramID();
const FileSys::PatchManager pm{title_id, system.GetFileSystemController(),
system.GetContentProvider()};
@@ -271,6 +275,27 @@ void AOC_U::GetAddOnContentListChangedEventWithProcessId(Kernel::HLERequestConte
rb.PushCopyObjects(aoc_change_event->GetReadableEvent());
}
void AOC_U::NotifyMountAddOnContent(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_AOC, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void AOC_U::NotifyUnmountAddOnContent(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_AOC, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void AOC_U::CheckAddOnContentMountStatus(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_AOC, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void AOC_U::CreateEcPurchasedEventManager(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_AOC, "(STUBBED) called");

View File

@@ -29,6 +29,9 @@ private:
void PrepareAddOnContent(Kernel::HLERequestContext& ctx);
void GetAddOnContentListChangedEvent(Kernel::HLERequestContext& ctx);
void GetAddOnContentListChangedEventWithProcessId(Kernel::HLERequestContext& ctx);
void NotifyMountAddOnContent(Kernel::HLERequestContext& ctx);
void NotifyUnmountAddOnContent(Kernel::HLERequestContext& ctx);
void CheckAddOnContentMountStatus(Kernel::HLERequestContext& ctx);
void CreateEcPurchasedEventManager(Kernel::HLERequestContext& ctx);
void CreatePermanentEcPurchasedEventManager(Kernel::HLERequestContext& ctx);

View File

@@ -11,7 +11,6 @@
#include "core/core.h"
#include "core/file_sys/vfs.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_readable_event.h"
#include "core/hle/service/bcat/backend/backend.h"
#include "core/hle/service/bcat/bcat.h"
@@ -178,7 +177,7 @@ private:
void RequestSyncDeliveryCache(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_BCAT, "called");
backend.Synchronize({system.CurrentProcess()->GetTitleID(),
backend.Synchronize({system.GetCurrentProcessProgramID(),
GetCurrentBuildID(system.GetCurrentProcessBuildID())},
GetProgressBackend(SyncType::Normal));
@@ -195,7 +194,7 @@ private:
LOG_DEBUG(Service_BCAT, "called, name={}", name);
backend.SynchronizeDirectory({system.CurrentProcess()->GetTitleID(),
backend.SynchronizeDirectory({system.GetCurrentProcessProgramID(),
GetCurrentBuildID(system.GetCurrentProcessBuildID())},
name, GetProgressBackend(SyncType::Directory));
@@ -556,7 +555,7 @@ private:
void Module::Interface::CreateDeliveryCacheStorageService(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_BCAT, "called");
const auto title_id = system.CurrentProcess()->GetTitleID();
const auto title_id = system.GetCurrentProcessProgramID();
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IDeliveryCacheStorageService>(system, fsc.GetBCATDirectory(title_id));

View File

@@ -11,7 +11,6 @@
#include "common/swap.h"
#include "core/core.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/service/fatal/fatal.h"
#include "core/hle/service/fatal/fatal_p.h"
#include "core/hle/service/fatal/fatal_u.h"
@@ -66,7 +65,7 @@ enum class FatalType : u32 {
static void GenerateErrorReport(Core::System& system, ResultCode error_code,
const FatalInfo& info) {
const auto title_id = system.CurrentProcess()->GetTitleID();
const auto title_id = system.GetCurrentProcessProgramID();
std::string crash_report = fmt::format(
"Yuzu {}-{} crash report\n"
"Title ID: {:016x}\n"

View File

@@ -20,7 +20,6 @@
#include "core/file_sys/sdmc_factory.h"
#include "core/file_sys/vfs.h"
#include "core/file_sys/vfs_offset.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/filesystem/fsp_ldr.h"
#include "core/hle/service/filesystem/fsp_pr.h"
@@ -320,7 +319,7 @@ ResultVal<FileSys::VirtualFile> FileSystemController::OpenRomFSCurrentProcess()
return ResultUnknown;
}
return romfs_factory->OpenCurrentProcess(system.CurrentProcess()->GetTitleID());
return romfs_factory->OpenCurrentProcess(system.GetCurrentProcessProgramID());
}
ResultVal<FileSys::VirtualFile> FileSystemController::OpenPatchedRomFS(
@@ -505,7 +504,7 @@ FileSys::SaveDataSize FileSystemController::ReadSaveDataSize(FileSys::SaveDataTy
const auto res = system.GetAppLoader().ReadControlData(nacp);
if (res != Loader::ResultStatus::Success) {
const FileSys::PatchManager pm{system.CurrentProcess()->GetTitleID(),
const FileSys::PatchManager pm{system.GetCurrentProcessProgramID(),
system.GetFileSystemController(),
system.GetContentProvider()};
const auto metadata = pm.GetControlMetadata();

View File

@@ -26,7 +26,6 @@
#include "core/file_sys/system_archive/system_archive.h"
#include "core/file_sys/vfs.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/filesystem/fsp_srv.h"
#include "core/reporter.h"
@@ -1035,7 +1034,7 @@ void FSP_SRV::OpenDataStorageWithProgramIndex(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_FS, "called, program_index={}", program_index);
auto patched_romfs = fsc.OpenPatchedRomFSWithProgramIndex(
system.CurrentProcess()->GetTitleID(), program_index, FileSys::ContentRecordType::Program);
system.GetCurrentProcessProgramID(), program_index, FileSys::ContentRecordType::Program);
if (patched_romfs.Failed()) {
// TODO: Find the right error code to use here

View File

@@ -26,7 +26,7 @@ std::optional<u64> GetTitleIDForProcessID(const Core::System& system, u64 proces
return std::nullopt;
}
return (*iter)->GetTitleID();
return (*iter)->GetProgramID();
}
} // Anonymous namespace

View File

@@ -4,13 +4,18 @@
#include "common/settings.h"
#include "core/core_timing.h"
#include "core/hid/emulated_console.h"
#include "core/hid/hid_core.h"
#include "core/hle/service/hid/controllers/console_sixaxis.h"
namespace Service::HID {
constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C200;
Controller_ConsoleSixAxis::Controller_ConsoleSixAxis(Core::System& system_)
: ControllerBase{system_} {}
Controller_ConsoleSixAxis::Controller_ConsoleSixAxis(Core::HID::HIDCore& hid_core_)
: ControllerBase{hid_core_} {
console = hid_core.GetEmulatedConsole();
}
Controller_ConsoleSixAxis::~Controller_ConsoleSixAxis() = default;
void Controller_ConsoleSixAxis::OnInit() {}
@@ -19,44 +24,31 @@ void Controller_ConsoleSixAxis::OnRelease() {}
void Controller_ConsoleSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
std::size_t size) {
seven_six_axis.header.timestamp = core_timing.GetCPUTicks();
seven_six_axis.header.total_entry_count = 17;
if (!IsControllerActivated() || !is_transfer_memory_set) {
seven_six_axis.header.entry_count = 0;
seven_six_axis.header.last_entry_index = 0;
seven_sixaxis_lifo.buffer_count = 0;
seven_sixaxis_lifo.buffer_tail = 0;
return;
}
seven_six_axis.header.entry_count = 16;
const auto& last_entry =
seven_six_axis.sevensixaxis_states[seven_six_axis.header.last_entry_index];
seven_six_axis.header.last_entry_index = (seven_six_axis.header.last_entry_index + 1) % 17;
auto& cur_entry = seven_six_axis.sevensixaxis_states[seven_six_axis.header.last_entry_index];
cur_entry.sampling_number = last_entry.sampling_number + 1;
cur_entry.sampling_number2 = cur_entry.sampling_number;
const auto& last_entry = seven_sixaxis_lifo.ReadCurrentEntry().state;
next_seven_sixaxis_state.sampling_number = last_entry.sampling_number + 1;
// Try to read sixaxis sensor states
MotionDevice motion_device{};
const auto& device = motions[0];
if (device) {
std::tie(motion_device.accel, motion_device.gyro, motion_device.rotation,
motion_device.orientation, motion_device.quaternion) = device->GetStatus();
console_six_axis.is_seven_six_axis_sensor_at_rest = motion_device.gyro.Length2() < 0.0001f;
}
const auto motion_status = console->GetMotion();
cur_entry.accel = motion_device.accel;
console_six_axis.is_seven_six_axis_sensor_at_rest = motion_status.is_at_rest;
next_seven_sixaxis_state.accel = motion_status.accel;
// Zero gyro values as they just mess up with the camera
// Note: Probably a correct sensivity setting must be set
cur_entry.gyro = {};
cur_entry.quaternion = {
next_seven_sixaxis_state.gyro = {};
next_seven_sixaxis_state.quaternion = {
{
motion_device.quaternion.xyz.y,
motion_device.quaternion.xyz.x,
-motion_device.quaternion.w,
motion_status.quaternion.xyz.y,
motion_status.quaternion.xyz.x,
-motion_status.quaternion.w,
},
-motion_device.quaternion.xyz.z,
-motion_status.quaternion.xyz.z,
};
console_six_axis.sampling_number++;
@@ -67,14 +59,8 @@ void Controller_ConsoleSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_ti
// Update console six axis shared memory
std::memcpy(data + SHARED_MEMORY_OFFSET, &console_six_axis, sizeof(console_six_axis));
// Update seven six axis transfer memory
std::memcpy(transfer_memory, &seven_six_axis, sizeof(seven_six_axis));
}
void Controller_ConsoleSixAxis::OnLoadInputDevices() {
const auto player = Settings::values.players.GetValue()[0];
std::transform(player.motions.begin() + Settings::NativeMotion::MOTION_HID_BEGIN,
player.motions.begin() + Settings::NativeMotion::MOTION_HID_END, motions.begin(),
Input::CreateDevice<Input::MotionDevice>);
seven_sixaxis_lifo.WriteNextEntry(next_seven_sixaxis_state);
std::memcpy(transfer_memory, &seven_sixaxis_lifo, sizeof(seven_sixaxis_lifo));
}
void Controller_ConsoleSixAxis::SetTransferMemoryPointer(u8* t_mem) {
@@ -83,8 +69,7 @@ void Controller_ConsoleSixAxis::SetTransferMemoryPointer(u8* t_mem) {
}
void Controller_ConsoleSixAxis::ResetTimestamp() {
auto& cur_entry = seven_six_axis.sevensixaxis_states[seven_six_axis.header.last_entry_index];
cur_entry.sampling_number = 0;
cur_entry.sampling_number2 = 0;
seven_sixaxis_lifo.buffer_count = 0;
seven_sixaxis_lifo.buffer_tail = 0;
}
} // namespace Service::HID

View File

@@ -5,16 +5,21 @@
#pragma once
#include <array>
#include "common/bit_field.h"
#include "common/common_types.h"
#include "common/quaternion.h"
#include "core/frontend/input.h"
#include "core/hid/hid_types.h"
#include "core/hle/service/hid/controllers/controller_base.h"
#include "core/hle/service/hid/ring_lifo.h"
namespace Core::HID {
class EmulatedConsole;
} // namespace Core::HID
namespace Service::HID {
class Controller_ConsoleSixAxis final : public ControllerBase {
public:
explicit Controller_ConsoleSixAxis(Core::System& system_);
explicit Controller_ConsoleSixAxis(Core::HID::HIDCore& hid_core_);
~Controller_ConsoleSixAxis() override;
// Called when the controller is initialized
@@ -26,9 +31,6 @@ public:
// When the controller is requesting an update for the shared memory
void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, size_t size) override;
// Called when input devices should be loaded
void OnLoadInputDevices() override;
// Called on InitializeSevenSixAxisSensor
void SetTransferMemoryPointer(u8* t_mem);
@@ -38,43 +40,31 @@ public:
private:
struct SevenSixAxisState {
INSERT_PADDING_WORDS(4); // unused
s64_le sampling_number{};
s64_le sampling_number2{};
s64 sampling_number{};
u64 unknown{};
Common::Vec3f accel{};
Common::Vec3f gyro{};
Common::Quaternion<f32> quaternion{};
};
static_assert(sizeof(SevenSixAxisState) == 0x50, "SevenSixAxisState is an invalid size");
struct SevenSixAxisMemory {
CommonHeader header{};
std::array<SevenSixAxisState, 0x21> sevensixaxis_states{};
};
static_assert(sizeof(SevenSixAxisMemory) == 0xA70, "SevenSixAxisMemory is an invalid size");
static_assert(sizeof(SevenSixAxisState) == 0x48, "SevenSixAxisState is an invalid size");
// This is nn::hid::detail::ConsoleSixAxisSensorSharedMemoryFormat
struct ConsoleSharedMemory {
u64_le sampling_number{};
u64 sampling_number{};
bool is_seven_six_axis_sensor_at_rest{};
INSERT_PADDING_BYTES(4); // padding
f32 verticalization_error{};
Common::Vec3f gyro_bias{};
};
static_assert(sizeof(ConsoleSharedMemory) == 0x20, "ConsoleSharedMemory is an invalid size");
struct MotionDevice {
Common::Vec3f accel;
Common::Vec3f gyro;
Common::Vec3f rotation;
std::array<Common::Vec3f, 3> orientation;
Common::Quaternion<f32> quaternion;
};
Lifo<SevenSixAxisState, 0x21> seven_sixaxis_lifo{};
static_assert(sizeof(seven_sixaxis_lifo) == 0xA70, "SevenSixAxisState is an invalid size");
using MotionArray =
std::array<std::unique_ptr<Input::MotionDevice>, Settings::NativeMotion::NUM_MOTIONS_HID>;
MotionArray motions;
Core::HID::EmulatedConsole* console;
u8* transfer_memory = nullptr;
bool is_transfer_memory_set = false;
ConsoleSharedMemory console_six_axis{};
SevenSixAxisMemory seven_six_axis{};
SevenSixAxisState next_seven_sixaxis_state{};
};
} // namespace Service::HID

View File

@@ -6,12 +6,12 @@
namespace Service::HID {
ControllerBase::ControllerBase(Core::System& system_) : system(system_) {}
ControllerBase::ControllerBase(Core::HID::HIDCore& hid_core_) : hid_core(hid_core_) {}
ControllerBase::~ControllerBase() = default;
void ControllerBase::ActivateController() {
if (is_activated) {
OnRelease();
return;
}
is_activated = true;
OnInit();

View File

@@ -11,14 +11,14 @@ namespace Core::Timing {
class CoreTiming;
}
namespace Core {
class System;
namespace Core::HID {
class HIDCore;
}
namespace Service::HID {
class ControllerBase {
public:
explicit ControllerBase(Core::System& system_);
explicit ControllerBase(Core::HID::HIDCore& hid_core_);
virtual ~ControllerBase();
// Called when the controller is initialized
@@ -35,26 +35,17 @@ public:
virtual void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
std::size_t size) {}
// Called when input devices should be loaded
virtual void OnLoadInputDevices() = 0;
void ActivateController();
void DeactivateController();
bool IsControllerActivated() const;
static const std::size_t hid_entry_count = 17;
protected:
bool is_activated{false};
struct CommonHeader {
s64_le timestamp;
s64_le total_entry_count;
s64_le last_entry_index;
s64_le entry_count;
};
static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size");
Core::System& system;
Core::HID::HIDCore& hid_core;
};
} // namespace Service::HID

View File

@@ -6,15 +6,19 @@
#include "common/common_types.h"
#include "common/settings.h"
#include "core/core_timing.h"
#include "core/hid/emulated_controller.h"
#include "core/hid/hid_core.h"
#include "core/hid/hid_types.h"
#include "core/hle/service/hid/controllers/debug_pad.h"
namespace Service::HID {
constexpr std::size_t SHARED_MEMORY_OFFSET = 0x00000;
constexpr s32 HID_JOYSTICK_MAX = 0x7fff;
[[maybe_unused]] constexpr s32 HID_JOYSTICK_MIN = -0x7fff;
enum class JoystickId : std::size_t { Joystick_Left, Joystick_Right };
Controller_DebugPad::Controller_DebugPad(Core::HID::HIDCore& hid_core_)
: ControllerBase{hid_core_} {
controller = hid_core.GetEmulatedController(Core::HID::NpadIdType::Other);
}
Controller_DebugPad::Controller_DebugPad(Core::System& system_) : ControllerBase{system_} {}
Controller_DebugPad::~Controller_DebugPad() = default;
void Controller_DebugPad::OnInit() {}
@@ -23,63 +27,29 @@ void Controller_DebugPad::OnRelease() {}
void Controller_DebugPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
std::size_t size) {
shared_memory.header.timestamp = core_timing.GetCPUTicks();
shared_memory.header.total_entry_count = 17;
if (!IsControllerActivated()) {
shared_memory.header.entry_count = 0;
shared_memory.header.last_entry_index = 0;
debug_pad_lifo.buffer_count = 0;
debug_pad_lifo.buffer_tail = 0;
std::memcpy(data + SHARED_MEMORY_OFFSET, &debug_pad_lifo, sizeof(debug_pad_lifo));
return;
}
shared_memory.header.entry_count = 16;
const auto& last_entry = shared_memory.pad_states[shared_memory.header.last_entry_index];
shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17;
auto& cur_entry = shared_memory.pad_states[shared_memory.header.last_entry_index];
cur_entry.sampling_number = last_entry.sampling_number + 1;
cur_entry.sampling_number2 = cur_entry.sampling_number;
const auto& last_entry = debug_pad_lifo.ReadCurrentEntry().state;
next_state.sampling_number = last_entry.sampling_number + 1;
if (Settings::values.debug_pad_enabled) {
cur_entry.attribute.connected.Assign(1);
auto& pad = cur_entry.pad_state;
next_state.attribute.connected.Assign(1);
using namespace Settings::NativeButton;
pad.a.Assign(buttons[A - BUTTON_HID_BEGIN]->GetStatus());
pad.b.Assign(buttons[B - BUTTON_HID_BEGIN]->GetStatus());
pad.x.Assign(buttons[X - BUTTON_HID_BEGIN]->GetStatus());
pad.y.Assign(buttons[Y - BUTTON_HID_BEGIN]->GetStatus());
pad.l.Assign(buttons[L - BUTTON_HID_BEGIN]->GetStatus());
pad.r.Assign(buttons[R - BUTTON_HID_BEGIN]->GetStatus());
pad.zl.Assign(buttons[ZL - BUTTON_HID_BEGIN]->GetStatus());
pad.zr.Assign(buttons[ZR - BUTTON_HID_BEGIN]->GetStatus());
pad.plus.Assign(buttons[Plus - BUTTON_HID_BEGIN]->GetStatus());
pad.minus.Assign(buttons[Minus - BUTTON_HID_BEGIN]->GetStatus());
pad.d_left.Assign(buttons[DLeft - BUTTON_HID_BEGIN]->GetStatus());
pad.d_up.Assign(buttons[DUp - BUTTON_HID_BEGIN]->GetStatus());
pad.d_right.Assign(buttons[DRight - BUTTON_HID_BEGIN]->GetStatus());
pad.d_down.Assign(buttons[DDown - BUTTON_HID_BEGIN]->GetStatus());
const auto& button_state = controller->GetDebugPadButtons();
const auto& stick_state = controller->GetSticks();
const auto [stick_l_x_f, stick_l_y_f] =
analogs[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetStatus();
const auto [stick_r_x_f, stick_r_y_f] =
analogs[static_cast<std::size_t>(JoystickId::Joystick_Right)]->GetStatus();
cur_entry.l_stick.x = static_cast<s32>(stick_l_x_f * HID_JOYSTICK_MAX);
cur_entry.l_stick.y = static_cast<s32>(stick_l_y_f * HID_JOYSTICK_MAX);
cur_entry.r_stick.x = static_cast<s32>(stick_r_x_f * HID_JOYSTICK_MAX);
cur_entry.r_stick.y = static_cast<s32>(stick_r_y_f * HID_JOYSTICK_MAX);
next_state.pad_state = button_state;
next_state.l_stick = stick_state.left;
next_state.r_stick = stick_state.right;
}
std::memcpy(data, &shared_memory, sizeof(SharedMemory));
debug_pad_lifo.WriteNextEntry(next_state);
std::memcpy(data + SHARED_MEMORY_OFFSET, &debug_pad_lifo, sizeof(debug_pad_lifo));
}
void Controller_DebugPad::OnLoadInputDevices() {
std::transform(Settings::values.debug_pad_buttons.begin(),
Settings::values.debug_pad_buttons.begin() +
Settings::NativeButton::NUM_BUTTONS_HID,
buttons.begin(), Input::CreateDevice<Input::ButtonDevice>);
std::transform(Settings::values.debug_pad_analogs.begin(),
Settings::values.debug_pad_analogs.end(), analogs.begin(),
Input::CreateDevice<Input::AnalogDevice>);
}
} // namespace Service::HID

View File

@@ -8,15 +8,20 @@
#include "common/bit_field.h"
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/settings.h"
#include "common/swap.h"
#include "core/frontend/input.h"
#include "core/hle/service/hid/controllers/controller_base.h"
#include "core/hle/service/hid/ring_lifo.h"
namespace Core::HID {
class EmulatedController;
struct DebugPadButton;
struct AnalogStickState;
} // namespace Core::HID
namespace Service::HID {
class Controller_DebugPad final : public ControllerBase {
public:
explicit Controller_DebugPad(Core::System& system_);
explicit Controller_DebugPad(Core::HID::HIDCore& hid_core_);
~Controller_DebugPad() override;
// Called when the controller is initialized
@@ -28,66 +33,31 @@ public:
// When the controller is requesting an update for the shared memory
void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override;
// Called when input devices should be loaded
void OnLoadInputDevices() override;
private:
struct AnalogStick {
s32_le x;
s32_le y;
};
static_assert(sizeof(AnalogStick) == 0x8);
struct PadState {
// This is nn::hid::DebugPadAttribute
struct DebugPadAttribute {
union {
u32_le raw{};
BitField<0, 1, u32> a;
BitField<1, 1, u32> b;
BitField<2, 1, u32> x;
BitField<3, 1, u32> y;
BitField<4, 1, u32> l;
BitField<5, 1, u32> r;
BitField<6, 1, u32> zl;
BitField<7, 1, u32> zr;
BitField<8, 1, u32> plus;
BitField<9, 1, u32> minus;
BitField<10, 1, u32> d_left;
BitField<11, 1, u32> d_up;
BitField<12, 1, u32> d_right;
BitField<13, 1, u32> d_down;
};
};
static_assert(sizeof(PadState) == 0x4, "PadState is an invalid size");
struct Attributes {
union {
u32_le raw{};
u32 raw{};
BitField<0, 1, u32> connected;
};
};
static_assert(sizeof(Attributes) == 0x4, "Attributes is an invalid size");
static_assert(sizeof(DebugPadAttribute) == 0x4, "DebugPadAttribute is an invalid size");
struct PadStates {
s64_le sampling_number;
s64_le sampling_number2;
Attributes attribute;
PadState pad_state;
AnalogStick r_stick;
AnalogStick l_stick;
// This is nn::hid::DebugPadState
struct DebugPadState {
s64 sampling_number;
DebugPadAttribute attribute;
Core::HID::DebugPadButton pad_state;
Core::HID::AnalogStickState r_stick;
Core::HID::AnalogStickState l_stick;
};
static_assert(sizeof(PadStates) == 0x28, "PadStates is an invalid state");
static_assert(sizeof(DebugPadState) == 0x20, "DebugPadState is an invalid state");
struct SharedMemory {
CommonHeader header;
std::array<PadStates, 17> pad_states;
INSERT_PADDING_BYTES(0x138);
};
static_assert(sizeof(SharedMemory) == 0x400, "SharedMemory is an invalid size");
SharedMemory shared_memory{};
// This is nn::hid::detail::DebugPadLifo
Lifo<DebugPadState, hid_entry_count> debug_pad_lifo{};
static_assert(sizeof(debug_pad_lifo) == 0x2C8, "debug_pad_lifo is an invalid size");
DebugPadState next_state{};
std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::NUM_BUTTONS_HID>
buttons;
std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NUM_STICKS_HID>
analogs;
Core::HID::EmulatedController* controller;
};
} // namespace Service::HID

View File

@@ -7,6 +7,7 @@
#include "common/settings.h"
#include "core/core_timing.h"
#include "core/frontend/emu_window.h"
#include "core/hid/hid_core.h"
#include "core/hle/service/hid/controllers/gesture.h"
namespace Service::HID {
@@ -23,16 +24,14 @@ constexpr f32 Square(s32 num) {
return static_cast<f32>(num * num);
}
Controller_Gesture::Controller_Gesture(Core::System& system_) : ControllerBase(system_) {}
Controller_Gesture::Controller_Gesture(Core::HID::HIDCore& hid_core_) : ControllerBase(hid_core_) {
console = hid_core.GetEmulatedConsole();
}
Controller_Gesture::~Controller_Gesture() = default;
void Controller_Gesture::OnInit() {
for (std::size_t id = 0; id < MAX_FINGERS; ++id) {
mouse_finger_id[id] = MAX_POINTS;
keyboard_finger_id[id] = MAX_POINTS;
udp_finger_id[id] = MAX_POINTS;
}
shared_memory.header.entry_count = 0;
gesture_lifo.buffer_count = 0;
gesture_lifo.buffer_tail = 0;
force_update = true;
}
@@ -40,50 +39,38 @@ void Controller_Gesture::OnRelease() {}
void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
std::size_t size) {
shared_memory.header.timestamp = core_timing.GetCPUTicks();
shared_memory.header.total_entry_count = 17;
if (!IsControllerActivated()) {
shared_memory.header.entry_count = 0;
shared_memory.header.last_entry_index = 0;
gesture_lifo.buffer_count = 0;
gesture_lifo.buffer_tail = 0;
std::memcpy(data + SHARED_MEMORY_OFFSET, &gesture_lifo, sizeof(gesture_lifo));
return;
}
ReadTouchInput();
GestureProperties gesture = GetGestureProperties();
f32 time_difference = static_cast<f32>(shared_memory.header.timestamp - last_update_timestamp) /
(1000 * 1000 * 1000);
f32 time_difference =
static_cast<f32>(gesture_lifo.timestamp - last_update_timestamp) / (1000 * 1000 * 1000);
// Only update if necesary
if (!ShouldUpdateGesture(gesture, time_difference)) {
return;
}
last_update_timestamp = shared_memory.header.timestamp;
last_update_timestamp = gesture_lifo.timestamp;
UpdateGestureSharedMemory(data, size, gesture, time_difference);
}
void Controller_Gesture::ReadTouchInput() {
const Input::TouchStatus& mouse_status = touch_mouse_device->GetStatus();
const Input::TouchStatus& udp_status = touch_udp_device->GetStatus();
for (std::size_t id = 0; id < mouse_status.size(); ++id) {
mouse_finger_id[id] = UpdateTouchInputEvent(mouse_status[id], mouse_finger_id[id]);
udp_finger_id[id] = UpdateTouchInputEvent(udp_status[id], udp_finger_id[id]);
}
if (Settings::values.use_touch_from_button) {
const Input::TouchStatus& keyboard_status = touch_btn_device->GetStatus();
for (std::size_t id = 0; id < mouse_status.size(); ++id) {
keyboard_finger_id[id] =
UpdateTouchInputEvent(keyboard_status[id], keyboard_finger_id[id]);
}
const auto touch_status = console->GetTouch();
for (std::size_t id = 0; id < fingers.size(); ++id) {
fingers[id] = touch_status[id];
}
}
bool Controller_Gesture::ShouldUpdateGesture(const GestureProperties& gesture,
f32 time_difference) {
const auto& last_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index];
const auto& last_entry = GetLastGestureEntry();
if (force_update) {
force_update = false;
return true;
@@ -97,7 +84,7 @@ bool Controller_Gesture::ShouldUpdateGesture(const GestureProperties& gesture,
}
// Update on press and hold event after 0.5 seconds
if (last_entry.type == TouchType::Touch && last_entry.point_count == 1 &&
if (last_entry.type == GestureType::Touch && last_entry.point_count == 1 &&
time_difference > press_delay) {
return enable_press_and_tap;
}
@@ -108,27 +95,19 @@ bool Controller_Gesture::ShouldUpdateGesture(const GestureProperties& gesture,
void Controller_Gesture::UpdateGestureSharedMemory(u8* data, std::size_t size,
GestureProperties& gesture,
f32 time_difference) {
TouchType type = TouchType::Idle;
Attribute attributes{};
GestureType type = GestureType::Idle;
GestureAttribute attributes{};
const auto& last_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index];
shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17;
auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index];
const auto& last_entry = gesture_lifo.ReadCurrentEntry().state;
if (shared_memory.header.entry_count < 16) {
shared_memory.header.entry_count++;
}
cur_entry.sampling_number = last_entry.sampling_number + 1;
cur_entry.sampling_number2 = cur_entry.sampling_number;
// Reset values to default
cur_entry.delta = {};
cur_entry.vel_x = 0;
cur_entry.vel_y = 0;
cur_entry.direction = Direction::None;
cur_entry.rotation_angle = 0;
cur_entry.scale = 0;
// Reset next state to default
next_state.sampling_number = last_entry.sampling_number + 1;
next_state.delta = {};
next_state.vel_x = 0;
next_state.vel_y = 0;
next_state.direction = GestureDirection::None;
next_state.rotation_angle = 0;
next_state.scale = 0;
if (gesture.active_points > 0) {
if (last_gesture.active_points == 0) {
@@ -141,46 +120,47 @@ void Controller_Gesture::UpdateGestureSharedMemory(u8* data, std::size_t size,
}
// Apply attributes
cur_entry.detection_count = gesture.detection_count;
cur_entry.type = type;
cur_entry.attributes = attributes;
cur_entry.pos = gesture.mid_point;
cur_entry.point_count = static_cast<s32>(gesture.active_points);
cur_entry.points = gesture.points;
next_state.detection_count = gesture.detection_count;
next_state.type = type;
next_state.attributes = attributes;
next_state.pos = gesture.mid_point;
next_state.point_count = static_cast<s32>(gesture.active_points);
next_state.points = gesture.points;
last_gesture = gesture;
std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory));
gesture_lifo.WriteNextEntry(next_state);
std::memcpy(data + SHARED_MEMORY_OFFSET, &gesture_lifo, sizeof(gesture_lifo));
}
void Controller_Gesture::NewGesture(GestureProperties& gesture, TouchType& type,
Attribute& attributes) {
void Controller_Gesture::NewGesture(GestureProperties& gesture, GestureType& type,
GestureAttribute& attributes) {
const auto& last_entry = GetLastGestureEntry();
gesture.detection_count++;
type = TouchType::Touch;
type = GestureType::Touch;
// New touch after cancel is not considered new
if (last_entry.type != TouchType::Cancel) {
if (last_entry.type != GestureType::Cancel) {
attributes.is_new_touch.Assign(1);
enable_press_and_tap = true;
}
}
void Controller_Gesture::UpdateExistingGesture(GestureProperties& gesture, TouchType& type,
void Controller_Gesture::UpdateExistingGesture(GestureProperties& gesture, GestureType& type,
f32 time_difference) {
const auto& last_entry = GetLastGestureEntry();
// Promote to pan type if touch moved
for (size_t id = 0; id < MAX_POINTS; id++) {
if (gesture.points[id] != last_gesture.points[id]) {
type = TouchType::Pan;
type = GestureType::Pan;
break;
}
}
// Number of fingers changed cancel the last event and clear data
if (gesture.active_points != last_gesture.active_points) {
type = TouchType::Cancel;
type = GestureType::Cancel;
enable_press_and_tap = false;
gesture.active_points = 0;
gesture.mid_point = {};
@@ -189,41 +169,41 @@ void Controller_Gesture::UpdateExistingGesture(GestureProperties& gesture, Touch
}
// Calculate extra parameters of panning
if (type == TouchType::Pan) {
if (type == GestureType::Pan) {
UpdatePanEvent(gesture, last_gesture, type, time_difference);
return;
}
// Promote to press type
if (last_entry.type == TouchType::Touch) {
type = TouchType::Press;
if (last_entry.type == GestureType::Touch) {
type = GestureType::Press;
}
}
void Controller_Gesture::EndGesture(GestureProperties& gesture,
GestureProperties& last_gesture_props, TouchType& type,
Attribute& attributes, f32 time_difference) {
GestureProperties& last_gesture_props, GestureType& type,
GestureAttribute& attributes, f32 time_difference) {
const auto& last_entry = GetLastGestureEntry();
if (last_gesture_props.active_points != 0) {
switch (last_entry.type) {
case TouchType::Touch:
case GestureType::Touch:
if (enable_press_and_tap) {
SetTapEvent(gesture, last_gesture_props, type, attributes);
return;
}
type = TouchType::Cancel;
type = GestureType::Cancel;
force_update = true;
break;
case TouchType::Press:
case TouchType::Tap:
case TouchType::Swipe:
case TouchType::Pinch:
case TouchType::Rotate:
type = TouchType::Complete;
case GestureType::Press:
case GestureType::Tap:
case GestureType::Swipe:
case GestureType::Pinch:
case GestureType::Rotate:
type = GestureType::Complete;
force_update = true;
break;
case TouchType::Pan:
case GestureType::Pan:
EndPanEvent(gesture, last_gesture_props, type, time_difference);
break;
default:
@@ -231,15 +211,15 @@ void Controller_Gesture::EndGesture(GestureProperties& gesture,
}
return;
}
if (last_entry.type == TouchType::Complete || last_entry.type == TouchType::Cancel) {
if (last_entry.type == GestureType::Complete || last_entry.type == GestureType::Cancel) {
gesture.detection_count++;
}
}
void Controller_Gesture::SetTapEvent(GestureProperties& gesture,
GestureProperties& last_gesture_props, TouchType& type,
Attribute& attributes) {
type = TouchType::Tap;
GestureProperties& last_gesture_props, GestureType& type,
GestureAttribute& attributes) {
type = GestureType::Tap;
gesture = last_gesture_props;
force_update = true;
f32 tap_time_difference =
@@ -251,44 +231,42 @@ void Controller_Gesture::SetTapEvent(GestureProperties& gesture,
}
void Controller_Gesture::UpdatePanEvent(GestureProperties& gesture,
GestureProperties& last_gesture_props, TouchType& type,
GestureProperties& last_gesture_props, GestureType& type,
f32 time_difference) {
auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index];
const auto& last_entry = GetLastGestureEntry();
cur_entry.delta = gesture.mid_point - last_entry.pos;
cur_entry.vel_x = static_cast<f32>(cur_entry.delta.x) / time_difference;
cur_entry.vel_y = static_cast<f32>(cur_entry.delta.y) / time_difference;
next_state.delta = gesture.mid_point - last_entry.pos;
next_state.vel_x = static_cast<f32>(next_state.delta.x) / time_difference;
next_state.vel_y = static_cast<f32>(next_state.delta.y) / time_difference;
last_pan_time_difference = time_difference;
// Promote to pinch type
if (std::abs(gesture.average_distance - last_gesture_props.average_distance) >
pinch_threshold) {
type = TouchType::Pinch;
cur_entry.scale = gesture.average_distance / last_gesture_props.average_distance;
type = GestureType::Pinch;
next_state.scale = gesture.average_distance / last_gesture_props.average_distance;
}
const f32 angle_between_two_lines = std::atan((gesture.angle - last_gesture_props.angle) /
(1 + (gesture.angle * last_gesture_props.angle)));
// Promote to rotate type
if (std::abs(angle_between_two_lines) > angle_threshold) {
type = TouchType::Rotate;
cur_entry.scale = 0;
cur_entry.rotation_angle = angle_between_two_lines * 180.0f / Common::PI;
type = GestureType::Rotate;
next_state.scale = 0;
next_state.rotation_angle = angle_between_two_lines * 180.0f / Common::PI;
}
}
void Controller_Gesture::EndPanEvent(GestureProperties& gesture,
GestureProperties& last_gesture_props, TouchType& type,
GestureProperties& last_gesture_props, GestureType& type,
f32 time_difference) {
auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index];
const auto& last_entry = GetLastGestureEntry();
cur_entry.vel_x =
next_state.vel_x =
static_cast<f32>(last_entry.delta.x) / (last_pan_time_difference + time_difference);
cur_entry.vel_y =
next_state.vel_y =
static_cast<f32>(last_entry.delta.y) / (last_pan_time_difference + time_difference);
const f32 curr_vel =
std::sqrt((cur_entry.vel_x * cur_entry.vel_x) + (cur_entry.vel_y * cur_entry.vel_y));
std::sqrt((next_state.vel_x * next_state.vel_x) + (next_state.vel_y * next_state.vel_y));
// Set swipe event with parameters
if (curr_vel > swipe_threshold) {
@@ -297,105 +275,50 @@ void Controller_Gesture::EndPanEvent(GestureProperties& gesture,
}
// End panning without swipe
type = TouchType::Complete;
cur_entry.vel_x = 0;
cur_entry.vel_y = 0;
type = GestureType::Complete;
next_state.vel_x = 0;
next_state.vel_y = 0;
force_update = true;
}
void Controller_Gesture::SetSwipeEvent(GestureProperties& gesture,
GestureProperties& last_gesture_props, TouchType& type) {
auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index];
GestureProperties& last_gesture_props, GestureType& type) {
const auto& last_entry = GetLastGestureEntry();
type = TouchType::Swipe;
type = GestureType::Swipe;
gesture = last_gesture_props;
force_update = true;
cur_entry.delta = last_entry.delta;
next_state.delta = last_entry.delta;
if (std::abs(cur_entry.delta.x) > std::abs(cur_entry.delta.y)) {
if (cur_entry.delta.x > 0) {
cur_entry.direction = Direction::Right;
if (std::abs(next_state.delta.x) > std::abs(next_state.delta.y)) {
if (next_state.delta.x > 0) {
next_state.direction = GestureDirection::Right;
return;
}
cur_entry.direction = Direction::Left;
next_state.direction = GestureDirection::Left;
return;
}
if (cur_entry.delta.y > 0) {
cur_entry.direction = Direction::Down;
if (next_state.delta.y > 0) {
next_state.direction = GestureDirection::Down;
return;
}
cur_entry.direction = Direction::Up;
}
void Controller_Gesture::OnLoadInputDevices() {
touch_mouse_device = Input::CreateDevice<Input::TouchDevice>("engine:emu_window");
touch_udp_device = Input::CreateDevice<Input::TouchDevice>("engine:cemuhookudp");
touch_btn_device = Input::CreateDevice<Input::TouchDevice>("engine:touch_from_button");
}
std::optional<std::size_t> Controller_Gesture::GetUnusedFingerID() const {
// Dont assign any touch input to a point if disabled
if (!Settings::values.touchscreen.enabled) {
return std::nullopt;
}
std::size_t first_free_id = 0;
while (first_free_id < MAX_POINTS) {
if (!fingers[first_free_id].pressed) {
return first_free_id;
} else {
first_free_id++;
}
}
return std::nullopt;
}
Controller_Gesture::GestureState& Controller_Gesture::GetLastGestureEntry() {
return shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17];
next_state.direction = GestureDirection::Up;
}
const Controller_Gesture::GestureState& Controller_Gesture::GetLastGestureEntry() const {
return shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17];
}
std::size_t Controller_Gesture::UpdateTouchInputEvent(
const std::tuple<float, float, bool>& touch_input, std::size_t finger_id) {
const auto& [x, y, pressed] = touch_input;
if (finger_id > MAX_POINTS) {
LOG_ERROR(Service_HID, "Invalid finger id {}", finger_id);
return MAX_POINTS;
}
if (pressed) {
if (finger_id == MAX_POINTS) {
const auto first_free_id = GetUnusedFingerID();
if (!first_free_id) {
// Invalid finger id do nothing
return MAX_POINTS;
}
finger_id = first_free_id.value();
fingers[finger_id].pressed = true;
}
fingers[finger_id].pos = {x, y};
return finger_id;
}
if (finger_id != MAX_POINTS) {
fingers[finger_id].pressed = false;
}
return MAX_POINTS;
return gesture_lifo.ReadCurrentEntry().state;
}
Controller_Gesture::GestureProperties Controller_Gesture::GetGestureProperties() {
GestureProperties gesture;
std::array<Finger, MAX_POINTS> active_fingers;
std::array<Core::HID::TouchFinger, MAX_POINTS> active_fingers;
const auto end_iter = std::copy_if(fingers.begin(), fingers.end(), active_fingers.begin(),
[](const auto& finger) { return finger.pressed; });
gesture.active_points =
static_cast<std::size_t>(std::distance(active_fingers.begin(), end_iter));
for (size_t id = 0; id < gesture.active_points; ++id) {
const auto& [active_x, active_y] = active_fingers[id].pos;
const auto& [active_x, active_y] = active_fingers[id].position;
gesture.points[id] = {
.x = static_cast<s32>(active_x * Layout::ScreenUndocked::Width),
.y = static_cast<s32>(active_y * Layout::ScreenUndocked::Height),

View File

@@ -8,13 +8,14 @@
#include "common/bit_field.h"
#include "common/common_types.h"
#include "common/point.h"
#include "core/frontend/input.h"
#include "core/hid/emulated_console.h"
#include "core/hle/service/hid/controllers/controller_base.h"
#include "core/hle/service/hid/ring_lifo.h"
namespace Service::HID {
class Controller_Gesture final : public ControllerBase {
public:
explicit Controller_Gesture(Core::System& system_);
explicit Controller_Gesture(Core::HID::HIDCore& hid_core_);
~Controller_Gesture() override;
// Called when the controller is initialized
@@ -26,14 +27,12 @@ public:
// When the controller is requesting an update for the shared memory
void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, size_t size) override;
// Called when input devices should be loaded
void OnLoadInputDevices() override;
private:
static constexpr size_t MAX_FINGERS = 16;
static constexpr size_t MAX_POINTS = 4;
enum class TouchType : u32 {
// This is nn::hid::GestureType
enum class GestureType : u32 {
Idle, // Nothing touching the screen
Complete, // Set at the end of a touch event
Cancel, // Set when the number of fingers change
@@ -46,7 +45,8 @@ private:
Rotate, // All points rotating from the midpoint
};
enum class Direction : u32 {
// This is nn::hid::GestureDirection
enum class GestureDirection : u32 {
None,
Left,
Up,
@@ -54,51 +54,41 @@ private:
Down,
};
struct Attribute {
// This is nn::hid::GestureAttribute
struct GestureAttribute {
union {
u32_le raw{};
u32 raw{};
BitField<4, 1, u32> is_new_touch;
BitField<8, 1, u32> is_double_tap;
};
};
static_assert(sizeof(Attribute) == 4, "Attribute is an invalid size");
static_assert(sizeof(GestureAttribute) == 4, "GestureAttribute is an invalid size");
// This is nn::hid::GestureState
struct GestureState {
s64_le sampling_number;
s64_le sampling_number2;
s64_le detection_count;
TouchType type;
Direction direction;
Common::Point<s32_le> pos;
Common::Point<s32_le> delta;
s64 sampling_number;
s64 detection_count;
GestureType type;
GestureDirection direction;
Common::Point<s32> pos;
Common::Point<s32> delta;
f32 vel_x;
f32 vel_y;
Attribute attributes;
GestureAttribute attributes;
f32 scale;
f32 rotation_angle;
s32_le point_count;
std::array<Common::Point<s32_le>, 4> points;
};
static_assert(sizeof(GestureState) == 0x68, "GestureState is an invalid size");
struct SharedMemory {
CommonHeader header;
std::array<GestureState, 17> gesture_states;
};
static_assert(sizeof(SharedMemory) == 0x708, "SharedMemory is an invalid size");
struct Finger {
Common::Point<f32> pos{};
bool pressed{};
s32 point_count;
std::array<Common::Point<s32>, 4> points;
};
static_assert(sizeof(GestureState) == 0x60, "GestureState is an invalid size");
struct GestureProperties {
std::array<Common::Point<s32_le>, MAX_POINTS> points{};
std::array<Common::Point<s32>, MAX_POINTS> points{};
std::size_t active_points{};
Common::Point<s32_le> mid_point{};
s64_le detection_count{};
u64_le delta_time{};
Common::Point<s32> mid_point{};
s64 detection_count{};
u64 delta_time{};
f32 average_distance{};
f32 angle{};
};
@@ -114,61 +104,48 @@ private:
f32 time_difference);
// Initializes new gesture
void NewGesture(GestureProperties& gesture, TouchType& type, Attribute& attributes);
void NewGesture(GestureProperties& gesture, GestureType& type, GestureAttribute& attributes);
// Updates existing gesture state
void UpdateExistingGesture(GestureProperties& gesture, TouchType& type, f32 time_difference);
void UpdateExistingGesture(GestureProperties& gesture, GestureType& type, f32 time_difference);
// Terminates exiting gesture
void EndGesture(GestureProperties& gesture, GestureProperties& last_gesture_props,
TouchType& type, Attribute& attributes, f32 time_difference);
GestureType& type, GestureAttribute& attributes, f32 time_difference);
// Set current event to a tap event
void SetTapEvent(GestureProperties& gesture, GestureProperties& last_gesture_props,
TouchType& type, Attribute& attributes);
GestureType& type, GestureAttribute& attributes);
// Calculates and set the extra parameters related to a pan event
void UpdatePanEvent(GestureProperties& gesture, GestureProperties& last_gesture_props,
TouchType& type, f32 time_difference);
GestureType& type, f32 time_difference);
// Terminates the pan event
void EndPanEvent(GestureProperties& gesture, GestureProperties& last_gesture_props,
TouchType& type, f32 time_difference);
GestureType& type, f32 time_difference);
// Set current event to a swipe event
void SetSwipeEvent(GestureProperties& gesture, GestureProperties& last_gesture_props,
TouchType& type);
// Returns an unused finger id, if there is no fingers available std::nullopt is returned.
[[nodiscard]] std::optional<size_t> GetUnusedFingerID() const;
GestureType& type);
// Retrieves the last gesture entry, as indicated by shared memory indices.
[[nodiscard]] GestureState& GetLastGestureEntry();
[[nodiscard]] const GestureState& GetLastGestureEntry() const;
/**
* If the touch is new it tries to assign a new finger id, if there is no fingers available no
* changes will be made. Updates the coordinates if the finger id it's already set. If the touch
* ends delays the output by one frame to set the end_touch flag before finally freeing the
* finger id
*/
size_t UpdateTouchInputEvent(const std::tuple<float, float, bool>& touch_input,
size_t finger_id);
// Returns the average distance, angle and middle point of the active fingers
GestureProperties GetGestureProperties();
SharedMemory shared_memory{};
std::unique_ptr<Input::TouchDevice> touch_mouse_device;
std::unique_ptr<Input::TouchDevice> touch_udp_device;
std::unique_ptr<Input::TouchDevice> touch_btn_device;
std::array<size_t, MAX_FINGERS> mouse_finger_id{};
std::array<size_t, MAX_FINGERS> keyboard_finger_id{};
std::array<size_t, MAX_FINGERS> udp_finger_id{};
std::array<Finger, MAX_POINTS> fingers{};
// This is nn::hid::detail::GestureLifo
Lifo<GestureState, hid_entry_count> gesture_lifo{};
static_assert(sizeof(gesture_lifo) == 0x708, "gesture_lifo is an invalid size");
GestureState next_state{};
Core::HID::EmulatedConsole* console;
std::array<Core::HID::TouchFinger, MAX_POINTS> fingers{};
GestureProperties last_gesture{};
s64_le last_update_timestamp{};
s64_le last_tap_timestamp{};
s64 last_update_timestamp{};
s64 last_tap_timestamp{};
f32 last_pan_time_difference{};
bool force_update{false};
bool enable_press_and_tap{false};

View File

@@ -6,13 +6,18 @@
#include "common/common_types.h"
#include "common/settings.h"
#include "core/core_timing.h"
#include "core/hid/emulated_devices.h"
#include "core/hid/hid_core.h"
#include "core/hle/service/hid/controllers/keyboard.h"
namespace Service::HID {
constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3800;
constexpr u8 KEYS_PER_BYTE = 8;
Controller_Keyboard::Controller_Keyboard(Core::System& system_) : ControllerBase{system_} {}
Controller_Keyboard::Controller_Keyboard(Core::HID::HIDCore& hid_core_)
: ControllerBase{hid_core_} {
emulated_devices = hid_core.GetEmulatedDevices();
}
Controller_Keyboard::~Controller_Keyboard() = default;
void Controller_Keyboard::OnInit() {}
@@ -21,51 +26,27 @@ void Controller_Keyboard::OnRelease() {}
void Controller_Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
std::size_t size) {
shared_memory.header.timestamp = core_timing.GetCPUTicks();
shared_memory.header.total_entry_count = 17;
if (!IsControllerActivated()) {
shared_memory.header.entry_count = 0;
shared_memory.header.last_entry_index = 0;
keyboard_lifo.buffer_count = 0;
keyboard_lifo.buffer_tail = 0;
std::memcpy(data + SHARED_MEMORY_OFFSET, &keyboard_lifo, sizeof(keyboard_lifo));
return;
}
shared_memory.header.entry_count = 16;
const auto& last_entry = shared_memory.pad_states[shared_memory.header.last_entry_index];
shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17;
auto& cur_entry = shared_memory.pad_states[shared_memory.header.last_entry_index];
const auto& last_entry = keyboard_lifo.ReadCurrentEntry().state;
next_state.sampling_number = last_entry.sampling_number + 1;
cur_entry.sampling_number = last_entry.sampling_number + 1;
cur_entry.sampling_number2 = cur_entry.sampling_number;
cur_entry.key.fill(0);
if (Settings::values.keyboard_enabled) {
for (std::size_t i = 0; i < keyboard_keys.size(); ++i) {
auto& entry = cur_entry.key[i / KEYS_PER_BYTE];
entry = static_cast<u8>(entry | (keyboard_keys[i]->GetStatus() << (i % KEYS_PER_BYTE)));
}
const auto& keyboard_state = emulated_devices->GetKeyboard();
const auto& keyboard_modifier_state = emulated_devices->GetKeyboardModifier();
using namespace Settings::NativeKeyboard;
// TODO: Assign the correct key to all modifiers
cur_entry.modifier.control.Assign(keyboard_mods[LeftControl]->GetStatus());
cur_entry.modifier.shift.Assign(keyboard_mods[LeftShift]->GetStatus());
cur_entry.modifier.left_alt.Assign(keyboard_mods[LeftAlt]->GetStatus());
cur_entry.modifier.right_alt.Assign(keyboard_mods[RightAlt]->GetStatus());
cur_entry.modifier.gui.Assign(0);
cur_entry.modifier.caps_lock.Assign(keyboard_mods[CapsLock]->GetStatus());
cur_entry.modifier.scroll_lock.Assign(keyboard_mods[ScrollLock]->GetStatus());
cur_entry.modifier.num_lock.Assign(keyboard_mods[NumLock]->GetStatus());
cur_entry.modifier.katakana.Assign(0);
cur_entry.modifier.hiragana.Assign(0);
next_state.key = keyboard_state;
next_state.modifier = keyboard_modifier_state;
next_state.attribute.is_connected.Assign(1);
}
std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory));
keyboard_lifo.WriteNextEntry(next_state);
std::memcpy(data + SHARED_MEMORY_OFFSET, &keyboard_lifo, sizeof(keyboard_lifo));
}
void Controller_Keyboard::OnLoadInputDevices() {
std::transform(Settings::values.keyboard_keys.begin(), Settings::values.keyboard_keys.end(),
keyboard_keys.begin(), Input::CreateDevice<Input::ButtonDevice>);
std::transform(Settings::values.keyboard_mods.begin(), Settings::values.keyboard_mods.end(),
keyboard_mods.begin(), Input::CreateDevice<Input::ButtonDevice>);
}
} // namespace Service::HID

View File

@@ -8,15 +8,20 @@
#include "common/bit_field.h"
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/settings.h"
#include "common/swap.h"
#include "core/frontend/input.h"
#include "core/hle/service/hid/controllers/controller_base.h"
#include "core/hle/service/hid/ring_lifo.h"
namespace Core::HID {
class EmulatedDevices;
struct KeyboardModifier;
struct KeyboardKey;
} // namespace Core::HID
namespace Service::HID {
class Controller_Keyboard final : public ControllerBase {
public:
explicit Controller_Keyboard(Core::System& system_);
explicit Controller_Keyboard(Core::HID::HIDCore& hid_core_);
~Controller_Keyboard() override;
// Called when the controller is initialized
@@ -28,47 +33,21 @@ public:
// When the controller is requesting an update for the shared memory
void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override;
// Called when input devices should be loaded
void OnLoadInputDevices() override;
private:
struct Modifiers {
union {
u32_le raw{};
BitField<0, 1, u32> control;
BitField<1, 1, u32> shift;
BitField<2, 1, u32> left_alt;
BitField<3, 1, u32> right_alt;
BitField<4, 1, u32> gui;
BitField<8, 1, u32> caps_lock;
BitField<9, 1, u32> scroll_lock;
BitField<10, 1, u32> num_lock;
BitField<11, 1, u32> katakana;
BitField<12, 1, u32> hiragana;
};
};
static_assert(sizeof(Modifiers) == 0x4, "Modifiers is an invalid size");
// This is nn::hid::detail::KeyboardState
struct KeyboardState {
s64_le sampling_number;
s64_le sampling_number2;
Modifiers modifier;
std::array<u8, 32> key;
s64 sampling_number;
Core::HID::KeyboardModifier modifier;
Core::HID::KeyboardAttribute attribute;
Core::HID::KeyboardKey key;
};
static_assert(sizeof(KeyboardState) == 0x38, "KeyboardState is an invalid size");
static_assert(sizeof(KeyboardState) == 0x30, "KeyboardState is an invalid size");
struct SharedMemory {
CommonHeader header;
std::array<KeyboardState, 17> pad_states;
INSERT_PADDING_BYTES(0x28);
};
static_assert(sizeof(SharedMemory) == 0x400, "SharedMemory is an invalid size");
SharedMemory shared_memory{};
// This is nn::hid::detail::KeyboardLifo
Lifo<KeyboardState, hid_entry_count> keyboard_lifo{};
static_assert(sizeof(keyboard_lifo) == 0x3D8, "keyboard_lifo is an invalid size");
KeyboardState next_state{};
std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeKeyboard::NumKeyboardKeys>
keyboard_keys;
std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeKeyboard::NumKeyboardMods>
keyboard_mods;
Core::HID::EmulatedDevices* emulated_devices;
};
} // namespace Service::HID

View File

@@ -6,12 +6,17 @@
#include "common/common_types.h"
#include "core/core_timing.h"
#include "core/frontend/emu_window.h"
#include "core/hid/emulated_devices.h"
#include "core/hid/hid_core.h"
#include "core/hle/service/hid/controllers/mouse.h"
namespace Service::HID {
constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3400;
Controller_Mouse::Controller_Mouse(Core::System& system_) : ControllerBase{system_} {}
Controller_Mouse::Controller_Mouse(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {
emulated_devices = hid_core.GetEmulatedDevices();
}
Controller_Mouse::~Controller_Mouse() = default;
void Controller_Mouse::OnInit() {}
@@ -19,50 +24,35 @@ void Controller_Mouse::OnRelease() {}
void Controller_Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
std::size_t size) {
shared_memory.header.timestamp = core_timing.GetCPUTicks();
shared_memory.header.total_entry_count = 17;
if (!IsControllerActivated()) {
shared_memory.header.entry_count = 0;
shared_memory.header.last_entry_index = 0;
mouse_lifo.buffer_count = 0;
mouse_lifo.buffer_tail = 0;
std::memcpy(data + SHARED_MEMORY_OFFSET, &mouse_lifo, sizeof(mouse_lifo));
return;
}
shared_memory.header.entry_count = 16;
auto& last_entry = shared_memory.mouse_states[shared_memory.header.last_entry_index];
shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17;
auto& cur_entry = shared_memory.mouse_states[shared_memory.header.last_entry_index];
const auto& last_entry = mouse_lifo.ReadCurrentEntry().state;
next_state.sampling_number = last_entry.sampling_number + 1;
cur_entry.sampling_number = last_entry.sampling_number + 1;
cur_entry.sampling_number2 = cur_entry.sampling_number;
cur_entry.attribute.raw = 0;
next_state.attribute.raw = 0;
if (Settings::values.mouse_enabled) {
const auto [px, py, sx, sy] = mouse_device->GetStatus();
const auto x = static_cast<s32>(px * Layout::ScreenUndocked::Width);
const auto y = static_cast<s32>(py * Layout::ScreenUndocked::Height);
cur_entry.x = x;
cur_entry.y = y;
cur_entry.delta_x = x - last_entry.x;
cur_entry.delta_y = y - last_entry.y;
cur_entry.mouse_wheel_x = sx;
cur_entry.mouse_wheel_y = sy;
cur_entry.attribute.is_connected.Assign(1);
const auto& mouse_button_state = emulated_devices->GetMouseButtons();
const auto& mouse_position_state = emulated_devices->GetMousePosition();
const auto& mouse_wheel_state = emulated_devices->GetMouseWheel();
next_state.attribute.is_connected.Assign(1);
next_state.x = static_cast<s32>(mouse_position_state.x * Layout::ScreenUndocked::Width);
next_state.y = static_cast<s32>(mouse_position_state.y * Layout::ScreenUndocked::Height);
next_state.delta_x = next_state.x - last_entry.x;
next_state.delta_y = next_state.y - last_entry.y;
next_state.delta_wheel_x = mouse_wheel_state.x - last_mouse_wheel_state.x;
next_state.delta_wheel_y = mouse_wheel_state.y - last_mouse_wheel_state.y;
using namespace Settings::NativeMouseButton;
cur_entry.button.left.Assign(mouse_button_devices[Left]->GetStatus());
cur_entry.button.right.Assign(mouse_button_devices[Right]->GetStatus());
cur_entry.button.middle.Assign(mouse_button_devices[Middle]->GetStatus());
cur_entry.button.forward.Assign(mouse_button_devices[Forward]->GetStatus());
cur_entry.button.back.Assign(mouse_button_devices[Back]->GetStatus());
last_mouse_wheel_state = mouse_wheel_state;
next_state.button = mouse_button_state;
}
std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory));
mouse_lifo.WriteNextEntry(next_state);
std::memcpy(data + SHARED_MEMORY_OFFSET, &mouse_lifo, sizeof(mouse_lifo));
}
void Controller_Mouse::OnLoadInputDevices() {
mouse_device = Input::CreateDevice<Input::MouseDevice>(Settings::values.mouse_device);
std::transform(Settings::values.mouse_buttons.begin(), Settings::values.mouse_buttons.end(),
mouse_button_devices.begin(), Input::CreateDevice<Input::ButtonDevice>);
}
} // namespace Service::HID

View File

@@ -7,15 +7,20 @@
#include <array>
#include "common/bit_field.h"
#include "common/common_types.h"
#include "common/settings.h"
#include "common/swap.h"
#include "core/frontend/input.h"
#include "core/hle/service/hid/controllers/controller_base.h"
#include "core/hle/service/hid/ring_lifo.h"
namespace Core::HID {
class EmulatedDevices;
struct MouseState;
struct AnalogStickState;
} // namespace Core::HID
namespace Service::HID {
class Controller_Mouse final : public ControllerBase {
public:
explicit Controller_Mouse(Core::System& system_);
explicit Controller_Mouse(Core::HID::HIDCore& hid_core_);
~Controller_Mouse() override;
// Called when the controller is initialized
@@ -27,53 +32,13 @@ public:
// When the controller is requesting an update for the shared memory
void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override;
// Called when input devices should be loaded
void OnLoadInputDevices() override;
private:
struct Buttons {
union {
u32_le raw{};
BitField<0, 1, u32> left;
BitField<1, 1, u32> right;
BitField<2, 1, u32> middle;
BitField<3, 1, u32> forward;
BitField<4, 1, u32> back;
};
};
static_assert(sizeof(Buttons) == 0x4, "Buttons is an invalid size");
// This is nn::hid::detail::MouseLifo
Lifo<Core::HID::MouseState, hid_entry_count> mouse_lifo{};
static_assert(sizeof(mouse_lifo) == 0x350, "mouse_lifo is an invalid size");
Core::HID::MouseState next_state{};
struct Attributes {
union {
u32_le raw{};
BitField<0, 1, u32> transferable;
BitField<1, 1, u32> is_connected;
};
};
static_assert(sizeof(Attributes) == 0x4, "Attributes is an invalid size");
struct MouseState {
s64_le sampling_number;
s64_le sampling_number2;
s32_le x;
s32_le y;
s32_le delta_x;
s32_le delta_y;
s32_le mouse_wheel_x;
s32_le mouse_wheel_y;
Buttons button;
Attributes attribute;
};
static_assert(sizeof(MouseState) == 0x30, "MouseState is an invalid size");
struct SharedMemory {
CommonHeader header;
std::array<MouseState, 17> mouse_states;
};
SharedMemory shared_memory{};
std::unique_ptr<Input::MouseDevice> mouse_device;
std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeMouseButton::NumMouseButtons>
mouse_button_devices;
Core::HID::AnalogStickState last_mouse_wheel_state;
Core::HID::EmulatedDevices* emulated_devices;
};
} // namespace Service::HID

File diff suppressed because it is too large Load Diff

View File

@@ -11,9 +11,14 @@
#include "common/bit_field.h"
#include "common/common_types.h"
#include "common/quaternion.h"
#include "common/settings.h"
#include "core/frontend/input.h"
#include "core/hid/hid_types.h"
#include "core/hle/service/hid/controllers/controller_base.h"
#include "core/hle/service/hid/ring_lifo.h"
namespace Core::HID {
class EmulatedController;
enum class ControllerTriggerType;
} // namespace Core::HID
namespace Kernel {
class KEvent;
@@ -26,12 +31,9 @@ class ServiceContext;
namespace Service::HID {
constexpr u32 NPAD_HANDHELD = 32;
constexpr u32 NPAD_UNKNOWN = 16; // TODO(ogniK): What is this?
class Controller_NPad final : public ControllerBase {
public:
explicit Controller_NPad(Core::System& system_,
explicit Controller_NPad(Core::HID::HIDCore& hid_core_,
KernelHelpers::ServiceContext& service_context_);
~Controller_NPad() override;
@@ -48,60 +50,39 @@ public:
void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
std::size_t size) override;
// Called when input devices should be loaded
void OnLoadInputDevices() override;
enum class NPadControllerType {
None,
ProController,
Handheld,
JoyDual,
JoyLeft,
JoyRight,
GameCube,
Pokeball,
};
enum class NpadType : u8 {
ProController = 3,
Handheld = 4,
JoyconDual = 5,
JoyconLeft = 6,
JoyconRight = 7,
GameCube = 8,
Pokeball = 9,
MaxNpadType = 10,
};
enum class DeviceIndex : u8 {
Left = 0,
Right = 1,
None = 2,
MaxDeviceIndex = 3,
};
// This is nn::hid::GyroscopeZeroDriftMode
enum class GyroscopeZeroDriftMode : u32 {
Loose = 0,
Standard = 1,
Tight = 2,
};
enum class NpadHoldType : u64 {
// This is nn::hid::NpadJoyHoldType
enum class NpadJoyHoldType : u64 {
Vertical = 0,
Horizontal = 1,
};
enum class NpadAssignments : u32 {
// This is nn::hid::NpadJoyAssignmentMode
enum class NpadJoyAssignmentMode : u32 {
Dual = 0,
Single = 1,
};
// This is nn::hid::NpadJoyDeviceType
enum class NpadJoyDeviceType : s64 {
Left = 0,
Right = 1,
};
// This is nn::hid::NpadHandheldActivationMode
enum class NpadHandheldActivationMode : u64 {
Dual = 0,
Single = 1,
None = 2,
};
// This is nn::hid::NpadCommunicationMode
enum class NpadCommunicationMode : u64 {
Mode_5ms = 0,
Mode_10ms = 1,
@@ -109,74 +90,22 @@ public:
Default = 3,
};
struct DeviceHandle {
NpadType npad_type;
u8 npad_id;
DeviceIndex device_index;
INSERT_PADDING_BYTES_NOINIT(1);
};
static_assert(sizeof(DeviceHandle) == 4, "DeviceHandle is an invalid size");
struct NpadStyleSet {
union {
u32_le raw{};
BitField<0, 1, u32> fullkey;
BitField<1, 1, u32> handheld;
BitField<2, 1, u32> joycon_dual;
BitField<3, 1, u32> joycon_left;
BitField<4, 1, u32> joycon_right;
BitField<5, 1, u32> gamecube;
BitField<6, 1, u32> palma;
BitField<7, 1, u32> lark;
BitField<8, 1, u32> handheld_lark;
BitField<9, 1, u32> lucia;
BitField<29, 1, u32> system_ext;
BitField<30, 1, u32> system;
};
};
static_assert(sizeof(NpadStyleSet) == 4, "NpadStyleSet is an invalid size");
struct VibrationValue {
f32 amp_low;
f32 freq_low;
f32 amp_high;
f32 freq_high;
};
static_assert(sizeof(VibrationValue) == 0x10, "Vibration is an invalid size");
static constexpr VibrationValue DEFAULT_VIBRATION_VALUE{
.amp_low = 0.0f,
.freq_low = 160.0f,
.amp_high = 0.0f,
.freq_high = 320.0f,
static constexpr Core::HID::VibrationValue DEFAULT_VIBRATION_VALUE{
.low_amplitude = 0.0f,
.low_frequency = 160.0f,
.high_amplitude = 0.0f,
.high_frequency = 320.0f,
};
struct LedPattern {
explicit LedPattern(u64 light1, u64 light2, u64 light3, u64 light4) {
position1.Assign(light1);
position2.Assign(light2);
position3.Assign(light3);
position4.Assign(light4);
}
union {
u64 raw{};
BitField<0, 1, u64> position1;
BitField<1, 1, u64> position2;
BitField<2, 1, u64> position3;
BitField<3, 1, u64> position4;
};
};
void SetSupportedStyleSet(NpadStyleSet style_set);
NpadStyleSet GetSupportedStyleSet() const;
void SetSupportedStyleSet(Core::HID::NpadStyleTag style_set);
Core::HID::NpadStyleTag GetSupportedStyleSet() const;
void SetSupportedNpadIdTypes(u8* data, std::size_t length);
void GetSupportedNpadIdTypes(u32* data, std::size_t max_length);
std::size_t GetSupportedNpadIdTypesSize() const;
void SetHoldType(NpadHoldType joy_hold_type);
NpadHoldType GetHoldType() const;
void SetHoldType(NpadJoyHoldType joy_hold_type);
NpadJoyHoldType GetHoldType() const;
void SetNpadHandheldActivationMode(NpadHandheldActivationMode activation_mode);
NpadHandheldActivationMode GetNpadHandheldActivationMode() const;
@@ -184,162 +113,106 @@ public:
void SetNpadCommunicationMode(NpadCommunicationMode communication_mode_);
NpadCommunicationMode GetNpadCommunicationMode() const;
void SetNpadMode(u32 npad_id, NpadAssignments assignment_mode);
void SetNpadMode(Core::HID::NpadIdType npad_id, NpadJoyAssignmentMode assignment_mode);
bool VibrateControllerAtIndex(std::size_t npad_index, std::size_t device_index,
const VibrationValue& vibration_value);
bool VibrateControllerAtIndex(Core::HID::NpadIdType npad_id, std::size_t device_index,
const Core::HID::VibrationValue& vibration_value);
void VibrateController(const DeviceHandle& vibration_device_handle,
const VibrationValue& vibration_value);
void VibrateController(const Core::HID::VibrationDeviceHandle& vibration_device_handle,
const Core::HID::VibrationValue& vibration_value);
void VibrateControllers(const std::vector<DeviceHandle>& vibration_device_handles,
const std::vector<VibrationValue>& vibration_values);
void VibrateControllers(
const std::vector<Core::HID::VibrationDeviceHandle>& vibration_device_handles,
const std::vector<Core::HID::VibrationValue>& vibration_values);
VibrationValue GetLastVibration(const DeviceHandle& vibration_device_handle) const;
Core::HID::VibrationValue GetLastVibration(
const Core::HID::VibrationDeviceHandle& vibration_device_handle) const;
void InitializeVibrationDevice(const DeviceHandle& vibration_device_handle);
void InitializeVibrationDevice(const Core::HID::VibrationDeviceHandle& vibration_device_handle);
void InitializeVibrationDeviceAtIndex(std::size_t npad_index, std::size_t device_index);
void InitializeVibrationDeviceAtIndex(Core::HID::NpadIdType npad_id, std::size_t device_index);
void SetPermitVibrationSession(bool permit_vibration_session);
bool IsVibrationDeviceMounted(const DeviceHandle& vibration_device_handle) const;
bool IsVibrationDeviceMounted(
const Core::HID::VibrationDeviceHandle& vibration_device_handle) const;
Kernel::KReadableEvent& GetStyleSetChangedEvent(u32 npad_id);
void SignalStyleSetChangedEvent(u32 npad_id) const;
Kernel::KReadableEvent& GetStyleSetChangedEvent(Core::HID::NpadIdType npad_id);
void SignalStyleSetChangedEvent(Core::HID::NpadIdType npad_id) const;
// Adds a new controller at an index.
void AddNewControllerAt(NPadControllerType controller, std::size_t npad_index);
void AddNewControllerAt(Core::HID::NpadStyleIndex controller, Core::HID::NpadIdType npad_id);
// Adds a new controller at an index with connection status.
void UpdateControllerAt(NPadControllerType controller, std::size_t npad_index, bool connected);
void UpdateControllerAt(Core::HID::NpadStyleIndex controller, Core::HID::NpadIdType npad_id,
bool connected);
void DisconnectNpad(u32 npad_id);
void DisconnectNpadAtIndex(std::size_t index);
void DisconnectNpad(Core::HID::NpadIdType npad_id);
void SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode drift_mode);
GyroscopeZeroDriftMode GetGyroscopeZeroDriftMode() const;
bool IsSixAxisSensorAtRest() const;
void SetSixAxisEnabled(bool six_axis_status);
void SetSixAxisFusionParameters(f32 parameter1, f32 parameter2);
std::pair<f32, f32> GetSixAxisFusionParameters();
void ResetSixAxisFusionParameters();
LedPattern GetLedPattern(u32 npad_id);
bool IsUnintendedHomeButtonInputProtectionEnabled(u32 npad_id) const;
void SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled, u32 npad_id);
void SetGyroscopeZeroDriftMode(Core::HID::SixAxisSensorHandle sixaxis_handle,
GyroscopeZeroDriftMode drift_mode);
GyroscopeZeroDriftMode GetGyroscopeZeroDriftMode(
Core::HID::SixAxisSensorHandle sixaxis_handle) const;
bool IsSixAxisSensorAtRest(Core::HID::SixAxisSensorHandle sixaxis_handle) const;
void SetSixAxisEnabled(Core::HID::SixAxisSensorHandle sixaxis_handle, bool sixaxis_status);
void SetSixAxisFusionEnabled(Core::HID::SixAxisSensorHandle sixaxis_handle,
bool sixaxis_fusion_status);
void SetSixAxisFusionParameters(
Core::HID::SixAxisSensorHandle sixaxis_handle,
Core::HID::SixAxisSensorFusionParameters sixaxis_fusion_parameters);
Core::HID::SixAxisSensorFusionParameters GetSixAxisFusionParameters(
Core::HID::SixAxisSensorHandle sixaxis_handle);
void ResetSixAxisFusionParameters(Core::HID::SixAxisSensorHandle sixaxis_handle);
Core::HID::LedPattern GetLedPattern(Core::HID::NpadIdType npad_id);
bool IsUnintendedHomeButtonInputProtectionEnabled(Core::HID::NpadIdType npad_id) const;
void SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled,
Core::HID::NpadIdType npad_id);
void SetAnalogStickUseCenterClamp(bool use_center_clamp);
void ClearAllConnectedControllers();
void DisconnectAllConnectedControllers();
void ConnectAllDisconnectedControllers();
void ClearAllControllers();
void MergeSingleJoyAsDualJoy(u32 npad_id_1, u32 npad_id_2);
void MergeSingleJoyAsDualJoy(Core::HID::NpadIdType npad_id_1, Core::HID::NpadIdType npad_id_2);
void StartLRAssignmentMode();
void StopLRAssignmentMode();
bool SwapNpadAssignment(u32 npad_id_1, u32 npad_id_2);
bool SwapNpadAssignment(Core::HID::NpadIdType npad_id_1, Core::HID::NpadIdType npad_id_2);
// Logical OR for all buttons presses on all controllers
// Specifically for cheat engine and other features.
u32 GetAndResetPressState();
Core::HID::NpadButton GetAndResetPressState();
static Controller_NPad::NPadControllerType MapSettingsTypeToNPad(Settings::ControllerType type);
static Settings::ControllerType MapNPadToSettingsType(Controller_NPad::NPadControllerType type);
static std::size_t NPadIdToIndex(u32 npad_id);
static u32 IndexToNPad(std::size_t index);
static bool IsNpadIdValid(u32 npad_id);
static bool IsDeviceHandleValid(const DeviceHandle& device_handle);
static bool IsNpadIdValid(Core::HID::NpadIdType npad_id);
static bool IsDeviceHandleValid(const Core::HID::SixAxisSensorHandle& device_handle);
static bool IsDeviceHandleValid(const Core::HID::VibrationDeviceHandle& device_handle);
private:
struct CommonHeader {
s64_le timestamp;
s64_le total_entry_count;
s64_le last_entry_index;
s64_le entry_count;
};
static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size");
enum class ColorAttributes : u32_le {
// This is nn::hid::detail::ColorAttribute
enum class ColorAttribute : u32 {
Ok = 0,
ReadError = 1,
NoController = 2,
};
static_assert(sizeof(ColorAttributes) == 4, "ColorAttributes is an invalid size");
static_assert(sizeof(ColorAttribute) == 4, "ColorAttribute is an invalid size");
struct ControllerColor {
u32_le body;
u32_le button;
// This is nn::hid::detail::NpadFullKeyColorState
struct NpadFullKeyColorState {
ColorAttribute attribute;
Core::HID::NpadControllerColor fullkey;
};
static_assert(sizeof(ControllerColor) == 8, "ControllerColor is an invalid size");
static_assert(sizeof(NpadFullKeyColorState) == 0xC, "NpadFullKeyColorState is an invalid size");
struct FullKeyColor {
ColorAttributes attribute;
ControllerColor fullkey;
// This is nn::hid::detail::NpadJoyColorState
struct NpadJoyColorState {
ColorAttribute attribute;
Core::HID::NpadControllerColor left;
Core::HID::NpadControllerColor right;
};
static_assert(sizeof(FullKeyColor) == 0xC, "FullKeyColor is an invalid size");
static_assert(sizeof(NpadJoyColorState) == 0x14, "NpadJoyColorState is an invalid size");
struct JoyconColor {
ColorAttributes attribute;
ControllerColor left;
ControllerColor right;
};
static_assert(sizeof(JoyconColor) == 0x14, "JoyconColor is an invalid size");
struct ControllerPadState {
// This is nn::hid::NpadAttribute
struct NpadAttribute {
union {
u64_le raw{};
// Button states
BitField<0, 1, u64> a;
BitField<1, 1, u64> b;
BitField<2, 1, u64> x;
BitField<3, 1, u64> y;
BitField<4, 1, u64> l_stick;
BitField<5, 1, u64> r_stick;
BitField<6, 1, u64> l;
BitField<7, 1, u64> r;
BitField<8, 1, u64> zl;
BitField<9, 1, u64> zr;
BitField<10, 1, u64> plus;
BitField<11, 1, u64> minus;
// D-Pad
BitField<12, 1, u64> d_left;
BitField<13, 1, u64> d_up;
BitField<14, 1, u64> d_right;
BitField<15, 1, u64> d_down;
// Left JoyStick
BitField<16, 1, u64> l_stick_left;
BitField<17, 1, u64> l_stick_up;
BitField<18, 1, u64> l_stick_right;
BitField<19, 1, u64> l_stick_down;
// Right JoyStick
BitField<20, 1, u64> r_stick_left;
BitField<21, 1, u64> r_stick_up;
BitField<22, 1, u64> r_stick_right;
BitField<23, 1, u64> r_stick_down;
// Not always active?
BitField<24, 1, u64> left_sl;
BitField<25, 1, u64> left_sr;
BitField<26, 1, u64> right_sl;
BitField<27, 1, u64> right_sr;
BitField<28, 1, u64> palma;
BitField<30, 1, u64> handheld_left_b;
};
};
static_assert(sizeof(ControllerPadState) == 8, "ControllerPadState is an invalid size");
struct AnalogPosition {
s32_le x;
s32_le y;
};
static_assert(sizeof(AnalogPosition) == 8, "AnalogPosition is an invalid size");
struct ConnectionState {
union {
u32_le raw{};
u32 raw{};
BitField<0, 1, u32> is_connected;
BitField<1, 1, u32> is_wired;
BitField<2, 1, u32> is_left_connected;
@@ -348,79 +221,60 @@ private:
BitField<5, 1, u32> is_right_wired;
};
};
static_assert(sizeof(ConnectionState) == 4, "ConnectionState is an invalid size");
static_assert(sizeof(NpadAttribute) == 4, "NpadAttribute is an invalid size");
struct ControllerPad {
ControllerPadState pad_states;
AnalogPosition l_stick;
AnalogPosition r_stick;
// This is nn::hid::NpadFullKeyState
// This is nn::hid::NpadHandheldState
// This is nn::hid::NpadJoyDualState
// This is nn::hid::NpadJoyLeftState
// This is nn::hid::NpadJoyRightState
// This is nn::hid::NpadPalmaState
// This is nn::hid::NpadSystemExtState
struct NPadGenericState {
s64_le sampling_number;
Core::HID::NpadButtonState npad_buttons;
Core::HID::AnalogStickState l_stick;
Core::HID::AnalogStickState r_stick;
NpadAttribute connection_status;
INSERT_PADDING_BYTES(4); // Reserved
};
static_assert(sizeof(ControllerPad) == 0x18, "ControllerPad is an invalid size");
static_assert(sizeof(NPadGenericState) == 0x28, "NPadGenericState is an invalid size");
struct GenericStates {
s64_le timestamp;
s64_le timestamp2;
ControllerPad pad;
ConnectionState connection_status;
};
static_assert(sizeof(GenericStates) == 0x30, "NPadGenericStates is an invalid size");
struct NPadGeneric {
CommonHeader common;
std::array<GenericStates, 17> npad;
};
static_assert(sizeof(NPadGeneric) == 0x350, "NPadGeneric is an invalid size");
struct SixAxisAttributes {
// This is nn::hid::SixAxisSensorAttribute
struct SixAxisSensorAttribute {
union {
u32_le raw{};
u32 raw{};
BitField<0, 1, u32> is_connected;
BitField<1, 1, u32> is_interpolated;
};
};
static_assert(sizeof(SixAxisAttributes) == 4, "SixAxisAttributes is an invalid size");
static_assert(sizeof(SixAxisSensorAttribute) == 4, "SixAxisSensorAttribute is an invalid size");
struct SixAxisStates {
s64_le timestamp{};
INSERT_PADDING_WORDS(2);
s64_le timestamp2{};
// This is nn::hid::SixAxisSensorState
struct SixAxisSensorState {
s64 delta_time{};
s64 sampling_number{};
Common::Vec3f accel{};
Common::Vec3f gyro{};
Common::Vec3f rotation{};
std::array<Common::Vec3f, 3> orientation{};
SixAxisAttributes attribute;
SixAxisSensorAttribute attribute;
INSERT_PADDING_BYTES(4); // Reserved
};
static_assert(sizeof(SixAxisStates) == 0x68, "SixAxisStates is an invalid size");
static_assert(sizeof(SixAxisSensorState) == 0x60, "SixAxisSensorState is an invalid size");
struct SixAxisGeneric {
CommonHeader common{};
std::array<SixAxisStates, 17> sixaxis{};
// This is nn::hid::server::NpadGcTriggerState
struct NpadGcTriggerState {
s64 sampling_number{};
s32 l_analog{};
s32 r_analog{};
};
static_assert(sizeof(SixAxisGeneric) == 0x708, "SixAxisGeneric is an invalid size");
struct TriggerState {
s64_le timestamp{};
s64_le timestamp2{};
s32_le l_analog{};
s32_le r_analog{};
};
static_assert(sizeof(TriggerState) == 0x18, "TriggerState is an invalid size");
struct TriggerGeneric {
INSERT_PADDING_BYTES(0x4);
s64_le timestamp;
INSERT_PADDING_BYTES(0x4);
s64_le total_entry_count;
s64_le last_entry_index;
s64_le entry_count;
std::array<TriggerState, 17> trigger{};
};
static_assert(sizeof(TriggerGeneric) == 0x1C8, "TriggerGeneric is an invalid size");
static_assert(sizeof(NpadGcTriggerState) == 0x10, "NpadGcTriggerState is an invalid size");
// This is nn::hid::NpadSystemProperties
struct NPadSystemProperties {
union {
s64_le raw{};
s64 raw{};
BitField<0, 1, s64> is_charging_joy_dual;
BitField<1, 1, s64> is_charging_joy_left;
BitField<2, 1, s64> is_charging_joy_right;
@@ -438,17 +292,20 @@ private:
};
static_assert(sizeof(NPadSystemProperties) == 0x8, "NPadSystemProperties is an invalid size");
struct NPadButtonProperties {
// This is nn::hid::NpadSystemButtonProperties
struct NpadSystemButtonProperties {
union {
s32_le raw{};
s32 raw{};
BitField<0, 1, s32> is_home_button_protection_enabled;
};
};
static_assert(sizeof(NPadButtonProperties) == 0x4, "NPadButtonProperties is an invalid size");
static_assert(sizeof(NpadSystemButtonProperties) == 0x4,
"NPadButtonProperties is an invalid size");
struct NPadDevice {
// This is nn::hid::system::DeviceType
struct DeviceType {
union {
u32_le raw{};
u32 raw{};
BitField<0, 1, s32> fullkey;
BitField<1, 1, s32> debug_pad;
BitField<2, 1, s32> handheld_left;
@@ -465,26 +322,29 @@ private:
BitField<13, 1, s32> handheld_lark_nes_left;
BitField<14, 1, s32> handheld_lark_nes_right;
BitField<15, 1, s32> lucia;
BitField<16, 1, s32> lagon;
BitField<17, 1, s32> lager;
BitField<31, 1, s32> system;
};
};
struct MotionDevice {
Common::Vec3f accel;
Common::Vec3f gyro;
Common::Vec3f rotation;
std::array<Common::Vec3f, 3> orientation;
Common::Quaternion<f32> quaternion;
};
struct NfcXcdHandle {
INSERT_PADDING_BYTES(0x60);
// This is nn::hid::detail::NfcXcdDeviceHandleStateImpl
struct NfcXcdDeviceHandleStateImpl {
u64 handle;
bool is_available;
bool is_activated;
INSERT_PADDING_BYTES(0x6); // Reserved
u64 sampling_number;
};
static_assert(sizeof(NfcXcdDeviceHandleStateImpl) == 0x18,
"NfcXcdDeviceHandleStateImpl is an invalid size");
// This is nn::hid::system::AppletFooterUiAttributesSet
struct AppletFooterUiAttributes {
INSERT_PADDING_BYTES(0x4);
};
// This is nn::hid::system::AppletFooterUiType
enum class AppletFooterUiType : u8 {
None = 0,
HandheldNone = 1,
@@ -510,95 +370,150 @@ private:
Lagon = 21,
};
struct NPadEntry {
NpadStyleSet style_set;
NpadAssignments assignment_mode;
FullKeyColor fullkey_color;
JoyconColor joycon_color;
struct AppletFooterUi {
AppletFooterUiAttributes attributes;
AppletFooterUiType type;
INSERT_PADDING_BYTES(0x5B); // Reserved
};
static_assert(sizeof(AppletFooterUi) == 0x60, "AppletFooterUi is an invalid size");
NPadGeneric fullkey_states;
NPadGeneric handheld_states;
NPadGeneric joy_dual_states;
NPadGeneric joy_left_states;
NPadGeneric joy_right_states;
NPadGeneric palma_states;
NPadGeneric system_ext_states;
SixAxisGeneric sixaxis_fullkey;
SixAxisGeneric sixaxis_handheld;
SixAxisGeneric sixaxis_dual_left;
SixAxisGeneric sixaxis_dual_right;
SixAxisGeneric sixaxis_left;
SixAxisGeneric sixaxis_right;
NPadDevice device_type;
INSERT_PADDING_BYTES(0x4); // reserved
// This is nn::hid::NpadLarkType
enum class NpadLarkType : u32 {
Invalid,
H1,
H2,
NL,
NR,
};
// This is nn::hid::NpadLuciaType
enum class NpadLuciaType : u32 {
Invalid,
J,
E,
U,
};
// This is nn::hid::NpadLagonType
enum class NpadLagonType : u32 {
Invalid,
};
// This is nn::hid::NpadLagerType
enum class NpadLagerType : u32 {
Invalid,
J,
E,
U,
};
// This is nn::hid::detail::NpadInternalState
struct NpadInternalState {
Core::HID::NpadStyleTag style_tag;
NpadJoyAssignmentMode assignment_mode;
NpadFullKeyColorState fullkey_color;
NpadJoyColorState joycon_color;
Lifo<NPadGenericState, hid_entry_count> fullkey_lifo;
Lifo<NPadGenericState, hid_entry_count> handheld_lifo;
Lifo<NPadGenericState, hid_entry_count> joy_dual_lifo;
Lifo<NPadGenericState, hid_entry_count> joy_left_lifo;
Lifo<NPadGenericState, hid_entry_count> joy_right_lifo;
Lifo<NPadGenericState, hid_entry_count> palma_lifo;
Lifo<NPadGenericState, hid_entry_count> system_ext_lifo;
Lifo<SixAxisSensorState, hid_entry_count> sixaxis_fullkey_lifo;
Lifo<SixAxisSensorState, hid_entry_count> sixaxis_handheld_lifo;
Lifo<SixAxisSensorState, hid_entry_count> sixaxis_dual_left_lifo;
Lifo<SixAxisSensorState, hid_entry_count> sixaxis_dual_right_lifo;
Lifo<SixAxisSensorState, hid_entry_count> sixaxis_left_lifo;
Lifo<SixAxisSensorState, hid_entry_count> sixaxis_right_lifo;
DeviceType device_type;
INSERT_PADDING_BYTES(0x4); // Reserved
NPadSystemProperties system_properties;
NPadButtonProperties button_properties;
u32 battery_level_dual;
u32 battery_level_left;
u32 battery_level_right;
AppletFooterUiAttributes footer_attributes;
AppletFooterUiType footer_type;
// nfc_states needs to be checked switchbrew does not match with HW
NfcXcdHandle nfc_states;
INSERT_PADDING_BYTES(0x8); // Mutex
TriggerGeneric gc_trigger_states;
INSERT_PADDING_BYTES(0xc1f);
NpadSystemButtonProperties button_properties;
Core::HID::NpadBatteryLevel battery_level_dual;
Core::HID::NpadBatteryLevel battery_level_left;
Core::HID::NpadBatteryLevel battery_level_right;
union {
Lifo<NfcXcdDeviceHandleStateImpl, 0x2> nfc_xcd_device_lifo{};
AppletFooterUi applet_footer;
};
INSERT_PADDING_BYTES(0x20); // Unknown
Lifo<NpadGcTriggerState, hid_entry_count> gc_trigger_lifo;
NpadLarkType lark_type_l_and_main;
NpadLarkType lark_type_r;
NpadLuciaType lucia_type;
NpadLagonType lagon_type;
NpadLagerType lager_type;
// FW 13.x Investigate there is some sort of bitflag related to joycons
INSERT_PADDING_BYTES(0x4);
INSERT_PADDING_BYTES(0xc08); // Unknown
};
static_assert(sizeof(NPadEntry) == 0x5000, "NPadEntry is an invalid size");
static_assert(sizeof(NpadInternalState) == 0x5000, "NpadInternalState is an invalid size");
struct ControllerHolder {
NPadControllerType type;
bool is_connected;
struct VibrationData {
bool device_mounted{};
Core::HID::VibrationValue latest_vibration_value{};
std::chrono::steady_clock::time_point last_vibration_timepoint{};
};
void InitNewlyAddedController(std::size_t controller_idx);
bool IsControllerSupported(NPadControllerType controller) const;
void RequestPadStateUpdate(u32 npad_id);
struct NpadControllerData {
Core::HID::EmulatedController* device;
Kernel::KEvent* styleset_changed_event{};
NpadInternalState shared_memory_entry{};
std::atomic<u32> press_state{};
std::array<VibrationData, 2> vibration{};
bool unintended_home_button_input_protection{};
bool is_connected{};
Core::HID::NpadStyleIndex npad_type{Core::HID::NpadStyleIndex::None};
NpadStyleSet style{};
std::array<NPadEntry, 10> shared_memory_entries{};
using ButtonArray = std::array<
std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::NUM_BUTTONS_HID>,
10>;
using StickArray = std::array<
std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NUM_STICKS_HID>,
10>;
using VibrationArray = std::array<std::array<std::unique_ptr<Input::VibrationDevice>,
Settings::NativeVibration::NUM_VIBRATIONS_HID>,
10>;
using MotionArray = std::array<
std::array<std::unique_ptr<Input::MotionDevice>, Settings::NativeMotion::NUM_MOTIONS_HID>,
10>;
// Motion parameters
bool sixaxis_at_rest{true};
bool sixaxis_sensor_enabled{true};
bool sixaxis_fusion_enabled{false};
Core::HID::SixAxisSensorFusionParameters sixaxis_fusion{};
GyroscopeZeroDriftMode gyroscope_zero_drift_mode{GyroscopeZeroDriftMode::Standard};
// Current pad state
NPadGenericState npad_pad_state{};
NPadGenericState npad_libnx_state{};
NpadGcTriggerState npad_trigger_state{};
SixAxisSensorState sixaxis_fullkey_state{};
SixAxisSensorState sixaxis_handheld_state{};
SixAxisSensorState sixaxis_dual_left_state{};
SixAxisSensorState sixaxis_dual_right_state{};
SixAxisSensorState sixaxis_left_lifo_state{};
SixAxisSensorState sixaxis_right_lifo_state{};
int callback_key;
};
void ControllerUpdate(Core::HID::ControllerTriggerType type, std::size_t controller_idx);
void InitNewlyAddedController(Core::HID::NpadIdType npad_id);
bool IsControllerSupported(Core::HID::NpadStyleIndex controller) const;
void RequestPadStateUpdate(Core::HID::NpadIdType npad_id);
void WriteEmptyEntry(NpadInternalState& npad);
NpadControllerData& GetControllerFromHandle(
const Core::HID::SixAxisSensorHandle& device_handle);
const NpadControllerData& GetControllerFromHandle(
const Core::HID::SixAxisSensorHandle& device_handle) const;
NpadControllerData& GetControllerFromHandle(
const Core::HID::VibrationDeviceHandle& device_handle);
const NpadControllerData& GetControllerFromHandle(
const Core::HID::VibrationDeviceHandle& device_handle) const;
NpadControllerData& GetControllerFromNpadIdType(Core::HID::NpadIdType npad_id);
const NpadControllerData& GetControllerFromNpadIdType(Core::HID::NpadIdType npad_id) const;
std::atomic<u64> press_state{};
std::array<NpadControllerData, 10> controller_data{};
KernelHelpers::ServiceContext& service_context;
std::mutex mutex;
ButtonArray buttons;
StickArray sticks;
VibrationArray vibrations;
MotionArray motions;
std::vector<u32> supported_npad_id_types{};
NpadHoldType hold_type{NpadHoldType::Vertical};
std::vector<Core::HID::NpadIdType> supported_npad_id_types{};
NpadJoyHoldType hold_type{NpadJoyHoldType::Vertical};
NpadHandheldActivationMode handheld_activation_mode{NpadHandheldActivationMode::Dual};
NpadCommunicationMode communication_mode{NpadCommunicationMode::Default};
// Each controller should have their own styleset changed event
std::array<Kernel::KEvent*, 10> styleset_changed_events{};
std::array<std::array<std::chrono::steady_clock::time_point, 2>, 10>
last_vibration_timepoints{};
std::array<std::array<VibrationValue, 2>, 10> latest_vibration_values{};
bool permit_vibration_session_enabled{false};
std::array<std::array<bool, 2>, 10> vibration_devices_mounted{};
std::array<ControllerHolder, 10> connected_controllers{};
std::array<bool, 10> unintended_home_button_input_protection{};
bool analog_stick_use_center_clamp{};
GyroscopeZeroDriftMode gyroscope_zero_drift_mode{GyroscopeZeroDriftMode::Standard};
bool sixaxis_sensors_enabled{true};
f32 sixaxis_fusion_parameter1{};
f32 sixaxis_fusion_parameter2{};
bool sixaxis_at_rest{true};
std::array<ControllerPad, 10> npad_pad_states{};
std::array<TriggerState, 10> npad_trigger_states{};
bool is_in_lr_assignment_mode{false};
};
} // namespace Service::HID

View File

@@ -5,11 +5,12 @@
#include <cstring>
#include "common/common_types.h"
#include "core/core_timing.h"
#include "core/hid/hid_core.h"
#include "core/hle/service/hid/controllers/stubbed.h"
namespace Service::HID {
Controller_Stubbed::Controller_Stubbed(Core::System& system_) : ControllerBase{system_} {}
Controller_Stubbed::Controller_Stubbed(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {}
Controller_Stubbed::~Controller_Stubbed() = default;
void Controller_Stubbed::OnInit() {}
@@ -31,10 +32,9 @@ void Controller_Stubbed::OnUpdate(const Core::Timing::CoreTiming& core_timing, u
std::memcpy(data + common_offset, &header, sizeof(CommonHeader));
}
void Controller_Stubbed::OnLoadInputDevices() {}
void Controller_Stubbed::SetCommonHeaderOffset(std::size_t off) {
common_offset = off;
smart_update = true;
}
} // namespace Service::HID

View File

@@ -10,7 +10,7 @@
namespace Service::HID {
class Controller_Stubbed final : public ControllerBase {
public:
explicit Controller_Stubbed(Core::System& system_);
explicit Controller_Stubbed(Core::HID::HIDCore& hid_core_);
~Controller_Stubbed() override;
// Called when the controller is initialized
@@ -22,12 +22,17 @@ public:
// When the controller is requesting an update for the shared memory
void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override;
// Called when input devices should be loaded
void OnLoadInputDevices() override;
void SetCommonHeaderOffset(std::size_t off);
private:
struct CommonHeader {
s64 timestamp;
s64 total_entry_count;
s64 last_entry_index;
s64 entry_count;
};
static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size");
bool smart_update{};
std::size_t common_offset{};
};

View File

@@ -7,72 +7,82 @@
#include "common/common_types.h"
#include "common/logging/log.h"
#include "common/settings.h"
#include "core/core.h"
#include "core/core_timing.h"
#include "core/frontend/emu_window.h"
#include "core/frontend/input.h"
#include "core/hid/emulated_console.h"
#include "core/hid/hid_core.h"
#include "core/hle/service/hid/controllers/touchscreen.h"
namespace Service::HID {
constexpr std::size_t SHARED_MEMORY_OFFSET = 0x400;
Controller_Touchscreen::Controller_Touchscreen(Core::System& system_) : ControllerBase{system_} {}
Controller_Touchscreen::Controller_Touchscreen(Core::HID::HIDCore& hid_core_)
: ControllerBase{hid_core_} {
console = hid_core.GetEmulatedConsole();
}
Controller_Touchscreen::~Controller_Touchscreen() = default;
void Controller_Touchscreen::OnInit() {
for (std::size_t id = 0; id < MAX_FINGERS; ++id) {
mouse_finger_id[id] = MAX_FINGERS;
keyboard_finger_id[id] = MAX_FINGERS;
udp_finger_id[id] = MAX_FINGERS;
}
}
void Controller_Touchscreen::OnInit() {}
void Controller_Touchscreen::OnRelease() {}
void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
std::size_t size) {
shared_memory.header.timestamp = core_timing.GetCPUTicks();
shared_memory.header.total_entry_count = 17;
touch_screen_lifo.timestamp = core_timing.GetCPUTicks();
if (!IsControllerActivated()) {
shared_memory.header.entry_count = 0;
shared_memory.header.last_entry_index = 0;
touch_screen_lifo.buffer_count = 0;
touch_screen_lifo.buffer_tail = 0;
std::memcpy(data, &touch_screen_lifo, sizeof(touch_screen_lifo));
return;
}
shared_memory.header.entry_count = 16;
const auto& last_entry =
shared_memory.shared_memory_entries[shared_memory.header.last_entry_index];
shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17;
auto& cur_entry = shared_memory.shared_memory_entries[shared_memory.header.last_entry_index];
const auto touch_status = console->GetTouch();
for (std::size_t id = 0; id < MAX_FINGERS; id++) {
const auto& current_touch = touch_status[id];
auto& finger = fingers[id];
finger.position = current_touch.position;
finger.id = current_touch.id;
cur_entry.sampling_number = last_entry.sampling_number + 1;
cur_entry.sampling_number2 = cur_entry.sampling_number;
if (finger.attribute.start_touch) {
finger.attribute.raw = 0;
continue;
}
const Input::TouchStatus& mouse_status = touch_mouse_device->GetStatus();
const Input::TouchStatus& udp_status = touch_udp_device->GetStatus();
for (std::size_t id = 0; id < mouse_status.size(); ++id) {
mouse_finger_id[id] = UpdateTouchInputEvent(mouse_status[id], mouse_finger_id[id]);
udp_finger_id[id] = UpdateTouchInputEvent(udp_status[id], udp_finger_id[id]);
}
if (finger.attribute.end_touch) {
finger.attribute.raw = 0;
finger.pressed = false;
continue;
}
if (Settings::values.use_touch_from_button) {
const Input::TouchStatus& keyboard_status = touch_btn_device->GetStatus();
for (std::size_t id = 0; id < mouse_status.size(); ++id) {
keyboard_finger_id[id] =
UpdateTouchInputEvent(keyboard_status[id], keyboard_finger_id[id]);
if (!finger.pressed && current_touch.pressed) {
finger.attribute.start_touch.Assign(1);
finger.pressed = true;
continue;
}
if (finger.pressed && !current_touch.pressed) {
finger.attribute.raw = 0;
finger.attribute.end_touch.Assign(1);
}
}
std::array<Finger, 16> active_fingers;
std::array<Core::HID::TouchFinger, MAX_FINGERS> active_fingers;
const auto end_iter = std::copy_if(fingers.begin(), fingers.end(), active_fingers.begin(),
[](const auto& finger) { return finger.pressed; });
const auto active_fingers_count =
static_cast<std::size_t>(std::distance(active_fingers.begin(), end_iter));
const u64 tick = core_timing.GetCPUTicks();
cur_entry.entry_count = static_cast<s32_le>(active_fingers_count);
const auto& last_entry = touch_screen_lifo.ReadCurrentEntry().state;
next_state.sampling_number = last_entry.sampling_number + 1;
next_state.entry_count = static_cast<s32>(active_fingers_count);
for (std::size_t id = 0; id < MAX_FINGERS; ++id) {
auto& touch_entry = cur_entry.states[id];
auto& touch_entry = next_state.states[id];
if (id < active_fingers_count) {
const auto& [active_x, active_y] = active_fingers[id].position;
touch_entry.position = {
@@ -97,66 +107,9 @@ void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timin
touch_entry.finger = 0;
}
}
std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(TouchScreenSharedMemory));
}
void Controller_Touchscreen::OnLoadInputDevices() {
touch_mouse_device = Input::CreateDevice<Input::TouchDevice>("engine:emu_window");
touch_udp_device = Input::CreateDevice<Input::TouchDevice>("engine:cemuhookudp");
touch_btn_device = Input::CreateDevice<Input::TouchDevice>("engine:touch_from_button");
}
std::optional<std::size_t> Controller_Touchscreen::GetUnusedFingerID() const {
// Dont assign any touch input to a finger if disabled
if (!Settings::values.touchscreen.enabled) {
return std::nullopt;
}
std::size_t first_free_id = 0;
while (first_free_id < MAX_FINGERS) {
if (!fingers[first_free_id].pressed) {
return first_free_id;
} else {
first_free_id++;
}
}
return std::nullopt;
}
std::size_t Controller_Touchscreen::UpdateTouchInputEvent(
const std::tuple<float, float, bool>& touch_input, std::size_t finger_id) {
const auto& [x, y, pressed] = touch_input;
if (finger_id > MAX_FINGERS) {
LOG_ERROR(Service_HID, "Invalid finger id {}", finger_id);
return MAX_FINGERS;
}
if (pressed) {
Attributes attribute{};
if (finger_id == MAX_FINGERS) {
const auto first_free_id = GetUnusedFingerID();
if (!first_free_id) {
// Invalid finger id do nothing
return MAX_FINGERS;
}
finger_id = first_free_id.value();
fingers[finger_id].pressed = true;
fingers[finger_id].id = static_cast<u32_le>(finger_id);
attribute.start_touch.Assign(1);
}
fingers[finger_id].position = {x, y};
fingers[finger_id].attribute = attribute;
return finger_id;
}
if (finger_id != MAX_FINGERS) {
if (!fingers[finger_id].attribute.end_touch) {
fingers[finger_id].attribute.end_touch.Assign(1);
fingers[finger_id].attribute.start_touch.Assign(0);
return finger_id;
}
fingers[finger_id].pressed = false;
}
return MAX_FINGERS;
touch_screen_lifo.WriteNextEntry(next_state);
std::memcpy(data + SHARED_MEMORY_OFFSET, &touch_screen_lifo, sizeof(touch_screen_lifo));
}
} // namespace Service::HID

View File

@@ -9,18 +9,25 @@
#include "common/common_types.h"
#include "common/point.h"
#include "common/swap.h"
#include "core/frontend/input.h"
#include "core/hid/hid_types.h"
#include "core/hle/service/hid/controllers/controller_base.h"
#include "core/hle/service/hid/ring_lifo.h"
namespace Core::HID {
class EmulatedConsole;
} // namespace Core::HID
namespace Service::HID {
class Controller_Touchscreen final : public ControllerBase {
public:
// This is nn::hid::TouchScreenModeForNx
enum class TouchScreenModeForNx : u8 {
UseSystemSetting,
Finger,
Heat2,
};
// This is nn::hid::TouchScreenConfigurationForNx
struct TouchScreenConfigurationForNx {
TouchScreenModeForNx mode;
INSERT_PADDING_BYTES_NOINIT(0x7);
@@ -29,7 +36,7 @@ public:
static_assert(sizeof(TouchScreenConfigurationForNx) == 0x17,
"TouchScreenConfigurationForNx is an invalid size");
explicit Controller_Touchscreen(Core::System& system_);
explicit Controller_Touchscreen(Core::HID::HIDCore& hid_core_);
~Controller_Touchscreen() override;
// Called when the controller is initialized
@@ -41,73 +48,24 @@ public:
// When the controller is requesting an update for the shared memory
void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override;
// Called when input devices should be loaded
void OnLoadInputDevices() override;
private:
static constexpr std::size_t MAX_FINGERS = 16;
// Returns an unused finger id, if there is no fingers available std::nullopt will be returned
std::optional<std::size_t> GetUnusedFingerID() const;
// If the touch is new it tries to assing a new finger id, if there is no fingers avaliable no
// changes will be made. Updates the coordinates if the finger id it's already set. If the touch
// ends delays the output by one frame to set the end_touch flag before finally freeing the
// finger id
std::size_t UpdateTouchInputEvent(const std::tuple<float, float, bool>& touch_input,
std::size_t finger_id);
struct Attributes {
union {
u32 raw{};
BitField<0, 1, u32> start_touch;
BitField<1, 1, u32> end_touch;
};
// This is nn::hid::TouchScreenState
struct TouchScreenState {
s64 sampling_number;
s32 entry_count;
INSERT_PADDING_BYTES(4); // Reserved
std::array<Core::HID::TouchState, MAX_FINGERS> states;
};
static_assert(sizeof(Attributes) == 0x4, "Attributes is an invalid size");
static_assert(sizeof(TouchScreenState) == 0x290, "TouchScreenState is an invalid size");
struct TouchState {
u64_le delta_time;
Attributes attribute;
u32_le finger;
Common::Point<u32_le> position;
u32_le diameter_x;
u32_le diameter_y;
u32_le rotation_angle;
};
static_assert(sizeof(TouchState) == 0x28, "Touchstate is an invalid size");
// This is nn::hid::detail::TouchScreenLifo
Lifo<TouchScreenState, hid_entry_count> touch_screen_lifo{};
static_assert(sizeof(touch_screen_lifo) == 0x2C38, "touch_screen_lifo is an invalid size");
TouchScreenState next_state{};
struct TouchScreenEntry {
s64_le sampling_number;
s64_le sampling_number2;
s32_le entry_count;
std::array<TouchState, MAX_FINGERS> states;
};
static_assert(sizeof(TouchScreenEntry) == 0x298, "TouchScreenEntry is an invalid size");
struct TouchScreenSharedMemory {
CommonHeader header;
std::array<TouchScreenEntry, 17> shared_memory_entries{};
INSERT_PADDING_BYTES(0x3c8);
};
static_assert(sizeof(TouchScreenSharedMemory) == 0x3000,
"TouchScreenSharedMemory is an invalid size");
struct Finger {
u64_le last_touch{};
Common::Point<float> position;
u32_le id{};
bool pressed{};
Attributes attribute;
};
TouchScreenSharedMemory shared_memory{};
std::unique_ptr<Input::TouchDevice> touch_mouse_device;
std::unique_ptr<Input::TouchDevice> touch_udp_device;
std::unique_ptr<Input::TouchDevice> touch_btn_device;
std::array<std::size_t, MAX_FINGERS> mouse_finger_id;
std::array<std::size_t, MAX_FINGERS> keyboard_finger_id;
std::array<std::size_t, MAX_FINGERS> udp_finger_id;
std::array<Finger, MAX_FINGERS> fingers;
std::array<Core::HID::TouchFinger, MAX_FINGERS> fingers;
Core::HID::EmulatedConsole* console;
};
} // namespace Service::HID

View File

@@ -5,12 +5,13 @@
#include <cstring>
#include "common/common_types.h"
#include "core/core_timing.h"
#include "core/hid/hid_core.h"
#include "core/hle/service/hid/controllers/xpad.h"
namespace Service::HID {
constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C00;
Controller_XPad::Controller_XPad(Core::System& system_) : ControllerBase{system_} {}
Controller_XPad::Controller_XPad(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {}
Controller_XPad::~Controller_XPad() = default;
void Controller_XPad::OnInit() {}
@@ -19,28 +20,19 @@ void Controller_XPad::OnRelease() {}
void Controller_XPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
std::size_t size) {
for (auto& xpad_entry : shared_memory.shared_memory_entries) {
xpad_entry.header.timestamp = core_timing.GetCPUTicks();
xpad_entry.header.total_entry_count = 17;
if (!IsControllerActivated()) {
xpad_entry.header.entry_count = 0;
xpad_entry.header.last_entry_index = 0;
return;
}
xpad_entry.header.entry_count = 16;
const auto& last_entry = xpad_entry.pad_states[xpad_entry.header.last_entry_index];
xpad_entry.header.last_entry_index = (xpad_entry.header.last_entry_index + 1) % 17;
auto& cur_entry = xpad_entry.pad_states[xpad_entry.header.last_entry_index];
cur_entry.sampling_number = last_entry.sampling_number + 1;
cur_entry.sampling_number2 = cur_entry.sampling_number;
if (!IsControllerActivated()) {
basic_xpad_lifo.buffer_count = 0;
basic_xpad_lifo.buffer_tail = 0;
std::memcpy(data + SHARED_MEMORY_OFFSET, &basic_xpad_lifo, sizeof(basic_xpad_lifo));
return;
}
const auto& last_entry = basic_xpad_lifo.ReadCurrentEntry().state;
next_state.sampling_number = last_entry.sampling_number + 1;
// TODO(ogniK): Update xpad states
std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory));
basic_xpad_lifo.WriteNextEntry(next_state);
std::memcpy(data + SHARED_MEMORY_OFFSET, &basic_xpad_lifo, sizeof(basic_xpad_lifo));
}
void Controller_XPad::OnLoadInputDevices() {}
} // namespace Service::HID

View File

@@ -8,12 +8,14 @@
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/swap.h"
#include "core/hid/hid_types.h"
#include "core/hle/service/hid/controllers/controller_base.h"
#include "core/hle/service/hid/ring_lifo.h"
namespace Service::HID {
class Controller_XPad final : public ControllerBase {
public:
explicit Controller_XPad(Core::System& system_);
explicit Controller_XPad(Core::HID::HIDCore& hid_core_);
~Controller_XPad() override;
// Called when the controller is initialized
@@ -25,13 +27,11 @@ public:
// When the controller is requesting an update for the shared memory
void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override;
// Called when input devices should be loaded
void OnLoadInputDevices() override;
private:
struct Attributes {
// This is nn::hid::BasicXpadAttributeSet
struct BasicXpadAttributeSet {
union {
u32_le raw{};
u32 raw{};
BitField<0, 1, u32> is_connected;
BitField<1, 1, u32> is_wired;
BitField<2, 1, u32> is_left_connected;
@@ -40,11 +40,12 @@ private:
BitField<5, 1, u32> is_right_wired;
};
};
static_assert(sizeof(Attributes) == 4, "Attributes is an invalid size");
static_assert(sizeof(BasicXpadAttributeSet) == 4, "BasicXpadAttributeSet is an invalid size");
struct Buttons {
// This is nn::hid::BasicXpadButtonSet
struct BasicXpadButtonSet {
union {
u32_le raw{};
u32 raw{};
// Button states
BitField<0, 1, u32> a;
BitField<1, 1, u32> b;
@@ -88,35 +89,21 @@ private:
BitField<30, 1, u32> handheld_left_b;
};
};
static_assert(sizeof(Buttons) == 4, "Buttons is an invalid size");
static_assert(sizeof(BasicXpadButtonSet) == 4, "BasicXpadButtonSet is an invalid size");
struct AnalogStick {
s32_le x;
s32_le y;
// This is nn::hid::detail::BasicXpadState
struct BasicXpadState {
s64 sampling_number;
BasicXpadAttributeSet attributes;
BasicXpadButtonSet pad_states;
Core::HID::AnalogStickState l_stick;
Core::HID::AnalogStickState r_stick;
};
static_assert(sizeof(AnalogStick) == 0x8, "AnalogStick is an invalid size");
static_assert(sizeof(BasicXpadState) == 0x20, "BasicXpadState is an invalid size");
struct XPadState {
s64_le sampling_number;
s64_le sampling_number2;
Attributes attributes;
Buttons pad_states;
AnalogStick l_stick;
AnalogStick r_stick;
};
static_assert(sizeof(XPadState) == 0x28, "XPadState is an invalid size");
struct XPadEntry {
CommonHeader header;
std::array<XPadState, 17> pad_states{};
INSERT_PADDING_BYTES(0x138);
};
static_assert(sizeof(XPadEntry) == 0x400, "XPadEntry is an invalid size");
struct SharedMemory {
std::array<XPadEntry, 4> shared_memory_entries{};
};
static_assert(sizeof(SharedMemory) == 0x1000, "SharedMemory is an invalid size");
SharedMemory shared_memory{};
// This is nn::hid::detail::BasicXpadLifo
Lifo<BasicXpadState, hid_entry_count> basic_xpad_lifo{};
static_assert(sizeof(basic_xpad_lifo) == 0x2C8, "basic_xpad_lifo is an invalid size");
BasicXpadState next_state{};
};
} // namespace Service::HID

View File

@@ -8,7 +8,7 @@
#include "common/settings.h"
#include "core/core.h"
#include "core/core_timing.h"
#include "core/frontend/input.h"
#include "core/hid/hid_core.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/k_readable_event.h"
#include "core/hle/kernel/k_shared_memory.h"
@@ -34,10 +34,10 @@
namespace Service::HID {
// Updating period for each HID device.
// HID is polled every 15ms, this value was derived from
// https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering#joy-con-status-data-packet
constexpr auto pad_update_ns = std::chrono::nanoseconds{1000 * 1000}; // (1ms, 1000Hz)
constexpr auto motion_update_ns = std::chrono::nanoseconds{15 * 1000 * 1000}; // (15ms, 66.666Hz)
// Period time is obtained by measuring the number of samples in a second on HW using a homebrew
constexpr auto pad_update_ns = std::chrono::nanoseconds{4 * 1000 * 1000}; // (4ms, 250Hz)
constexpr auto mouse_keyboard_update_ns = std::chrono::nanoseconds{8 * 1000 * 1000}; // (8ms, 125Hz)
constexpr auto motion_update_ns = std::chrono::nanoseconds{5 * 1000 * 1000}; // (5ms, 200Hz)
constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000;
IAppletResource::IAppletResource(Core::System& system_,
@@ -79,17 +79,24 @@ IAppletResource::IAppletResource(Core::System& system_,
const auto guard = LockService();
UpdateControllers(user_data, ns_late);
});
mouse_keyboard_update_event = Core::Timing::CreateEvent(
"HID::UpdateMouseKeyboardCallback",
[this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
const auto guard = LockService();
UpdateMouseKeyboard(user_data, ns_late);
});
motion_update_event = Core::Timing::CreateEvent(
"HID::MotionPadCallback",
"HID::UpdateMotionCallback",
[this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
const auto guard = LockService();
UpdateMotion(user_data, ns_late);
});
system.CoreTiming().ScheduleEvent(pad_update_ns, pad_update_event);
system.CoreTiming().ScheduleEvent(mouse_keyboard_update_ns, mouse_keyboard_update_event);
system.CoreTiming().ScheduleEvent(motion_update_ns, motion_update_event);
ReloadInputDevices();
system.HIDCore().ReloadInputDevices();
}
void IAppletResource::ActivateController(HidController controller) {
@@ -102,6 +109,7 @@ void IAppletResource::DeactivateController(HidController controller) {
IAppletResource::~IAppletResource() {
system.CoreTiming().UnscheduleEvent(pad_update_event, 0);
system.CoreTiming().UnscheduleEvent(mouse_keyboard_update_event, 0);
system.CoreTiming().UnscheduleEvent(motion_update_event, 0);
}
@@ -117,23 +125,44 @@ void IAppletResource::UpdateControllers(std::uintptr_t user_data,
std::chrono::nanoseconds ns_late) {
auto& core_timing = system.CoreTiming();
const bool should_reload = Settings::values.is_device_reload_pending.exchange(false);
for (const auto& controller : controllers) {
if (should_reload) {
controller->OnLoadInputDevices();
// Keyboard has it's own update event
if (controller == controllers[static_cast<size_t>(HidController::Keyboard)]) {
continue;
}
// Mouse has it's own update event
if (controller == controllers[static_cast<size_t>(HidController::Mouse)]) {
continue;
}
controller->OnUpdate(core_timing, system.Kernel().GetHidSharedMem().GetPointer(),
SHARED_MEMORY_SIZE);
}
// If ns_late is higher than the update rate ignore the delay
if (ns_late > motion_update_ns) {
if (ns_late > pad_update_ns) {
ns_late = {};
}
core_timing.ScheduleEvent(pad_update_ns - ns_late, pad_update_event);
}
void IAppletResource::UpdateMouseKeyboard(std::uintptr_t user_data,
std::chrono::nanoseconds ns_late) {
auto& core_timing = system.CoreTiming();
controllers[static_cast<size_t>(HidController::Mouse)]->OnUpdate(
core_timing, system.Kernel().GetHidSharedMem().GetPointer(), SHARED_MEMORY_SIZE);
controllers[static_cast<size_t>(HidController::Keyboard)]->OnUpdate(
core_timing, system.Kernel().GetHidSharedMem().GetPointer(), SHARED_MEMORY_SIZE);
// If ns_late is higher than the update rate ignore the delay
if (ns_late > mouse_keyboard_update_ns) {
ns_late = {};
}
core_timing.ScheduleEvent(mouse_keyboard_update_ns - ns_late, mouse_keyboard_update_event);
}
void IAppletResource::UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
auto& core_timing = system.CoreTiming();
@@ -166,7 +195,7 @@ public:
private:
void InitializeVibrationDevice(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto vibration_device_handle{rp.PopRaw<Controller_NPad::DeviceHandle>()};
const auto vibration_device_handle{rp.PopRaw<Core::HID::VibrationDeviceHandle>()};
if (applet_resource != nullptr) {
applet_resource->GetController<Controller_NPad>(HidController::NPad)
@@ -422,6 +451,7 @@ void Hid::ActivateXpad(Kernel::HLERequestContext& ctx) {
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id;
};
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()};
@@ -448,19 +478,18 @@ void Hid::GetXpadIDs(Kernel::HLERequestContext& ctx) {
void Hid::ActivateSixAxisSensor(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Controller_NPad::DeviceHandle sixaxis_handle;
u32 basic_xpad_id;
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id;
};
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()};
applet_resource->GetController<Controller_NPad>(HidController::NPad).SetSixAxisEnabled(true);
// This function does nothing on 10.0.0+
LOG_DEBUG(Service_HID,
"called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
LOG_WARNING(Service_HID, "(STUBBED) called, basic_xpad_id={}, applet_resource_user_id={}",
parameters.basic_xpad_id, parameters.applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
@@ -469,19 +498,18 @@ void Hid::ActivateSixAxisSensor(Kernel::HLERequestContext& ctx) {
void Hid::DeactivateSixAxisSensor(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Controller_NPad::DeviceHandle sixaxis_handle;
u32 basic_xpad_id;
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id;
};
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()};
applet_resource->GetController<Controller_NPad>(HidController::NPad).SetSixAxisEnabled(false);
// This function does nothing on 10.0.0+
LOG_DEBUG(Service_HID,
"called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
LOG_WARNING(Service_HID, "(STUBBED) called, basic_xpad_id={}, applet_resource_user_id={}",
parameters.basic_xpad_id, parameters.applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
@@ -490,14 +518,16 @@ void Hid::DeactivateSixAxisSensor(Kernel::HLERequestContext& ctx) {
void Hid::StartSixAxisSensor(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Controller_NPad::DeviceHandle sixaxis_handle;
Core::HID::SixAxisSensorHandle sixaxis_handle;
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id;
};
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()};
applet_resource->GetController<Controller_NPad>(HidController::NPad).SetSixAxisEnabled(true);
applet_resource->GetController<Controller_NPad>(HidController::NPad)
.SetSixAxisEnabled(parameters.sixaxis_handle, true);
LOG_DEBUG(Service_HID,
"called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
@@ -511,14 +541,16 @@ void Hid::StartSixAxisSensor(Kernel::HLERequestContext& ctx) {
void Hid::StopSixAxisSensor(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Controller_NPad::DeviceHandle sixaxis_handle;
Core::HID::SixAxisSensorHandle sixaxis_handle;
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id;
};
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()};
applet_resource->GetController<Controller_NPad>(HidController::NPad).SetSixAxisEnabled(false);
applet_resource->GetController<Controller_NPad>(HidController::NPad)
.SetSixAxisEnabled(parameters.sixaxis_handle, false);
LOG_DEBUG(Service_HID,
"called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
@@ -534,19 +566,23 @@ void Hid::EnableSixAxisSensorFusion(Kernel::HLERequestContext& ctx) {
struct Parameters {
bool enable_sixaxis_sensor_fusion;
INSERT_PADDING_BYTES_NOINIT(3);
Controller_NPad::DeviceHandle sixaxis_handle;
Core::HID::SixAxisSensorHandle sixaxis_handle;
u64 applet_resource_user_id;
};
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()};
LOG_WARNING(Service_HID,
"(STUBBED) called, enable_sixaxis_sensor_fusion={}, npad_type={}, npad_id={}, "
"device_index={}, applet_resource_user_id={}",
parameters.enable_sixaxis_sensor_fusion, parameters.sixaxis_handle.npad_type,
parameters.sixaxis_handle.npad_id, parameters.sixaxis_handle.device_index,
parameters.applet_resource_user_id);
applet_resource->GetController<Controller_NPad>(HidController::NPad)
.SetSixAxisFusionEnabled(parameters.sixaxis_handle,
parameters.enable_sixaxis_sensor_fusion);
LOG_DEBUG(Service_HID,
"called, enable_sixaxis_sensor_fusion={}, npad_type={}, npad_id={}, "
"device_index={}, applet_resource_user_id={}",
parameters.enable_sixaxis_sensor_fusion, parameters.sixaxis_handle.npad_type,
parameters.sixaxis_handle.npad_id, parameters.sixaxis_handle.device_index,
parameters.applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
@@ -555,9 +591,9 @@ void Hid::EnableSixAxisSensorFusion(Kernel::HLERequestContext& ctx) {
void Hid::SetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Controller_NPad::DeviceHandle sixaxis_handle;
f32 parameter1;
f32 parameter2;
Core::HID::SixAxisSensorHandle sixaxis_handle;
Core::HID::SixAxisSensorFusionParameters sixaxis_fusion;
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id;
};
static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
@@ -565,14 +601,14 @@ void Hid::SetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) {
const auto parameters{rp.PopRaw<Parameters>()};
applet_resource->GetController<Controller_NPad>(HidController::NPad)
.SetSixAxisFusionParameters(parameters.parameter1, parameters.parameter2);
.SetSixAxisFusionParameters(parameters.sixaxis_handle, parameters.sixaxis_fusion);
LOG_WARNING(Service_HID,
"(STUBBED) called, npad_type={}, npad_id={}, device_index={}, parameter1={}, "
"parameter2={}, applet_resource_user_id={}",
parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
parameters.sixaxis_handle.device_index, parameters.parameter1,
parameters.parameter2, parameters.applet_resource_user_id);
LOG_DEBUG(Service_HID,
"called, npad_type={}, npad_id={}, device_index={}, parameter1={}, "
"parameter2={}, applet_resource_user_id={}",
parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
parameters.sixaxis_handle.device_index, parameters.sixaxis_fusion.parameter1,
parameters.sixaxis_fusion.parameter2, parameters.applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
@@ -581,35 +617,33 @@ void Hid::SetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) {
void Hid::GetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Controller_NPad::DeviceHandle sixaxis_handle;
Core::HID::SixAxisSensorHandle sixaxis_handle;
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id;
};
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
f32 parameter1 = 0;
f32 parameter2 = 0;
const auto parameters{rp.PopRaw<Parameters>()};
std::tie(parameter1, parameter2) =
const auto sixaxis_fusion_parameters =
applet_resource->GetController<Controller_NPad>(HidController::NPad)
.GetSixAxisFusionParameters();
.GetSixAxisFusionParameters(parameters.sixaxis_handle);
LOG_WARNING(
Service_HID,
"(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
LOG_DEBUG(Service_HID,
"called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push(parameter1);
rb.Push(parameter2);
rb.PushRaw(sixaxis_fusion_parameters);
}
void Hid::ResetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Controller_NPad::DeviceHandle sixaxis_handle;
Core::HID::SixAxisSensorHandle sixaxis_handle;
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id;
};
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
@@ -617,13 +651,12 @@ void Hid::ResetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) {
const auto parameters{rp.PopRaw<Parameters>()};
applet_resource->GetController<Controller_NPad>(HidController::NPad)
.ResetSixAxisFusionParameters();
.ResetSixAxisFusionParameters(parameters.sixaxis_handle);
LOG_WARNING(
Service_HID,
"(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
LOG_DEBUG(Service_HID,
"called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
@@ -631,12 +664,12 @@ void Hid::ResetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) {
void Hid::SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto sixaxis_handle{rp.PopRaw<Controller_NPad::DeviceHandle>()};
const auto sixaxis_handle{rp.PopRaw<Core::HID::SixAxisSensorHandle>()};
const auto drift_mode{rp.PopEnum<Controller_NPad::GyroscopeZeroDriftMode>()};
const auto applet_resource_user_id{rp.Pop<u64>()};
applet_resource->GetController<Controller_NPad>(HidController::NPad)
.SetGyroscopeZeroDriftMode(drift_mode);
.SetGyroscopeZeroDriftMode(sixaxis_handle, drift_mode);
LOG_DEBUG(Service_HID,
"called, npad_type={}, npad_id={}, device_index={}, drift_mode={}, "
@@ -651,10 +684,11 @@ void Hid::SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
void Hid::GetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Controller_NPad::DeviceHandle sixaxis_handle;
Core::HID::SixAxisSensorHandle sixaxis_handle;
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id;
};
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()};
@@ -666,21 +700,23 @@ void Hid::GetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.PushEnum(applet_resource->GetController<Controller_NPad>(HidController::NPad)
.GetGyroscopeZeroDriftMode());
.GetGyroscopeZeroDriftMode(parameters.sixaxis_handle));
}
void Hid::ResetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Controller_NPad::DeviceHandle sixaxis_handle;
Core::HID::SixAxisSensorHandle sixaxis_handle;
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id;
};
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()};
const auto drift_mode{Controller_NPad::GyroscopeZeroDriftMode::Standard};
applet_resource->GetController<Controller_NPad>(HidController::NPad)
.SetGyroscopeZeroDriftMode(Controller_NPad::GyroscopeZeroDriftMode::Standard);
.SetGyroscopeZeroDriftMode(parameters.sixaxis_handle, drift_mode);
LOG_DEBUG(Service_HID,
"called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
@@ -694,10 +730,11 @@ void Hid::ResetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
void Hid::IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Controller_NPad::DeviceHandle sixaxis_handle;
Core::HID::SixAxisSensorHandle sixaxis_handle;
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id;
};
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()};
@@ -709,16 +746,17 @@ void Hid::IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(applet_resource->GetController<Controller_NPad>(HidController::NPad)
.IsSixAxisSensorAtRest());
.IsSixAxisSensorAtRest(parameters.sixaxis_handle));
}
void Hid::IsFirmwareUpdateAvailableForSixAxisSensor(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Controller_NPad::DeviceHandle sixaxis_handle;
Core::HID::SixAxisSensorHandle sixaxis_handle;
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id;
};
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()};
@@ -740,13 +778,14 @@ void Hid::ActivateGesture(Kernel::HLERequestContext& ctx) {
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id;
};
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()};
applet_resource->ActivateController(HidController::Gesture);
LOG_DEBUG(Service_HID, "called, unknown={}, applet_resource_user_id={}", parameters.unknown,
parameters.applet_resource_user_id);
LOG_WARNING(Service_HID, "(STUBBED) called, unknown={}, applet_resource_user_id={}",
parameters.unknown, parameters.applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
@@ -754,12 +793,20 @@ void Hid::ActivateGesture(Kernel::HLERequestContext& ctx) {
void Hid::SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto supported_styleset{rp.Pop<u32>()};
struct Parameters {
Core::HID::NpadStyleSet supported_styleset;
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id;
};
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()};
applet_resource->GetController<Controller_NPad>(HidController::NPad)
.SetSupportedStyleSet({supported_styleset});
.SetSupportedStyleSet({parameters.supported_styleset});
LOG_DEBUG(Service_HID, "called, supported_styleset={}", supported_styleset);
LOG_DEBUG(Service_HID, "called, supported_styleset={}, applet_resource_user_id={}",
parameters.supported_styleset, parameters.applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
@@ -773,9 +820,9 @@ void Hid::GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(applet_resource->GetController<Controller_NPad>(HidController::NPad)
.GetSupportedStyleSet()
.raw);
rb.PushEnum(applet_resource->GetController<Controller_NPad>(HidController::NPad)
.GetSupportedStyleSet()
.raw);
}
void Hid::SetSupportedNpadIdType(Kernel::HLERequestContext& ctx) {
@@ -818,11 +865,12 @@ void Hid::DeactivateNpad(Kernel::HLERequestContext& ctx) {
void Hid::AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
u32 npad_id;
Core::HID::NpadIdType npad_id;
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id;
u64 unknown;
};
static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()};
@@ -838,10 +886,11 @@ void Hid::AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) {
void Hid::DisconnectNpad(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
u32 npad_id;
Core::HID::NpadIdType npad_id;
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id;
};
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()};
@@ -857,7 +906,7 @@ void Hid::DisconnectNpad(Kernel::HLERequestContext& ctx) {
void Hid::GetPlayerLedPattern(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto npad_id{rp.Pop<u32>()};
const auto npad_id{rp.PopEnum<Core::HID::NpadIdType>()};
LOG_DEBUG(Service_HID, "called, npad_id={}", npad_id);
@@ -872,16 +921,17 @@ void Hid::ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) {
// Should have no effect with how our npad sets up the data
IPC::RequestParser rp{ctx};
struct Parameters {
u32 unknown;
s32 revision;
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id;
};
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()};
applet_resource->ActivateController(HidController::NPad);
LOG_DEBUG(Service_HID, "called, unknown={}, applet_resource_user_id={}", parameters.unknown,
LOG_DEBUG(Service_HID, "called, revision={}, applet_resource_user_id={}", parameters.revision,
parameters.applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2};
@@ -891,7 +941,7 @@ void Hid::ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) {
void Hid::SetNpadJoyHoldType(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
const auto hold_type{rp.PopEnum<Controller_NPad::NpadHoldType>()};
const auto hold_type{rp.PopEnum<Controller_NPad::NpadJoyHoldType>()};
applet_resource->GetController<Controller_NPad>(HidController::NPad).SetHoldType(hold_type);
@@ -916,15 +966,16 @@ void Hid::GetNpadJoyHoldType(Kernel::HLERequestContext& ctx) {
void Hid::SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
u32 npad_id;
Core::HID::NpadIdType npad_id;
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id;
};
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()};
applet_resource->GetController<Controller_NPad>(HidController::NPad)
.SetNpadMode(parameters.npad_id, Controller_NPad::NpadAssignments::Single);
.SetNpadMode(parameters.npad_id, Controller_NPad::NpadJoyAssignmentMode::Single);
LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}",
parameters.npad_id, parameters.applet_resource_user_id);
@@ -937,16 +988,17 @@ void Hid::SetNpadJoyAssignmentModeSingle(Kernel::HLERequestContext& ctx) {
// TODO: Check the differences between this and SetNpadJoyAssignmentModeSingleByDefault
IPC::RequestParser rp{ctx};
struct Parameters {
u32 npad_id;
Core::HID::NpadIdType npad_id;
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id;
u64 npad_joy_device_type;
};
static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()};
applet_resource->GetController<Controller_NPad>(HidController::NPad)
.SetNpadMode(parameters.npad_id, Controller_NPad::NpadAssignments::Single);
.SetNpadMode(parameters.npad_id, Controller_NPad::NpadJoyAssignmentMode::Single);
LOG_WARNING(Service_HID,
"(STUBBED) called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}",
@@ -960,15 +1012,16 @@ void Hid::SetNpadJoyAssignmentModeSingle(Kernel::HLERequestContext& ctx) {
void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
u32 npad_id;
Core::HID::NpadIdType npad_id;
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id;
};
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()};
applet_resource->GetController<Controller_NPad>(HidController::NPad)
.SetNpadMode(parameters.npad_id, Controller_NPad::NpadAssignments::Dual);
.SetNpadMode(parameters.npad_id, Controller_NPad::NpadJoyAssignmentMode::Dual);
LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}",
parameters.npad_id, parameters.applet_resource_user_id);
@@ -979,8 +1032,8 @@ void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) {
void Hid::MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto npad_id_1{rp.Pop<u32>()};
const auto npad_id_2{rp.Pop<u32>()};
const auto npad_id_1{rp.PopEnum<Core::HID::NpadIdType>()};
const auto npad_id_2{rp.PopEnum<Core::HID::NpadIdType>()};
const auto applet_resource_user_id{rp.Pop<u64>()};
applet_resource->GetController<Controller_NPad>(HidController::NPad)
@@ -1046,8 +1099,8 @@ void Hid::GetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) {
void Hid::SwapNpadAssignment(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto npad_id_1{rp.Pop<u32>()};
const auto npad_id_2{rp.Pop<u32>()};
const auto npad_id_1{rp.PopEnum<Core::HID::NpadIdType>()};
const auto npad_id_2{rp.PopEnum<Core::HID::NpadIdType>()};
const auto applet_resource_user_id{rp.Pop<u64>()};
const bool res = applet_resource->GetController<Controller_NPad>(HidController::NPad)
@@ -1068,10 +1121,11 @@ void Hid::SwapNpadAssignment(Kernel::HLERequestContext& ctx) {
void Hid::IsUnintendedHomeButtonInputProtectionEnabled(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
u32 npad_id;
Core::HID::NpadIdType npad_id;
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id;
};
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()};
@@ -1089,9 +1143,10 @@ void Hid::EnableUnintendedHomeButtonInputProtection(Kernel::HLERequestContext& c
struct Parameters {
bool unintended_home_button_input_protection;
INSERT_PADDING_BYTES_NOINIT(3);
u32 npad_id;
Core::HID::NpadIdType npad_id;
u64 applet_resource_user_id;
};
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()};
@@ -1113,6 +1168,7 @@ void Hid::SetNpadAnalogStickUseCenterClamp(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
bool analog_stick_use_center_clamp;
INSERT_PADDING_BYTES_NOINIT(7);
u64 applet_resource_user_id;
};
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
@@ -1132,38 +1188,38 @@ void Hid::SetNpadAnalogStickUseCenterClamp(Kernel::HLERequestContext& ctx) {
void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto vibration_device_handle{rp.PopRaw<Controller_NPad::DeviceHandle>()};
const auto vibration_device_handle{rp.PopRaw<Core::HID::VibrationDeviceHandle>()};
VibrationDeviceInfo vibration_device_info;
Core::HID::VibrationDeviceInfo vibration_device_info;
switch (vibration_device_handle.npad_type) {
case Controller_NPad::NpadType::ProController:
case Controller_NPad::NpadType::Handheld:
case Controller_NPad::NpadType::JoyconDual:
case Controller_NPad::NpadType::JoyconLeft:
case Controller_NPad::NpadType::JoyconRight:
case Core::HID::NpadStyleIndex::ProController:
case Core::HID::NpadStyleIndex::Handheld:
case Core::HID::NpadStyleIndex::JoyconDual:
case Core::HID::NpadStyleIndex::JoyconLeft:
case Core::HID::NpadStyleIndex::JoyconRight:
default:
vibration_device_info.type = VibrationDeviceType::LinearResonantActuator;
vibration_device_info.type = Core::HID::VibrationDeviceType::LinearResonantActuator;
break;
case Controller_NPad::NpadType::GameCube:
vibration_device_info.type = VibrationDeviceType::GcErm;
case Core::HID::NpadStyleIndex::GameCube:
vibration_device_info.type = Core::HID::VibrationDeviceType::GcErm;
break;
case Controller_NPad::NpadType::Pokeball:
vibration_device_info.type = VibrationDeviceType::Unknown;
case Core::HID::NpadStyleIndex::Pokeball:
vibration_device_info.type = Core::HID::VibrationDeviceType::Unknown;
break;
}
switch (vibration_device_handle.device_index) {
case Controller_NPad::DeviceIndex::Left:
vibration_device_info.position = VibrationDevicePosition::Left;
case Core::HID::DeviceIndex::Left:
vibration_device_info.position = Core::HID::VibrationDevicePosition::Left;
break;
case Controller_NPad::DeviceIndex::Right:
vibration_device_info.position = VibrationDevicePosition::Right;
case Core::HID::DeviceIndex::Right:
vibration_device_info.position = Core::HID::VibrationDevicePosition::Right;
break;
case Controller_NPad::DeviceIndex::None:
case Core::HID::DeviceIndex::None:
default:
UNREACHABLE_MSG("DeviceIndex should never be None!");
vibration_device_info.position = VibrationDevicePosition::None;
vibration_device_info.position = Core::HID::VibrationDevicePosition::None;
break;
}
@@ -1178,11 +1234,12 @@ void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) {
void Hid::SendVibrationValue(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Controller_NPad::DeviceHandle vibration_device_handle;
Controller_NPad::VibrationValue vibration_value;
Core::HID::VibrationDeviceHandle vibration_device_handle;
Core::HID::VibrationValue vibration_value;
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id;
};
static_assert(sizeof(Parameters) == 0x20, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()};
@@ -1202,10 +1259,11 @@ void Hid::SendVibrationValue(Kernel::HLERequestContext& ctx) {
void Hid::GetActualVibrationValue(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Controller_NPad::DeviceHandle vibration_device_handle;
Core::HID::VibrationDeviceHandle vibration_device_handle;
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id;
};
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()};
@@ -1256,10 +1314,10 @@ void Hid::SendVibrationValues(Kernel::HLERequestContext& ctx) {
const auto handles = ctx.ReadBuffer(0);
const auto vibrations = ctx.ReadBuffer(1);
std::vector<Controller_NPad::DeviceHandle> vibration_device_handles(
handles.size() / sizeof(Controller_NPad::DeviceHandle));
std::vector<Controller_NPad::VibrationValue> vibration_values(
vibrations.size() / sizeof(Controller_NPad::VibrationValue));
std::vector<Core::HID::VibrationDeviceHandle> vibration_device_handles(
handles.size() / sizeof(Core::HID::VibrationDeviceHandle));
std::vector<Core::HID::VibrationValue> vibration_values(vibrations.size() /
sizeof(Core::HID::VibrationValue));
std::memcpy(vibration_device_handles.data(), handles.data(), handles.size());
std::memcpy(vibration_values.data(), vibrations.data(), vibrations.size());
@@ -1276,9 +1334,10 @@ void Hid::SendVibrationValues(Kernel::HLERequestContext& ctx) {
void Hid::SendVibrationGcErmCommand(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Controller_NPad::DeviceHandle vibration_device_handle;
Core::HID::VibrationDeviceHandle vibration_device_handle;
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id;
VibrationGcErmCommand gc_erm_command;
Core::HID::VibrationGcErmCommand gc_erm_command;
};
static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
@@ -1292,26 +1351,26 @@ void Hid::SendVibrationGcErmCommand(Kernel::HLERequestContext& ctx) {
*/
const auto vibration_value = [parameters] {
switch (parameters.gc_erm_command) {
case VibrationGcErmCommand::Stop:
return Controller_NPad::VibrationValue{
.amp_low = 0.0f,
.freq_low = 160.0f,
.amp_high = 0.0f,
.freq_high = 320.0f,
case Core::HID::VibrationGcErmCommand::Stop:
return Core::HID::VibrationValue{
.low_amplitude = 0.0f,
.low_frequency = 160.0f,
.high_amplitude = 0.0f,
.high_frequency = 320.0f,
};
case VibrationGcErmCommand::Start:
return Controller_NPad::VibrationValue{
.amp_low = 1.0f,
.freq_low = 160.0f,
.amp_high = 1.0f,
.freq_high = 320.0f,
case Core::HID::VibrationGcErmCommand::Start:
return Core::HID::VibrationValue{
.low_amplitude = 1.0f,
.low_frequency = 160.0f,
.high_amplitude = 1.0f,
.high_frequency = 320.0f,
};
case VibrationGcErmCommand::StopHard:
return Controller_NPad::VibrationValue{
.amp_low = 0.0f,
.freq_low = 0.0f,
.amp_high = 0.0f,
.freq_high = 0.0f,
case Core::HID::VibrationGcErmCommand::StopHard:
return Core::HID::VibrationValue{
.low_amplitude = 0.0f,
.low_frequency = 0.0f,
.high_amplitude = 0.0f,
.high_frequency = 0.0f,
};
default:
return Controller_NPad::DEFAULT_VIBRATION_VALUE;
@@ -1336,7 +1395,7 @@ void Hid::SendVibrationGcErmCommand(Kernel::HLERequestContext& ctx) {
void Hid::GetActualVibrationGcErmCommand(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Controller_NPad::DeviceHandle vibration_device_handle;
Core::HID::VibrationDeviceHandle vibration_device_handle;
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id;
};
@@ -1347,8 +1406,8 @@ void Hid::GetActualVibrationGcErmCommand(Kernel::HLERequestContext& ctx) {
.GetLastVibration(parameters.vibration_device_handle);
const auto gc_erm_command = [last_vibration] {
if (last_vibration.amp_low != 0.0f || last_vibration.amp_high != 0.0f) {
return VibrationGcErmCommand::Start;
if (last_vibration.low_amplitude != 0.0f || last_vibration.high_amplitude != 0.0f) {
return Core::HID::VibrationGcErmCommand::Start;
}
/**
@@ -1357,11 +1416,11 @@ void Hid::GetActualVibrationGcErmCommand(Kernel::HLERequestContext& ctx) {
* SendVibrationGcErmCommand, in order to differentiate between Stop and StopHard commands.
* This is done to reuse the controller vibration functions made for regular controllers.
*/
if (last_vibration.freq_low == 0.0f && last_vibration.freq_high == 0.0f) {
return VibrationGcErmCommand::StopHard;
if (last_vibration.low_frequency == 0.0f && last_vibration.high_frequency == 0.0f) {
return Core::HID::VibrationGcErmCommand::StopHard;
}
return VibrationGcErmCommand::Stop;
return Core::HID::VibrationGcErmCommand::Stop;
}();
LOG_DEBUG(Service_HID,
@@ -1401,10 +1460,11 @@ void Hid::EndPermitVibrationSession(Kernel::HLERequestContext& ctx) {
void Hid::IsVibrationDeviceMounted(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Controller_NPad::DeviceHandle vibration_device_handle;
Core::HID::VibrationDeviceHandle vibration_device_handle;
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id;
};
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()};
@@ -1435,18 +1495,18 @@ void Hid::ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
void Hid::StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Controller_NPad::DeviceHandle sixaxis_handle;
Core::HID::ConsoleSixAxisSensorHandle console_sixaxis_handle;
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id;
};
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()};
LOG_WARNING(
Service_HID,
"(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
LOG_WARNING(Service_HID,
"(STUBBED) called, unknown_1={}, unknown_2={}, applet_resource_user_id={}",
parameters.console_sixaxis_handle.unknown_1,
parameters.console_sixaxis_handle.unknown_2, parameters.applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
@@ -1455,18 +1515,18 @@ void Hid::StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
void Hid::StopConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Controller_NPad::DeviceHandle sixaxis_handle;
Core::HID::ConsoleSixAxisSensorHandle console_sixaxis_handle;
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id;
};
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()};
LOG_WARNING(
Service_HID,
"(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
LOG_WARNING(Service_HID,
"(STUBBED) called, unknown_1={}, unknown_2={}, applet_resource_user_id={}",
parameters.console_sixaxis_handle.unknown_1,
parameters.console_sixaxis_handle.unknown_2, parameters.applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
@@ -1620,10 +1680,8 @@ void Hid::SetNpadCommunicationMode(Kernel::HLERequestContext& ctx) {
void Hid::GetNpadCommunicationMode(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}",
applet_resource_user_id);
LOG_WARNING(Service_HID, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
@@ -1825,7 +1883,7 @@ public:
{317, nullptr, "GetNpadLeftRightInterfaceType"},
{318, nullptr, "HasBattery"},
{319, nullptr, "HasLeftRightBattery"},
{321, nullptr, "GetUniquePadsFromNpad"},
{321, &HidSys::GetUniquePadsFromNpad, "GetUniquePadsFromNpad"},
{322, nullptr, "GetIrSensorState"},
{323, nullptr, "GetXcdHandleForNpadWithIrSensor"},
{324, nullptr, "GetUniquePadButtonSet"},
@@ -1996,6 +2054,18 @@ private:
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void GetUniquePadsFromNpad(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto npad_id_type{rp.PopEnum<Core::HID::NpadIdType>()};
const s64 total_entries = 0;
LOG_WARNING(Service_HID, "(STUBBED) called, npad_id_type={}", npad_id_type);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(total_entries);
}
};
class HidTmp final : public ServiceFramework<HidTmp> {
@@ -2037,10 +2107,6 @@ public:
}
};
void ReloadInputDevices() {
Settings::values.is_device_reload_pending.store(true);
}
void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
std::make_shared<Hid>(system)->InstallAsService(service_manager);
std::make_shared<HidBus>(system)->InstallAsService(service_manager);

View File

@@ -60,21 +60,23 @@ public:
private:
template <typename T>
void MakeController(HidController controller) {
controllers[static_cast<std::size_t>(controller)] = std::make_unique<T>(system);
controllers[static_cast<std::size_t>(controller)] = std::make_unique<T>(system.HIDCore());
}
template <typename T>
void MakeControllerWithServiceContext(HidController controller) {
controllers[static_cast<std::size_t>(controller)] =
std::make_unique<T>(system, service_context);
std::make_unique<T>(system.HIDCore(), service_context);
}
void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx);
void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
void UpdateMouseKeyboard(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
void UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
KernelHelpers::ServiceContext& service_context;
std::shared_ptr<Core::Timing::EventType> pad_update_event;
std::shared_ptr<Core::Timing::EventType> mouse_keyboard_update_event;
std::shared_ptr<Core::Timing::EventType> motion_update_event;
std::array<std::unique_ptr<ControllerBase>, static_cast<size_t>(HidController::MaxControllers)>
@@ -161,38 +163,11 @@ private:
void GetNpadCommunicationMode(Kernel::HLERequestContext& ctx);
void SetTouchScreenConfiguration(Kernel::HLERequestContext& ctx);
enum class VibrationDeviceType : u32 {
Unknown = 0,
LinearResonantActuator = 1,
GcErm = 2,
};
enum class VibrationDevicePosition : u32 {
None = 0,
Left = 1,
Right = 2,
};
enum class VibrationGcErmCommand : u64 {
Stop = 0,
Start = 1,
StopHard = 2,
};
struct VibrationDeviceInfo {
VibrationDeviceType type{};
VibrationDevicePosition position{};
};
static_assert(sizeof(VibrationDeviceInfo) == 0x8, "VibrationDeviceInfo has incorrect size.");
std::shared_ptr<IAppletResource> applet_resource;
KernelHelpers::ServiceContext service_context;
};
/// Reload input devices. Used when input configuration changed
void ReloadInputDevices();
/// Registers all HID services with the specified service manager.
void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);

View File

@@ -0,0 +1,54 @@
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included
#pragma once
#include <array>
#include "common/common_types.h"
namespace Service::HID {
template <typename State>
struct AtomicStorage {
s64 sampling_number;
State state;
};
template <typename State, std::size_t max_buffer_size>
struct Lifo {
s64 timestamp{};
s64 total_buffer_count = static_cast<s64>(max_buffer_size);
s64 buffer_tail{};
s64 buffer_count{};
std::array<AtomicStorage<State>, max_buffer_size> entries{};
const AtomicStorage<State>& ReadCurrentEntry() const {
return entries[buffer_tail];
}
const AtomicStorage<State>& ReadPreviousEntry() const {
return entries[GetPreviousEntryIndex()];
}
std::size_t GetPreviousEntryIndex() const {
return static_cast<size_t>((buffer_tail + total_buffer_count - 1) % total_buffer_count);
}
std::size_t GetNextEntryIndex() const {
return static_cast<size_t>((buffer_tail + 1) % total_buffer_count);
}
void WriteNextEntry(const State& new_state) {
if (buffer_count < total_buffer_count - 1) {
buffer_count++;
}
buffer_tail = GetNextEntryIndex();
const auto& previous_entry = ReadPreviousEntry();
entries[buffer_tail].sampling_number = previous_entry.sampling_number + 1;
entries[buffer_tail].state = new_state;
}
};
} // namespace Service::HID

View File

@@ -12,7 +12,6 @@
#include "core/core.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/k_page_table.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_system_control.h"
#include "core/hle/kernel/svc_results.h"
#include "core/hle/service/ldr/ldr.h"
@@ -247,7 +246,7 @@ public:
return;
}
if (system.CurrentProcess()->GetTitleID() != header.application_id) {
if (system.GetCurrentProcessProgramID() != header.application_id) {
LOG_ERROR(Service_LDR,
"Attempting to load NRR with title ID other than current process. (actual "
"{:016X})!",
@@ -397,12 +396,12 @@ public:
CopyCode(nro_addr + nro_header.segment_headers[DATA_INDEX].memory_offset, data_start,
nro_header.segment_headers[DATA_INDEX].memory_size);
CASCADE_CODE(process->PageTable().SetCodeMemoryPermission(
CASCADE_CODE(process->PageTable().SetProcessMemoryPermission(
text_start, ro_start - text_start, Kernel::KMemoryPermission::ReadAndExecute));
CASCADE_CODE(process->PageTable().SetCodeMemoryPermission(ro_start, data_start - ro_start,
Kernel::KMemoryPermission::Read));
CASCADE_CODE(process->PageTable().SetProcessMemoryPermission(
ro_start, data_start - ro_start, Kernel::KMemoryPermission::Read));
return process->PageTable().SetCodeMemoryPermission(
return process->PageTable().SetProcessMemoryPermission(
data_start, bss_end_addr - data_start, Kernel::KMemoryPermission::ReadAndWrite);
}

View File

@@ -12,6 +12,7 @@
#include "core/hle/service/ns/errors.h"
#include "core/hle/service/ns/language.h"
#include "core/hle/service/ns/ns.h"
#include "core/hle/service/ns/pdm_qry.h"
#include "core/hle/service/ns/pl_u.h"
#include "core/hle/service/set/set.h"
@@ -570,11 +571,29 @@ IFactoryResetInterface::IFactoryResetInterface(Core::System& system_)
IFactoryResetInterface::~IFactoryResetInterface() = default;
IReadOnlyApplicationControlDataInterface::IReadOnlyApplicationControlDataInterface(
Core::System& system_)
: ServiceFramework{system_, "IReadOnlyApplicationControlDataInterface"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "GetApplicationControlData"},
{1, nullptr, "GetApplicationDesiredLanguage"},
{2, nullptr, "ConvertApplicationLanguageToLanguageCode"},
{3, nullptr, "ConvertLanguageCodeToApplicationLanguage"},
{4, nullptr, "SelectApplicationDesiredLanguage"},
};
// clang-format on
RegisterHandlers(functions);
}
IReadOnlyApplicationControlDataInterface::~IReadOnlyApplicationControlDataInterface() = default;
NS::NS(const char* name, Core::System& system_) : ServiceFramework{system_, name} {
// clang-format off
static const FunctionInfo functions[] = {
{7988, nullptr, "GetDynamicRightsInterface"},
{7989, nullptr, "GetReadOnlyApplicationControlDataInterface"},
{7989, &NS::PushInterface<IReadOnlyApplicationControlDataInterface>, "GetReadOnlyApplicationControlDataInterface"},
{7991, nullptr, "GetReadOnlyApplicationRecordInterface"},
{7992, &NS::PushInterface<IECommerceInterface>, "GetECommerceInterface"},
{7993, &NS::PushInterface<IApplicationVersionInterface>, "GetApplicationVersionInterface"},
@@ -738,6 +757,8 @@ void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system
std::make_shared<NS_SU>(system)->InstallAsService(service_manager);
std::make_shared<NS_VM>(system)->InstallAsService(service_manager);
std::make_shared<PDM_QRY>(system)->InstallAsService(service_manager);
std::make_shared<PL_U>(system)->InstallAsService(service_manager);
}

View File

@@ -74,6 +74,13 @@ public:
~IFactoryResetInterface() override;
};
class IReadOnlyApplicationControlDataInterface final
: public ServiceFramework<IReadOnlyApplicationControlDataInterface> {
public:
explicit IReadOnlyApplicationControlDataInterface(Core::System& system_);
~IReadOnlyApplicationControlDataInterface() override;
};
class NS final : public ServiceFramework<NS> {
public:
explicit NS(const char* name, Core::System& system_);

View File

@@ -0,0 +1,69 @@
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included
#include <memory>
#include "common/logging/log.h"
#include "common/uuid.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/service/ns/pdm_qry.h"
#include "core/hle/service/service.h"
#include "core/hle/service/sm/sm.h"
namespace Service::NS {
PDM_QRY::PDM_QRY(Core::System& system_) : ServiceFramework{system_, "pdm:qry"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "QueryAppletEvent"},
{1, nullptr, "QueryPlayStatistics"},
{2, nullptr, "QueryPlayStatisticsByUserAccountId"},
{3, nullptr, "QueryPlayStatisticsByNetworkServiceAccountId"},
{4, nullptr, "QueryPlayStatisticsByApplicationId"},
{5, &PDM_QRY::QueryPlayStatisticsByApplicationIdAndUserAccountId, "QueryPlayStatisticsByApplicationIdAndUserAccountId"},
{6, nullptr, "QueryPlayStatisticsByApplicationIdAndNetworkServiceAccountId"},
{7, nullptr, "QueryLastPlayTimeV0"},
{8, nullptr, "QueryPlayEvent"},
{9, nullptr, "GetAvailablePlayEventRange"},
{10, nullptr, "QueryAccountEvent"},
{11, nullptr, "QueryAccountPlayEvent"},
{12, nullptr, "GetAvailableAccountPlayEventRange"},
{13, nullptr, "QueryApplicationPlayStatisticsForSystemV0"},
{14, nullptr, "QueryRecentlyPlayedApplication"},
{15, nullptr, "GetRecentlyPlayedApplicationUpdateEvent"},
{16, nullptr, "QueryApplicationPlayStatisticsByUserAccountIdForSystemV0"},
{17, nullptr, "QueryLastPlayTime"},
{18, nullptr, "QueryApplicationPlayStatisticsForSystem"},
{19, nullptr, "QueryApplicationPlayStatisticsByUserAccountIdForSystem"},
};
// clang-format on
RegisterHandlers(functions);
}
PDM_QRY::~PDM_QRY() = default;
void PDM_QRY::QueryPlayStatisticsByApplicationIdAndUserAccountId(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto unknown = rp.Pop<bool>();
rp.Pop<u8>(); // Padding
const auto application_id = rp.Pop<u64>();
const auto user_account_uid = rp.PopRaw<Common::UUID>();
// TODO(German77): Read statistics of the game
PlayStatistics statistics{
.application_id = application_id,
.total_launches = 1,
};
LOG_WARNING(Service_NS,
"(STUBBED) called. unknown={}. application_id=0x{:016X}, user_account_uid=0x{}",
unknown, application_id, user_account_uid.Format());
IPC::ResponseBuilder rb{ctx, 12};
rb.Push(ResultSuccess);
rb.PushRaw(statistics);
}
} // namespace Service::NS

View File

@@ -0,0 +1,33 @@
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included
#pragma once
#include "core/hle/service/service.h"
namespace Service::NS {
struct PlayStatistics {
u64 application_id{};
u32 first_entry_index{};
u32 first_timestamp_user{};
u32 first_timestamp_network{};
u32 last_entry_index{};
u32 last_timestamp_user{};
u32 last_timestamp_network{};
u32 play_time_in_minutes{};
u32 total_launches{};
};
static_assert(sizeof(PlayStatistics) == 0x28, "PlayStatistics is an invalid size");
class PDM_QRY final : public ServiceFramework<PDM_QRY> {
public:
explicit PDM_QRY(Core::System& system_);
~PDM_QRY() override;
private:
void QueryPlayStatisticsByApplicationIdAndUserAccountId(Kernel::HLERequestContext& ctx);
};
} // namespace Service::NS

View File

@@ -7,7 +7,6 @@
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/patch_manager.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/service/pctl/pctl.h"
#include "core/hle/service/pctl/pctl_module.h"
@@ -45,7 +44,7 @@ public:
{1014, nullptr, "ConfirmPlayableApplicationVideoOld"},
{1015, nullptr, "ConfirmPlayableApplicationVideo"},
{1016, nullptr, "ConfirmShowNewsPermission"},
{1017, nullptr, "EndFreeCommunication"},
{1017, &IParentalControlService::EndFreeCommunication, "EndFreeCommunication"},
{1018, &IParentalControlService::IsFreeCommunicationAvailable, "IsFreeCommunicationAvailable"},
{1031, &IParentalControlService::IsRestrictionEnabled, "IsRestrictionEnabled"},
{1032, nullptr, "GetSafetyLevel"},
@@ -189,7 +188,7 @@ private:
// TODO(ogniK): Recovery flag initialization for pctl:r
const auto tid = system.CurrentProcess()->GetTitleID();
const auto tid = system.GetCurrentProcessProgramID();
if (tid != 0) {
const FileSys::PatchManager pm{tid, system.GetFileSystemController(),
system.GetContentProvider()};
@@ -237,6 +236,13 @@ private:
rb.Push(ResultSuccess);
}
void EndFreeCommunication(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_PCTL, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IsFreeCommunicationAvailable(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_PCTL, "(STUBBED) called");

Some files were not shown because too many files have changed in this diff Show More