Compare commits
70 Commits
im_steady_
...
leviathan
Author | SHA1 | Date | |
---|---|---|---|
a18c584f83 | |||
971f0a395b | |||
7843915b71 | |||
a7306fb589 | |||
6a0ef7de68 | |||
e33e38467c | |||
ce39e0dd45 | |||
600a02fe29 | |||
4f5b1fe41f | |||
c695166391 | |||
3f5d6c115f | |||
b7c7505aca | |||
d669f7e15f | |||
74a1fba8e0 | |||
5f63b6aed0 | |||
e195aa523b | |||
520150c78a | |||
62edb120c1 | |||
bb6b22482f | |||
c45078844c | |||
e6f30ed8ee | |||
b65efa5823 | |||
5c6a5487c7 | |||
69f5f567d2 | |||
a13ece1ca5 | |||
519c12da15 | |||
d74fd9e2fe | |||
d011d3ff0e | |||
3f05b8facd | |||
65d3300875 | |||
7b2ac196d2 | |||
2212c9653d | |||
fe04a7523a | |||
45a76637f5 | |||
bf7c45e560 | |||
6f4a080b98 | |||
da6824d9fd | |||
b36f45b239 | |||
07ae6659e7 | |||
880b004321 | |||
21ebe3e462 | |||
7b5d234558 | |||
84b0e29b56 | |||
5ecdcfa334 | |||
5f4857691e | |||
b50ce645ac | |||
b6d19329ac | |||
8c769b71a1 | |||
9512992fe2 | |||
6b10f04322 | |||
c206a04747 | |||
ec6ddaf766 | |||
36ea7565fa | |||
00b0938f10 | |||
ed58445111 | |||
b28b05e2aa | |||
8151a4d301 | |||
8ac8d703b9 | |||
21bc2c14bc | |||
8347e5cdb9 | |||
dac53b4ba0 | |||
0bb7990c49 | |||
e797a917a9 | |||
a764f49910 | |||
c334959440 | |||
2fa53ec1d9 | |||
e37ad99f22 | |||
02b897ce27 | |||
79f0202045 | |||
b881949b6d |
@ -5,6 +5,6 @@
|
||||
|
||||
GITDATE="`git show -s --date=short --format='%ad' | sed 's/-//g'`"
|
||||
GITREV="`git show -s --format='%h'`"
|
||||
ARTIFACTS_DIR="artifacts"
|
||||
ARTIFACTS_DIR="$PWD/artifacts"
|
||||
|
||||
mkdir -p "${ARTIFACTS_DIR}/"
|
||||
|
@ -11,7 +11,7 @@ ccache -s
|
||||
mkdir build || true && cd build
|
||||
cmake .. \
|
||||
-DBoost_USE_STATIC_LIBS=ON \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||
-DCMAKE_CXX_FLAGS="-march=x86-64-v2" \
|
||||
-DCMAKE_CXX_COMPILER=/usr/lib/ccache/g++ \
|
||||
-DCMAKE_C_COMPILER=/usr/lib/ccache/gcc \
|
||||
@ -31,6 +31,19 @@ ccache -s
|
||||
|
||||
ctest -VV -C Release
|
||||
|
||||
# Separate debug symbols from specified executables
|
||||
for EXE in yuzu; do
|
||||
EXE_PATH="bin/$EXE"
|
||||
# Copy debug symbols out
|
||||
objcopy --only-keep-debug $EXE_PATH $EXE_PATH.debug
|
||||
# Add debug link and strip debug symbols
|
||||
objcopy -g --add-gnu-debuglink=$EXE_PATH.debug $EXE_PATH $EXE_PATH.out
|
||||
# Overwrite original with stripped copy
|
||||
mv $EXE_PATH.out $EXE_PATH
|
||||
done
|
||||
# Strip debug symbols from all executables
|
||||
find bin/ -type f -not -regex '.*.debug' -exec strip -g {} ';'
|
||||
|
||||
DESTDIR="$PWD/AppDir" ninja install
|
||||
rm -vf AppDir/usr/bin/yuzu-cmd AppDir/usr/bin/yuzu-tester
|
||||
|
||||
|
@ -59,4 +59,9 @@ if [ "${RELEASE_NAME}" = "mainline" ] || [ "${RELEASE_NAME}" = "early-access" ];
|
||||
cp "build/${APPIMAGE_NAME}" "${DIR_NAME}/yuzu-${RELEASE_NAME}.AppImage"
|
||||
fi
|
||||
|
||||
# Copy debug symbols to artifacts
|
||||
cd build/bin
|
||||
tar $COMPRESSION_FLAGS "${ARTIFACTS_DIR}/${REV_NAME}-debug.tar.xz" *.debug
|
||||
cd -
|
||||
|
||||
. .ci/scripts/common/post-upload.sh
|
||||
|
4
dist/qt_themes/default/style.qss
vendored
4
dist/qt_themes/default/style.qss
vendored
@ -120,6 +120,10 @@ QWidget#connectedControllers {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
QWidget#closeButtons {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
QWidget#playersSupported,
|
||||
QWidget#controllersSupported,
|
||||
QWidget#controllerSupported1,
|
||||
|
4
dist/qt_themes/qdarkstyle/style.qss
vendored
4
dist/qt_themes/qdarkstyle/style.qss
vendored
@ -1380,6 +1380,10 @@ QWidget#connectedControllers {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
QWidget#closeButtons {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
QWidget#playersSupported,
|
||||
QWidget#controllersSupported,
|
||||
QWidget#controllerSupported1,
|
||||
|
@ -2305,6 +2305,10 @@ QWidget#connectedControllers {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
QWidget#closeButtons {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
QWidget#playersSupported,
|
||||
QWidget#controllersSupported,
|
||||
QWidget#controllerSupported1,
|
||||
|
2
externals/CMakeLists.txt
vendored
2
externals/CMakeLists.txt
vendored
@ -168,7 +168,7 @@ if (NOT TARGET LLVM::Demangle)
|
||||
add_library(LLVM::Demangle ALIAS demangle)
|
||||
endif()
|
||||
|
||||
add_library(stb stb/stb_dxt.cpp)
|
||||
add_library(stb stb/stb_dxt.cpp stb/stb_image.cpp stb/stb_image_resize.cpp)
|
||||
target_include_directories(stb PUBLIC ./stb)
|
||||
|
||||
add_library(bc_decoder bc_decoder/bc_decoder.cpp)
|
||||
|
2
externals/nx_tzdb/CMakeLists.txt
vendored
2
externals/nx_tzdb/CMakeLists.txt
vendored
@ -27,7 +27,7 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Windows" OR ANDROID)
|
||||
set(CAN_BUILD_NX_TZDB false)
|
||||
endif()
|
||||
|
||||
set(NX_TZDB_VERSION "220816")
|
||||
set(NX_TZDB_VERSION "221202")
|
||||
set(NX_TZDB_ARCHIVE "${CMAKE_CURRENT_BINARY_DIR}/${NX_TZDB_VERSION}.zip")
|
||||
|
||||
set(NX_TZDB_ROMFS_DIR "${CMAKE_CURRENT_BINARY_DIR}/nx_tzdb")
|
||||
|
2
externals/nx_tzdb/tzdb_to_nx
vendored
2
externals/nx_tzdb/tzdb_to_nx
vendored
Submodule externals/nx_tzdb/tzdb_to_nx updated: 212afa2394...0d17dd066d
7529
externals/stb/stb_image.cpp
vendored
Normal file
7529
externals/stb/stb_image.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
772
externals/stb/stb_image.h
vendored
Normal file
772
externals/stb/stb_image.h
vendored
Normal file
@ -0,0 +1,772 @@
|
||||
// SPDX-FileCopyrightText: stb http://nothings.org/stb
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
/* stb_image - v2.28 - public domain image loader - http://nothings.org/stb
|
||||
no warranty implied; use at your own risk
|
||||
|
||||
Do this:
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
before you include this file in *one* C or C++ file to create the implementation.
|
||||
|
||||
// i.e. it should look like this:
|
||||
#include ...
|
||||
#include ...
|
||||
#include ...
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include "stb_image.h"
|
||||
|
||||
You can #define STBI_ASSERT(x) before the #include to avoid using assert.h.
|
||||
And #define STBI_MALLOC, STBI_REALLOC, and STBI_FREE to avoid using malloc,realloc,free
|
||||
|
||||
|
||||
QUICK NOTES:
|
||||
Primarily of interest to game developers and other people who can
|
||||
avoid problematic images and only need the trivial interface
|
||||
|
||||
JPEG baseline & progressive (12 bpc/arithmetic not supported, same as stock IJG lib)
|
||||
PNG 1/2/4/8/16-bit-per-channel
|
||||
|
||||
TGA (not sure what subset, if a subset)
|
||||
BMP non-1bpp, non-RLE
|
||||
PSD (composited view only, no extra channels, 8/16 bit-per-channel)
|
||||
|
||||
GIF (*comp always reports as 4-channel)
|
||||
HDR (radiance rgbE format)
|
||||
PIC (Softimage PIC)
|
||||
PNM (PPM and PGM binary only)
|
||||
|
||||
Animated GIF still needs a proper API, but here's one way to do it:
|
||||
http://gist.github.com/urraka/685d9a6340b26b830d49
|
||||
|
||||
- decode from memory or through FILE (define STBI_NO_STDIO to remove code)
|
||||
- decode from arbitrary I/O callbacks
|
||||
- SIMD acceleration on x86/x64 (SSE2) and ARM (NEON)
|
||||
|
||||
Full documentation under "DOCUMENTATION" below.
|
||||
|
||||
|
||||
LICENSE
|
||||
|
||||
See end of file for license information.
|
||||
|
||||
RECENT REVISION HISTORY:
|
||||
|
||||
2.28 (2023-01-29) many error fixes, security errors, just tons of stuff
|
||||
2.27 (2021-07-11) document stbi_info better, 16-bit PNM support, bug fixes
|
||||
2.26 (2020-07-13) many minor fixes
|
||||
2.25 (2020-02-02) fix warnings
|
||||
2.24 (2020-02-02) fix warnings; thread-local failure_reason and flip_vertically
|
||||
2.23 (2019-08-11) fix clang static analysis warning
|
||||
2.22 (2019-03-04) gif fixes, fix warnings
|
||||
2.21 (2019-02-25) fix typo in comment
|
||||
2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs
|
||||
2.19 (2018-02-11) fix warning
|
||||
2.18 (2018-01-30) fix warnings
|
||||
2.17 (2018-01-29) bugfix, 1-bit BMP, 16-bitness query, fix warnings
|
||||
2.16 (2017-07-23) all functions have 16-bit variants; optimizations; bugfixes
|
||||
2.15 (2017-03-18) fix png-1,2,4; all Imagenet JPGs; no runtime SSE detection on GCC
|
||||
2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs
|
||||
2.13 (2016-12-04) experimental 16-bit API, only for PNG so far; fixes
|
||||
2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes
|
||||
2.11 (2016-04-02) 16-bit PNGS; enable SSE2 in non-gcc x64
|
||||
RGB-format JPEG; remove white matting in PSD;
|
||||
allocate large structures on the stack;
|
||||
correct channel count for PNG & BMP
|
||||
2.10 (2016-01-22) avoid warning introduced in 2.09
|
||||
2.09 (2016-01-16) 16-bit TGA; comments in PNM files; STBI_REALLOC_SIZED
|
||||
|
||||
See end of file for full revision history.
|
||||
|
||||
|
||||
============================ Contributors =========================
|
||||
|
||||
Image formats Extensions, features
|
||||
Sean Barrett (jpeg, png, bmp) Jetro Lauha (stbi_info)
|
||||
Nicolas Schulz (hdr, psd) Martin "SpartanJ" Golini (stbi_info)
|
||||
Jonathan Dummer (tga) James "moose2000" Brown (iPhone PNG)
|
||||
Jean-Marc Lienher (gif) Ben "Disch" Wenger (io callbacks)
|
||||
Tom Seddon (pic) Omar Cornut (1/2/4-bit PNG)
|
||||
Thatcher Ulrich (psd) Nicolas Guillemot (vertical flip)
|
||||
Ken Miller (pgm, ppm) Richard Mitton (16-bit PSD)
|
||||
github:urraka (animated gif) Junggon Kim (PNM comments)
|
||||
Christopher Forseth (animated gif) Daniel Gibson (16-bit TGA)
|
||||
socks-the-fox (16-bit PNG)
|
||||
Jeremy Sawicki (handle all ImageNet JPGs)
|
||||
Optimizations & bugfixes Mikhail Morozov (1-bit BMP)
|
||||
Fabian "ryg" Giesen Anael Seghezzi (is-16-bit query)
|
||||
Arseny Kapoulkine Simon Breuss (16-bit PNM)
|
||||
John-Mark Allen
|
||||
Carmelo J Fdez-Aguera
|
||||
|
||||
Bug & warning fixes
|
||||
Marc LeBlanc David Woo Guillaume George Martins Mozeiko
|
||||
Christpher Lloyd Jerry Jansson Joseph Thomson Blazej Dariusz Roszkowski
|
||||
Phil Jordan Dave Moore Roy Eltham
|
||||
Hayaki Saito Nathan Reed Won Chun
|
||||
Luke Graham Johan Duparc Nick Verigakis the Horde3D community
|
||||
Thomas Ruf Ronny Chevalier github:rlyeh
|
||||
Janez Zemva John Bartholomew Michal Cichon github:romigrou
|
||||
Jonathan Blow Ken Hamada Tero Hanninen github:svdijk
|
||||
Eugene Golushkov Laurent Gomila Cort Stratton github:snagar
|
||||
Aruelien Pocheville Sergio Gonzalez Thibault Reuille github:Zelex
|
||||
Cass Everitt Ryamond Barbiero github:grim210
|
||||
Paul Du Bois Engin Manap Aldo Culquicondor github:sammyhw
|
||||
Philipp Wiesemann Dale Weiler Oriol Ferrer Mesia github:phprus
|
||||
Josh Tobin Neil Bickford Matthew Gregan github:poppolopoppo
|
||||
Julian Raschke Gregory Mullen Christian Floisand github:darealshinji
|
||||
Baldur Karlsson Kevin Schmidt JR Smith github:Michaelangel007
|
||||
Brad Weinberger Matvey Cherevko github:mosra
|
||||
Luca Sas Alexander Veselov Zack Middleton [reserved]
|
||||
Ryan C. Gordon [reserved] [reserved]
|
||||
DO NOT ADD YOUR NAME HERE
|
||||
|
||||
Jacko Dirks
|
||||
|
||||
To add your name to the credits, pick a random blank space in the middle and fill it.
|
||||
80% of merge conflicts on stb PRs are due to people adding their name at the end
|
||||
of the credits.
|
||||
*/
|
||||
|
||||
#ifndef STBI_INCLUDE_STB_IMAGE_H
|
||||
#define STBI_INCLUDE_STB_IMAGE_H
|
||||
|
||||
// DOCUMENTATION
|
||||
//
|
||||
// Limitations:
|
||||
// - no 12-bit-per-channel JPEG
|
||||
// - no JPEGs with arithmetic coding
|
||||
// - GIF always returns *comp=4
|
||||
//
|
||||
// Basic usage (see HDR discussion below for HDR usage):
|
||||
// int x,y,n;
|
||||
// unsigned char *data = stbi_load(filename, &x, &y, &n, 0);
|
||||
// // ... process data if not NULL ...
|
||||
// // ... x = width, y = height, n = # 8-bit components per pixel ...
|
||||
// // ... replace '0' with '1'..'4' to force that many components per pixel
|
||||
// // ... but 'n' will always be the number that it would have been if you said 0
|
||||
// stbi_image_free(data);
|
||||
//
|
||||
// Standard parameters:
|
||||
// int *x -- outputs image width in pixels
|
||||
// int *y -- outputs image height in pixels
|
||||
// int *channels_in_file -- outputs # of image components in image file
|
||||
// int desired_channels -- if non-zero, # of image components requested in result
|
||||
//
|
||||
// The return value from an image loader is an 'unsigned char *' which points
|
||||
// to the pixel data, or NULL on an allocation failure or if the image is
|
||||
// corrupt or invalid. The pixel data consists of *y scanlines of *x pixels,
|
||||
// with each pixel consisting of N interleaved 8-bit components; the first
|
||||
// pixel pointed to is top-left-most in the image. There is no padding between
|
||||
// image scanlines or between pixels, regardless of format. The number of
|
||||
// components N is 'desired_channels' if desired_channels is non-zero, or
|
||||
// *channels_in_file otherwise. If desired_channels is non-zero,
|
||||
// *channels_in_file has the number of components that _would_ have been
|
||||
// output otherwise. E.g. if you set desired_channels to 4, you will always
|
||||
// get RGBA output, but you can check *channels_in_file to see if it's trivially
|
||||
// opaque because e.g. there were only 3 channels in the source image.
|
||||
//
|
||||
// An output image with N components has the following components interleaved
|
||||
// in this order in each pixel:
|
||||
//
|
||||
// N=#comp components
|
||||
// 1 grey
|
||||
// 2 grey, alpha
|
||||
// 3 red, green, blue
|
||||
// 4 red, green, blue, alpha
|
||||
//
|
||||
// If image loading fails for any reason, the return value will be NULL,
|
||||
// and *x, *y, *channels_in_file will be unchanged. The function
|
||||
// stbi_failure_reason() can be queried for an extremely brief, end-user
|
||||
// unfriendly explanation of why the load failed. Define STBI_NO_FAILURE_STRINGS
|
||||
// to avoid compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly
|
||||
// more user-friendly ones.
|
||||
//
|
||||
// Paletted PNG, BMP, GIF, and PIC images are automatically depalettized.
|
||||
//
|
||||
// To query the width, height and component count of an image without having to
|
||||
// decode the full file, you can use the stbi_info family of functions:
|
||||
//
|
||||
// int x,y,n,ok;
|
||||
// ok = stbi_info(filename, &x, &y, &n);
|
||||
// // returns ok=1 and sets x, y, n if image is a supported format,
|
||||
// // 0 otherwise.
|
||||
//
|
||||
// Note that stb_image pervasively uses ints in its public API for sizes,
|
||||
// including sizes of memory buffers. This is now part of the API and thus
|
||||
// hard to change without causing breakage. As a result, the various image
|
||||
// loaders all have certain limits on image size; these differ somewhat
|
||||
// by format but generally boil down to either just under 2GB or just under
|
||||
// 1GB. When the decoded image would be larger than this, stb_image decoding
|
||||
// will fail.
|
||||
//
|
||||
// Additionally, stb_image will reject image files that have any of their
|
||||
// dimensions set to a larger value than the configurable STBI_MAX_DIMENSIONS,
|
||||
// which defaults to 2**24 = 16777216 pixels. Due to the above memory limit,
|
||||
// the only way to have an image with such dimensions load correctly
|
||||
// is for it to have a rather extreme aspect ratio. Either way, the
|
||||
// assumption here is that such larger images are likely to be malformed
|
||||
// or malicious. If you do need to load an image with individual dimensions
|
||||
// larger than that, and it still fits in the overall size limit, you can
|
||||
// #define STBI_MAX_DIMENSIONS on your own to be something larger.
|
||||
//
|
||||
// ===========================================================================
|
||||
//
|
||||
// UNICODE:
|
||||
//
|
||||
// If compiling for Windows and you wish to use Unicode filenames, compile
|
||||
// with
|
||||
// #define STBI_WINDOWS_UTF8
|
||||
// and pass utf8-encoded filenames. Call stbi_convert_wchar_to_utf8 to convert
|
||||
// Windows wchar_t filenames to utf8.
|
||||
//
|
||||
// ===========================================================================
|
||||
//
|
||||
// Philosophy
|
||||
//
|
||||
// stb libraries are designed with the following priorities:
|
||||
//
|
||||
// 1. easy to use
|
||||
// 2. easy to maintain
|
||||
// 3. good performance
|
||||
//
|
||||
// Sometimes I let "good performance" creep up in priority over "easy to maintain",
|
||||
// and for best performance I may provide less-easy-to-use APIs that give higher
|
||||
// performance, in addition to the easy-to-use ones. Nevertheless, it's important
|
||||
// to keep in mind that from the standpoint of you, a client of this library,
|
||||
// all you care about is #1 and #3, and stb libraries DO NOT emphasize #3 above all.
|
||||
//
|
||||
// Some secondary priorities arise directly from the first two, some of which
|
||||
// provide more explicit reasons why performance can't be emphasized.
|
||||
//
|
||||
// - Portable ("ease of use")
|
||||
// - Small source code footprint ("easy to maintain")
|
||||
// - No dependencies ("ease of use")
|
||||
//
|
||||
// ===========================================================================
|
||||
//
|
||||
// I/O callbacks
|
||||
//
|
||||
// I/O callbacks allow you to read from arbitrary sources, like packaged
|
||||
// files or some other source. Data read from callbacks are processed
|
||||
// through a small internal buffer (currently 128 bytes) to try to reduce
|
||||
// overhead.
|
||||
//
|
||||
// The three functions you must define are "read" (reads some bytes of data),
|
||||
// "skip" (skips some bytes of data), "eof" (reports if the stream is at the end).
|
||||
//
|
||||
// ===========================================================================
|
||||
//
|
||||
// SIMD support
|
||||
//
|
||||
// The JPEG decoder will try to automatically use SIMD kernels on x86 when
|
||||
// supported by the compiler. For ARM Neon support, you must explicitly
|
||||
// request it.
|
||||
//
|
||||
// (The old do-it-yourself SIMD API is no longer supported in the current
|
||||
// code.)
|
||||
//
|
||||
// On x86, SSE2 will automatically be used when available based on a run-time
|
||||
// test; if not, the generic C versions are used as a fall-back. On ARM targets,
|
||||
// the typical path is to have separate builds for NEON and non-NEON devices
|
||||
// (at least this is true for iOS and Android). Therefore, the NEON support is
|
||||
// toggled by a build flag: define STBI_NEON to get NEON loops.
|
||||
//
|
||||
// If for some reason you do not want to use any of SIMD code, or if
|
||||
// you have issues compiling it, you can disable it entirely by
|
||||
// defining STBI_NO_SIMD.
|
||||
//
|
||||
// ===========================================================================
|
||||
//
|
||||
// HDR image support (disable by defining STBI_NO_HDR)
|
||||
//
|
||||
// stb_image supports loading HDR images in general, and currently the Radiance
|
||||
// .HDR file format specifically. You can still load any file through the existing
|
||||
// interface; if you attempt to load an HDR file, it will be automatically remapped
|
||||
// to LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1;
|
||||
// both of these constants can be reconfigured through this interface:
|
||||
//
|
||||
// stbi_hdr_to_ldr_gamma(2.2f);
|
||||
// stbi_hdr_to_ldr_scale(1.0f);
|
||||
//
|
||||
// (note, do not use _inverse_ constants; stbi_image will invert them
|
||||
// appropriately).
|
||||
//
|
||||
// Additionally, there is a new, parallel interface for loading files as
|
||||
// (linear) floats to preserve the full dynamic range:
|
||||
//
|
||||
// float *data = stbi_loadf(filename, &x, &y, &n, 0);
|
||||
//
|
||||
// If you load LDR images through this interface, those images will
|
||||
// be promoted to floating point values, run through the inverse of
|
||||
// constants corresponding to the above:
|
||||
//
|
||||
// stbi_ldr_to_hdr_scale(1.0f);
|
||||
// stbi_ldr_to_hdr_gamma(2.2f);
|
||||
//
|
||||
// Finally, given a filename (or an open file or memory block--see header
|
||||
// file for details) containing image data, you can query for the "most
|
||||
// appropriate" interface to use (that is, whether the image is HDR or
|
||||
// not), using:
|
||||
//
|
||||
// stbi_is_hdr(char *filename);
|
||||
//
|
||||
// ===========================================================================
|
||||
//
|
||||
// iPhone PNG support:
|
||||
//
|
||||
// We optionally support converting iPhone-formatted PNGs (which store
|
||||
// premultiplied BGRA) back to RGB, even though they're internally encoded
|
||||
// differently. To enable this conversion, call
|
||||
// stbi_convert_iphone_png_to_rgb(1).
|
||||
//
|
||||
// Call stbi_set_unpremultiply_on_load(1) as well to force a divide per
|
||||
// pixel to remove any premultiplied alpha *only* if the image file explicitly
|
||||
// says there's premultiplied data (currently only happens in iPhone images,
|
||||
// and only if iPhone convert-to-rgb processing is on).
|
||||
//
|
||||
// ===========================================================================
|
||||
//
|
||||
// ADDITIONAL CONFIGURATION
|
||||
//
|
||||
// - You can suppress implementation of any of the decoders to reduce
|
||||
// your code footprint by #defining one or more of the following
|
||||
// symbols before creating the implementation.
|
||||
//
|
||||
// STBI_NO_JPEG
|
||||
// STBI_NO_PNG
|
||||
// STBI_NO_BMP
|
||||
// STBI_NO_PSD
|
||||
// STBI_NO_TGA
|
||||
// STBI_NO_GIF
|
||||
// STBI_NO_HDR
|
||||
// STBI_NO_PIC
|
||||
// STBI_NO_PNM (.ppm and .pgm)
|
||||
//
|
||||
// - You can request *only* certain decoders and suppress all other ones
|
||||
// (this will be more forward-compatible, as addition of new decoders
|
||||
// doesn't require you to disable them explicitly):
|
||||
//
|
||||
// STBI_ONLY_JPEG
|
||||
// STBI_ONLY_PNG
|
||||
// STBI_ONLY_BMP
|
||||
// STBI_ONLY_PSD
|
||||
// STBI_ONLY_TGA
|
||||
// STBI_ONLY_GIF
|
||||
// STBI_ONLY_HDR
|
||||
// STBI_ONLY_PIC
|
||||
// STBI_ONLY_PNM (.ppm and .pgm)
|
||||
//
|
||||
// - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still
|
||||
// want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB
|
||||
//
|
||||
// - If you define STBI_MAX_DIMENSIONS, stb_image will reject images greater
|
||||
// than that size (in either width or height) without further processing.
|
||||
// This is to let programs in the wild set an upper bound to prevent
|
||||
// denial-of-service attacks on untrusted data, as one could generate a
|
||||
// valid image of gigantic dimensions and force stb_image to allocate a
|
||||
// huge block of memory and spend disproportionate time decoding it. By
|
||||
// default this is set to (1 << 24), which is 16777216, but that's still
|
||||
// very big.
|
||||
|
||||
#ifndef STBI_NO_STDIO
|
||||
#include <stdio.h>
|
||||
#endif // STBI_NO_STDIO
|
||||
|
||||
#define STBI_VERSION 1
|
||||
|
||||
enum
|
||||
{
|
||||
STBI_default = 0, // only used for desired_channels
|
||||
|
||||
STBI_grey = 1,
|
||||
STBI_grey_alpha = 2,
|
||||
STBI_rgb = 3,
|
||||
STBI_rgb_alpha = 4
|
||||
};
|
||||
|
||||
#include <stdlib.h>
|
||||
typedef unsigned char stbi_uc;
|
||||
typedef unsigned short stbi_us;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef STBIDEF
|
||||
#ifdef STB_IMAGE_STATIC
|
||||
#define STBIDEF static
|
||||
#else
|
||||
#define STBIDEF extern
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PRIMARY API - works on images of any type
|
||||
//
|
||||
|
||||
//
|
||||
// load image by filename, open file, or memory buffer
|
||||
//
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int (*read) (void *user,char *data,int size); // fill 'data' with 'size' bytes. return number of bytes actually read
|
||||
void (*skip) (void *user,int n); // skip the next 'n' bytes, or 'unget' the last -n bytes if negative
|
||||
int (*eof) (void *user); // returns nonzero if we are at end of file/data
|
||||
} stbi_io_callbacks;
|
||||
|
||||
////////////////////////////////////
|
||||
//
|
||||
// 8-bits-per-channel interface
|
||||
//
|
||||
|
||||
STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *channels_in_file, int desired_channels);
|
||||
STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *channels_in_file, int desired_channels);
|
||||
|
||||
#ifndef STBI_NO_STDIO
|
||||
STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);
|
||||
STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels);
|
||||
// for stbi_load_from_file, file pointer is left pointing immediately after image
|
||||
#endif
|
||||
|
||||
#ifndef STBI_NO_GIF
|
||||
STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp);
|
||||
#endif
|
||||
|
||||
#ifdef STBI_WINDOWS_UTF8
|
||||
STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input);
|
||||
#endif
|
||||
|
||||
////////////////////////////////////
|
||||
//
|
||||
// 16-bits-per-channel interface
|
||||
//
|
||||
|
||||
STBIDEF stbi_us *stbi_load_16_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels);
|
||||
STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels);
|
||||
|
||||
#ifndef STBI_NO_STDIO
|
||||
STBIDEF stbi_us *stbi_load_16 (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);
|
||||
STBIDEF stbi_us *stbi_load_from_file_16(FILE *f, int *x, int *y, int *channels_in_file, int desired_channels);
|
||||
#endif
|
||||
|
||||
////////////////////////////////////
|
||||
//
|
||||
// float-per-channel interface
|
||||
//
|
||||
#ifndef STBI_NO_LINEAR
|
||||
STBIDEF float *stbi_loadf_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels);
|
||||
STBIDEF float *stbi_loadf_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels);
|
||||
|
||||
#ifndef STBI_NO_STDIO
|
||||
STBIDEF float *stbi_loadf (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);
|
||||
STBIDEF float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef STBI_NO_HDR
|
||||
STBIDEF void stbi_hdr_to_ldr_gamma(float gamma);
|
||||
STBIDEF void stbi_hdr_to_ldr_scale(float scale);
|
||||
#endif // STBI_NO_HDR
|
||||
|
||||
#ifndef STBI_NO_LINEAR
|
||||
STBIDEF void stbi_ldr_to_hdr_gamma(float gamma);
|
||||
STBIDEF void stbi_ldr_to_hdr_scale(float scale);
|
||||
#endif // STBI_NO_LINEAR
|
||||
|
||||
// stbi_is_hdr is always defined, but always returns false if STBI_NO_HDR
|
||||
STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user);
|
||||
STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len);
|
||||
#ifndef STBI_NO_STDIO
|
||||
STBIDEF int stbi_is_hdr (char const *filename);
|
||||
STBIDEF int stbi_is_hdr_from_file(FILE *f);
|
||||
#endif // STBI_NO_STDIO
|
||||
|
||||
|
||||
// get a VERY brief reason for failure
|
||||
// on most compilers (and ALL modern mainstream compilers) this is threadsafe
|
||||
STBIDEF const char *stbi_failure_reason (void);
|
||||
|
||||
// free the loaded image -- this is just free()
|
||||
STBIDEF void stbi_image_free (void *retval_from_stbi_load);
|
||||
|
||||
// get image dimensions & components without fully decoding
|
||||
STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp);
|
||||
STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp);
|
||||
STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len);
|
||||
STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *clbk, void *user);
|
||||
|
||||
#ifndef STBI_NO_STDIO
|
||||
STBIDEF int stbi_info (char const *filename, int *x, int *y, int *comp);
|
||||
STBIDEF int stbi_info_from_file (FILE *f, int *x, int *y, int *comp);
|
||||
STBIDEF int stbi_is_16_bit (char const *filename);
|
||||
STBIDEF int stbi_is_16_bit_from_file(FILE *f);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// for image formats that explicitly notate that they have premultiplied alpha,
|
||||
// we just return the colors as stored in the file. set this flag to force
|
||||
// unpremultiplication. results are undefined if the unpremultiply overflow.
|
||||
STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply);
|
||||
|
||||
// indicate whether we should process iphone images back to canonical format,
|
||||
// or just pass them through "as-is"
|
||||
STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert);
|
||||
|
||||
// flip the image vertically, so the first pixel in the output array is the bottom left
|
||||
STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip);
|
||||
|
||||
// as above, but only applies to images loaded on the thread that calls the function
|
||||
// this function is only available if your compiler supports thread-local variables;
|
||||
// calling it will fail to link if your compiler doesn't
|
||||
STBIDEF void stbi_set_unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply);
|
||||
STBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert);
|
||||
STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip);
|
||||
|
||||
// ZLIB client - used by PNG, available for other purposes
|
||||
|
||||
STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen);
|
||||
STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header);
|
||||
STBIDEF char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen);
|
||||
STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen);
|
||||
|
||||
STBIDEF char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen);
|
||||
STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
//
|
||||
//
|
||||
//// end header file /////////////////////////////////////////////////////
|
||||
#endif // STBI_INCLUDE_STB_IMAGE_H
|
||||
|
||||
/*
|
||||
revision history:
|
||||
2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs
|
||||
2.19 (2018-02-11) fix warning
|
||||
2.18 (2018-01-30) fix warnings
|
||||
2.17 (2018-01-29) change sbti__shiftsigned to avoid clang -O2 bug
|
||||
1-bit BMP
|
||||
*_is_16_bit api
|
||||
avoid warnings
|
||||
2.16 (2017-07-23) all functions have 16-bit variants;
|
||||
STBI_NO_STDIO works again;
|
||||
compilation fixes;
|
||||
fix rounding in unpremultiply;
|
||||
optimize vertical flip;
|
||||
disable raw_len validation;
|
||||
documentation fixes
|
||||
2.15 (2017-03-18) fix png-1,2,4 bug; now all Imagenet JPGs decode;
|
||||
warning fixes; disable run-time SSE detection on gcc;
|
||||
uniform handling of optional "return" values;
|
||||
thread-safe initialization of zlib tables
|
||||
2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs
|
||||
2.13 (2016-11-29) add 16-bit API, only supported for PNG right now
|
||||
2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes
|
||||
2.11 (2016-04-02) allocate large structures on the stack
|
||||
remove white matting for transparent PSD
|
||||
fix reported channel count for PNG & BMP
|
||||
re-enable SSE2 in non-gcc 64-bit
|
||||
support RGB-formatted JPEG
|
||||
read 16-bit PNGs (only as 8-bit)
|
||||
2.10 (2016-01-22) avoid warning introduced in 2.09 by STBI_REALLOC_SIZED
|
||||
2.09 (2016-01-16) allow comments in PNM files
|
||||
16-bit-per-pixel TGA (not bit-per-component)
|
||||
info() for TGA could break due to .hdr handling
|
||||
info() for BMP to shares code instead of sloppy parse
|
||||
can use STBI_REALLOC_SIZED if allocator doesn't support realloc
|
||||
code cleanup
|
||||
2.08 (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA
|
||||
2.07 (2015-09-13) fix compiler warnings
|
||||
partial animated GIF support
|
||||
limited 16-bpc PSD support
|
||||
#ifdef unused functions
|
||||
bug with < 92 byte PIC,PNM,HDR,TGA
|
||||
2.06 (2015-04-19) fix bug where PSD returns wrong '*comp' value
|
||||
2.05 (2015-04-19) fix bug in progressive JPEG handling, fix warning
|
||||
2.04 (2015-04-15) try to re-enable SIMD on MinGW 64-bit
|
||||
2.03 (2015-04-12) extra corruption checking (mmozeiko)
|
||||
stbi_set_flip_vertically_on_load (nguillemot)
|
||||
fix NEON support; fix mingw support
|
||||
2.02 (2015-01-19) fix incorrect assert, fix warning
|
||||
2.01 (2015-01-17) fix various warnings; suppress SIMD on gcc 32-bit without -msse2
|
||||
2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG
|
||||
2.00 (2014-12-25) optimize JPG, including x86 SSE2 & NEON SIMD (ryg)
|
||||
progressive JPEG (stb)
|
||||
PGM/PPM support (Ken Miller)
|
||||
STBI_MALLOC,STBI_REALLOC,STBI_FREE
|
||||
GIF bugfix -- seemingly never worked
|
||||
STBI_NO_*, STBI_ONLY_*
|
||||
1.48 (2014-12-14) fix incorrectly-named assert()
|
||||
1.47 (2014-12-14) 1/2/4-bit PNG support, both direct and paletted (Omar Cornut & stb)
|
||||
optimize PNG (ryg)
|
||||
fix bug in interlaced PNG with user-specified channel count (stb)
|
||||
1.46 (2014-08-26)
|
||||
fix broken tRNS chunk (colorkey-style transparency) in non-paletted PNG
|
||||
1.45 (2014-08-16)
|
||||
fix MSVC-ARM internal compiler error by wrapping malloc
|
||||
1.44 (2014-08-07)
|
||||
various warning fixes from Ronny Chevalier
|
||||
1.43 (2014-07-15)
|
||||
fix MSVC-only compiler problem in code changed in 1.42
|
||||
1.42 (2014-07-09)
|
||||
don't define _CRT_SECURE_NO_WARNINGS (affects user code)
|
||||
fixes to stbi__cleanup_jpeg path
|
||||
added STBI_ASSERT to avoid requiring assert.h
|
||||
1.41 (2014-06-25)
|
||||
fix search&replace from 1.36 that messed up comments/error messages
|
||||
1.40 (2014-06-22)
|
||||
fix gcc struct-initialization warning
|
||||
1.39 (2014-06-15)
|
||||
fix to TGA optimization when req_comp != number of components in TGA;
|
||||
fix to GIF loading because BMP wasn't rewinding (whoops, no GIFs in my test suite)
|
||||
add support for BMP version 5 (more ignored fields)
|
||||
1.38 (2014-06-06)
|
||||
suppress MSVC warnings on integer casts truncating values
|
||||
fix accidental rename of 'skip' field of I/O
|
||||
1.37 (2014-06-04)
|
||||
remove duplicate typedef
|
||||
1.36 (2014-06-03)
|
||||
convert to header file single-file library
|
||||
if de-iphone isn't set, load iphone images color-swapped instead of returning NULL
|
||||
1.35 (2014-05-27)
|
||||
various warnings
|
||||
fix broken STBI_SIMD path
|
||||
fix bug where stbi_load_from_file no longer left file pointer in correct place
|
||||
fix broken non-easy path for 32-bit BMP (possibly never used)
|
||||
TGA optimization by Arseny Kapoulkine
|
||||
1.34 (unknown)
|
||||
use STBI_NOTUSED in stbi__resample_row_generic(), fix one more leak in tga failure case
|
||||
1.33 (2011-07-14)
|
||||
make stbi_is_hdr work in STBI_NO_HDR (as specified), minor compiler-friendly improvements
|
||||
1.32 (2011-07-13)
|
||||
support for "info" function for all supported filetypes (SpartanJ)
|
||||
1.31 (2011-06-20)
|
||||
a few more leak fixes, bug in PNG handling (SpartanJ)
|
||||
1.30 (2011-06-11)
|
||||
added ability to load files via callbacks to accomidate custom input streams (Ben Wenger)
|
||||
removed deprecated format-specific test/load functions
|
||||
removed support for installable file formats (stbi_loader) -- would have been broken for IO callbacks anyway
|
||||
error cases in bmp and tga give messages and don't leak (Raymond Barbiero, grisha)
|
||||
fix inefficiency in decoding 32-bit BMP (David Woo)
|
||||
1.29 (2010-08-16)
|
||||
various warning fixes from Aurelien Pocheville
|
||||
1.28 (2010-08-01)
|
||||
fix bug in GIF palette transparency (SpartanJ)
|
||||
1.27 (2010-08-01)
|
||||
cast-to-stbi_uc to fix warnings
|
||||
1.26 (2010-07-24)
|
||||
fix bug in file buffering for PNG reported by SpartanJ
|
||||
1.25 (2010-07-17)
|
||||
refix trans_data warning (Won Chun)
|
||||
1.24 (2010-07-12)
|
||||
perf improvements reading from files on platforms with lock-heavy fgetc()
|
||||
minor perf improvements for jpeg
|
||||
deprecated type-specific functions so we'll get feedback if they're needed
|
||||
attempt to fix trans_data warning (Won Chun)
|
||||
1.23 fixed bug in iPhone support
|
||||
1.22 (2010-07-10)
|
||||
removed image *writing* support
|
||||
stbi_info support from Jetro Lauha
|
||||
GIF support from Jean-Marc Lienher
|
||||
iPhone PNG-extensions from James Brown
|
||||
warning-fixes from Nicolas Schulz and Janez Zemva (i.stbi__err. Janez (U+017D)emva)
|
||||
1.21 fix use of 'stbi_uc' in header (reported by jon blow)
|
||||
1.20 added support for Softimage PIC, by Tom Seddon
|
||||
1.19 bug in interlaced PNG corruption check (found by ryg)
|
||||
1.18 (2008-08-02)
|
||||
fix a threading bug (local mutable static)
|
||||
1.17 support interlaced PNG
|
||||
1.16 major bugfix - stbi__convert_format converted one too many pixels
|
||||
1.15 initialize some fields for thread safety
|
||||
1.14 fix threadsafe conversion bug
|
||||
header-file-only version (#define STBI_HEADER_FILE_ONLY before including)
|
||||
1.13 threadsafe
|
||||
1.12 const qualifiers in the API
|
||||
1.11 Support installable IDCT, colorspace conversion routines
|
||||
1.10 Fixes for 64-bit (don't use "unsigned long")
|
||||
optimized upsampling by Fabian "ryg" Giesen
|
||||
1.09 Fix format-conversion for PSD code (bad global variables!)
|
||||
1.08 Thatcher Ulrich's PSD code integrated by Nicolas Schulz
|
||||
1.07 attempt to fix C++ warning/errors again
|
||||
1.06 attempt to fix C++ warning/errors again
|
||||
1.05 fix TGA loading to return correct *comp and use good luminance calc
|
||||
1.04 default float alpha is 1, not 255; use 'void *' for stbi_image_free
|
||||
1.03 bugfixes to STBI_NO_STDIO, STBI_NO_HDR
|
||||
1.02 support for (subset of) HDR files, float interface for preferred access to them
|
||||
1.01 fix bug: possible bug in handling right-side up bmps... not sure
|
||||
fix bug: the stbi__bmp_load() and stbi__tga_load() functions didn't work at all
|
||||
1.00 interface to zlib that skips zlib header
|
||||
0.99 correct handling of alpha in palette
|
||||
0.98 TGA loader by lonesock; dynamically add loaders (untested)
|
||||
0.97 jpeg errors on too large a file; also catch another malloc failure
|
||||
0.96 fix detection of invalid v value - particleman@mollyrocket forum
|
||||
0.95 during header scan, seek to markers in case of padding
|
||||
0.94 STBI_NO_STDIO to disable stdio usage; rename all #defines the same
|
||||
0.93 handle jpegtran output; verbose errors
|
||||
0.92 read 4,8,16,24,32-bit BMP files of several formats
|
||||
0.91 output 24-bit Windows 3.0 BMP files
|
||||
0.90 fix a few more warnings; bump version number to approach 1.0
|
||||
0.61 bugfixes due to Marc LeBlanc, Christopher Lloyd
|
||||
0.60 fix compiling as c++
|
||||
0.59 fix warnings: merge Dave Moore's -Wall fixes
|
||||
0.58 fix bug: zlib uncompressed mode len/nlen was wrong endian
|
||||
0.57 fix bug: jpg last huffman symbol before marker was >9 bits but less than 16 available
|
||||
0.56 fix bug: zlib uncompressed mode len vs. nlen
|
||||
0.55 fix bug: restart_interval not initialized to 0
|
||||
0.54 allow NULL for 'int *comp'
|
||||
0.53 fix bug in png 3->4; speedup png decoding
|
||||
0.52 png handles req_comp=3,4 directly; minor cleanup; jpeg comments
|
||||
0.51 obey req_comp requests, 1-component jpegs return as 1-component,
|
||||
on 'test' only check type, not whether we support this variant
|
||||
0.50 (2006-11-19)
|
||||
first released version
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
------------------------------------------------------------------------------
|
||||
This software is available under 2 licenses -- choose whichever you prefer.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE A - MIT License
|
||||
Copyright (c) 2017 Sean Barrett
|
||||
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.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE B - Public Domain (www.unlicense.org)
|
||||
This is free and unencumbered software released into the public domain.
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
|
||||
software, either in source code form or as a compiled binary, for any purpose,
|
||||
commercial or non-commercial, and by any means.
|
||||
In jurisdictions that recognize copyright laws, the author or authors of this
|
||||
software dedicate any and all copyright interest in the software to the public
|
||||
domain. We make this dedication for the benefit of the public at large and to
|
||||
the detriment of our heirs and successors. We intend this dedication to be an
|
||||
overt act of relinquishment in perpetuity of all present and future rights to
|
||||
this software under copyright law.
|
||||
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 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.
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
2282
externals/stb/stb_image_resize.cpp
vendored
Normal file
2282
externals/stb/stb_image_resize.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
426
externals/stb/stb_image_resize.h
vendored
Normal file
426
externals/stb/stb_image_resize.h
vendored
Normal file
@ -0,0 +1,426 @@
|
||||
// SPDX-FileCopyrightText: Jorge L Rodriguez
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
/* stb_image_resize - v0.97 - public domain image resizing
|
||||
by Jorge L Rodriguez (@VinoBS) - 2014
|
||||
http://github.com/nothings/stb
|
||||
|
||||
Written with emphasis on usability, portability, and efficiency. (No
|
||||
SIMD or threads, so it be easily outperformed by libs that use those.)
|
||||
Only scaling and translation is supported, no rotations or shears.
|
||||
Easy API downsamples w/Mitchell filter, upsamples w/cubic interpolation.
|
||||
|
||||
COMPILING & LINKING
|
||||
In one C/C++ file that #includes this file, do this:
|
||||
#define STB_IMAGE_RESIZE_IMPLEMENTATION
|
||||
before the #include. That will create the implementation in that file.
|
||||
|
||||
QUICKSTART
|
||||
stbir_resize_uint8( input_pixels , in_w , in_h , 0,
|
||||
output_pixels, out_w, out_h, 0, num_channels)
|
||||
stbir_resize_float(...)
|
||||
stbir_resize_uint8_srgb( input_pixels , in_w , in_h , 0,
|
||||
output_pixels, out_w, out_h, 0,
|
||||
num_channels , alpha_chan , 0)
|
||||
stbir_resize_uint8_srgb_edgemode(
|
||||
input_pixels , in_w , in_h , 0,
|
||||
output_pixels, out_w, out_h, 0,
|
||||
num_channels , alpha_chan , 0, STBIR_EDGE_CLAMP)
|
||||
// WRAP/REFLECT/ZERO
|
||||
|
||||
FULL API
|
||||
See the "header file" section of the source for API documentation.
|
||||
|
||||
ADDITIONAL DOCUMENTATION
|
||||
|
||||
SRGB & FLOATING POINT REPRESENTATION
|
||||
The sRGB functions presume IEEE floating point. If you do not have
|
||||
IEEE floating point, define STBIR_NON_IEEE_FLOAT. This will use
|
||||
a slower implementation.
|
||||
|
||||
MEMORY ALLOCATION
|
||||
The resize functions here perform a single memory allocation using
|
||||
malloc. To control the memory allocation, before the #include that
|
||||
triggers the implementation, do:
|
||||
|
||||
#define STBIR_MALLOC(size,context) ...
|
||||
#define STBIR_FREE(ptr,context) ...
|
||||
|
||||
Each resize function makes exactly one call to malloc/free, so to use
|
||||
temp memory, store the temp memory in the context and return that.
|
||||
|
||||
ASSERT
|
||||
Define STBIR_ASSERT(boolval) to override assert() and not use assert.h
|
||||
|
||||
OPTIMIZATION
|
||||
Define STBIR_SATURATE_INT to compute clamp values in-range using
|
||||
integer operations instead of float operations. This may be faster
|
||||
on some platforms.
|
||||
|
||||
DEFAULT FILTERS
|
||||
For functions which don't provide explicit control over what filters
|
||||
to use, you can change the compile-time defaults with
|
||||
|
||||
#define STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_something
|
||||
#define STBIR_DEFAULT_FILTER_DOWNSAMPLE STBIR_FILTER_something
|
||||
|
||||
See stbir_filter in the header-file section for the list of filters.
|
||||
|
||||
NEW FILTERS
|
||||
A number of 1D filter kernels are used. For a list of
|
||||
supported filters see the stbir_filter enum. To add a new filter,
|
||||
write a filter function and add it to stbir__filter_info_table.
|
||||
|
||||
PROGRESS
|
||||
For interactive use with slow resize operations, you can install
|
||||
a progress-report callback:
|
||||
|
||||
#define STBIR_PROGRESS_REPORT(val) some_func(val)
|
||||
|
||||
The parameter val is a float which goes from 0 to 1 as progress is made.
|
||||
|
||||
For example:
|
||||
|
||||
static void my_progress_report(float progress);
|
||||
#define STBIR_PROGRESS_REPORT(val) my_progress_report(val)
|
||||
|
||||
#define STB_IMAGE_RESIZE_IMPLEMENTATION
|
||||
#include "stb_image_resize.h"
|
||||
|
||||
static void my_progress_report(float progress)
|
||||
{
|
||||
printf("Progress: %f%%\n", progress*100);
|
||||
}
|
||||
|
||||
MAX CHANNELS
|
||||
If your image has more than 64 channels, define STBIR_MAX_CHANNELS
|
||||
to the max you'll have.
|
||||
|
||||
ALPHA CHANNEL
|
||||
Most of the resizing functions provide the ability to control how
|
||||
the alpha channel of an image is processed. The important things
|
||||
to know about this:
|
||||
|
||||
1. The best mathematically-behaved version of alpha to use is
|
||||
called "premultiplied alpha", in which the other color channels
|
||||
have had the alpha value multiplied in. If you use premultiplied
|
||||
alpha, linear filtering (such as image resampling done by this
|
||||
library, or performed in texture units on GPUs) does the "right
|
||||
thing". While premultiplied alpha is standard in the movie CGI
|
||||
industry, it is still uncommon in the videogame/real-time world.
|
||||
|
||||
If you linearly filter non-premultiplied alpha, strange effects
|
||||
occur. (For example, the 50/50 average of 99% transparent bright green
|
||||
and 1% transparent black produces 50% transparent dark green when
|
||||
non-premultiplied, whereas premultiplied it produces 50%
|
||||
transparent near-black. The former introduces green energy
|
||||
that doesn't exist in the source image.)
|
||||
|
||||
2. Artists should not edit premultiplied-alpha images; artists
|
||||
want non-premultiplied alpha images. Thus, art tools generally output
|
||||
non-premultiplied alpha images.
|
||||
|
||||
3. You will get best results in most cases by converting images
|
||||
to premultiplied alpha before processing them mathematically.
|
||||
|
||||
4. If you pass the flag STBIR_FLAG_ALPHA_PREMULTIPLIED, the
|
||||
resizer does not do anything special for the alpha channel;
|
||||
it is resampled identically to other channels. This produces
|
||||
the correct results for premultiplied-alpha images, but produces
|
||||
less-than-ideal results for non-premultiplied-alpha images.
|
||||
|
||||
5. If you do not pass the flag STBIR_FLAG_ALPHA_PREMULTIPLIED,
|
||||
then the resizer weights the contribution of input pixels
|
||||
based on their alpha values, or, equivalently, it multiplies
|
||||
the alpha value into the color channels, resamples, then divides
|
||||
by the resultant alpha value. Input pixels which have alpha=0 do
|
||||
not contribute at all to output pixels unless _all_ of the input
|
||||
pixels affecting that output pixel have alpha=0, in which case
|
||||
the result for that pixel is the same as it would be without
|
||||
STBIR_FLAG_ALPHA_PREMULTIPLIED. However, this is only true for
|
||||
input images in integer formats. For input images in float format,
|
||||
input pixels with alpha=0 have no effect, and output pixels
|
||||
which have alpha=0 will be 0 in all channels. (For float images,
|
||||
you can manually achieve the same result by adding a tiny epsilon
|
||||
value to the alpha channel of every image, and then subtracting
|
||||
or clamping it at the end.)
|
||||
|
||||
6. You can suppress the behavior described in #5 and make
|
||||
all-0-alpha pixels have 0 in all channels by #defining
|
||||
STBIR_NO_ALPHA_EPSILON.
|
||||
|
||||
7. You can separately control whether the alpha channel is
|
||||
interpreted as linear or affected by the colorspace. By default
|
||||
it is linear; you almost never want to apply the colorspace.
|
||||
(For example, graphics hardware does not apply sRGB conversion
|
||||
to the alpha channel.)
|
||||
|
||||
CONTRIBUTORS
|
||||
Jorge L Rodriguez: Implementation
|
||||
Sean Barrett: API design, optimizations
|
||||
Aras Pranckevicius: bugfix
|
||||
Nathan Reed: warning fixes
|
||||
|
||||
REVISIONS
|
||||
0.97 (2020-02-02) fixed warning
|
||||
0.96 (2019-03-04) fixed warnings
|
||||
0.95 (2017-07-23) fixed warnings
|
||||
0.94 (2017-03-18) fixed warnings
|
||||
0.93 (2017-03-03) fixed bug with certain combinations of heights
|
||||
0.92 (2017-01-02) fix integer overflow on large (>2GB) images
|
||||
0.91 (2016-04-02) fix warnings; fix handling of subpixel regions
|
||||
0.90 (2014-09-17) first released version
|
||||
|
||||
LICENSE
|
||||
See end of file for license information.
|
||||
|
||||
TODO
|
||||
Don't decode all of the image data when only processing a partial tile
|
||||
Don't use full-width decode buffers when only processing a partial tile
|
||||
When processing wide images, break processing into tiles so data fits in L1 cache
|
||||
Installable filters?
|
||||
Resize that respects alpha test coverage
|
||||
(Reference code: FloatImage::alphaTestCoverage and FloatImage::scaleAlphaToCoverage:
|
||||
https://code.google.com/p/nvidia-texture-tools/source/browse/trunk/src/nvimage/FloatImage.cpp )
|
||||
*/
|
||||
|
||||
#ifndef STBIR_INCLUDE_STB_IMAGE_RESIZE_H
|
||||
#define STBIR_INCLUDE_STB_IMAGE_RESIZE_H
|
||||
|
||||
#ifdef _MSC_VER
|
||||
typedef unsigned char stbir_uint8;
|
||||
typedef unsigned short stbir_uint16;
|
||||
typedef unsigned int stbir_uint32;
|
||||
#else
|
||||
#include <stdint.h>
|
||||
typedef uint8_t stbir_uint8;
|
||||
typedef uint16_t stbir_uint16;
|
||||
typedef uint32_t stbir_uint32;
|
||||
#endif
|
||||
|
||||
#ifndef STBIRDEF
|
||||
#ifdef STB_IMAGE_RESIZE_STATIC
|
||||
#define STBIRDEF static
|
||||
#else
|
||||
#ifdef __cplusplus
|
||||
#define STBIRDEF extern "C"
|
||||
#else
|
||||
#define STBIRDEF extern
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Easy-to-use API:
|
||||
//
|
||||
// * "input pixels" points to an array of image data with 'num_channels' channels (e.g. RGB=3, RGBA=4)
|
||||
// * input_w is input image width (x-axis), input_h is input image height (y-axis)
|
||||
// * stride is the offset between successive rows of image data in memory, in bytes. you can
|
||||
// specify 0 to mean packed continuously in memory
|
||||
// * alpha channel is treated identically to other channels.
|
||||
// * colorspace is linear or sRGB as specified by function name
|
||||
// * returned result is 1 for success or 0 in case of an error.
|
||||
// #define STBIR_ASSERT() to trigger an assert on parameter validation errors.
|
||||
// * Memory required grows approximately linearly with input and output size, but with
|
||||
// discontinuities at input_w == output_w and input_h == output_h.
|
||||
// * These functions use a "default" resampling filter defined at compile time. To change the filter,
|
||||
// you can change the compile-time defaults by #defining STBIR_DEFAULT_FILTER_UPSAMPLE
|
||||
// and STBIR_DEFAULT_FILTER_DOWNSAMPLE, or you can use the medium-complexity API.
|
||||
|
||||
STBIRDEF int stbir_resize_uint8( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
|
||||
unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
|
||||
int num_channels);
|
||||
|
||||
STBIRDEF int stbir_resize_float( const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
|
||||
float *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
|
||||
int num_channels);
|
||||
|
||||
|
||||
// The following functions interpret image data as gamma-corrected sRGB.
|
||||
// Specify STBIR_ALPHA_CHANNEL_NONE if you have no alpha channel,
|
||||
// or otherwise provide the index of the alpha channel. Flags value
|
||||
// of 0 will probably do the right thing if you're not sure what
|
||||
// the flags mean.
|
||||
|
||||
#define STBIR_ALPHA_CHANNEL_NONE -1
|
||||
|
||||
// Set this flag if your texture has premultiplied alpha. Otherwise, stbir will
|
||||
// use alpha-weighted resampling (effectively premultiplying, resampling,
|
||||
// then unpremultiplying).
|
||||
#define STBIR_FLAG_ALPHA_PREMULTIPLIED (1 << 0)
|
||||
// The specified alpha channel should be handled as gamma-corrected value even
|
||||
// when doing sRGB operations.
|
||||
#define STBIR_FLAG_ALPHA_USES_COLORSPACE (1 << 1)
|
||||
|
||||
STBIRDEF int stbir_resize_uint8_srgb(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
|
||||
unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
|
||||
int num_channels, int alpha_channel, int flags);
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
STBIR_EDGE_CLAMP = 1,
|
||||
STBIR_EDGE_REFLECT = 2,
|
||||
STBIR_EDGE_WRAP = 3,
|
||||
STBIR_EDGE_ZERO = 4,
|
||||
} stbir_edge;
|
||||
|
||||
// This function adds the ability to specify how requests to sample off the edge of the image are handled.
|
||||
STBIRDEF int stbir_resize_uint8_srgb_edgemode(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
|
||||
unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
|
||||
int num_channels, int alpha_channel, int flags,
|
||||
stbir_edge edge_wrap_mode);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Medium-complexity API
|
||||
//
|
||||
// This extends the easy-to-use API as follows:
|
||||
//
|
||||
// * Alpha-channel can be processed separately
|
||||
// * If alpha_channel is not STBIR_ALPHA_CHANNEL_NONE
|
||||
// * Alpha channel will not be gamma corrected (unless flags&STBIR_FLAG_GAMMA_CORRECT)
|
||||
// * Filters will be weighted by alpha channel (unless flags&STBIR_FLAG_ALPHA_PREMULTIPLIED)
|
||||
// * Filter can be selected explicitly
|
||||
// * uint16 image type
|
||||
// * sRGB colorspace available for all types
|
||||
// * context parameter for passing to STBIR_MALLOC
|
||||
|
||||
typedef enum
|
||||
{
|
||||
STBIR_FILTER_DEFAULT = 0, // use same filter type that easy-to-use API chooses
|
||||
STBIR_FILTER_BOX = 1, // A trapezoid w/1-pixel wide ramps, same result as box for integer scale ratios
|
||||
STBIR_FILTER_TRIANGLE = 2, // On upsampling, produces same results as bilinear texture filtering
|
||||
STBIR_FILTER_CUBICBSPLINE = 3, // The cubic b-spline (aka Mitchell-Netrevalli with B=1,C=0), gaussian-esque
|
||||
STBIR_FILTER_CATMULLROM = 4, // An interpolating cubic spline
|
||||
STBIR_FILTER_MITCHELL = 5, // Mitchell-Netrevalli filter with B=1/3, C=1/3
|
||||
} stbir_filter;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
STBIR_COLORSPACE_LINEAR,
|
||||
STBIR_COLORSPACE_SRGB,
|
||||
|
||||
STBIR_MAX_COLORSPACES,
|
||||
} stbir_colorspace;
|
||||
|
||||
// The following functions are all identical except for the type of the image data
|
||||
|
||||
STBIRDEF int stbir_resize_uint8_generic( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
|
||||
unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
|
||||
int num_channels, int alpha_channel, int flags,
|
||||
stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
|
||||
void *alloc_context);
|
||||
|
||||
STBIRDEF int stbir_resize_uint16_generic(const stbir_uint16 *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
|
||||
stbir_uint16 *output_pixels , int output_w, int output_h, int output_stride_in_bytes,
|
||||
int num_channels, int alpha_channel, int flags,
|
||||
stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
|
||||
void *alloc_context);
|
||||
|
||||
STBIRDEF int stbir_resize_float_generic( const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
|
||||
float *output_pixels , int output_w, int output_h, int output_stride_in_bytes,
|
||||
int num_channels, int alpha_channel, int flags,
|
||||
stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
|
||||
void *alloc_context);
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Full-complexity API
|
||||
//
|
||||
// This extends the medium API as follows:
|
||||
//
|
||||
// * uint32 image type
|
||||
// * not typesafe
|
||||
// * separate filter types for each axis
|
||||
// * separate edge modes for each axis
|
||||
// * can specify scale explicitly for subpixel correctness
|
||||
// * can specify image source tile using texture coordinates
|
||||
|
||||
typedef enum
|
||||
{
|
||||
STBIR_TYPE_UINT8 ,
|
||||
STBIR_TYPE_UINT16,
|
||||
STBIR_TYPE_UINT32,
|
||||
STBIR_TYPE_FLOAT ,
|
||||
|
||||
STBIR_MAX_TYPES
|
||||
} stbir_datatype;
|
||||
|
||||
STBIRDEF int stbir_resize( const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
|
||||
void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
|
||||
stbir_datatype datatype,
|
||||
int num_channels, int alpha_channel, int flags,
|
||||
stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
|
||||
stbir_filter filter_horizontal, stbir_filter filter_vertical,
|
||||
stbir_colorspace space, void *alloc_context);
|
||||
|
||||
STBIRDEF int stbir_resize_subpixel(const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
|
||||
void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
|
||||
stbir_datatype datatype,
|
||||
int num_channels, int alpha_channel, int flags,
|
||||
stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
|
||||
stbir_filter filter_horizontal, stbir_filter filter_vertical,
|
||||
stbir_colorspace space, void *alloc_context,
|
||||
float x_scale, float y_scale,
|
||||
float x_offset, float y_offset);
|
||||
|
||||
STBIRDEF int stbir_resize_region( const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
|
||||
void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
|
||||
stbir_datatype datatype,
|
||||
int num_channels, int alpha_channel, int flags,
|
||||
stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
|
||||
stbir_filter filter_horizontal, stbir_filter filter_vertical,
|
||||
stbir_colorspace space, void *alloc_context,
|
||||
float s0, float t0, float s1, float t1);
|
||||
// (s0, t0) & (s1, t1) are the top-left and bottom right corner (uv addressing style: [0, 1]x[0, 1]) of a region of the input image to use.
|
||||
|
||||
//
|
||||
//
|
||||
//// end header file /////////////////////////////////////////////////////
|
||||
#endif // STBIR_INCLUDE_STB_IMAGE_RESIZE_H
|
||||
|
||||
/*
|
||||
------------------------------------------------------------------------------
|
||||
This software is available under 2 licenses -- choose whichever you prefer.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE A - MIT License
|
||||
Copyright (c) 2017 Sean Barrett
|
||||
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.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE B - Public Domain (www.unlicense.org)
|
||||
This is free and unencumbered software released into the public domain.
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
|
||||
software, either in source code form or as a compiled binary, for any purpose,
|
||||
commercial or non-commercial, and by any means.
|
||||
In jurisdictions that recognize copyright laws, the author or authors of this
|
||||
software dedicate any and all copyright interest in the software to the public
|
||||
domain. We make this dedication for the benefit of the public at large and to
|
||||
the detriment of our heirs and successors. We intend this dedication to be an
|
||||
overt act of relinquishment in perpetuity of all present and future rights to
|
||||
this software under copyright law.
|
||||
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 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.
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
@ -77,6 +77,7 @@ void AudioRenderer::Wait() {
|
||||
"{}, got {}",
|
||||
Message::RenderResponse, msg);
|
||||
}
|
||||
PostDSPClearCommandBuffer();
|
||||
}
|
||||
|
||||
void AudioRenderer::Send(Direction dir, u32 message) {
|
||||
@ -96,6 +97,14 @@ void AudioRenderer::SetCommandBuffer(s32 session_id, CpuAddr buffer, u64 size, u
|
||||
command_buffers[session_id].reset_buffer = reset;
|
||||
}
|
||||
|
||||
void AudioRenderer::PostDSPClearCommandBuffer() noexcept {
|
||||
for (auto& buffer : command_buffers) {
|
||||
buffer.buffer = 0;
|
||||
buffer.size = 0;
|
||||
buffer.reset_buffer = false;
|
||||
}
|
||||
}
|
||||
|
||||
u32 AudioRenderer::GetRemainCommandCount(s32 session_id) const noexcept {
|
||||
return command_buffers[session_id].remaining_command_count;
|
||||
}
|
||||
|
@ -85,6 +85,8 @@ private:
|
||||
*/
|
||||
void CreateSinkStreams();
|
||||
|
||||
void PostDSPClearCommandBuffer() noexcept;
|
||||
|
||||
/// Core system
|
||||
Core::System& system;
|
||||
/// The output sink the AudioRenderer will send samples to
|
||||
|
@ -189,6 +189,14 @@ if(ARCHITECTURE_x86_64)
|
||||
target_link_libraries(common PRIVATE xbyak::xbyak)
|
||||
endif()
|
||||
|
||||
if (ARCHITECTURE_arm64 AND (ANDROID OR LINUX))
|
||||
target_sources(common
|
||||
PRIVATE
|
||||
arm64/native_clock.cpp
|
||||
arm64/native_clock.h
|
||||
)
|
||||
endif()
|
||||
|
||||
if (MSVC)
|
||||
target_compile_definitions(common PRIVATE
|
||||
# The standard library doesn't provide any replacement for codecvt yet
|
||||
|
72
src/common/arm64/native_clock.cpp
Normal file
72
src/common/arm64/native_clock.cpp
Normal file
@ -0,0 +1,72 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/arm64/native_clock.h"
|
||||
|
||||
namespace Common::Arm64 {
|
||||
|
||||
namespace {
|
||||
|
||||
NativeClock::FactorType GetFixedPointFactor(u64 num, u64 den) {
|
||||
return (static_cast<NativeClock::FactorType>(num) << 64) / den;
|
||||
}
|
||||
|
||||
u64 MultiplyHigh(u64 m, NativeClock::FactorType factor) {
|
||||
return static_cast<u64>((m * factor) >> 64);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
NativeClock::NativeClock() {
|
||||
const u64 host_cntfrq = GetHostCNTFRQ();
|
||||
ns_cntfrq_factor = GetFixedPointFactor(NsRatio::den, host_cntfrq);
|
||||
us_cntfrq_factor = GetFixedPointFactor(UsRatio::den, host_cntfrq);
|
||||
ms_cntfrq_factor = GetFixedPointFactor(MsRatio::den, host_cntfrq);
|
||||
guest_cntfrq_factor = GetFixedPointFactor(CNTFRQ, host_cntfrq);
|
||||
gputick_cntfrq_factor = GetFixedPointFactor(GPUTickFreq, host_cntfrq);
|
||||
}
|
||||
|
||||
std::chrono::nanoseconds NativeClock::GetTimeNS() const {
|
||||
return std::chrono::nanoseconds{MultiplyHigh(GetHostTicksElapsed(), ns_cntfrq_factor)};
|
||||
}
|
||||
|
||||
std::chrono::microseconds NativeClock::GetTimeUS() const {
|
||||
return std::chrono::microseconds{MultiplyHigh(GetHostTicksElapsed(), us_cntfrq_factor)};
|
||||
}
|
||||
|
||||
std::chrono::milliseconds NativeClock::GetTimeMS() const {
|
||||
return std::chrono::milliseconds{MultiplyHigh(GetHostTicksElapsed(), ms_cntfrq_factor)};
|
||||
}
|
||||
|
||||
u64 NativeClock::GetCNTPCT() const {
|
||||
return MultiplyHigh(GetHostTicksElapsed(), guest_cntfrq_factor);
|
||||
}
|
||||
|
||||
u64 NativeClock::GetGPUTick() const {
|
||||
return MultiplyHigh(GetHostTicksElapsed(), gputick_cntfrq_factor);
|
||||
}
|
||||
|
||||
u64 NativeClock::GetHostTicksNow() const {
|
||||
u64 cntvct_el0 = 0;
|
||||
asm volatile("dsb ish\n\t"
|
||||
"mrs %[cntvct_el0], cntvct_el0\n\t"
|
||||
"dsb ish\n\t"
|
||||
: [cntvct_el0] "=r"(cntvct_el0));
|
||||
return cntvct_el0;
|
||||
}
|
||||
|
||||
u64 NativeClock::GetHostTicksElapsed() const {
|
||||
return GetHostTicksNow();
|
||||
}
|
||||
|
||||
bool NativeClock::IsNative() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
u64 NativeClock::GetHostCNTFRQ() {
|
||||
u64 cntfrq_el0 = 0;
|
||||
asm("mrs %[cntfrq_el0], cntfrq_el0" : [cntfrq_el0] "=r"(cntfrq_el0));
|
||||
return cntfrq_el0;
|
||||
}
|
||||
|
||||
} // namespace Common::Arm64
|
47
src/common/arm64/native_clock.h
Normal file
47
src/common/arm64/native_clock.h
Normal file
@ -0,0 +1,47 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/wall_clock.h"
|
||||
|
||||
namespace Common::Arm64 {
|
||||
|
||||
class NativeClock final : public WallClock {
|
||||
public:
|
||||
explicit NativeClock();
|
||||
|
||||
std::chrono::nanoseconds GetTimeNS() const override;
|
||||
|
||||
std::chrono::microseconds GetTimeUS() const override;
|
||||
|
||||
std::chrono::milliseconds GetTimeMS() const override;
|
||||
|
||||
u64 GetCNTPCT() const override;
|
||||
|
||||
u64 GetGPUTick() const override;
|
||||
|
||||
u64 GetHostTicksNow() const override;
|
||||
|
||||
u64 GetHostTicksElapsed() const override;
|
||||
|
||||
bool IsNative() const override;
|
||||
|
||||
static u64 GetHostCNTFRQ();
|
||||
|
||||
public:
|
||||
using FactorType = unsigned __int128;
|
||||
|
||||
FactorType GetGuestCNTFRQFactor() const {
|
||||
return guest_cntfrq_factor;
|
||||
}
|
||||
|
||||
private:
|
||||
FactorType ns_cntfrq_factor;
|
||||
FactorType us_cntfrq_factor;
|
||||
FactorType ms_cntfrq_factor;
|
||||
FactorType guest_cntfrq_factor;
|
||||
FactorType gputick_cntfrq_factor;
|
||||
};
|
||||
|
||||
} // namespace Common::Arm64
|
@ -39,8 +39,12 @@
|
||||
#define Crash() exit(1)
|
||||
#endif
|
||||
|
||||
#define LTO_NOINLINE __attribute__((noinline))
|
||||
|
||||
#else // _MSC_VER
|
||||
|
||||
#define LTO_NOINLINE
|
||||
|
||||
// Locale Cross-Compatibility
|
||||
#define locale_t _locale_t
|
||||
|
||||
|
@ -211,6 +211,11 @@ struct Elf64_Rela {
|
||||
Elf64_Sxword r_addend; /* Addend */
|
||||
};
|
||||
|
||||
/* RELR relocation table entry */
|
||||
|
||||
using Elf32_Relr = Elf32_Word;
|
||||
using Elf64_Relr = Elf64_Xword;
|
||||
|
||||
/* How to extract and insert information held in the r_info field. */
|
||||
|
||||
static inline u32 Elf32RelSymIndex(Elf32_Word r_info) {
|
||||
@ -328,6 +333,9 @@ constexpr u32 ElfDtFiniArray = 26; /* Array with addresses of fini fct */
|
||||
constexpr u32 ElfDtInitArraySz = 27; /* Size in bytes of DT_INIT_ARRAY */
|
||||
constexpr u32 ElfDtFiniArraySz = 28; /* Size in bytes of DT_FINI_ARRAY */
|
||||
constexpr u32 ElfDtSymtabShndx = 34; /* Address of SYMTAB_SHNDX section */
|
||||
constexpr u32 ElfDtRelrsz = 35; /* Size of RELR relative relocations */
|
||||
constexpr u32 ElfDtRelr = 36; /* Address of RELR relative relocations */
|
||||
constexpr u32 ElfDtRelrent = 37; /* Size of one RELR relative relocation */
|
||||
|
||||
} // namespace ELF
|
||||
} // namespace Common
|
||||
|
@ -10,6 +10,10 @@
|
||||
#include "common/x64/rdtsc.h"
|
||||
#endif
|
||||
|
||||
#if defined(ARCHITECTURE_arm64) && defined(__linux__)
|
||||
#include "common/arm64/native_clock.h"
|
||||
#endif
|
||||
|
||||
namespace Common {
|
||||
|
||||
class StandardWallClock final : public WallClock {
|
||||
@ -53,7 +57,7 @@ private:
|
||||
};
|
||||
|
||||
std::unique_ptr<WallClock> CreateOptimalClock() {
|
||||
#ifdef ARCHITECTURE_x86_64
|
||||
#if defined(ARCHITECTURE_x86_64)
|
||||
const auto& caps = GetCPUCaps();
|
||||
|
||||
if (caps.invariant_tsc && caps.tsc_frequency >= std::nano::den) {
|
||||
@ -64,6 +68,8 @@ std::unique_ptr<WallClock> CreateOptimalClock() {
|
||||
// - Is not more precise than 1 GHz (1ns resolution)
|
||||
return std::make_unique<StandardWallClock>();
|
||||
}
|
||||
#elif defined(ARCHITECTURE_arm64) && defined(__linux__)
|
||||
return std::make_unique<Arm64::NativeClock>();
|
||||
#else
|
||||
return std::make_unique<StandardWallClock>();
|
||||
#endif
|
||||
|
@ -181,20 +181,10 @@ add_library(core STATIC
|
||||
frontend/framebuffer_layout.cpp
|
||||
frontend/framebuffer_layout.h
|
||||
frontend/graphics_context.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/irs_types.h
|
||||
hid/motion_input.cpp
|
||||
hid/motion_input.h
|
||||
hle/api_version.h
|
||||
@ -466,14 +456,18 @@ add_library(core STATIC
|
||||
hle/service/caps/caps_a.h
|
||||
hle/service/caps/caps_c.cpp
|
||||
hle/service/caps/caps_c.h
|
||||
hle/service/caps/caps_u.cpp
|
||||
hle/service/caps/caps_u.h
|
||||
hle/service/caps/caps_manager.cpp
|
||||
hle/service/caps/caps_manager.h
|
||||
hle/service/caps/caps_result.h
|
||||
hle/service/caps/caps_sc.cpp
|
||||
hle/service/caps/caps_sc.h
|
||||
hle/service/caps/caps_ss.cpp
|
||||
hle/service/caps/caps_ss.h
|
||||
hle/service/caps/caps_su.cpp
|
||||
hle/service/caps/caps_su.h
|
||||
hle/service/caps/caps_types.h
|
||||
hle/service/caps/caps_u.cpp
|
||||
hle/service/caps/caps_u.h
|
||||
hle/service/erpt/erpt.cpp
|
||||
hle/service/erpt/erpt.h
|
||||
hle/service/es/es.cpp
|
||||
@ -517,59 +511,53 @@ add_library(core STATIC
|
||||
hle/service/grc/grc.h
|
||||
hle/service/hid/hid.cpp
|
||||
hle/service/hid/hid.h
|
||||
hle/service/hid/hid_debug_server.cpp
|
||||
hle/service/hid/hid_debug_server.h
|
||||
hle/service/hid/hid_firmware_settings.cpp
|
||||
hle/service/hid/hid_firmware_settings.h
|
||||
hle/service/hid/hid_result.h
|
||||
hle/service/hid/hid_server.cpp
|
||||
hle/service/hid/hid_server.h
|
||||
hle/service/hid/hid_system_server.cpp
|
||||
hle/service/hid/hid_system_server.h
|
||||
hle/service/hid/hid_types.h
|
||||
hle/service/hid/hid_util.h
|
||||
hle/service/hid/hidbus.cpp
|
||||
hle/service/hid/hidbus.h
|
||||
hle/service/hid/irs.cpp
|
||||
hle/service/hid/irs.h
|
||||
hle/service/hid/irs_ring_lifo.h
|
||||
hle/service/hid/ring_lifo.h
|
||||
hle/service/hid/resource_manager.cpp
|
||||
hle/service/hid/resource_manager.h
|
||||
hle/service/hid/xcd.cpp
|
||||
hle/service/hid/xcd.h
|
||||
hle/service/hid/errors.h
|
||||
hle/service/hid/controllers/console_sixaxis.cpp
|
||||
hle/service/hid/controllers/console_sixaxis.h
|
||||
hle/service/hid/controllers/controller_base.cpp
|
||||
hle/service/hid/controllers/controller_base.h
|
||||
hle/service/hid/controllers/debug_pad.cpp
|
||||
hle/service/hid/controllers/debug_pad.h
|
||||
hle/service/hid/controllers/gesture.cpp
|
||||
hle/service/hid/controllers/gesture.h
|
||||
hle/service/hid/controllers/keyboard.cpp
|
||||
hle/service/hid/controllers/keyboard.h
|
||||
hle/service/hid/controllers/mouse.cpp
|
||||
hle/service/hid/controllers/mouse.h
|
||||
hle/service/hid/controllers/npad.cpp
|
||||
hle/service/hid/controllers/npad.h
|
||||
hle/service/hid/controllers/palma.cpp
|
||||
hle/service/hid/controllers/palma.h
|
||||
hle/service/hid/controllers/stubbed.cpp
|
||||
hle/service/hid/controllers/stubbed.h
|
||||
hle/service/hid/controllers/touchscreen.cpp
|
||||
hle/service/hid/controllers/touchscreen.h
|
||||
hle/service/hid/controllers/xpad.cpp
|
||||
hle/service/hid/controllers/xpad.h
|
||||
hle/service/hid/hidbus/hidbus_base.cpp
|
||||
hle/service/hid/hidbus/hidbus_base.h
|
||||
hle/service/hid/hidbus/ringcon.cpp
|
||||
hle/service/hid/hidbus/ringcon.h
|
||||
hle/service/hid/hidbus/starlink.cpp
|
||||
hle/service/hid/hidbus/starlink.h
|
||||
hle/service/hid/hidbus/stubbed.cpp
|
||||
hle/service/hid/hidbus/stubbed.h
|
||||
hle/service/hid/irsensor/clustering_processor.cpp
|
||||
hle/service/hid/irsensor/clustering_processor.h
|
||||
hle/service/hid/irsensor/image_transfer_processor.cpp
|
||||
hle/service/hid/irsensor/image_transfer_processor.h
|
||||
hle/service/hid/irsensor/ir_led_processor.cpp
|
||||
hle/service/hid/irsensor/ir_led_processor.h
|
||||
hle/service/hid/irsensor/moment_processor.cpp
|
||||
hle/service/hid/irsensor/moment_processor.h
|
||||
hle/service/hid/irsensor/pointing_processor.cpp
|
||||
hle/service/hid/irsensor/pointing_processor.h
|
||||
hle/service/hid/irsensor/processor_base.cpp
|
||||
hle/service/hid/irsensor/processor_base.h
|
||||
hle/service/hid/irsensor/tera_plugin_processor.cpp
|
||||
hle/service/hid/irsensor/tera_plugin_processor.h
|
||||
hle/service/hid/resource_manager/npad_resource/npad.cpp
|
||||
hle/service/hid/resource_manager/npad_resource/npad.h
|
||||
hle/service/hid/resource_manager/npad_resource/npad_controller_state.cpp
|
||||
hle/service/hid/resource_manager/npad_resource/npad_controller_state.h
|
||||
hle/service/hid/resource_manager/npad_resource/npad_state.cpp
|
||||
hle/service/hid/resource_manager/npad_resource/npad_state.h
|
||||
hle/service/hid/resource_manager/npad_resource/npad_shared_types.h
|
||||
hle/service/hid/resource_manager/base_resource.cpp
|
||||
hle/service/hid/resource_manager/base_resource.h
|
||||
hle/service/hid/resource_manager/debug_pad.cpp
|
||||
hle/service/hid/resource_manager/debug_pad.h
|
||||
hle/service/hid/resource_manager/gesture.cpp
|
||||
hle/service/hid/resource_manager/gesture.h
|
||||
hle/service/hid/resource_manager/keyboard.cpp
|
||||
hle/service/hid/resource_manager/keyboard.h
|
||||
hle/service/hid/resource_manager/mouse.cpp
|
||||
hle/service/hid/resource_manager/mouse.h
|
||||
hle/service/hid/resource_manager/palma.cpp
|
||||
hle/service/hid/resource_manager/palma.h
|
||||
hle/service/hid/resource_manager/ring_lifo.h
|
||||
hle/service/hid/resource_manager/sixaxis.cpp
|
||||
hle/service/hid/resource_manager/sixaxis.h
|
||||
hle/service/hid/resource_manager/touch_screen.cpp
|
||||
hle/service/hid/resource_manager/touch_screen.h
|
||||
hle/service/hid/hidbus/hidbus_result.h
|
||||
hle/service/hid/hidbus/hidbus_types.h
|
||||
hle/service/hid/irs/irs_result.h
|
||||
hle/service/hid/irs/irs_types.h
|
||||
hle/service/lbl/lbl.cpp
|
||||
hle/service/lbl/lbl.h
|
||||
hle/service/ldn/lan_discovery.cpp
|
||||
@ -781,28 +769,40 @@ add_library(core STATIC
|
||||
hle/service/ssl/ssl.cpp
|
||||
hle/service/ssl/ssl.h
|
||||
hle/service/ssl/ssl_backend.h
|
||||
hle/service/time/clock_interfaces/steady_clock.cpp
|
||||
hle/service/time/clock_interfaces/steady_clock.h
|
||||
hle/service/time/clock_interfaces/system_clock.cpp
|
||||
hle/service/time/clock_interfaces/system_clock.h
|
||||
hle/service/time/clock_types/local_system_clock.cpp
|
||||
hle/service/time/clock_types/local_system_clock.h
|
||||
hle/service/time/clock_types/network_system_clock.cpp
|
||||
hle/service/time/clock_types/network_system_clock.h
|
||||
hle/service/time/clock_types/steady_clock.cpp
|
||||
hle/service/time/clock_types/steady_clock.h
|
||||
hle/service/time/clock_types/user_system_clock.cpp
|
||||
hle/service/time/clock_types/user_system_clock.h
|
||||
hle/service/time/time_zone/time_zone_service.cpp
|
||||
hle/service/time/time_zone/time_zone_service.h
|
||||
hle/service/time/time_zone/time_zone_types.h
|
||||
hle/service/time/clock_types.h
|
||||
hle/service/time/ephemeral_network_system_clock_context_writer.h
|
||||
hle/service/time/ephemeral_network_system_clock_core.h
|
||||
hle/service/time/errors.h
|
||||
hle/service/time/local_system_clock_context_writer.h
|
||||
hle/service/time/network_system_clock_context_writer.h
|
||||
hle/service/time/standard_local_system_clock_core.h
|
||||
hle/service/time/standard_network_system_clock_core.h
|
||||
hle/service/time/standard_steady_clock_core.cpp
|
||||
hle/service/time/standard_steady_clock_core.h
|
||||
hle/service/time/standard_user_system_clock_core.cpp
|
||||
hle/service/time/standard_user_system_clock_core.h
|
||||
hle/service/time/steady_clock_core.h
|
||||
hle/service/time/system_clock_context_update_callback.cpp
|
||||
hle/service/time/system_clock_context_update_callback.h
|
||||
hle/service/time/system_clock_core.cpp
|
||||
hle/service/time/system_clock_core.h
|
||||
hle/service/time/tick_based_steady_clock_core.cpp
|
||||
hle/service/time/tick_based_steady_clock_core.h
|
||||
hle/service/time/time.cpp
|
||||
hle/service/time/time.h
|
||||
hle/service/time/time_interface.cpp
|
||||
hle/service/time/time_interface.h
|
||||
hle/service/time/time_manager.cpp
|
||||
hle/service/time/time_manager.h
|
||||
hle/service/time/time_result.h
|
||||
hle/service/time/time_types.h
|
||||
hle/service/time/time_util.h
|
||||
hle/service/time/time_sharedmemory.cpp
|
||||
hle/service/time/time_sharedmemory.h
|
||||
hle/service/time/time_zone_content_manager.cpp
|
||||
hle/service/time/time_zone_content_manager.h
|
||||
hle/service/time/time_zone_manager.cpp
|
||||
hle/service/time/time_zone_manager.h
|
||||
hle/service/time/time_zone_service.cpp
|
||||
hle/service/time/time_zone_service.h
|
||||
hle/service/time/time_zone_types.h
|
||||
hle/service/usb/usb.cpp
|
||||
hle/service/usb/usb.h
|
||||
hle/service/vi/display/vi_display.cpp
|
||||
|
@ -42,6 +42,7 @@
|
||||
#include "core/hle/service/glue/glue_manager.h"
|
||||
#include "core/hle/service/service.h"
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
#include "core/hle/service/time/time_manager.h"
|
||||
#include "core/internal_network/network.h"
|
||||
#include "core/loader/loader.h"
|
||||
#include "core/memory.h"
|
||||
@ -132,7 +133,7 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
|
||||
struct System::Impl {
|
||||
explicit Impl(System& system)
|
||||
: kernel{system}, fs_controller{system}, memory{system}, hid_core{}, room_network{},
|
||||
cpu_manager{system}, reporter{system}, applet_manager{system},
|
||||
cpu_manager{system}, reporter{system}, applet_manager{system}, time_manager{system},
|
||||
gpu_dirty_memory_write_manager{} {
|
||||
memory.SetGPUDirtyManagers(gpu_dirty_memory_write_manager);
|
||||
}
|
||||
@ -147,6 +148,8 @@ struct System::Impl {
|
||||
core_timing.SetMulticore(is_multicore);
|
||||
core_timing.Initialize([&system]() { system.RegisterHostThread(); });
|
||||
|
||||
RefreshTime();
|
||||
|
||||
// Create a default fs if one doesn't already exist.
|
||||
if (virtual_filesystem == nullptr) {
|
||||
virtual_filesystem = std::make_shared<FileSys::RealVfsFilesystem>();
|
||||
@ -184,6 +187,16 @@ struct System::Impl {
|
||||
Initialize(system);
|
||||
}
|
||||
|
||||
void RefreshTime() {
|
||||
const auto posix_time = std::chrono::system_clock::now().time_since_epoch();
|
||||
const auto current_time =
|
||||
std::chrono::duration_cast<std::chrono::seconds>(posix_time).count();
|
||||
Settings::values.custom_rtc_differential =
|
||||
(Settings::values.custom_rtc_enabled ? Settings::values.custom_rtc.GetValue()
|
||||
: current_time) -
|
||||
current_time;
|
||||
}
|
||||
|
||||
void Run() {
|
||||
std::unique_lock<std::mutex> lk(suspend_guard);
|
||||
|
||||
@ -257,6 +270,9 @@ struct System::Impl {
|
||||
service_manager = std::make_shared<Service::SM::ServiceManager>(kernel);
|
||||
services = std::make_unique<Service::Services>(service_manager, system);
|
||||
|
||||
// Initialize time manager, which must happen after kernel is created
|
||||
time_manager.Initialize();
|
||||
|
||||
is_powered_on = true;
|
||||
exit_locked = false;
|
||||
exit_requested = false;
|
||||
@ -409,6 +425,7 @@ struct System::Impl {
|
||||
service_manager.reset();
|
||||
cheat_engine.reset();
|
||||
telemetry_session.reset();
|
||||
time_manager.Shutdown();
|
||||
core_timing.ClearPendingEvents();
|
||||
app_loader.reset();
|
||||
audio_core.reset();
|
||||
@ -526,6 +543,7 @@ struct System::Impl {
|
||||
|
||||
/// Service State
|
||||
Service::Glue::ARPManager arp_manager;
|
||||
Service::Time::TimeManager time_manager;
|
||||
|
||||
/// Service manager
|
||||
std::shared_ptr<Service::SM::ServiceManager> service_manager;
|
||||
@ -938,6 +956,14 @@ const Service::APM::Controller& System::GetAPMController() const {
|
||||
return impl->apm_controller;
|
||||
}
|
||||
|
||||
Service::Time::TimeManager& System::GetTimeManager() {
|
||||
return impl->time_manager;
|
||||
}
|
||||
|
||||
const Service::Time::TimeManager& System::GetTimeManager() const {
|
||||
return impl->time_manager;
|
||||
}
|
||||
|
||||
void System::SetExitLocked(bool locked) {
|
||||
impl->exit_locked = locked;
|
||||
}
|
||||
@ -1049,7 +1075,13 @@ void System::Exit() {
|
||||
}
|
||||
|
||||
void System::ApplySettings() {
|
||||
impl->RefreshTime();
|
||||
|
||||
if (IsPoweredOn()) {
|
||||
if (Settings::values.custom_rtc_enabled) {
|
||||
const s64 posix_time{Settings::values.custom_rtc.GetValue()};
|
||||
GetTimeManager().UpdateLocalSystemClockTime(posix_time);
|
||||
}
|
||||
Renderer().RefreshBaseSettings();
|
||||
}
|
||||
}
|
||||
|
@ -68,6 +68,10 @@ namespace SM {
|
||||
class ServiceManager;
|
||||
} // namespace SM
|
||||
|
||||
namespace Time {
|
||||
class TimeManager;
|
||||
} // namespace Time
|
||||
|
||||
} // namespace Service
|
||||
|
||||
namespace Tegra {
|
||||
@ -401,6 +405,9 @@ public:
|
||||
[[nodiscard]] Service::APM::Controller& GetAPMController();
|
||||
[[nodiscard]] const Service::APM::Controller& GetAPMController() const;
|
||||
|
||||
[[nodiscard]] Service::Time::TimeManager& GetTimeManager();
|
||||
[[nodiscard]] const Service::Time::TimeManager& GetTimeManager() const;
|
||||
|
||||
[[nodiscard]] Core::Debugger& GetDebugger();
|
||||
[[nodiscard]] const Core::Debugger& GetDebugger() const;
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
#include "common/swap.h"
|
||||
#include "core/file_sys/system_archive/time_zone_binary.h"
|
||||
#include "core/file_sys/vfs_vector.h"
|
||||
#include "core/hle/service/time/time_zone/time_zone_types.h"
|
||||
#include "core/hle/service/time/time_zone_types.h"
|
||||
|
||||
#include "nx_tzdb.h"
|
||||
|
||||
|
@ -6,9 +6,7 @@
|
||||
#include "common/settings.h"
|
||||
#include "common/settings_enums.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"
|
||||
|
||||
namespace Core::Frontend {
|
||||
|
||||
@ -24,54 +22,54 @@ void DefaultControllerApplet::ReconfigureControllers(ReconfigureCallback callbac
|
||||
const ControllerParameters& parameters) const {
|
||||
LOG_INFO(Service_HID, "called, deducing the best configuration based on the given parameters!");
|
||||
|
||||
const std::size_t min_supported_players =
|
||||
parameters.enable_single_mode ? 1 : parameters.min_players;
|
||||
//const std::size_t min_supported_players =
|
||||
// parameters.enable_single_mode ? 1 : parameters.min_players;
|
||||
|
||||
// Disconnect Handheld first.
|
||||
auto* handheld = hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld);
|
||||
handheld->Disconnect();
|
||||
//// Disconnect Handheld first.
|
||||
//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 < hid_core.available_controllers - 2; ++index) {
|
||||
auto* controller = hid_core.GetEmulatedControllerByIndex(index);
|
||||
//// Deduce the best configuration based on the input parameters.
|
||||
//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.
|
||||
controller->Disconnect();
|
||||
// // First, disconnect all controllers regardless of the value of keep_controllers_connected.
|
||||
// // This makes it easy to connect the desired controllers.
|
||||
// controller->Disconnect();
|
||||
|
||||
// Only connect the minimum number of required players.
|
||||
if (index >= min_supported_players) {
|
||||
continue;
|
||||
}
|
||||
// // Only connect the minimum number of required players.
|
||||
// if (index >= min_supported_players) {
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// 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) {
|
||||
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController);
|
||||
controller->Connect(true);
|
||||
} else if (parameters.allow_dual_joycons) {
|
||||
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconDual);
|
||||
controller->Connect(true);
|
||||
} 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) {
|
||||
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconLeft);
|
||||
controller->Connect(true);
|
||||
} else {
|
||||
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconRight);
|
||||
controller->Connect(true);
|
||||
}
|
||||
} else if (index == 0 && parameters.enable_single_mode && parameters.allow_handheld &&
|
||||
!Settings::IsDockedMode()) {
|
||||
// We should *never* reach here under any normal circumstances.
|
||||
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Handheld);
|
||||
controller->Connect(true);
|
||||
} else {
|
||||
ASSERT_MSG(false, "Unable to add a new controller based on the given parameters!");
|
||||
}
|
||||
}
|
||||
// // 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) {
|
||||
// controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController);
|
||||
// controller->Connect(true);
|
||||
// } else if (parameters.allow_dual_joycons) {
|
||||
// controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconDual);
|
||||
// controller->Connect(true);
|
||||
// } 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) {
|
||||
// controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconLeft);
|
||||
// controller->Connect(true);
|
||||
// } else {
|
||||
// controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconRight);
|
||||
// controller->Connect(true);
|
||||
// }
|
||||
// } 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.
|
||||
// controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Handheld);
|
||||
// controller->Connect(true);
|
||||
// } else {
|
||||
// ASSERT_MSG(false, "Unable to add a new controller based on the given parameters!");
|
||||
// }
|
||||
//}
|
||||
|
||||
callback(true);
|
||||
}
|
||||
|
@ -1,324 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#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[0] = Common::ParamPackage(player.motions[0]);
|
||||
|
||||
ReloadInput();
|
||||
}
|
||||
|
||||
void EmulatedConsole::SetTouchParams() {
|
||||
std::size_t index = 0;
|
||||
|
||||
// We can't use mouse as touch if native mouse is enabled
|
||||
if (!Settings::values.mouse_enabled) {
|
||||
touch_params[index++] =
|
||||
Common::ParamPackage{"engine:mouse,axis_x:0,axis_y:1,button:0,port:2"};
|
||||
}
|
||||
|
||||
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"};
|
||||
|
||||
for (int i = 0; i < static_cast<int>(MaxActiveTouchInputs); i++) {
|
||||
Common::ParamPackage touchscreen_param{};
|
||||
touchscreen_param.Set("engine", "touch");
|
||||
touchscreen_param.Set("axis_x", i * 2);
|
||||
touchscreen_param.Set("axis_y", (i * 2) + 1);
|
||||
touchscreen_param.Set("button", i);
|
||||
touch_params[index++] = std::move(touchscreen_param);
|
||||
}
|
||||
|
||||
if (Settings::values.touch_from_button_maps.empty()) {
|
||||
LOG_WARNING(Input, "touch_from_button_maps is unset by frontend config");
|
||||
return;
|
||||
}
|
||||
|
||||
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 >= MaxTouchDevices) {
|
||||
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_params[index] = std::move(touch_button_params);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
void EmulatedConsole::ReloadInput() {
|
||||
// If you load any device here add the equivalent to the UnloadInput() function
|
||||
SetTouchParams();
|
||||
|
||||
motion_params[1] = Common::ParamPackage{"engine:virtual_gamepad,port:8,motion:0"};
|
||||
|
||||
for (std::size_t index = 0; index < motion_devices.size(); ++index) {
|
||||
motion_devices[index] = Common::Input::CreateInputDevice(motion_params[index]);
|
||||
if (!motion_devices[index]) {
|
||||
continue;
|
||||
}
|
||||
motion_devices[index]->SetCallback({
|
||||
.on_change =
|
||||
[this](const Common::Input::CallbackStatus& callback) { SetMotion(callback); },
|
||||
});
|
||||
}
|
||||
|
||||
// Restore motion state
|
||||
auto& emulated_motion = console.motion_values.emulated;
|
||||
auto& motion = console.motion_state;
|
||||
emulated_motion.ResetRotations();
|
||||
emulated_motion.ResetQuaternion();
|
||||
motion.accel = emulated_motion.GetAcceleration();
|
||||
motion.gyro = emulated_motion.GetGyroscope();
|
||||
motion.rotation = emulated_motion.GetRotations();
|
||||
motion.orientation = emulated_motion.GetOrientation();
|
||||
motion.is_at_rest = !emulated_motion.IsMoving(motion_sensitivity);
|
||||
|
||||
// Unique index for identifying touch device source
|
||||
std::size_t index = 0;
|
||||
for (auto& touch_device : touch_devices) {
|
||||
touch_device = Common::Input::CreateInputDevice(touch_params[index]);
|
||||
if (!touch_device) {
|
||||
continue;
|
||||
}
|
||||
touch_device->SetCallback({
|
||||
.on_change =
|
||||
[this, index](const Common::Input::CallbackStatus& callback) {
|
||||
SetTouch(callback, index);
|
||||
},
|
||||
});
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
void EmulatedConsole::UnloadInput() {
|
||||
for (auto& motion : motion_devices) {
|
||||
motion.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[0];
|
||||
}
|
||||
|
||||
void EmulatedConsole::SetMotionParam(Common::ParamPackage param) {
|
||||
motion_params[0] = std::move(param);
|
||||
ReloadInput();
|
||||
}
|
||||
|
||||
void EmulatedConsole::SetMotion(const Common::Input::CallbackStatus& callback) {
|
||||
std::unique_lock 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) {
|
||||
lock.unlock();
|
||||
TriggerOnChange(ConsoleTriggerType::Motion);
|
||||
return;
|
||||
}
|
||||
|
||||
auto& motion = console.motion_state;
|
||||
motion.accel = emulated.GetAcceleration();
|
||||
motion.gyro = emulated.GetGyroscope();
|
||||
motion.rotation = emulated.GetRotations();
|
||||
motion.orientation = emulated.GetOrientation();
|
||||
motion.quaternion = emulated.GetQuaternion();
|
||||
motion.gyro_bias = emulated.GetGyroBias();
|
||||
motion.is_at_rest = !emulated.IsMoving(motion_sensitivity);
|
||||
// Find what is this value
|
||||
motion.verticalization_error = 0.0f;
|
||||
|
||||
lock.unlock();
|
||||
TriggerOnChange(ConsoleTriggerType::Motion);
|
||||
}
|
||||
|
||||
void EmulatedConsole::SetTouch(const Common::Input::CallbackStatus& callback, std::size_t index) {
|
||||
if (index >= MaxTouchDevices) {
|
||||
return;
|
||||
}
|
||||
std::unique_lock lock{mutex};
|
||||
|
||||
const auto touch_input = TransformToTouch(callback);
|
||||
auto touch_index = GetIndexFromFingerId(index);
|
||||
bool is_new_input = false;
|
||||
|
||||
if (!touch_index.has_value() && touch_input.pressed.value) {
|
||||
touch_index = GetNextFreeIndex();
|
||||
is_new_input = true;
|
||||
}
|
||||
|
||||
// No free entries or invalid state. Ignore input
|
||||
if (!touch_index.has_value()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto& touch_value = console.touch_values[touch_index.value()];
|
||||
|
||||
if (is_new_input) {
|
||||
touch_value.pressed.value = true;
|
||||
touch_value.id = static_cast<int>(index);
|
||||
}
|
||||
|
||||
touch_value.x = touch_input.x;
|
||||
touch_value.y = touch_input.y;
|
||||
|
||||
if (!touch_input.pressed.value) {
|
||||
touch_value.pressed.value = false;
|
||||
}
|
||||
|
||||
if (is_configuring) {
|
||||
lock.unlock();
|
||||
TriggerOnChange(ConsoleTriggerType::Touch);
|
||||
return;
|
||||
}
|
||||
|
||||
// Touch outside allowed range. Ignore input
|
||||
if (touch_index.value() >= MaxActiveTouchInputs) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.touch_state[touch_index.value()] = {
|
||||
.position = {touch_value.x.value, touch_value.y.value},
|
||||
.id = static_cast<u32>(touch_index.value()),
|
||||
.pressed = touch_input.pressed.value,
|
||||
};
|
||||
|
||||
lock.unlock();
|
||||
TriggerOnChange(ConsoleTriggerType::Touch);
|
||||
}
|
||||
|
||||
ConsoleMotionValues EmulatedConsole::GetMotionValues() const {
|
||||
std::scoped_lock lock{mutex};
|
||||
return console.motion_values;
|
||||
}
|
||||
|
||||
TouchValues EmulatedConsole::GetTouchValues() const {
|
||||
std::scoped_lock lock{mutex};
|
||||
return console.touch_values;
|
||||
}
|
||||
|
||||
ConsoleMotion EmulatedConsole::GetMotion() const {
|
||||
std::scoped_lock lock{mutex};
|
||||
return console.motion_state;
|
||||
}
|
||||
|
||||
TouchFingerState EmulatedConsole::GetTouch() const {
|
||||
std::scoped_lock lock{mutex};
|
||||
return console.touch_state;
|
||||
}
|
||||
|
||||
std::optional<std::size_t> EmulatedConsole::GetIndexFromFingerId(std::size_t finger_id) const {
|
||||
for (std::size_t index = 0; index < MaxTouchDevices; ++index) {
|
||||
const auto& finger = console.touch_values[index];
|
||||
if (!finger.pressed.value) {
|
||||
continue;
|
||||
}
|
||||
if (finger.id == static_cast<int>(finger_id)) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::size_t> EmulatedConsole::GetNextFreeIndex() const {
|
||||
for (std::size_t index = 0; index < MaxTouchDevices; ++index) {
|
||||
if (!console.touch_values[index].pressed.value) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
void EmulatedConsole::TriggerOnChange(ConsoleTriggerType type) {
|
||||
std::scoped_lock lock{callback_mutex};
|
||||
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::scoped_lock lock{callback_mutex};
|
||||
callback_list.insert_or_assign(last_callback_key, std::move(update_callback));
|
||||
return last_callback_key++;
|
||||
}
|
||||
|
||||
void EmulatedConsole::DeleteCallback(int key) {
|
||||
std::scoped_lock lock{callback_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
|
@ -1,200 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
#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 {
|
||||
static constexpr std::size_t MaxTouchDevices = 32;
|
||||
static constexpr std::size_t MaxActiveTouchInputs = 16;
|
||||
|
||||
struct ConsoleMotionInfo {
|
||||
Common::Input::MotionStatus raw_status{};
|
||||
MotionInput emulated{};
|
||||
};
|
||||
|
||||
using ConsoleMotionDevices = std::array<std::unique_ptr<Common::Input::InputDevice>, 2>;
|
||||
using TouchDevices = std::array<std::unique_ptr<Common::Input::InputDevice>, MaxTouchDevices>;
|
||||
|
||||
using ConsoleMotionParams = std::array<Common::ParamPackage, 2>;
|
||||
using TouchParams = std::array<Common::ParamPackage, MaxTouchDevices>;
|
||||
|
||||
using ConsoleMotionValues = ConsoleMotionInfo;
|
||||
using TouchValues = std::array<Common::Input::TouchStatus, MaxTouchDevices>;
|
||||
|
||||
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{};
|
||||
Common::Vec3f gyro_bias{};
|
||||
f32 verticalization_error{};
|
||||
bool is_at_rest{};
|
||||
};
|
||||
|
||||
using TouchFingerState = std::array<TouchFinger, MaxActiveTouchInputs>;
|
||||
|
||||
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(const 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(const Common::Input::CallbackStatus& callback, std::size_t index);
|
||||
|
||||
std::optional<std::size_t> GetIndexFromFingerId(std::size_t finger_id) const;
|
||||
|
||||
std::optional<std::size_t> GetNextFreeIndex() const;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
mutable std::mutex callback_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
@ -1,615 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/input.h"
|
||||
#include "common/param_package.h"
|
||||
#include "common/settings.h"
|
||||
#include "common/vector_math.h"
|
||||
#include "core/hid/hid_types.h"
|
||||
#include "core/hid/irs_types.h"
|
||||
#include "core/hid/motion_input.h"
|
||||
|
||||
namespace Core::HID {
|
||||
const std::size_t max_emulated_controllers = 2;
|
||||
const std::size_t output_devices_size = 4;
|
||||
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 ColorDevices =
|
||||
std::array<std::unique_ptr<Common::Input::InputDevice>, max_emulated_controllers>;
|
||||
using BatteryDevices =
|
||||
std::array<std::unique_ptr<Common::Input::InputDevice>, max_emulated_controllers>;
|
||||
using CameraDevices =
|
||||
std::array<std::unique_ptr<Common::Input::InputDevice>, max_emulated_controllers>;
|
||||
using RingAnalogDevices =
|
||||
std::array<std::unique_ptr<Common::Input::InputDevice>, max_emulated_controllers>;
|
||||
using NfcDevices =
|
||||
std::array<std::unique_ptr<Common::Input::InputDevice>, max_emulated_controllers>;
|
||||
using OutputDevices = std::array<std::unique_ptr<Common::Input::OutputDevice>, output_devices_size>;
|
||||
|
||||
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 ColorParams = std::array<Common::ParamPackage, max_emulated_controllers>;
|
||||
using BatteryParams = std::array<Common::ParamPackage, max_emulated_controllers>;
|
||||
using CameraParams = std::array<Common::ParamPackage, max_emulated_controllers>;
|
||||
using RingAnalogParams = std::array<Common::ParamPackage, max_emulated_controllers>;
|
||||
using NfcParams = std::array<Common::ParamPackage, max_emulated_controllers>;
|
||||
using OutputParams = std::array<Common::ParamPackage, output_devices_size>;
|
||||
|
||||
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 CameraValues = Common::Input::CameraStatus;
|
||||
using RingAnalogValue = Common::Input::AnalogStatus;
|
||||
using NfcValues = Common::Input::NfcStatus;
|
||||
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 CameraState {
|
||||
Core::IrSensor::ImageTransferProcessorFormat format{};
|
||||
std::vector<u8> data{};
|
||||
std::size_t sample{};
|
||||
};
|
||||
|
||||
struct RingSensorForce {
|
||||
f32 force;
|
||||
};
|
||||
|
||||
using NfcState = Common::Input::NfcStatus;
|
||||
|
||||
struct ControllerMotion {
|
||||
Common::Vec3f accel{};
|
||||
Common::Vec3f gyro{};
|
||||
Common::Vec3f rotation{};
|
||||
Common::Vec3f euler{};
|
||||
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{};
|
||||
CameraValues camera_values{};
|
||||
RingAnalogValue ring_analog_value{};
|
||||
NfcValues nfc_values{};
|
||||
|
||||
// Data for HID services
|
||||
HomeButtonState home_button_state{};
|
||||
CaptureButtonState capture_button_state{};
|
||||
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{};
|
||||
CameraState camera_state{};
|
||||
RingSensorForce ring_analog_state{};
|
||||
NfcState nfc_state{};
|
||||
Common::Input::PollingMode left_polling_mode{};
|
||||
Common::Input::PollingMode right_polling_mode{};
|
||||
};
|
||||
|
||||
enum class ControllerTriggerType {
|
||||
Button,
|
||||
Stick,
|
||||
Trigger,
|
||||
Motion,
|
||||
Color,
|
||||
Battery,
|
||||
Vibration,
|
||||
IrSensor,
|
||||
RingController,
|
||||
Nfc,
|
||||
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 supported controller types. Disconnects the controller if current type is not
|
||||
* supported
|
||||
* @param supported_styles bitflag with supported types
|
||||
*/
|
||||
void SetSupportedNpadStyleTag(NpadStyleTag supported_styles);
|
||||
|
||||
/**
|
||||
* Sets the connected status to true
|
||||
* @param use_temporary_value If true tmp_npad_type will be used
|
||||
*/
|
||||
void Connect(bool use_temporary_value = false);
|
||||
|
||||
/// 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;
|
||||
|
||||
/// 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();
|
||||
|
||||
/// Enables Home and Screenshot buttons
|
||||
void EnableSystemButtons();
|
||||
|
||||
/// Disables Home and Screenshot buttons
|
||||
void DisableSystemButtons();
|
||||
|
||||
/// Sets Home and Screenshot buttons to false
|
||||
void ResetSystemButtons();
|
||||
|
||||
/// 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() 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);
|
||||
|
||||
/// Auto calibrates the current motion devices
|
||||
void StartMotionCalibration();
|
||||
|
||||
/// 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 camera status from the controller with parameters
|
||||
CameraValues GetCameraValues() const;
|
||||
|
||||
/// Returns the latest status of analog input from the ring sensor with parameters
|
||||
RingAnalogValue GetRingSensorValues() const;
|
||||
|
||||
/// Returns the latest status of button input for the hid::HomeButton service
|
||||
HomeButtonState GetHomeButtons() const;
|
||||
|
||||
/// Returns the latest status of button input for the hid::CaptureButton service
|
||||
CaptureButtonState GetCaptureButtons() const;
|
||||
|
||||
/// Returns the latest status of button input for the hid::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;
|
||||
|
||||
/// Returns the latest camera status from the controller
|
||||
const CameraState& GetCamera() const;
|
||||
|
||||
/// Returns the latest ringcon force sensor value
|
||||
RingSensorForce GetRingSensorForce() const;
|
||||
|
||||
/// Returns the latest ntag status from the controller
|
||||
const NfcState& GetNfc() const;
|
||||
|
||||
/**
|
||||
* Sends a specific vibration to the output device
|
||||
* @return true if vibration had no errors
|
||||
*/
|
||||
bool SetVibration(std::size_t device_index, VibrationValue vibration);
|
||||
|
||||
/**
|
||||
* Sends a small vibration to the output device
|
||||
* @return true if SetVibration was successful
|
||||
*/
|
||||
bool IsVibrationEnabled(std::size_t device_index);
|
||||
|
||||
/**
|
||||
* Sets the desired data to be polled from a controller
|
||||
* @param device_index index of the controller to set the polling mode
|
||||
* @param polling_mode type of input desired buttons, gyro, nfc, ir, etc.
|
||||
* @return driver result from this command
|
||||
*/
|
||||
Common::Input::DriverResult SetPollingMode(EmulatedDeviceIndex device_index,
|
||||
Common::Input::PollingMode polling_mode);
|
||||
/**
|
||||
* Get the current polling mode from a controller
|
||||
* @param device_index index of the controller to set the polling mode
|
||||
* @return current polling mode
|
||||
*/
|
||||
Common::Input::PollingMode GetPollingMode(EmulatedDeviceIndex device_index) const;
|
||||
|
||||
/**
|
||||
* Sets the desired camera format to be polled from a controller
|
||||
* @param camera_format size of each frame
|
||||
* @return true if SetCameraFormat was successful
|
||||
*/
|
||||
bool SetCameraFormat(Core::IrSensor::ImageTransferProcessorFormat camera_format);
|
||||
|
||||
// Returns the current mapped ring device
|
||||
Common::ParamPackage GetRingParam() const;
|
||||
|
||||
/**
|
||||
* Updates the current mapped ring device
|
||||
* @param param ParamPackage with ring sensor data to be mapped
|
||||
*/
|
||||
void SetRingParam(Common::ParamPackage param);
|
||||
|
||||
/// Returns true if the device has nfc support
|
||||
bool HasNfc() const;
|
||||
|
||||
/// Sets the joycon in nfc mode and increments the handle count
|
||||
bool AddNfcHandle();
|
||||
|
||||
/// Decrements the handle count if zero sets the joycon in active mode
|
||||
bool RemoveNfcHandle();
|
||||
|
||||
/// Start searching for nfc tags
|
||||
bool StartNfcPolling();
|
||||
|
||||
/// Stop searching for nfc tags
|
||||
bool StopNfcPolling();
|
||||
|
||||
/// Returns true if the nfc tag was readable
|
||||
bool ReadAmiiboData(std::vector<u8>& data);
|
||||
|
||||
/// Returns true if the nfc tag was written
|
||||
bool WriteNfc(const std::vector<u8>& data);
|
||||
|
||||
/// Returns true if the nfc tag was readable
|
||||
bool ReadMifareData(const Common::Input::MifareRequest& request,
|
||||
Common::Input::MifareRequest& out_data);
|
||||
|
||||
/// Returns true if the nfc tag was written
|
||||
bool WriteMifareData(const Common::Input::MifareRequest& request);
|
||||
|
||||
/// Returns the led pattern corresponding to this emulated controller
|
||||
LedPattern GetLedPattern() const;
|
||||
|
||||
/// Asks the output device to change the player led pattern
|
||||
void SetLedPattern();
|
||||
|
||||
/// Changes sensitivity of the motion sensor
|
||||
void SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode mode);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/// Swaps the state of the turbo buttons and updates motion input
|
||||
void StatusUpdate();
|
||||
|
||||
private:
|
||||
/// creates input devices from params
|
||||
void LoadDevices();
|
||||
|
||||
/// Set the params for TAS devices
|
||||
void LoadTASParams();
|
||||
|
||||
/// Set the params for virtual pad devices
|
||||
void LoadVirtualGamepadParams();
|
||||
|
||||
/**
|
||||
* @param use_temporary_value If true tmp_npad_type will be used
|
||||
* @return true if the controller style is fullkey
|
||||
*/
|
||||
bool IsControllerFullkey(bool use_temporary_value = false) const;
|
||||
|
||||
/**
|
||||
* Checks the current controller type against the supported_style_tag
|
||||
* @param use_temporary_value If true tmp_npad_type will be used
|
||||
* @return true if the controller is supported
|
||||
*/
|
||||
bool IsControllerSupported(bool use_temporary_value = false) const;
|
||||
|
||||
/**
|
||||
* 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(const 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(const 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(const 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(const Common::Input::CallbackStatus& callback, std::size_t index);
|
||||
|
||||
/**
|
||||
* Updates the color status of the controller
|
||||
* @param callback A CallbackStatus containing the color status
|
||||
* @param index color ID of the to be updated
|
||||
*/
|
||||
void SetColors(const 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 battery ID of the to be updated
|
||||
*/
|
||||
void SetBattery(const Common::Input::CallbackStatus& callback, std::size_t index);
|
||||
|
||||
/**
|
||||
* Updates the camera status of the controller
|
||||
* @param callback A CallbackStatus containing the camera status
|
||||
*/
|
||||
void SetCamera(const Common::Input::CallbackStatus& callback);
|
||||
|
||||
/**
|
||||
* Updates the ring analog sensor status of the ring controller
|
||||
* @param callback A CallbackStatus containing the force status
|
||||
*/
|
||||
void SetRingAnalog(const Common::Input::CallbackStatus& callback);
|
||||
|
||||
/**
|
||||
* Updates the nfc status of the controller
|
||||
* @param callback A CallbackStatus containing the nfc status
|
||||
*/
|
||||
void SetNfc(const Common::Input::CallbackStatus& callback);
|
||||
|
||||
/**
|
||||
* Converts a color format from bgra to rgba
|
||||
* @param color in bgra format
|
||||
* @return NpadColor in rgba format
|
||||
*/
|
||||
NpadColor GetNpadColor(u32 color);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
NpadButton GetTurboButtonMask() const;
|
||||
|
||||
const NpadIdType npad_id_type;
|
||||
NpadStyleIndex npad_type{NpadStyleIndex::None};
|
||||
NpadStyleIndex original_npad_type{NpadStyleIndex::None};
|
||||
NpadStyleTag supported_style_tag{NpadStyleSet::All};
|
||||
bool is_connected{false};
|
||||
bool is_configuring{false};
|
||||
bool system_buttons_enabled{true};
|
||||
f32 motion_sensitivity{Core::HID::MotionInput::IsAtRestStandard};
|
||||
u32 turbo_button_state{0};
|
||||
std::size_t nfc_handles{0};
|
||||
|
||||
// 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;
|
||||
ColorParams color_params;
|
||||
CameraParams camera_params;
|
||||
RingAnalogParams ring_params;
|
||||
NfcParams nfc_params;
|
||||
OutputParams output_params;
|
||||
|
||||
ButtonDevices button_devices;
|
||||
StickDevices stick_devices;
|
||||
ControllerMotionDevices motion_devices;
|
||||
TriggerDevices trigger_devices;
|
||||
BatteryDevices battery_devices;
|
||||
ColorDevices color_devices;
|
||||
CameraDevices camera_devices;
|
||||
RingAnalogDevices ring_analog_devices;
|
||||
NfcDevices nfc_devices;
|
||||
OutputDevices output_devices;
|
||||
|
||||
// TAS related variables
|
||||
ButtonParams tas_button_params;
|
||||
StickParams tas_stick_params;
|
||||
ButtonDevices tas_button_devices;
|
||||
StickDevices tas_stick_devices;
|
||||
|
||||
// Virtual gamepad related variables
|
||||
ButtonParams virtual_button_params;
|
||||
StickParams virtual_stick_params;
|
||||
ControllerMotionParams virtual_motion_params;
|
||||
ButtonDevices virtual_button_devices;
|
||||
StickDevices virtual_stick_devices;
|
||||
ControllerMotionDevices virtual_motion_devices;
|
||||
|
||||
mutable std::mutex mutex;
|
||||
mutable std::mutex callback_mutex;
|
||||
mutable std::mutex npad_mutex;
|
||||
mutable std::mutex connect_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
|
@ -1,483 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#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
|
||||
|
||||
// Native Mouse is mapped on port 1, pad 0
|
||||
const Common::ParamPackage mouse_params{"engine:mouse,port:1,pad:0"};
|
||||
|
||||
// Keyboard keys is mapped on port 1, pad 0 for normal keys, pad 1 for moddifier keys
|
||||
const Common::ParamPackage keyboard_params{"engine:keyboard,port:1"};
|
||||
|
||||
std::size_t key_index = 0;
|
||||
for (auto& mouse_device : mouse_button_devices) {
|
||||
Common::ParamPackage mouse_button_params = mouse_params;
|
||||
mouse_button_params.Set("button", static_cast<int>(key_index));
|
||||
mouse_device = Common::Input::CreateInputDevice(mouse_button_params);
|
||||
key_index++;
|
||||
}
|
||||
|
||||
Common::ParamPackage mouse_position_params = mouse_params;
|
||||
mouse_position_params.Set("axis_x", 0);
|
||||
mouse_position_params.Set("axis_y", 1);
|
||||
mouse_position_params.Set("deadzone", 0.0f);
|
||||
mouse_position_params.Set("range", 1.0f);
|
||||
mouse_position_params.Set("threshold", 0.0f);
|
||||
mouse_stick_device = Common::Input::CreateInputDevice(mouse_position_params);
|
||||
|
||||
// First two axis are reserved for mouse position
|
||||
key_index = 2;
|
||||
for (auto& mouse_device : mouse_wheel_devices) {
|
||||
Common::ParamPackage mouse_wheel_params = mouse_params;
|
||||
mouse_wheel_params.Set("axis", static_cast<int>(key_index));
|
||||
mouse_device = Common::Input::CreateInputDevice(mouse_wheel_params);
|
||||
key_index++;
|
||||
}
|
||||
|
||||
key_index = 0;
|
||||
for (auto& keyboard_device : keyboard_devices) {
|
||||
Common::ParamPackage keyboard_key_params = keyboard_params;
|
||||
keyboard_key_params.Set("button", static_cast<int>(key_index));
|
||||
keyboard_key_params.Set("pad", 0);
|
||||
keyboard_device = Common::Input::CreateInputDevice(keyboard_key_params);
|
||||
key_index++;
|
||||
}
|
||||
|
||||
key_index = 0;
|
||||
for (auto& keyboard_device : keyboard_modifier_devices) {
|
||||
Common::ParamPackage keyboard_moddifier_params = keyboard_params;
|
||||
keyboard_moddifier_params.Set("button", static_cast<int>(key_index));
|
||||
keyboard_moddifier_params.Set("pad", 1);
|
||||
keyboard_device = Common::Input::CreateInputDevice(keyboard_moddifier_params);
|
||||
key_index++;
|
||||
}
|
||||
|
||||
for (std::size_t index = 0; index < mouse_button_devices.size(); ++index) {
|
||||
if (!mouse_button_devices[index]) {
|
||||
continue;
|
||||
}
|
||||
mouse_button_devices[index]->SetCallback({
|
||||
.on_change =
|
||||
[this, index](const Common::Input::CallbackStatus& callback) {
|
||||
SetMouseButton(callback, index);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
for (std::size_t index = 0; index < mouse_wheel_devices.size(); ++index) {
|
||||
if (!mouse_wheel_devices[index]) {
|
||||
continue;
|
||||
}
|
||||
mouse_wheel_devices[index]->SetCallback({
|
||||
.on_change =
|
||||
[this, index](const Common::Input::CallbackStatus& callback) {
|
||||
SetMouseWheel(callback, index);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (mouse_stick_device) {
|
||||
mouse_stick_device->SetCallback({
|
||||
.on_change =
|
||||
[this](const Common::Input::CallbackStatus& callback) {
|
||||
SetMousePosition(callback);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
for (std::size_t index = 0; index < keyboard_devices.size(); ++index) {
|
||||
if (!keyboard_devices[index]) {
|
||||
continue;
|
||||
}
|
||||
keyboard_devices[index]->SetCallback({
|
||||
.on_change =
|
||||
[this, index](const Common::Input::CallbackStatus& callback) {
|
||||
SetKeyboardButton(callback, index);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
for (std::size_t index = 0; index < keyboard_modifier_devices.size(); ++index) {
|
||||
if (!keyboard_modifier_devices[index]) {
|
||||
continue;
|
||||
}
|
||||
keyboard_modifier_devices[index]->SetCallback({
|
||||
.on_change =
|
||||
[this, index](const Common::Input::CallbackStatus& callback) {
|
||||
SetKeyboardModifier(callback, index);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void EmulatedDevices::UnloadInput() {
|
||||
for (auto& button : mouse_button_devices) {
|
||||
button.reset();
|
||||
}
|
||||
for (auto& analog : mouse_wheel_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(const Common::Input::CallbackStatus& callback,
|
||||
std::size_t index) {
|
||||
if (index >= device_status.keyboard_values.size()) {
|
||||
return;
|
||||
}
|
||||
std::unique_lock 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) {
|
||||
lock.unlock();
|
||||
TriggerOnChange(DeviceTriggerType::Keyboard);
|
||||
return;
|
||||
}
|
||||
|
||||
// Index should be converted from NativeKeyboard to KeyboardKeyIndex
|
||||
UpdateKey(index, current_status.value);
|
||||
|
||||
lock.unlock();
|
||||
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(const Common::Input::CallbackStatus& callback,
|
||||
std::size_t index) {
|
||||
if (index >= device_status.keyboard_moddifier_values.size()) {
|
||||
return;
|
||||
}
|
||||
std::unique_lock 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) {
|
||||
lock.unlock();
|
||||
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;
|
||||
}
|
||||
|
||||
lock.unlock();
|
||||
TriggerOnChange(DeviceTriggerType::KeyboardModdifier);
|
||||
}
|
||||
|
||||
void EmulatedDevices::SetMouseButton(const Common::Input::CallbackStatus& callback,
|
||||
std::size_t index) {
|
||||
if (index >= device_status.mouse_button_values.size()) {
|
||||
return;
|
||||
}
|
||||
std::unique_lock 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) {
|
||||
lock.unlock();
|
||||
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;
|
||||
}
|
||||
|
||||
lock.unlock();
|
||||
TriggerOnChange(DeviceTriggerType::Mouse);
|
||||
}
|
||||
|
||||
void EmulatedDevices::SetMouseWheel(const Common::Input::CallbackStatus& callback,
|
||||
std::size_t index) {
|
||||
if (index >= device_status.mouse_wheel_values.size()) {
|
||||
return;
|
||||
}
|
||||
std::unique_lock lock{mutex};
|
||||
const auto analog_value = TransformToAnalog(callback);
|
||||
|
||||
device_status.mouse_wheel_values[index] = analog_value;
|
||||
|
||||
if (is_configuring) {
|
||||
device_status.mouse_wheel_state = {};
|
||||
lock.unlock();
|
||||
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;
|
||||
}
|
||||
|
||||
lock.unlock();
|
||||
TriggerOnChange(DeviceTriggerType::Mouse);
|
||||
}
|
||||
|
||||
void EmulatedDevices::SetMousePosition(const Common::Input::CallbackStatus& callback) {
|
||||
std::unique_lock lock{mutex};
|
||||
const auto touch_value = TransformToTouch(callback);
|
||||
|
||||
device_status.mouse_stick_value = touch_value;
|
||||
|
||||
if (is_configuring) {
|
||||
device_status.mouse_position_state = {};
|
||||
lock.unlock();
|
||||
TriggerOnChange(DeviceTriggerType::Mouse);
|
||||
return;
|
||||
}
|
||||
|
||||
device_status.mouse_position_state.x = touch_value.x.value;
|
||||
device_status.mouse_position_state.y = touch_value.y.value;
|
||||
|
||||
lock.unlock();
|
||||
TriggerOnChange(DeviceTriggerType::Mouse);
|
||||
}
|
||||
|
||||
KeyboardValues EmulatedDevices::GetKeyboardValues() const {
|
||||
std::scoped_lock lock{mutex};
|
||||
return device_status.keyboard_values;
|
||||
}
|
||||
|
||||
KeyboardModifierValues EmulatedDevices::GetKeyboardModdifierValues() const {
|
||||
std::scoped_lock lock{mutex};
|
||||
return device_status.keyboard_moddifier_values;
|
||||
}
|
||||
|
||||
MouseButtonValues EmulatedDevices::GetMouseButtonsValues() const {
|
||||
std::scoped_lock lock{mutex};
|
||||
return device_status.mouse_button_values;
|
||||
}
|
||||
|
||||
KeyboardKey EmulatedDevices::GetKeyboard() const {
|
||||
std::scoped_lock lock{mutex};
|
||||
return device_status.keyboard_state;
|
||||
}
|
||||
|
||||
KeyboardModifier EmulatedDevices::GetKeyboardModifier() const {
|
||||
std::scoped_lock lock{mutex};
|
||||
return device_status.keyboard_moddifier_state;
|
||||
}
|
||||
|
||||
MouseButton EmulatedDevices::GetMouseButtons() const {
|
||||
std::scoped_lock lock{mutex};
|
||||
return device_status.mouse_button_state;
|
||||
}
|
||||
|
||||
MousePosition EmulatedDevices::GetMousePosition() const {
|
||||
std::scoped_lock lock{mutex};
|
||||
return device_status.mouse_position_state;
|
||||
}
|
||||
|
||||
AnalogStickState EmulatedDevices::GetMouseWheel() const {
|
||||
std::scoped_lock lock{mutex};
|
||||
return device_status.mouse_wheel_state;
|
||||
}
|
||||
|
||||
void EmulatedDevices::TriggerOnChange(DeviceTriggerType type) {
|
||||
std::scoped_lock lock{callback_mutex};
|
||||
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::scoped_lock lock{callback_mutex};
|
||||
callback_list.insert_or_assign(last_callback_key, std::move(update_callback));
|
||||
return last_callback_key++;
|
||||
}
|
||||
|
||||
void EmulatedDevices::DeleteCallback(int key) {
|
||||
std::scoped_lock lock{callback_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
|
@ -1,212 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#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 MouseWheelDevices = 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 MouseWheelValues =
|
||||
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{};
|
||||
MouseWheelValues mouse_wheel_values{};
|
||||
MouseStickValue mouse_stick_value{};
|
||||
|
||||
// Data for HID services
|
||||
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,
|
||||
RingController,
|
||||
};
|
||||
|
||||
struct InterfaceUpdateCallback {
|
||||
std::function<void(DeviceTriggerType)> on_change;
|
||||
};
|
||||
|
||||
class EmulatedDevices {
|
||||
public:
|
||||
/**
|
||||
* Contains all input data related to external devices that aren't necessarily 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(const 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(const 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(const 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 SetMouseWheel(const 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
|
||||
*/
|
||||
void SetMousePosition(const 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;
|
||||
MouseWheelDevices mouse_wheel_devices;
|
||||
MouseStickDevice mouse_stick_device;
|
||||
|
||||
mutable std::mutex mutex;
|
||||
mutable std::mutex callback_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
|
@ -2,220 +2,12 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#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() {}
|
||||
|
||||
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:
|
||||
ASSERT_MSG(false, "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:
|
||||
ASSERT_MSG(false, "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;
|
||||
player_1->SetSupportedNpadStyleTag(supported_style_tag);
|
||||
player_2->SetSupportedNpadStyleTag(supported_style_tag);
|
||||
player_3->SetSupportedNpadStyleTag(supported_style_tag);
|
||||
player_4->SetSupportedNpadStyleTag(supported_style_tag);
|
||||
player_5->SetSupportedNpadStyleTag(supported_style_tag);
|
||||
player_6->SetSupportedNpadStyleTag(supported_style_tag);
|
||||
player_7->SetSupportedNpadStyleTag(supported_style_tag);
|
||||
player_8->SetSupportedNpadStyleTag(supported_style_tag);
|
||||
other->SetSupportedNpadStyleTag(supported_style_tag);
|
||||
handheld->SetSupportedNpadStyleTag(supported_style_tag);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
NpadIdType HIDCore::GetFirstDisconnectedNpadId() 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::SetLastActiveController(NpadIdType npad_id) {
|
||||
last_active_controller = npad_id;
|
||||
}
|
||||
|
||||
NpadIdType HIDCore::GetLastActiveController() const {
|
||||
return last_active_controller;
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -6,13 +6,6 @@
|
||||
#include <memory>
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
#include "core/hid/hid_types.h"
|
||||
|
||||
namespace Core::HID {
|
||||
class EmulatedConsole;
|
||||
class EmulatedController;
|
||||
class EmulatedDevices;
|
||||
} // namespace Core::HID
|
||||
|
||||
namespace Core::HID {
|
||||
|
||||
@ -23,67 +16,6 @@ public:
|
||||
|
||||
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;
|
||||
|
||||
/// Returns the first disconnected npad id
|
||||
NpadIdType GetFirstDisconnectedNpadId() const;
|
||||
|
||||
/// Sets the npad id of the last active controller
|
||||
void SetLastActiveController(NpadIdType npad_id);
|
||||
|
||||
/// Returns the npad id of the last controller that pushed a button
|
||||
NpadIdType GetLastActiveController() 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{NpadStyleSet::All};
|
||||
NpadIdType last_active_controller{NpadIdType::Handheld};
|
||||
};
|
||||
|
||||
} // namespace Core::HID
|
||||
|
@ -1,60 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/core.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"
|
||||
|
||||
InputInterpreter::InputInterpreter(Core::System& system)
|
||||
: npad{system.ServiceManager()
|
||||
.GetService<Service::HID::Hid>("hid")
|
||||
->GetAppletResource()
|
||||
->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad)} {
|
||||
ResetButtonStates();
|
||||
}
|
||||
|
||||
InputInterpreter::~InputInterpreter() = default;
|
||||
|
||||
void InputInterpreter::PollInput() {
|
||||
const auto button_state = npad.GetAndResetPressState();
|
||||
|
||||
previous_index = current_index;
|
||||
current_index = (current_index + 1) % button_states.size();
|
||||
|
||||
button_states[current_index] = button_state;
|
||||
}
|
||||
|
||||
void InputInterpreter::ResetButtonStates() {
|
||||
previous_index = 0;
|
||||
current_index = 0;
|
||||
|
||||
button_states[0] = Core::HID::NpadButton::All;
|
||||
|
||||
for (std::size_t i = 1; i < button_states.size(); ++i) {
|
||||
button_states[i] = Core::HID::NpadButton::None;
|
||||
}
|
||||
}
|
||||
|
||||
bool InputInterpreter::IsButtonPressed(Core::HID::NpadButton button) const {
|
||||
return True(button_states[current_index] & button);
|
||||
}
|
||||
|
||||
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(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 True(held_buttons & button);
|
||||
}
|
@ -1,111 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Core::HID {
|
||||
enum class NpadButton : u64;
|
||||
}
|
||||
|
||||
namespace Service::HID {
|
||||
class Controller_NPad;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* held down after 400ms has elapsed since the initial button press and subsequent
|
||||
* repeated presses occur every 50ms.
|
||||
*/
|
||||
class InputInterpreter {
|
||||
public:
|
||||
explicit InputInterpreter(Core::System& system);
|
||||
virtual ~InputInterpreter();
|
||||
|
||||
/// Gets a button state from HID and inserts it into the array of button states.
|
||||
void PollInput();
|
||||
|
||||
/// Resets all the button states to their defaults.
|
||||
void ResetButtonStates();
|
||||
|
||||
/**
|
||||
* Checks whether the button is pressed.
|
||||
*
|
||||
* @param button The button to check.
|
||||
*
|
||||
* @returns True when the button is pressed.
|
||||
*/
|
||||
[[nodiscard]] bool IsButtonPressed(Core::HID::NpadButton button) const;
|
||||
|
||||
/**
|
||||
* Checks whether any of the buttons in the parameter list is pressed.
|
||||
*
|
||||
* @tparam HIDButton The buttons to check.
|
||||
*
|
||||
* @returns True when at least one of the buttons is pressed.
|
||||
*/
|
||||
template <Core::HID::NpadButton... T>
|
||||
[[nodiscard]] bool IsAnyButtonPressed() {
|
||||
return (IsButtonPressed(T) || ...);
|
||||
}
|
||||
|
||||
/**
|
||||
* The specified button is considered to be pressed once
|
||||
* if it is currently pressed and not pressed previously.
|
||||
*
|
||||
* @param button The button to check.
|
||||
*
|
||||
* @returns True when the button is pressed once.
|
||||
*/
|
||||
[[nodiscard]] bool IsButtonPressedOnce(Core::HID::NpadButton button) const;
|
||||
|
||||
/**
|
||||
* Checks whether any of the buttons in the parameter list is pressed once.
|
||||
*
|
||||
* @tparam T The buttons to check.
|
||||
*
|
||||
* @returns True when at least one of the buttons is pressed once.
|
||||
*/
|
||||
template <Core::HID::NpadButton... T>
|
||||
[[nodiscard]] bool IsAnyButtonPressedOnce() const {
|
||||
return (IsButtonPressedOnce(T) || ...);
|
||||
}
|
||||
|
||||
/**
|
||||
* The specified button is considered to be held down if it is pressed in all 9 button states.
|
||||
*
|
||||
* @param button The button to check.
|
||||
*
|
||||
* @returns True when the button is held down.
|
||||
*/
|
||||
[[nodiscard]] bool IsButtonHeld(Core::HID::NpadButton button) const;
|
||||
|
||||
/**
|
||||
* Checks whether any of the buttons in the parameter list is held down.
|
||||
*
|
||||
* @tparam T The buttons to check.
|
||||
*
|
||||
* @returns True when at least one of the buttons is held down.
|
||||
*/
|
||||
template <Core::HID::NpadButton... T>
|
||||
[[nodiscard]] bool IsAnyButtonHeld() const {
|
||||
return (IsButtonHeld(T) || ...);
|
||||
}
|
||||
|
||||
private:
|
||||
Service::HID::Controller_NPad& npad;
|
||||
|
||||
/// Stores 9 consecutive button states polled from HID.
|
||||
std::array<Core::HID::NpadButton, 9> button_states{};
|
||||
|
||||
std::size_t previous_index{};
|
||||
std::size_t current_index{};
|
||||
};
|
@ -2949,6 +2949,23 @@ Result KPageTable::UnlockForIpcUserBuffer(KProcessAddress address, size_t size)
|
||||
KMemoryAttribute::Locked, nullptr));
|
||||
}
|
||||
|
||||
Result KPageTable::LockForTransferMemory(KPageGroup* out, KProcessAddress address, size_t size,
|
||||
KMemoryPermission perm) {
|
||||
R_RETURN(this->LockMemoryAndOpen(out, nullptr, address, size, KMemoryState::FlagCanTransfer,
|
||||
KMemoryState::FlagCanTransfer, KMemoryPermission::All,
|
||||
KMemoryPermission::UserReadWrite, KMemoryAttribute::All,
|
||||
KMemoryAttribute::None, perm, KMemoryAttribute::Locked));
|
||||
}
|
||||
|
||||
Result KPageTable::UnlockForTransferMemory(KProcessAddress address, size_t size,
|
||||
const KPageGroup& pg) {
|
||||
R_RETURN(this->UnlockMemory(address, size, KMemoryState::FlagCanTransfer,
|
||||
KMemoryState::FlagCanTransfer, KMemoryPermission::None,
|
||||
KMemoryPermission::None, KMemoryAttribute::All,
|
||||
KMemoryAttribute::Locked, KMemoryPermission::UserReadWrite,
|
||||
KMemoryAttribute::Locked, std::addressof(pg)));
|
||||
}
|
||||
|
||||
Result KPageTable::LockForCodeMemory(KPageGroup* out, KProcessAddress addr, size_t size) {
|
||||
R_RETURN(this->LockMemoryAndOpen(
|
||||
out, nullptr, addr, size, KMemoryState::FlagCanCodeMemory, KMemoryState::FlagCanCodeMemory,
|
||||
|
@ -104,6 +104,9 @@ public:
|
||||
Result CleanupForIpcServer(KProcessAddress address, size_t size, KMemoryState dst_state);
|
||||
Result CleanupForIpcClient(KProcessAddress address, size_t size, KMemoryState dst_state);
|
||||
|
||||
Result LockForTransferMemory(KPageGroup* out, KProcessAddress address, size_t size,
|
||||
KMemoryPermission perm);
|
||||
Result UnlockForTransferMemory(KProcessAddress address, size_t size, const KPageGroup& pg);
|
||||
Result LockForCodeMemory(KPageGroup* out, KProcessAddress addr, size_t size);
|
||||
Result UnlockForCodeMemory(KProcessAddress addr, size_t size, const KPageGroup& pg);
|
||||
Result MakeAndOpenPageGroup(KPageGroup* out, KProcessAddress address, size_t num_pages,
|
||||
|
@ -1,6 +1,7 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/scope_exit.h"
|
||||
#include "core/hle/kernel/k_process.h"
|
||||
#include "core/hle/kernel/k_resource_limit.h"
|
||||
#include "core/hle/kernel/k_transfer_memory.h"
|
||||
@ -9,28 +10,50 @@
|
||||
namespace Kernel {
|
||||
|
||||
KTransferMemory::KTransferMemory(KernelCore& kernel)
|
||||
: KAutoObjectWithSlabHeapAndContainer{kernel} {}
|
||||
: KAutoObjectWithSlabHeapAndContainer{kernel}, m_lock{kernel} {}
|
||||
|
||||
KTransferMemory::~KTransferMemory() = default;
|
||||
|
||||
Result KTransferMemory::Initialize(KProcessAddress address, std::size_t size,
|
||||
Svc::MemoryPermission owner_perm) {
|
||||
Result KTransferMemory::Initialize(KProcessAddress addr, std::size_t size,
|
||||
Svc::MemoryPermission own_perm) {
|
||||
// Set members.
|
||||
m_owner = GetCurrentProcessPointer(m_kernel);
|
||||
|
||||
// TODO(bunnei): Lock for transfer memory
|
||||
// Get the owner page table.
|
||||
auto& page_table = m_owner->GetPageTable();
|
||||
|
||||
// Construct the page group, guarding to make sure our state is valid on exit.
|
||||
m_page_group.emplace(m_kernel, page_table.GetBlockInfoManager());
|
||||
auto pg_guard = SCOPE_GUARD({ m_page_group.reset(); });
|
||||
|
||||
// Lock the memory.
|
||||
R_TRY(page_table.LockForTransferMemory(std::addressof(*m_page_group), addr, size,
|
||||
ConvertToKMemoryPermission(own_perm)));
|
||||
|
||||
// Set remaining tracking members.
|
||||
m_owner->Open();
|
||||
m_owner_perm = owner_perm;
|
||||
m_address = address;
|
||||
m_size = size;
|
||||
m_owner_perm = own_perm;
|
||||
m_address = addr;
|
||||
m_is_initialized = true;
|
||||
m_is_mapped = false;
|
||||
|
||||
// We succeeded.
|
||||
pg_guard.Cancel();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void KTransferMemory::Finalize() {}
|
||||
void KTransferMemory::Finalize() {
|
||||
// Unlock.
|
||||
if (!m_is_mapped) {
|
||||
const size_t size = m_page_group->GetNumPages() * PageSize;
|
||||
ASSERT(R_SUCCEEDED(
|
||||
m_owner->GetPageTable().UnlockForTransferMemory(m_address, size, *m_page_group)));
|
||||
}
|
||||
|
||||
// Close the page group.
|
||||
m_page_group->Close();
|
||||
m_page_group->Finalize();
|
||||
}
|
||||
|
||||
void KTransferMemory::PostDestroy(uintptr_t arg) {
|
||||
KProcess* owner = reinterpret_cast<KProcess*>(arg);
|
||||
@ -38,4 +61,54 @@ void KTransferMemory::PostDestroy(uintptr_t arg) {
|
||||
owner->Close();
|
||||
}
|
||||
|
||||
Result KTransferMemory::Map(KProcessAddress address, size_t size, Svc::MemoryPermission map_perm) {
|
||||
// Validate the size.
|
||||
R_UNLESS(m_page_group->GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize);
|
||||
|
||||
// Validate the permission.
|
||||
R_UNLESS(m_owner_perm == map_perm, ResultInvalidState);
|
||||
|
||||
// Lock ourselves.
|
||||
KScopedLightLock lk(m_lock);
|
||||
|
||||
// Ensure we're not already mapped.
|
||||
R_UNLESS(!m_is_mapped, ResultInvalidState);
|
||||
|
||||
// Map the memory.
|
||||
const KMemoryState state = (m_owner_perm == Svc::MemoryPermission::None)
|
||||
? KMemoryState::Transfered
|
||||
: KMemoryState::SharedTransfered;
|
||||
R_TRY(GetCurrentProcess(m_kernel).GetPageTable().MapPageGroup(
|
||||
address, *m_page_group, state, KMemoryPermission::UserReadWrite));
|
||||
|
||||
// Mark ourselves as mapped.
|
||||
m_is_mapped = true;
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result KTransferMemory::Unmap(KProcessAddress address, size_t size) {
|
||||
// Validate the size.
|
||||
R_UNLESS(m_page_group->GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize);
|
||||
|
||||
// Lock ourselves.
|
||||
KScopedLightLock lk(m_lock);
|
||||
|
||||
// Unmap the memory.
|
||||
const KMemoryState state = (m_owner_perm == Svc::MemoryPermission::None)
|
||||
? KMemoryState::Transfered
|
||||
: KMemoryState::SharedTransfered;
|
||||
R_TRY(GetCurrentProcess(m_kernel).GetPageTable().UnmapPageGroup(address, *m_page_group, state));
|
||||
|
||||
// Mark ourselves as unmapped.
|
||||
ASSERT(m_is_mapped);
|
||||
m_is_mapped = false;
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
size_t KTransferMemory::GetSize() const {
|
||||
return m_is_initialized ? m_page_group->GetNumPages() * PageSize : 0;
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
|
@ -3,6 +3,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "core/hle/kernel/k_page_group.h"
|
||||
#include "core/hle/kernel/slab_helpers.h"
|
||||
#include "core/hle/kernel/svc_types.h"
|
||||
#include "core/hle/result.h"
|
||||
@ -48,16 +51,19 @@ public:
|
||||
return m_address;
|
||||
}
|
||||
|
||||
size_t GetSize() const {
|
||||
return m_is_initialized ? m_size : 0;
|
||||
}
|
||||
size_t GetSize() const;
|
||||
|
||||
Result Map(KProcessAddress address, size_t size, Svc::MemoryPermission map_perm);
|
||||
Result Unmap(KProcessAddress address, size_t size);
|
||||
|
||||
private:
|
||||
std::optional<KPageGroup> m_page_group{};
|
||||
KProcess* m_owner{};
|
||||
KProcessAddress m_address{};
|
||||
KLightLock m_lock;
|
||||
Svc::MemoryPermission m_owner_perm{};
|
||||
size_t m_size{};
|
||||
bool m_is_initialized{};
|
||||
bool m_is_mapped{};
|
||||
};
|
||||
|
||||
} // namespace Kernel
|
||||
|
@ -373,7 +373,7 @@ struct KernelCore::Impl {
|
||||
static inline thread_local u8 host_thread_id = UINT8_MAX;
|
||||
|
||||
/// Sets the host thread ID for the caller.
|
||||
u32 SetHostThreadId(std::size_t core_id) {
|
||||
LTO_NOINLINE u32 SetHostThreadId(std::size_t core_id) {
|
||||
// This should only be called during core init.
|
||||
ASSERT(host_thread_id == UINT8_MAX);
|
||||
|
||||
@ -384,13 +384,13 @@ struct KernelCore::Impl {
|
||||
}
|
||||
|
||||
/// Gets the host thread ID for the caller
|
||||
u32 GetHostThreadId() const {
|
||||
LTO_NOINLINE u32 GetHostThreadId() const {
|
||||
return host_thread_id;
|
||||
}
|
||||
|
||||
// Gets the dummy KThread for the caller, allocating a new one if this is the first time
|
||||
KThread* GetHostDummyThread(KThread* existing_thread) {
|
||||
const auto initialize{[](KThread* thread) {
|
||||
LTO_NOINLINE KThread* GetHostDummyThread(KThread* existing_thread) {
|
||||
const auto initialize{[](KThread* thread) LTO_NOINLINE {
|
||||
ASSERT(KThread::InitializeDummyThread(thread, nullptr).IsSuccess());
|
||||
return thread;
|
||||
}};
|
||||
@ -424,11 +424,11 @@ struct KernelCore::Impl {
|
||||
|
||||
static inline thread_local bool is_phantom_mode_for_singlecore{false};
|
||||
|
||||
bool IsPhantomModeForSingleCore() const {
|
||||
LTO_NOINLINE bool IsPhantomModeForSingleCore() const {
|
||||
return is_phantom_mode_for_singlecore;
|
||||
}
|
||||
|
||||
void SetIsPhantomModeForSingleCore(bool value) {
|
||||
LTO_NOINLINE void SetIsPhantomModeForSingleCore(bool value) {
|
||||
ASSERT(!is_multicore);
|
||||
is_phantom_mode_for_singlecore = value;
|
||||
}
|
||||
@ -439,14 +439,14 @@ struct KernelCore::Impl {
|
||||
|
||||
static inline thread_local KThread* current_thread{nullptr};
|
||||
|
||||
KThread* GetCurrentEmuThread() {
|
||||
LTO_NOINLINE KThread* GetCurrentEmuThread() {
|
||||
if (!current_thread) {
|
||||
current_thread = GetHostDummyThread(nullptr);
|
||||
}
|
||||
return current_thread;
|
||||
}
|
||||
|
||||
void SetCurrentEmuThread(KThread* thread) {
|
||||
LTO_NOINLINE void SetCurrentEmuThread(KThread* thread) {
|
||||
current_thread = thread;
|
||||
}
|
||||
|
||||
|
@ -71,15 +71,59 @@ Result CreateTransferMemory(Core::System& system, Handle* out, u64 address, u64
|
||||
}
|
||||
|
||||
Result MapTransferMemory(Core::System& system, Handle trmem_handle, uint64_t address, uint64_t size,
|
||||
MemoryPermission owner_perm) {
|
||||
UNIMPLEMENTED();
|
||||
R_THROW(ResultNotImplemented);
|
||||
MemoryPermission map_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 permission.
|
||||
R_UNLESS(IsValidTransferMemoryPermission(map_perm), ResultInvalidState);
|
||||
|
||||
// Get the transfer memory.
|
||||
KScopedAutoObject trmem = GetCurrentProcess(system.Kernel())
|
||||
.GetHandleTable()
|
||||
.GetObject<KTransferMemory>(trmem_handle);
|
||||
R_UNLESS(trmem.IsNotNull(), ResultInvalidHandle);
|
||||
|
||||
// Verify that the mapping is in range.
|
||||
R_UNLESS(GetCurrentProcess(system.Kernel())
|
||||
.GetPageTable()
|
||||
.CanContain(address, size, KMemoryState::Transfered),
|
||||
ResultInvalidMemoryRegion);
|
||||
|
||||
// Map the transfer memory.
|
||||
R_TRY(trmem->Map(address, size, map_perm));
|
||||
|
||||
// We succeeded.
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result UnmapTransferMemory(Core::System& system, Handle trmem_handle, uint64_t address,
|
||||
uint64_t size) {
|
||||
UNIMPLEMENTED();
|
||||
R_THROW(ResultNotImplemented);
|
||||
// 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);
|
||||
|
||||
// Get the transfer memory.
|
||||
KScopedAutoObject trmem = GetCurrentProcess(system.Kernel())
|
||||
.GetHandleTable()
|
||||
.GetObject<KTransferMemory>(trmem_handle);
|
||||
R_UNLESS(trmem.IsNotNull(), ResultInvalidHandle);
|
||||
|
||||
// Verify that the mapping is in range.
|
||||
R_UNLESS(GetCurrentProcess(system.Kernel())
|
||||
.GetPageTable()
|
||||
.CanContain(address, size, KMemoryState::Transfered),
|
||||
ResultInvalidMemoryRegion);
|
||||
|
||||
// Unmap the transfer memory.
|
||||
R_TRY(trmem->Unmap(address, size));
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result MapTransferMemory64(Core::System& system, Handle trmem_handle, uint64_t address,
|
||||
|
@ -31,7 +31,7 @@
|
||||
#include "core/hle/service/apm/apm_controller.h"
|
||||
#include "core/hle/service/apm/apm_interface.h"
|
||||
#include "core/hle/service/bcat/backend/backend.h"
|
||||
#include "core/hle/service/caps/caps.h"
|
||||
#include "core/hle/service/caps/caps_types.h"
|
||||
#include "core/hle/service/filesystem/filesystem.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
#include "core/hle/service/ns/ns.h"
|
||||
@ -764,6 +764,66 @@ void AppletMessageQueue::OperationModeChanged() {
|
||||
on_operation_mode_changed->Signal();
|
||||
}
|
||||
|
||||
ILockAccessor::ILockAccessor(Core::System& system_)
|
||||
: ServiceFramework{system_, "ILockAccessor"}, service_context{system_, "ILockAccessor"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{1, &ILockAccessor::TryLock, "TryLock"},
|
||||
{2, &ILockAccessor::Unlock, "Unlock"},
|
||||
{3, &ILockAccessor::GetEvent, "GetEvent"},
|
||||
{4,&ILockAccessor::IsLocked, "IsLocked"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
|
||||
lock_event = service_context.CreateEvent("ILockAccessor::LockEvent");
|
||||
}
|
||||
|
||||
ILockAccessor::~ILockAccessor() = default;
|
||||
|
||||
void ILockAccessor::TryLock(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto return_handle = rp.Pop<bool>();
|
||||
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called, return_handle={}", return_handle);
|
||||
|
||||
// TODO: When return_handle is true this function should return the lock handle
|
||||
|
||||
is_locked = true;
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push<u8>(is_locked);
|
||||
}
|
||||
|
||||
void ILockAccessor::Unlock(HLERequestContext& ctx) {
|
||||
LOG_INFO(Service_AM, "called");
|
||||
|
||||
is_locked = false;
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void ILockAccessor::GetEvent(HLERequestContext& ctx) {
|
||||
LOG_INFO(Service_AM, "called");
|
||||
|
||||
lock_event->Signal();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(lock_event->GetReadableEvent());
|
||||
}
|
||||
|
||||
void ILockAccessor::IsLocked(HLERequestContext& ctx) {
|
||||
LOG_INFO(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push<u8>(is_locked);
|
||||
}
|
||||
|
||||
ICommonStateGetter::ICommonStateGetter(Core::System& system_,
|
||||
std::shared_ptr<AppletMessageQueue> msg_queue_)
|
||||
: ServiceFramework{system_, "ICommonStateGetter"}, msg_queue{std::move(msg_queue_)},
|
||||
@ -787,7 +847,7 @@ ICommonStateGetter::ICommonStateGetter(Core::System& system_,
|
||||
{14, nullptr, "GetWakeupCount"},
|
||||
{20, nullptr, "PushToGeneralChannel"},
|
||||
{30, nullptr, "GetHomeButtonReaderLockAccessor"},
|
||||
{31, nullptr, "GetReaderLockAccessorEx"},
|
||||
{31, &ICommonStateGetter::GetReaderLockAccessorEx, "GetReaderLockAccessorEx"},
|
||||
{32, nullptr, "GetWriterLockAccessorEx"},
|
||||
{40, nullptr, "GetCradleFwVersion"},
|
||||
{50, &ICommonStateGetter::IsVrModeEnabled, "IsVrModeEnabled"},
|
||||
@ -805,7 +865,7 @@ ICommonStateGetter::ICommonStateGetter(Core::System& system_,
|
||||
{65, nullptr, "GetApplicationIdByContentActionName"},
|
||||
{66, &ICommonStateGetter::SetCpuBoostMode, "SetCpuBoostMode"},
|
||||
{67, nullptr, "CancelCpuBoostMode"},
|
||||
{68, nullptr, "GetBuiltInDisplayType"},
|
||||
{68, &ICommonStateGetter::GetBuiltInDisplayType, "GetBuiltInDisplayType"},
|
||||
{80, &ICommonStateGetter::PerformSystemButtonPressingIfInFocus, "PerformSystemButtonPressingIfInFocus"},
|
||||
{90, nullptr, "SetPerformanceConfigurationChangedNotification"},
|
||||
{91, nullptr, "GetCurrentPerformanceConfiguration"},
|
||||
@ -886,6 +946,18 @@ void ICommonStateGetter::RequestToAcquireSleepLock(HLERequestContext& ctx) {
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void ICommonStateGetter::GetReaderLockAccessorEx(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto unknown = rp.Pop<u32>();
|
||||
|
||||
LOG_INFO(Service_AM, "called, unknown={}", unknown);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<ILockAccessor>(system);
|
||||
}
|
||||
|
||||
void ICommonStateGetter::GetAcquiredSleepLockEvent(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "called");
|
||||
|
||||
@ -970,6 +1042,14 @@ void ICommonStateGetter::SetCpuBoostMode(HLERequestContext& ctx) {
|
||||
apm_sys->SetCpuBoostMode(ctx);
|
||||
}
|
||||
|
||||
void ICommonStateGetter::GetBuiltInDisplayType(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(0);
|
||||
}
|
||||
|
||||
void ICommonStateGetter::PerformSystemButtonPressingIfInFocus(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto system_button{rp.PopEnum<SystemButtonType>()};
|
||||
@ -1493,6 +1573,9 @@ ILibraryAppletSelfAccessor::ILibraryAppletSelfAccessor(Core::System& system_)
|
||||
case Applets::AppletId::MiiEdit:
|
||||
PushInShowMiiEditData();
|
||||
break;
|
||||
case Applets::AppletId::PhotoViewer:
|
||||
PushInShowAlbum();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -1569,6 +1652,23 @@ void ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo(HLERequestContext&
|
||||
rb.PushRaw(applet_info);
|
||||
}
|
||||
|
||||
void ILibraryAppletSelfAccessor::PushInShowAlbum() {
|
||||
const Applets::CommonArguments arguments{
|
||||
.arguments_version = Applets::CommonArgumentVersion::Version3,
|
||||
.size = Applets::CommonArgumentSize::Version3,
|
||||
.library_version = 1,
|
||||
.theme_color = Applets::ThemeColor::BasicBlack,
|
||||
.play_startup_sound = true,
|
||||
.system_tick = system.CoreTiming().GetClockTicks(),
|
||||
};
|
||||
|
||||
std::vector<u8> argument_data(sizeof(arguments));
|
||||
std::vector<u8> settings_data{2};
|
||||
std::memcpy(argument_data.data(), &arguments, sizeof(arguments));
|
||||
queue_data.emplace_back(std::move(argument_data));
|
||||
queue_data.emplace_back(std::move(settings_data));
|
||||
}
|
||||
|
||||
void ILibraryAppletSelfAccessor::PushInShowCabinetData() {
|
||||
const Applets::CommonArguments arguments{
|
||||
.arguments_version = Applets::CommonArgumentVersion::Version3,
|
||||
|
@ -195,6 +195,23 @@ private:
|
||||
ScreenshotPermission screenshot_permission = ScreenshotPermission::Inherit;
|
||||
};
|
||||
|
||||
class ILockAccessor final : public ServiceFramework<ILockAccessor> {
|
||||
public:
|
||||
explicit ILockAccessor(Core::System& system_);
|
||||
~ILockAccessor() override;
|
||||
|
||||
private:
|
||||
void TryLock(HLERequestContext& ctx);
|
||||
void Unlock(HLERequestContext& ctx);
|
||||
void GetEvent(HLERequestContext& ctx);
|
||||
void IsLocked(HLERequestContext& ctx);
|
||||
|
||||
bool is_locked{};
|
||||
|
||||
Kernel::KEvent* lock_event;
|
||||
KernelHelpers::ServiceContext service_context;
|
||||
};
|
||||
|
||||
class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> {
|
||||
public:
|
||||
explicit ICommonStateGetter(Core::System& system_,
|
||||
@ -237,6 +254,7 @@ private:
|
||||
void GetCurrentFocusState(HLERequestContext& ctx);
|
||||
void RequestToAcquireSleepLock(HLERequestContext& ctx);
|
||||
void GetAcquiredSleepLockEvent(HLERequestContext& ctx);
|
||||
void GetReaderLockAccessorEx(HLERequestContext& ctx);
|
||||
void GetDefaultDisplayResolutionChangeEvent(HLERequestContext& ctx);
|
||||
void GetOperationMode(HLERequestContext& ctx);
|
||||
void GetPerformanceMode(HLERequestContext& ctx);
|
||||
@ -248,6 +266,7 @@ private:
|
||||
void EndVrModeEx(HLERequestContext& ctx);
|
||||
void GetDefaultDisplayResolution(HLERequestContext& ctx);
|
||||
void SetCpuBoostMode(HLERequestContext& ctx);
|
||||
void GetBuiltInDisplayType(HLERequestContext& ctx);
|
||||
void PerformSystemButtonPressingIfInFocus(HLERequestContext& ctx);
|
||||
void GetSettingsPlatformRegion(HLERequestContext& ctx);
|
||||
void SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled(HLERequestContext& ctx);
|
||||
@ -327,6 +346,7 @@ private:
|
||||
void ExitProcessAndReturn(HLERequestContext& ctx);
|
||||
void GetCallerAppletIdentityInfo(HLERequestContext& ctx);
|
||||
|
||||
void PushInShowAlbum();
|
||||
void PushInShowCabinetData();
|
||||
void PushInShowMiiEditData();
|
||||
|
||||
|
@ -28,8 +28,8 @@ public:
|
||||
{11, &ILibraryAppletProxy::GetLibraryAppletCreator, "GetLibraryAppletCreator"},
|
||||
{20, &ILibraryAppletProxy::OpenLibraryAppletSelfAccessor, "OpenLibraryAppletSelfAccessor"},
|
||||
{21, &ILibraryAppletProxy::GetAppletCommonFunctions, "GetAppletCommonFunctions"},
|
||||
{22, nullptr, "GetHomeMenuFunctions"},
|
||||
{23, nullptr, "GetGlobalStateController"},
|
||||
{22, &ILibraryAppletProxy::GetHomeMenuFunctions, "GetHomeMenuFunctions"},
|
||||
{23, &ILibraryAppletProxy::GetGlobalStateController, "GetGlobalStateController"},
|
||||
{1000, &ILibraryAppletProxy::GetDebugFunctions, "GetDebugFunctions"},
|
||||
};
|
||||
// clang-format on
|
||||
@ -110,6 +110,22 @@ private:
|
||||
rb.PushIpcInterface<IAppletCommonFunctions>(system);
|
||||
}
|
||||
|
||||
void GetHomeMenuFunctions(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IHomeMenuFunctions>(system);
|
||||
}
|
||||
|
||||
void GetGlobalStateController(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IGlobalStateController>(system);
|
||||
}
|
||||
|
||||
void GetDebugFunctions(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "core/hle/service/am/applets/applet_cabinet.h"
|
||||
#include "core/hle/service/mii/mii_manager.h"
|
||||
#include "core/hle/service/nfc/common/device.h"
|
||||
#include "core/hle/service/hid/hid_types.h"
|
||||
|
||||
namespace Service::AM::Applets {
|
||||
|
||||
@ -73,7 +74,7 @@ void Cabinet::Execute() {
|
||||
// TODO: listen on all controllers
|
||||
if (nfp_device == nullptr) {
|
||||
nfp_device = std::make_shared<Service::NFC::NfcDevice>(
|
||||
system.HIDCore().GetFirstNpadId(), system, service_context, availability_change_event);
|
||||
Service::HID::NpadIdType::Player1, system, service_context, availability_change_event);
|
||||
nfp_device->Initialize();
|
||||
nfp_device->StartDetection(Service::NFC::NfcProtocol::All);
|
||||
}
|
||||
|
@ -9,13 +9,11 @@
|
||||
#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/service/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"
|
||||
#include "core/hle/service/hid/controllers/npad.h"
|
||||
|
||||
namespace Service::AM::Applets {
|
||||
|
||||
@ -26,7 +24,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) {
|
||||
Core::HID::NpadStyleTag npad_style_set;
|
||||
Service::HID::NpadStyleTag npad_style_set;
|
||||
npad_style_set.raw = private_arg.style_set;
|
||||
|
||||
return {
|
||||
@ -247,9 +245,9 @@ void Controller::ConfigurationComplete(bool is_success) {
|
||||
|
||||
// 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 : system.HIDCore().GetPlayerCount();
|
||||
result_info.player_count = is_single_mode ? 1 : 0;
|
||||
|
||||
result_info.selected_id = static_cast<u32>(system.HIDCore().GetFirstNpadId());
|
||||
result_info.selected_id = static_cast<u32>(Service::HID::NpadIdType::Player1);
|
||||
|
||||
result_info.result =
|
||||
is_success ? ControllerSupportResult::Success : ControllerSupportResult::Cancel;
|
||||
|
@ -15,7 +15,7 @@ namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Core::HID {
|
||||
namespace Service::HID {
|
||||
enum class NpadStyleSet : u32;
|
||||
}
|
||||
|
||||
@ -60,7 +60,7 @@ struct ControllerSupportArgPrivate {
|
||||
bool flag_1{};
|
||||
ControllerSupportMode mode{};
|
||||
ControllerSupportCaller caller{};
|
||||
Core::HID::NpadStyleSet style_set{};
|
||||
Service::HID::NpadStyleSet style_set{};
|
||||
u32 joy_hold_type{};
|
||||
};
|
||||
static_assert(sizeof(ControllerSupportArgPrivate) == 0x14,
|
||||
|
@ -138,6 +138,10 @@ void Error::Initialize() {
|
||||
CopyArgumentData(data, args->application_error);
|
||||
error_code = Result(args->application_error.error_code);
|
||||
break;
|
||||
case ErrorAppletMode::ShowErrorPctl:
|
||||
CopyArgumentData(data, args->error_record);
|
||||
error_code = Decode64BitError(args->error_record.error_code_64);
|
||||
break;
|
||||
case ErrorAppletMode::ShowErrorRecord:
|
||||
CopyArgumentData(data, args->error_record);
|
||||
error_code = Decode64BitError(args->error_record.error_code_64);
|
||||
@ -191,6 +195,7 @@ void Error::Execute() {
|
||||
frontend.ShowCustomErrorText(error_code, main_text_string, detail_text_string, callback);
|
||||
break;
|
||||
}
|
||||
case ErrorAppletMode::ShowErrorPctl:
|
||||
case ErrorAppletMode::ShowErrorRecord:
|
||||
reporter.SaveErrorReport(title_id, error_code,
|
||||
fmt::format("{:016X}", args->error_record.posix_time));
|
||||
|
@ -67,6 +67,34 @@ enum class AppletId : u32 {
|
||||
LoginShare = 0x18,
|
||||
WebAuth = 0x19,
|
||||
MyPage = 0x1A,
|
||||
Gift = 0x1B,
|
||||
UserMigration = 0x1C,
|
||||
PreomiaSys = 0x1D,
|
||||
Story = 0x1E,
|
||||
PreomiaUsr = 0x1F,
|
||||
PreomiaUsrDummy = 0x20,
|
||||
Sample = 0x21,
|
||||
PromoteQualification = 0x22,
|
||||
Unknown35 = 0x35,
|
||||
Unknown36 = 0x36,
|
||||
Unknown37 = 0x37,
|
||||
Unknown38 = 0x38,
|
||||
|
||||
DevlopmentTool = 0x3E8,
|
||||
CombinationLA = 0x3F1,
|
||||
AeSystemApplet = 0x3F2,
|
||||
AeOverlayApplet = 0x3F3,
|
||||
AeStarter = 0x3F4,
|
||||
AeLibraryAppletAlone = 0x3F5,
|
||||
AeLibraryApplet1 = 0x3F6,
|
||||
AeLibraryApplet2 = 0x3F7,
|
||||
AeLibraryApplet3 = 0x3F8,
|
||||
AeLibraryApplet4 = 0x3F9,
|
||||
AppletISA = 0x3FA,
|
||||
AppletIOA = 0x3FB,
|
||||
AppletISTA = 0x3FC,
|
||||
AppletILA1 = 0x3FD,
|
||||
AppletILA2 = 0x3FE,
|
||||
};
|
||||
|
||||
enum class LibraryAppletMode : u32 {
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include "core/hle/service/caps/caps.h"
|
||||
#include "core/hle/service/caps/caps_a.h"
|
||||
#include "core/hle/service/caps/caps_c.h"
|
||||
#include "core/hle/service/caps/caps_manager.h"
|
||||
#include "core/hle/service/caps/caps_sc.h"
|
||||
#include "core/hle/service/caps/caps_ss.h"
|
||||
#include "core/hle/service/caps/caps_su.h"
|
||||
@ -15,13 +16,21 @@ namespace Service::Capture {
|
||||
|
||||
void LoopProcess(Core::System& system) {
|
||||
auto server_manager = std::make_unique<ServerManager>(system);
|
||||
auto album_manager = std::make_shared<AlbumManager>(system);
|
||||
|
||||
server_manager->RegisterNamedService(
|
||||
"caps:a", std::make_shared<IAlbumAccessorService>(system, album_manager));
|
||||
server_manager->RegisterNamedService(
|
||||
"caps:c", std::make_shared<IAlbumControlService>(system, album_manager));
|
||||
server_manager->RegisterNamedService(
|
||||
"caps:u", std::make_shared<IAlbumApplicationService>(system, album_manager));
|
||||
|
||||
server_manager->RegisterNamedService("caps:ss", std::make_shared<IScreenShotService>(system));
|
||||
server_manager->RegisterNamedService("caps:sc",
|
||||
std::make_shared<IScreenShotControlService>(system));
|
||||
server_manager->RegisterNamedService("caps:su",
|
||||
std::make_shared<IScreenShotApplicationService>(system));
|
||||
|
||||
server_manager->RegisterNamedService("caps:a", std::make_shared<CAPS_A>(system));
|
||||
server_manager->RegisterNamedService("caps:c", std::make_shared<CAPS_C>(system));
|
||||
server_manager->RegisterNamedService("caps:u", std::make_shared<CAPS_U>(system));
|
||||
server_manager->RegisterNamedService("caps:sc", std::make_shared<CAPS_SC>(system));
|
||||
server_manager->RegisterNamedService("caps:ss", std::make_shared<CAPS_SS>(system));
|
||||
server_manager->RegisterNamedService("caps:su", std::make_shared<CAPS_SU>(system));
|
||||
ServerManager::RunServer(std::move(server_manager));
|
||||
}
|
||||
|
||||
|
@ -3,93 +3,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Service::SM {
|
||||
class ServiceManager;
|
||||
}
|
||||
|
||||
namespace Service::Capture {
|
||||
|
||||
enum class AlbumImageOrientation {
|
||||
Orientation0 = 0,
|
||||
Orientation1 = 1,
|
||||
Orientation2 = 2,
|
||||
Orientation3 = 3,
|
||||
};
|
||||
|
||||
enum class AlbumReportOption : s32 {
|
||||
Disable = 0,
|
||||
Enable = 1,
|
||||
};
|
||||
|
||||
enum class ContentType : u8 {
|
||||
Screenshot = 0,
|
||||
Movie = 1,
|
||||
ExtraMovie = 3,
|
||||
};
|
||||
|
||||
enum class AlbumStorage : u8 {
|
||||
NAND = 0,
|
||||
SD = 1,
|
||||
};
|
||||
|
||||
struct AlbumFileDateTime {
|
||||
s16 year{};
|
||||
s8 month{};
|
||||
s8 day{};
|
||||
s8 hour{};
|
||||
s8 minute{};
|
||||
s8 second{};
|
||||
s8 uid{};
|
||||
};
|
||||
static_assert(sizeof(AlbumFileDateTime) == 0x8, "AlbumFileDateTime has incorrect size.");
|
||||
|
||||
struct AlbumEntry {
|
||||
u64 size{};
|
||||
u64 application_id{};
|
||||
AlbumFileDateTime datetime{};
|
||||
AlbumStorage storage{};
|
||||
ContentType content{};
|
||||
INSERT_PADDING_BYTES(6);
|
||||
};
|
||||
static_assert(sizeof(AlbumEntry) == 0x20, "AlbumEntry has incorrect size.");
|
||||
|
||||
struct AlbumFileEntry {
|
||||
u64 size{}; // Size of the entry
|
||||
u64 hash{}; // AES256 with hardcoded key over AlbumEntry
|
||||
AlbumFileDateTime datetime{};
|
||||
AlbumStorage storage{};
|
||||
ContentType content{};
|
||||
INSERT_PADDING_BYTES(5);
|
||||
u8 unknown{1}; // Set to 1 on official SW
|
||||
};
|
||||
static_assert(sizeof(AlbumFileEntry) == 0x20, "AlbumFileEntry has incorrect size.");
|
||||
|
||||
struct ApplicationAlbumEntry {
|
||||
u64 size{}; // Size of the entry
|
||||
u64 hash{}; // AES256 with hardcoded key over AlbumEntry
|
||||
AlbumFileDateTime datetime{};
|
||||
AlbumStorage storage{};
|
||||
ContentType content{};
|
||||
INSERT_PADDING_BYTES(5);
|
||||
u8 unknown{1}; // Set to 1 on official SW
|
||||
};
|
||||
static_assert(sizeof(ApplicationAlbumEntry) == 0x20, "ApplicationAlbumEntry has incorrect size.");
|
||||
|
||||
struct ApplicationAlbumFileEntry {
|
||||
ApplicationAlbumEntry entry{};
|
||||
AlbumFileDateTime datetime{};
|
||||
u64 unknown{};
|
||||
};
|
||||
static_assert(sizeof(ApplicationAlbumFileEntry) == 0x30,
|
||||
"ApplicationAlbumFileEntry has incorrect size.");
|
||||
|
||||
void LoopProcess(Core::System& system);
|
||||
|
||||
} // namespace Service::Capture
|
||||
|
@ -1,40 +1,26 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/hle/service/caps/caps_a.h"
|
||||
#include "core/hle/service/caps/caps_manager.h"
|
||||
#include "core/hle/service/caps/caps_result.h"
|
||||
#include "core/hle/service/caps/caps_types.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
|
||||
namespace Service::Capture {
|
||||
|
||||
class IAlbumAccessorSession final : public ServiceFramework<IAlbumAccessorSession> {
|
||||
public:
|
||||
explicit IAlbumAccessorSession(Core::System& system_)
|
||||
: ServiceFramework{system_, "IAlbumAccessorSession"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{2001, nullptr, "OpenAlbumMovieReadStream"},
|
||||
{2002, nullptr, "CloseAlbumMovieReadStream"},
|
||||
{2003, nullptr, "GetAlbumMovieReadStreamMovieDataSize"},
|
||||
{2004, nullptr, "ReadMovieDataFromAlbumMovieReadStream"},
|
||||
{2005, nullptr, "GetAlbumMovieReadStreamBrokenReason"},
|
||||
{2006, nullptr, "GetAlbumMovieReadStreamImageDataSize"},
|
||||
{2007, nullptr, "ReadImageDataFromAlbumMovieReadStream"},
|
||||
{2008, nullptr, "ReadFileAttributeFromAlbumMovieReadStream"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
};
|
||||
|
||||
CAPS_A::CAPS_A(Core::System& system_) : ServiceFramework{system_, "caps:a"} {
|
||||
IAlbumAccessorService::IAlbumAccessorService(Core::System& system_,
|
||||
std::shared_ptr<AlbumManager> album_manager)
|
||||
: ServiceFramework{system_, "caps:a"}, manager{album_manager} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "GetAlbumFileCount"},
|
||||
{1, nullptr, "GetAlbumFileList"},
|
||||
{2, nullptr, "LoadAlbumFile"},
|
||||
{3, nullptr, "DeleteAlbumFile"},
|
||||
{3, &IAlbumAccessorService::DeleteAlbumFile, "DeleteAlbumFile"},
|
||||
{4, nullptr, "StorageCopyAlbumFile"},
|
||||
{5, nullptr, "IsAlbumMounted"},
|
||||
{5, &IAlbumAccessorService::IsAlbumMounted, "IsAlbumMounted"},
|
||||
{6, nullptr, "GetAlbumUsage"},
|
||||
{7, nullptr, "GetAlbumFileSize"},
|
||||
{8, nullptr, "LoadAlbumFileThumbnail"},
|
||||
@ -47,18 +33,18 @@ CAPS_A::CAPS_A(Core::System& system_) : ServiceFramework{system_, "caps:a"} {
|
||||
{15, nullptr, "GetAlbumUsage3"},
|
||||
{16, nullptr, "GetAlbumMountResult"},
|
||||
{17, nullptr, "GetAlbumUsage16"},
|
||||
{18, nullptr, "Unknown18"},
|
||||
{18, &IAlbumAccessorService::Unknown18, "Unknown18"},
|
||||
{19, nullptr, "Unknown19"},
|
||||
{100, nullptr, "GetAlbumFileCountEx0"},
|
||||
{101, nullptr, "GetAlbumFileListEx0"},
|
||||
{101, &IAlbumAccessorService::GetAlbumFileListEx0, "GetAlbumFileListEx0"},
|
||||
{202, nullptr, "SaveEditedScreenShot"},
|
||||
{301, nullptr, "GetLastThumbnail"},
|
||||
{302, nullptr, "GetLastOverlayMovieThumbnail"},
|
||||
{401, nullptr, "GetAutoSavingStorage"},
|
||||
{401, &IAlbumAccessorService::GetAutoSavingStorage, "GetAutoSavingStorage"},
|
||||
{501, nullptr, "GetRequiredStorageSpaceSizeToCopyAll"},
|
||||
{1001, nullptr, "LoadAlbumScreenShotThumbnailImageEx0"},
|
||||
{1002, nullptr, "LoadAlbumScreenShotImageEx1"},
|
||||
{1003, nullptr, "LoadAlbumScreenShotThumbnailImageEx1"},
|
||||
{1002, &IAlbumAccessorService::LoadAlbumScreenShotImageEx1, "LoadAlbumScreenShotImageEx1"},
|
||||
{1003, &IAlbumAccessorService::LoadAlbumScreenShotThumbnailImageEx1, "LoadAlbumScreenShotThumbnailImageEx1"},
|
||||
{8001, nullptr, "ForceAlbumUnmounted"},
|
||||
{8002, nullptr, "ResetAlbumMountStatus"},
|
||||
{8011, nullptr, "RefreshAlbumCache"},
|
||||
@ -74,6 +60,199 @@ CAPS_A::CAPS_A(Core::System& system_) : ServiceFramework{system_, "caps:a"} {
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
CAPS_A::~CAPS_A() = default;
|
||||
IAlbumAccessorService::~IAlbumAccessorService() = default;
|
||||
|
||||
void IAlbumAccessorService::DeleteAlbumFile(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto file_id{rp.PopRaw<AlbumFileId>()};
|
||||
|
||||
LOG_INFO(Service_Capture, "called, application_id=0x{:0x}, storage={}, type={}",
|
||||
file_id.application_id, file_id.storage, file_id.type);
|
||||
|
||||
Result result = manager->DeleteAlbumFile(file_id);
|
||||
result = TranslateResult(result);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
void IAlbumAccessorService::IsAlbumMounted(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto storage{rp.PopEnum<AlbumStorage>()};
|
||||
|
||||
LOG_INFO(Service_Capture, "called, storage={}", storage);
|
||||
|
||||
Result result = manager->IsAlbumMounted(storage);
|
||||
const bool is_mounted = result.IsSuccess();
|
||||
result = TranslateResult(result);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(result);
|
||||
rb.Push<u8>(is_mounted);
|
||||
}
|
||||
|
||||
void IAlbumAccessorService::Unknown18(HLERequestContext& ctx) {
|
||||
struct UnknownBuffer {
|
||||
INSERT_PADDING_BYTES(0x10);
|
||||
};
|
||||
static_assert(sizeof(UnknownBuffer) == 0x10, "UnknownBuffer is an invalid size");
|
||||
|
||||
LOG_WARNING(Service_Capture, "(STUBBED) called");
|
||||
|
||||
std::vector<UnknownBuffer> buffer{};
|
||||
|
||||
if (!buffer.empty()) {
|
||||
ctx.WriteBuffer(buffer);
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(static_cast<u32>(buffer.size()));
|
||||
}
|
||||
|
||||
void IAlbumAccessorService::GetAlbumFileListEx0(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto storage{rp.PopEnum<AlbumStorage>()};
|
||||
const auto flags{rp.Pop<u8>()};
|
||||
const auto album_entry_size{ctx.GetWriteBufferNumElements<AlbumEntry>()};
|
||||
|
||||
LOG_INFO(Service_Capture, "called, storage={}, flags={}", storage, flags);
|
||||
|
||||
std::vector<AlbumEntry> entries;
|
||||
Result result = manager->GetAlbumFileList(entries, storage, flags);
|
||||
result = TranslateResult(result);
|
||||
|
||||
entries.resize(std::min(album_entry_size, entries.size()));
|
||||
|
||||
if (!entries.empty()) {
|
||||
ctx.WriteBuffer(entries);
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(result);
|
||||
rb.Push<u64>(entries.size());
|
||||
}
|
||||
|
||||
void IAlbumAccessorService::GetAutoSavingStorage(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_Capture, "(STUBBED) called");
|
||||
|
||||
bool is_autosaving{};
|
||||
Result result = manager->GetAutoSavingStorage(is_autosaving);
|
||||
result = TranslateResult(result);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(result);
|
||||
rb.Push<u8>(is_autosaving);
|
||||
}
|
||||
|
||||
void IAlbumAccessorService::LoadAlbumScreenShotImageEx1(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto file_id{rp.PopRaw<AlbumFileId>()};
|
||||
const auto decoder_options{rp.PopRaw<ScreenShotDecodeOption>()};
|
||||
const auto image_buffer_size{ctx.GetWriteBufferSize(1)};
|
||||
|
||||
LOG_INFO(Service_Capture, "called, application_id=0x{:0x}, storage={}, type={}, flags={}",
|
||||
file_id.application_id, file_id.storage, file_id.type, decoder_options.flags);
|
||||
|
||||
std::vector<u8> image;
|
||||
LoadAlbumScreenShotImageOutput image_output;
|
||||
Result result =
|
||||
manager->LoadAlbumScreenShotImage(image_output, image, file_id, decoder_options);
|
||||
result = TranslateResult(result);
|
||||
|
||||
if (image.size() > image_buffer_size) {
|
||||
result = ResultWorkMemoryError;
|
||||
}
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
ctx.WriteBuffer(image_output, 0);
|
||||
ctx.WriteBuffer(image, 1);
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
void IAlbumAccessorService::LoadAlbumScreenShotThumbnailImageEx1(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto file_id{rp.PopRaw<AlbumFileId>()};
|
||||
const auto decoder_options{rp.PopRaw<ScreenShotDecodeOption>()};
|
||||
|
||||
LOG_INFO(Service_Capture, "called, application_id=0x{:0x}, storage={}, type={}, flags={}",
|
||||
file_id.application_id, file_id.storage, file_id.type, decoder_options.flags);
|
||||
|
||||
std::vector<u8> image(ctx.GetWriteBufferSize(1));
|
||||
LoadAlbumScreenShotImageOutput image_output;
|
||||
Result result =
|
||||
manager->LoadAlbumScreenShotThumbnail(image_output, image, file_id, decoder_options);
|
||||
result = TranslateResult(result);
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
ctx.WriteBuffer(image_output, 0);
|
||||
ctx.WriteBuffer(image, 1);
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
Result IAlbumAccessorService::TranslateResult(Result in_result) {
|
||||
if (in_result.IsSuccess()) {
|
||||
return in_result;
|
||||
}
|
||||
|
||||
if ((in_result.raw & 0x3801ff) == ResultUnknown1024.raw) {
|
||||
if (in_result.description - 0x514 < 100) {
|
||||
return ResultInvalidFileData;
|
||||
}
|
||||
if (in_result.description - 0x5dc < 100) {
|
||||
return ResultInvalidFileData;
|
||||
}
|
||||
|
||||
if (in_result.description - 0x578 < 100) {
|
||||
if (in_result == ResultFileCountLimit) {
|
||||
return ResultUnknown22;
|
||||
}
|
||||
return ResultUnknown25;
|
||||
}
|
||||
|
||||
if (in_result.raw < ResultUnknown1801.raw) {
|
||||
if (in_result == ResultUnknown1202) {
|
||||
return ResultUnknown810;
|
||||
}
|
||||
if (in_result == ResultUnknown1203) {
|
||||
return ResultUnknown810;
|
||||
}
|
||||
if (in_result == ResultUnknown1701) {
|
||||
return ResultUnknown5;
|
||||
}
|
||||
} else if (in_result.raw < ResultUnknown1803.raw) {
|
||||
if (in_result == ResultUnknown1801) {
|
||||
return ResultUnknown5;
|
||||
}
|
||||
if (in_result == ResultUnknown1802) {
|
||||
return ResultUnknown6;
|
||||
}
|
||||
} else {
|
||||
if (in_result == ResultUnknown1803) {
|
||||
return ResultUnknown7;
|
||||
}
|
||||
if (in_result == ResultUnknown1804) {
|
||||
return ResultOutOfRange;
|
||||
}
|
||||
}
|
||||
return ResultUnknown1024;
|
||||
}
|
||||
|
||||
if (in_result.module == ErrorModule::FS) {
|
||||
if ((in_result.description >> 0xc < 0x7d) || (in_result.description - 1000 < 2000) ||
|
||||
(((in_result.description - 3000) >> 3) < 0x271)) {
|
||||
// TODO: Translate FS error
|
||||
return in_result;
|
||||
}
|
||||
}
|
||||
|
||||
return in_result;
|
||||
}
|
||||
|
||||
} // namespace Service::Capture
|
||||
|
@ -10,11 +10,26 @@ class System;
|
||||
}
|
||||
|
||||
namespace Service::Capture {
|
||||
class AlbumManager;
|
||||
|
||||
class CAPS_A final : public ServiceFramework<CAPS_A> {
|
||||
class IAlbumAccessorService final : public ServiceFramework<IAlbumAccessorService> {
|
||||
public:
|
||||
explicit CAPS_A(Core::System& system_);
|
||||
~CAPS_A() override;
|
||||
explicit IAlbumAccessorService(Core::System& system_,
|
||||
std::shared_ptr<AlbumManager> album_manager);
|
||||
~IAlbumAccessorService() override;
|
||||
|
||||
private:
|
||||
void DeleteAlbumFile(HLERequestContext& ctx);
|
||||
void IsAlbumMounted(HLERequestContext& ctx);
|
||||
void Unknown18(HLERequestContext& ctx);
|
||||
void GetAlbumFileListEx0(HLERequestContext& ctx);
|
||||
void GetAutoSavingStorage(HLERequestContext& ctx);
|
||||
void LoadAlbumScreenShotImageEx1(HLERequestContext& ctx);
|
||||
void LoadAlbumScreenShotThumbnailImageEx1(HLERequestContext& ctx);
|
||||
|
||||
Result TranslateResult(Result in_result);
|
||||
|
||||
std::shared_ptr<AlbumManager> manager = nullptr;
|
||||
};
|
||||
|
||||
} // namespace Service::Capture
|
||||
|
@ -3,53 +3,21 @@
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/hle/service/caps/caps_c.h"
|
||||
#include "core/hle/service/caps/caps_manager.h"
|
||||
#include "core/hle/service/caps/caps_result.h"
|
||||
#include "core/hle/service/caps/caps_types.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
|
||||
namespace Service::Capture {
|
||||
|
||||
class IAlbumControlSession final : public ServiceFramework<IAlbumControlSession> {
|
||||
public:
|
||||
explicit IAlbumControlSession(Core::System& system_)
|
||||
: ServiceFramework{system_, "IAlbumControlSession"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{2001, nullptr, "OpenAlbumMovieReadStream"},
|
||||
{2002, nullptr, "CloseAlbumMovieReadStream"},
|
||||
{2003, nullptr, "GetAlbumMovieReadStreamMovieDataSize"},
|
||||
{2004, nullptr, "ReadMovieDataFromAlbumMovieReadStream"},
|
||||
{2005, nullptr, "GetAlbumMovieReadStreamBrokenReason"},
|
||||
{2006, nullptr, "GetAlbumMovieReadStreamImageDataSize"},
|
||||
{2007, nullptr, "ReadImageDataFromAlbumMovieReadStream"},
|
||||
{2008, nullptr, "ReadFileAttributeFromAlbumMovieReadStream"},
|
||||
{2401, nullptr, "OpenAlbumMovieWriteStream"},
|
||||
{2402, nullptr, "FinishAlbumMovieWriteStream"},
|
||||
{2403, nullptr, "CommitAlbumMovieWriteStream"},
|
||||
{2404, nullptr, "DiscardAlbumMovieWriteStream"},
|
||||
{2405, nullptr, "DiscardAlbumMovieWriteStreamNoDelete"},
|
||||
{2406, nullptr, "CommitAlbumMovieWriteStreamEx"},
|
||||
{2411, nullptr, "StartAlbumMovieWriteStreamDataSection"},
|
||||
{2412, nullptr, "EndAlbumMovieWriteStreamDataSection"},
|
||||
{2413, nullptr, "StartAlbumMovieWriteStreamMetaSection"},
|
||||
{2414, nullptr, "EndAlbumMovieWriteStreamMetaSection"},
|
||||
{2421, nullptr, "ReadDataFromAlbumMovieWriteStream"},
|
||||
{2422, nullptr, "WriteDataToAlbumMovieWriteStream"},
|
||||
{2424, nullptr, "WriteMetaToAlbumMovieWriteStream"},
|
||||
{2431, nullptr, "GetAlbumMovieWriteStreamBrokenReason"},
|
||||
{2433, nullptr, "GetAlbumMovieWriteStreamDataSize"},
|
||||
{2434, nullptr, "SetAlbumMovieWriteStreamDataSize"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
};
|
||||
|
||||
CAPS_C::CAPS_C(Core::System& system_) : ServiceFramework{system_, "caps:c"} {
|
||||
IAlbumControlService::IAlbumControlService(Core::System& system_,
|
||||
std::shared_ptr<AlbumManager> album_manager)
|
||||
: ServiceFramework{system_, "caps:c"}, manager{album_manager} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{1, nullptr, "CaptureRawImage"},
|
||||
{2, nullptr, "CaptureRawImageWithTimeout"},
|
||||
{33, &CAPS_C::SetShimLibraryVersion, "SetShimLibraryVersion"},
|
||||
{33, &IAlbumControlService::SetShimLibraryVersion, "SetShimLibraryVersion"},
|
||||
{1001, nullptr, "RequestTakingScreenShot"},
|
||||
{1002, nullptr, "RequestTakingScreenShotWithTimeout"},
|
||||
{1011, nullptr, "NotifyTakingScreenShotRefused"},
|
||||
@ -72,9 +40,9 @@ CAPS_C::CAPS_C(Core::System& system_) : ServiceFramework{system_, "caps:c"} {
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
CAPS_C::~CAPS_C() = default;
|
||||
IAlbumControlService::~IAlbumControlService() = default;
|
||||
|
||||
void CAPS_C::SetShimLibraryVersion(HLERequestContext& ctx) {
|
||||
void IAlbumControlService::SetShimLibraryVersion(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto library_version{rp.Pop<u64>()};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
|
@ -10,14 +10,18 @@ class System;
|
||||
}
|
||||
|
||||
namespace Service::Capture {
|
||||
class AlbumManager;
|
||||
|
||||
class CAPS_C final : public ServiceFramework<CAPS_C> {
|
||||
class IAlbumControlService final : public ServiceFramework<IAlbumControlService> {
|
||||
public:
|
||||
explicit CAPS_C(Core::System& system_);
|
||||
~CAPS_C() override;
|
||||
explicit IAlbumControlService(Core::System& system_,
|
||||
std::shared_ptr<AlbumManager> album_manager);
|
||||
~IAlbumControlService() override;
|
||||
|
||||
private:
|
||||
void SetShimLibraryVersion(HLERequestContext& ctx);
|
||||
|
||||
std::shared_ptr<AlbumManager> manager = nullptr;
|
||||
};
|
||||
|
||||
} // namespace Service::Capture
|
||||
|
386
src/core/hle/service/caps/caps_manager.cpp
Normal file
386
src/core/hle/service/caps/caps_manager.cpp
Normal file
@ -0,0 +1,386 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <sstream>
|
||||
#include <stb_image.h>
|
||||
#include <stb_image_resize.h>
|
||||
|
||||
#include "common/fs/file.h"
|
||||
#include "common/fs/path_util.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/service/caps/caps_manager.h"
|
||||
#include "core/hle/service/caps/caps_result.h"
|
||||
#include "core/hle/service/time/time_manager.h"
|
||||
#include "core/hle/service/time/time_zone_content_manager.h"
|
||||
|
||||
namespace Service::Capture {
|
||||
|
||||
AlbumManager::AlbumManager(Core::System& system_) : system{system_} {}
|
||||
|
||||
AlbumManager::~AlbumManager() = default;
|
||||
|
||||
Result AlbumManager::DeleteAlbumFile(const AlbumFileId& file_id) {
|
||||
if (file_id.storage > AlbumStorage::Sd) {
|
||||
return ResultInvalidStorage;
|
||||
}
|
||||
|
||||
if (!is_mounted) {
|
||||
return ResultIsNotMounted;
|
||||
}
|
||||
|
||||
std::filesystem::path path;
|
||||
const auto result = GetFile(path, file_id);
|
||||
|
||||
if (result.IsError()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (!Common::FS::RemoveFile(path)) {
|
||||
return ResultFileNotFound;
|
||||
}
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result AlbumManager::IsAlbumMounted(AlbumStorage storage) {
|
||||
if (storage > AlbumStorage::Sd) {
|
||||
return ResultInvalidStorage;
|
||||
}
|
||||
|
||||
is_mounted = true;
|
||||
|
||||
if (storage == AlbumStorage::Sd) {
|
||||
FindScreenshots();
|
||||
}
|
||||
|
||||
return is_mounted ? ResultSuccess : ResultIsNotMounted;
|
||||
}
|
||||
|
||||
Result AlbumManager::GetAlbumFileList(std::vector<AlbumEntry>& out_entries, AlbumStorage storage,
|
||||
u8 flags) const {
|
||||
if (storage > AlbumStorage::Sd) {
|
||||
return ResultInvalidStorage;
|
||||
}
|
||||
|
||||
if (!is_mounted) {
|
||||
return ResultIsNotMounted;
|
||||
}
|
||||
|
||||
for (auto& [file_id, path] : album_files) {
|
||||
if (file_id.storage != storage) {
|
||||
continue;
|
||||
}
|
||||
if (out_entries.size() >= SdAlbumFileLimit) {
|
||||
break;
|
||||
}
|
||||
|
||||
const auto entry_size = Common::FS::GetSize(path);
|
||||
out_entries.push_back({
|
||||
.entry_size = entry_size,
|
||||
.file_id = file_id,
|
||||
});
|
||||
}
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& out_entries,
|
||||
ContentType contex_type, s64 start_posix_time,
|
||||
s64 end_posix_time, u64 aruid) const {
|
||||
if (!is_mounted) {
|
||||
return ResultIsNotMounted;
|
||||
}
|
||||
|
||||
std::vector<ApplicationAlbumEntry> album_entries;
|
||||
const auto start_date = ConvertToAlbumDateTime(start_posix_time);
|
||||
const auto end_date = ConvertToAlbumDateTime(end_posix_time);
|
||||
const auto result = GetAlbumFileList(album_entries, contex_type, start_date, end_date, aruid);
|
||||
|
||||
if (result.IsError()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
for (const auto& album_entry : album_entries) {
|
||||
ApplicationAlbumFileEntry entry{
|
||||
.entry = album_entry,
|
||||
.datetime = album_entry.datetime,
|
||||
.unknown = {},
|
||||
};
|
||||
out_entries.push_back(entry);
|
||||
}
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumEntry>& out_entries,
|
||||
ContentType contex_type, AlbumFileDateTime start_date,
|
||||
AlbumFileDateTime end_date, u64 aruid) const {
|
||||
if (!is_mounted) {
|
||||
return ResultIsNotMounted;
|
||||
}
|
||||
|
||||
for (auto& [file_id, path] : album_files) {
|
||||
if (file_id.type != contex_type) {
|
||||
continue;
|
||||
}
|
||||
if (file_id.date > start_date) {
|
||||
continue;
|
||||
}
|
||||
if (file_id.date < end_date) {
|
||||
continue;
|
||||
}
|
||||
if (out_entries.size() >= SdAlbumFileLimit) {
|
||||
break;
|
||||
}
|
||||
|
||||
const auto entry_size = Common::FS::GetSize(path);
|
||||
ApplicationAlbumEntry entry{
|
||||
.size = entry_size,
|
||||
.hash{},
|
||||
.datetime = file_id.date,
|
||||
.storage = file_id.storage,
|
||||
.content = contex_type,
|
||||
.unknown = 1,
|
||||
};
|
||||
out_entries.push_back(entry);
|
||||
}
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result AlbumManager::GetAutoSavingStorage(bool& out_is_autosaving) const {
|
||||
out_is_autosaving = false;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result AlbumManager::LoadAlbumScreenShotImage(LoadAlbumScreenShotImageOutput& out_image_output,
|
||||
std::vector<u8>& out_image,
|
||||
const AlbumFileId& file_id,
|
||||
const ScreenShotDecodeOption& decoder_options) const {
|
||||
if (file_id.storage > AlbumStorage::Sd) {
|
||||
return ResultInvalidStorage;
|
||||
}
|
||||
|
||||
if (!is_mounted) {
|
||||
return ResultIsNotMounted;
|
||||
}
|
||||
|
||||
out_image_output = {
|
||||
.width = 1280,
|
||||
.height = 720,
|
||||
.attribute =
|
||||
{
|
||||
.unknown_0{},
|
||||
.orientation = AlbumImageOrientation::None,
|
||||
.unknown_1{},
|
||||
.unknown_2{},
|
||||
},
|
||||
};
|
||||
|
||||
std::filesystem::path path;
|
||||
const auto result = GetFile(path, file_id);
|
||||
|
||||
if (result.IsError()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
out_image.resize(out_image_output.height * out_image_output.width * STBI_rgb_alpha);
|
||||
|
||||
return LoadImage(out_image, path, static_cast<int>(out_image_output.width),
|
||||
+static_cast<int>(out_image_output.height), decoder_options.flags);
|
||||
}
|
||||
|
||||
Result AlbumManager::LoadAlbumScreenShotThumbnail(
|
||||
LoadAlbumScreenShotImageOutput& out_image_output, std::vector<u8>& out_image,
|
||||
const AlbumFileId& file_id, const ScreenShotDecodeOption& decoder_options) const {
|
||||
if (file_id.storage > AlbumStorage::Sd) {
|
||||
return ResultInvalidStorage;
|
||||
}
|
||||
|
||||
if (!is_mounted) {
|
||||
return ResultIsNotMounted;
|
||||
}
|
||||
|
||||
out_image_output = {
|
||||
.width = 320,
|
||||
.height = 180,
|
||||
.attribute =
|
||||
{
|
||||
.unknown_0{},
|
||||
.orientation = AlbumImageOrientation::None,
|
||||
.unknown_1{},
|
||||
.unknown_2{},
|
||||
},
|
||||
};
|
||||
|
||||
std::filesystem::path path;
|
||||
const auto result = GetFile(path, file_id);
|
||||
|
||||
if (result.IsError()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
out_image.resize(out_image_output.height * out_image_output.width * STBI_rgb_alpha);
|
||||
|
||||
return LoadImage(out_image, path, static_cast<int>(out_image_output.width),
|
||||
+static_cast<int>(out_image_output.height), decoder_options.flags);
|
||||
}
|
||||
|
||||
Result AlbumManager::GetFile(std::filesystem::path& out_path, const AlbumFileId& file_id) const {
|
||||
const auto file = album_files.find(file_id);
|
||||
|
||||
if (file == album_files.end()) {
|
||||
return ResultFileNotFound;
|
||||
}
|
||||
|
||||
out_path = file->second;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
void AlbumManager::FindScreenshots() {
|
||||
is_mounted = false;
|
||||
album_files.clear();
|
||||
|
||||
// TODO: Swap this with a blocking operation.
|
||||
const auto screenshots_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::ScreenshotsDir);
|
||||
Common::FS::IterateDirEntries(
|
||||
screenshots_dir,
|
||||
[this](const std::filesystem::path& full_path) {
|
||||
AlbumEntry entry;
|
||||
if (GetAlbumEntry(entry, full_path).IsError()) {
|
||||
return true;
|
||||
}
|
||||
while (album_files.contains(entry.file_id)) {
|
||||
if (++entry.file_id.date.unique_id == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
album_files[entry.file_id] = full_path;
|
||||
return true;
|
||||
},
|
||||
Common::FS::DirEntryFilter::File);
|
||||
|
||||
is_mounted = true;
|
||||
}
|
||||
|
||||
Result AlbumManager::GetAlbumEntry(AlbumEntry& out_entry, const std::filesystem::path& path) const {
|
||||
std::istringstream line_stream(path.filename().string());
|
||||
std::string date;
|
||||
std::string application;
|
||||
std::string time;
|
||||
|
||||
// Parse filename to obtain entry properties
|
||||
std::getline(line_stream, application, '_');
|
||||
std::getline(line_stream, date, '_');
|
||||
std::getline(line_stream, time, '_');
|
||||
|
||||
std::istringstream date_stream(date);
|
||||
std::istringstream time_stream(time);
|
||||
std::string year;
|
||||
std::string month;
|
||||
std::string day;
|
||||
std::string hour;
|
||||
std::string minute;
|
||||
std::string second;
|
||||
|
||||
std::getline(date_stream, year, '-');
|
||||
std::getline(date_stream, month, '-');
|
||||
std::getline(date_stream, day, '-');
|
||||
|
||||
std::getline(time_stream, hour, '-');
|
||||
std::getline(time_stream, minute, '-');
|
||||
std::getline(time_stream, second, '-');
|
||||
|
||||
try {
|
||||
out_entry = {
|
||||
.entry_size = 1,
|
||||
.file_id{
|
||||
.application_id = static_cast<u64>(std::stoll(application, 0, 16)),
|
||||
.date =
|
||||
{
|
||||
.year = static_cast<s16>(std::stoi(year)),
|
||||
.month = static_cast<s8>(std::stoi(month)),
|
||||
.day = static_cast<s8>(std::stoi(day)),
|
||||
.hour = static_cast<s8>(std::stoi(hour)),
|
||||
.minute = static_cast<s8>(std::stoi(minute)),
|
||||
.second = static_cast<s8>(std::stoi(second)),
|
||||
.unique_id = 0,
|
||||
},
|
||||
.storage = AlbumStorage::Sd,
|
||||
.type = ContentType::Screenshot,
|
||||
.unknown = 1,
|
||||
},
|
||||
};
|
||||
} catch (const std::invalid_argument&) {
|
||||
return ResultUnknown;
|
||||
} catch (const std::out_of_range&) {
|
||||
return ResultUnknown;
|
||||
} catch (const std::exception&) {
|
||||
return ResultUnknown;
|
||||
}
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result AlbumManager::LoadImage(std::span<u8> out_image, const std::filesystem::path& path,
|
||||
int width, int height, ScreenShotDecoderFlag flag) const {
|
||||
if (out_image.size() != static_cast<std::size_t>(width * height * STBI_rgb_alpha)) {
|
||||
return ResultUnknown;
|
||||
}
|
||||
|
||||
const Common::FS::IOFile db_file{path, Common::FS::FileAccessMode::Read,
|
||||
Common::FS::FileType::BinaryFile};
|
||||
|
||||
std::vector<u8> raw_file(db_file.GetSize());
|
||||
if (db_file.Read(raw_file) != raw_file.size()) {
|
||||
return ResultUnknown;
|
||||
}
|
||||
|
||||
int filter_flag = STBIR_FILTER_DEFAULT;
|
||||
int original_width, original_height, color_channels;
|
||||
const auto dbi_image =
|
||||
stbi_load_from_memory(raw_file.data(), static_cast<int>(raw_file.size()), &original_width,
|
||||
&original_height, &color_channels, STBI_rgb_alpha);
|
||||
|
||||
if (dbi_image == nullptr) {
|
||||
return ResultUnknown;
|
||||
}
|
||||
|
||||
switch (flag) {
|
||||
case ScreenShotDecoderFlag::EnableFancyUpsampling:
|
||||
filter_flag = STBIR_FILTER_TRIANGLE;
|
||||
break;
|
||||
case ScreenShotDecoderFlag::EnableBlockSmoothing:
|
||||
filter_flag = STBIR_FILTER_BOX;
|
||||
break;
|
||||
default:
|
||||
filter_flag = STBIR_FILTER_DEFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
stbir_resize_uint8_srgb(dbi_image, original_width, original_height, 0, out_image.data(), width,
|
||||
height, 0, STBI_rgb_alpha, 3, filter_flag);
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
AlbumFileDateTime AlbumManager::ConvertToAlbumDateTime(u64 posix_time) const {
|
||||
Time::TimeZone::CalendarInfo calendar_date{};
|
||||
const auto& time_zone_manager =
|
||||
system.GetTimeManager().GetTimeZoneContentManager().GetTimeZoneManager();
|
||||
|
||||
time_zone_manager.ToCalendarTimeWithMyRules(posix_time, calendar_date);
|
||||
|
||||
return {
|
||||
.year = calendar_date.time.year,
|
||||
.month = calendar_date.time.month,
|
||||
.day = calendar_date.time.day,
|
||||
.hour = calendar_date.time.hour,
|
||||
.minute = calendar_date.time.minute,
|
||||
.second = calendar_date.time.second,
|
||||
.unique_id = 0,
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace Service::Capture
|
79
src/core/hle/service/caps/caps_manager.h
Normal file
79
src/core/hle/service/caps/caps_manager.h
Normal file
@ -0,0 +1,79 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include "common/fs/fs.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/caps/caps_types.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace std {
|
||||
// Hash used to create lists from AlbumFileId data
|
||||
template <>
|
||||
struct hash<Service::Capture::AlbumFileId> {
|
||||
size_t operator()(const Service::Capture::AlbumFileId& pad_id) const noexcept {
|
||||
u64 hash_value = (static_cast<u64>(pad_id.date.year) << 8);
|
||||
hash_value ^= (static_cast<u64>(pad_id.date.month) << 7);
|
||||
hash_value ^= (static_cast<u64>(pad_id.date.day) << 6);
|
||||
hash_value ^= (static_cast<u64>(pad_id.date.hour) << 5);
|
||||
hash_value ^= (static_cast<u64>(pad_id.date.minute) << 4);
|
||||
hash_value ^= (static_cast<u64>(pad_id.date.second) << 3);
|
||||
hash_value ^= (static_cast<u64>(pad_id.date.unique_id) << 2);
|
||||
hash_value ^= (static_cast<u64>(pad_id.storage) << 1);
|
||||
hash_value ^= static_cast<u64>(pad_id.type);
|
||||
return static_cast<size_t>(hash_value);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
namespace Service::Capture {
|
||||
|
||||
class AlbumManager {
|
||||
public:
|
||||
explicit AlbumManager(Core::System& system_);
|
||||
~AlbumManager();
|
||||
|
||||
Result DeleteAlbumFile(const AlbumFileId& file_id);
|
||||
Result IsAlbumMounted(AlbumStorage storage);
|
||||
Result GetAlbumFileList(std::vector<AlbumEntry>& out_entries, AlbumStorage storage,
|
||||
u8 flags) const;
|
||||
Result GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& out_entries,
|
||||
ContentType contex_type, s64 start_posix_time, s64 end_posix_time,
|
||||
u64 aruid) const;
|
||||
Result GetAlbumFileList(std::vector<ApplicationAlbumEntry>& out_entries,
|
||||
ContentType contex_type, AlbumFileDateTime start_date,
|
||||
AlbumFileDateTime end_date, u64 aruid) const;
|
||||
Result GetAutoSavingStorage(bool& out_is_autosaving) const;
|
||||
Result LoadAlbumScreenShotImage(LoadAlbumScreenShotImageOutput& out_image_output,
|
||||
std::vector<u8>& out_image, const AlbumFileId& file_id,
|
||||
const ScreenShotDecodeOption& decoder_options) const;
|
||||
Result LoadAlbumScreenShotThumbnail(LoadAlbumScreenShotImageOutput& out_image_output,
|
||||
std::vector<u8>& out_image, const AlbumFileId& file_id,
|
||||
const ScreenShotDecodeOption& decoder_options) const;
|
||||
|
||||
private:
|
||||
static constexpr std::size_t NandAlbumFileLimit = 1000;
|
||||
static constexpr std::size_t SdAlbumFileLimit = 10000;
|
||||
|
||||
void FindScreenshots();
|
||||
Result GetFile(std::filesystem::path& out_path, const AlbumFileId& file_id) const;
|
||||
Result GetAlbumEntry(AlbumEntry& out_entry, const std::filesystem::path& path) const;
|
||||
Result LoadImage(std::span<u8> out_image, const std::filesystem::path& path, int width,
|
||||
int height, ScreenShotDecoderFlag flag) const;
|
||||
|
||||
AlbumFileDateTime ConvertToAlbumDateTime(u64 posix_time) const;
|
||||
|
||||
bool is_mounted{};
|
||||
std::unordered_map<AlbumFileId, std::filesystem::path> album_files;
|
||||
|
||||
Core::System& system;
|
||||
};
|
||||
|
||||
} // namespace Service::Capture
|
35
src/core/hle/service/caps/caps_result.h
Normal file
35
src/core/hle/service/caps/caps_result.h
Normal file
@ -0,0 +1,35 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/result.h"
|
||||
|
||||
namespace Service::Capture {
|
||||
|
||||
constexpr Result ResultWorkMemoryError(ErrorModule::Capture, 3);
|
||||
constexpr Result ResultUnknown5(ErrorModule::Capture, 5);
|
||||
constexpr Result ResultUnknown6(ErrorModule::Capture, 6);
|
||||
constexpr Result ResultUnknown7(ErrorModule::Capture, 7);
|
||||
constexpr Result ResultOutOfRange(ErrorModule::Capture, 8);
|
||||
constexpr Result ResulInvalidTimestamp(ErrorModule::Capture, 12);
|
||||
constexpr Result ResultInvalidStorage(ErrorModule::Capture, 13);
|
||||
constexpr Result ResultInvalidFileContents(ErrorModule::Capture, 14);
|
||||
constexpr Result ResultIsNotMounted(ErrorModule::Capture, 21);
|
||||
constexpr Result ResultUnknown22(ErrorModule::Capture, 22);
|
||||
constexpr Result ResultFileNotFound(ErrorModule::Capture, 23);
|
||||
constexpr Result ResultInvalidFileData(ErrorModule::Capture, 24);
|
||||
constexpr Result ResultUnknown25(ErrorModule::Capture, 25);
|
||||
constexpr Result ResultReadBufferShortage(ErrorModule::Capture, 30);
|
||||
constexpr Result ResultUnknown810(ErrorModule::Capture, 810);
|
||||
constexpr Result ResultUnknown1024(ErrorModule::Capture, 1024);
|
||||
constexpr Result ResultUnknown1202(ErrorModule::Capture, 1202);
|
||||
constexpr Result ResultUnknown1203(ErrorModule::Capture, 1203);
|
||||
constexpr Result ResultFileCountLimit(ErrorModule::Capture, 1401);
|
||||
constexpr Result ResultUnknown1701(ErrorModule::Capture, 1701);
|
||||
constexpr Result ResultUnknown1801(ErrorModule::Capture, 1801);
|
||||
constexpr Result ResultUnknown1802(ErrorModule::Capture, 1802);
|
||||
constexpr Result ResultUnknown1803(ErrorModule::Capture, 1803);
|
||||
constexpr Result ResultUnknown1804(ErrorModule::Capture, 1804);
|
||||
|
||||
} // namespace Service::Capture
|
@ -5,7 +5,8 @@
|
||||
|
||||
namespace Service::Capture {
|
||||
|
||||
CAPS_SC::CAPS_SC(Core::System& system_) : ServiceFramework{system_, "caps:sc"} {
|
||||
IScreenShotControlService::IScreenShotControlService(Core::System& system_)
|
||||
: ServiceFramework{system_, "caps:sc"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{1, nullptr, "CaptureRawImage"},
|
||||
@ -34,6 +35,6 @@ CAPS_SC::CAPS_SC(Core::System& system_) : ServiceFramework{system_, "caps:sc"} {
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
CAPS_SC::~CAPS_SC() = default;
|
||||
IScreenShotControlService::~IScreenShotControlService() = default;
|
||||
|
||||
} // namespace Service::Capture
|
||||
|
@ -11,10 +11,10 @@ class System;
|
||||
|
||||
namespace Service::Capture {
|
||||
|
||||
class CAPS_SC final : public ServiceFramework<CAPS_SC> {
|
||||
class IScreenShotControlService final : public ServiceFramework<IScreenShotControlService> {
|
||||
public:
|
||||
explicit CAPS_SC(Core::System& system_);
|
||||
~CAPS_SC() override;
|
||||
explicit IScreenShotControlService(Core::System& system_);
|
||||
~IScreenShotControlService() override;
|
||||
};
|
||||
|
||||
} // namespace Service::Capture
|
||||
|
@ -5,7 +5,8 @@
|
||||
|
||||
namespace Service::Capture {
|
||||
|
||||
CAPS_SS::CAPS_SS(Core::System& system_) : ServiceFramework{system_, "caps:ss"} {
|
||||
IScreenShotService::IScreenShotService(Core::System& system_)
|
||||
: ServiceFramework{system_, "caps:ss"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{201, nullptr, "SaveScreenShot"},
|
||||
@ -21,6 +22,6 @@ CAPS_SS::CAPS_SS(Core::System& system_) : ServiceFramework{system_, "caps:ss"} {
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
CAPS_SS::~CAPS_SS() = default;
|
||||
IScreenShotService::~IScreenShotService() = default;
|
||||
|
||||
} // namespace Service::Capture
|
||||
|
@ -11,10 +11,10 @@ class System;
|
||||
|
||||
namespace Service::Capture {
|
||||
|
||||
class CAPS_SS final : public ServiceFramework<CAPS_SS> {
|
||||
class IScreenShotService final : public ServiceFramework<IScreenShotService> {
|
||||
public:
|
||||
explicit CAPS_SS(Core::System& system_);
|
||||
~CAPS_SS() override;
|
||||
explicit IScreenShotService(Core::System& system_);
|
||||
~IScreenShotService() override;
|
||||
};
|
||||
|
||||
} // namespace Service::Capture
|
||||
|
@ -7,10 +7,11 @@
|
||||
|
||||
namespace Service::Capture {
|
||||
|
||||
CAPS_SU::CAPS_SU(Core::System& system_) : ServiceFramework{system_, "caps:su"} {
|
||||
IScreenShotApplicationService::IScreenShotApplicationService(Core::System& system_)
|
||||
: ServiceFramework{system_, "caps:su"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{32, &CAPS_SU::SetShimLibraryVersion, "SetShimLibraryVersion"},
|
||||
{32, &IScreenShotApplicationService::SetShimLibraryVersion, "SetShimLibraryVersion"},
|
||||
{201, nullptr, "SaveScreenShot"},
|
||||
{203, nullptr, "SaveScreenShotEx0"},
|
||||
{205, nullptr, "SaveScreenShotEx1"},
|
||||
@ -21,9 +22,9 @@ CAPS_SU::CAPS_SU(Core::System& system_) : ServiceFramework{system_, "caps:su"} {
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
CAPS_SU::~CAPS_SU() = default;
|
||||
IScreenShotApplicationService::~IScreenShotApplicationService() = default;
|
||||
|
||||
void CAPS_SU::SetShimLibraryVersion(HLERequestContext& ctx) {
|
||||
void IScreenShotApplicationService::SetShimLibraryVersion(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto library_version{rp.Pop<u64>()};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
|
@ -11,10 +11,10 @@ class System;
|
||||
|
||||
namespace Service::Capture {
|
||||
|
||||
class CAPS_SU final : public ServiceFramework<CAPS_SU> {
|
||||
class IScreenShotApplicationService final : public ServiceFramework<IScreenShotApplicationService> {
|
||||
public:
|
||||
explicit CAPS_SU(Core::System& system_);
|
||||
~CAPS_SU() override;
|
||||
explicit IScreenShotApplicationService(Core::System& system_);
|
||||
~IScreenShotApplicationService() override;
|
||||
|
||||
private:
|
||||
void SetShimLibraryVersion(HLERequestContext& ctx);
|
||||
|
184
src/core/hle/service/caps/caps_types.h
Normal file
184
src/core/hle/service/caps/caps_types.h
Normal file
@ -0,0 +1,184 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Service::Capture {
|
||||
|
||||
// This is nn::album::ImageOrientation
|
||||
enum class AlbumImageOrientation {
|
||||
None,
|
||||
Rotate90,
|
||||
Rotate180,
|
||||
Rotate270,
|
||||
};
|
||||
|
||||
// This is nn::album::AlbumReportOption
|
||||
enum class AlbumReportOption : s32 {
|
||||
Disable,
|
||||
Enable,
|
||||
};
|
||||
|
||||
enum class ContentType : u8 {
|
||||
Screenshot = 0,
|
||||
Movie = 1,
|
||||
ExtraMovie = 3,
|
||||
};
|
||||
|
||||
enum class AlbumStorage : u8 {
|
||||
Nand,
|
||||
Sd,
|
||||
};
|
||||
|
||||
enum class ScreenShotDecoderFlag : u64 {
|
||||
None = 0,
|
||||
EnableFancyUpsampling = 1 << 0,
|
||||
EnableBlockSmoothing = 1 << 1,
|
||||
};
|
||||
|
||||
// This is nn::capsrv::AlbumFileDateTime
|
||||
struct AlbumFileDateTime {
|
||||
s16 year{};
|
||||
s8 month{};
|
||||
s8 day{};
|
||||
s8 hour{};
|
||||
s8 minute{};
|
||||
s8 second{};
|
||||
s8 unique_id{};
|
||||
|
||||
friend constexpr bool operator==(const AlbumFileDateTime&, const AlbumFileDateTime&) = default;
|
||||
friend constexpr bool operator>(const AlbumFileDateTime& a, const AlbumFileDateTime& b) {
|
||||
if (a.year > b.year) {
|
||||
return true;
|
||||
}
|
||||
if (a.month > b.month) {
|
||||
return true;
|
||||
}
|
||||
if (a.day > b.day) {
|
||||
return true;
|
||||
}
|
||||
if (a.hour > b.hour) {
|
||||
return true;
|
||||
}
|
||||
if (a.minute > b.minute) {
|
||||
return true;
|
||||
}
|
||||
return a.second > b.second;
|
||||
};
|
||||
friend constexpr bool operator<(const AlbumFileDateTime& a, const AlbumFileDateTime& b) {
|
||||
if (a.year < b.year) {
|
||||
return true;
|
||||
}
|
||||
if (a.month < b.month) {
|
||||
return true;
|
||||
}
|
||||
if (a.day < b.day) {
|
||||
return true;
|
||||
}
|
||||
if (a.hour < b.hour) {
|
||||
return true;
|
||||
}
|
||||
if (a.minute < b.minute) {
|
||||
return true;
|
||||
}
|
||||
return a.second < b.second;
|
||||
};
|
||||
};
|
||||
static_assert(sizeof(AlbumFileDateTime) == 0x8, "AlbumFileDateTime has incorrect size.");
|
||||
|
||||
// This is nn::album::AlbumEntry
|
||||
struct AlbumFileEntry {
|
||||
u64 size{}; // Size of the entry
|
||||
u64 hash{}; // AES256 with hardcoded key over AlbumEntry
|
||||
AlbumFileDateTime datetime{};
|
||||
AlbumStorage storage{};
|
||||
ContentType content{};
|
||||
INSERT_PADDING_BYTES(5);
|
||||
u8 unknown{}; // Set to 1 on official SW
|
||||
};
|
||||
static_assert(sizeof(AlbumFileEntry) == 0x20, "AlbumFileEntry has incorrect size.");
|
||||
|
||||
struct AlbumFileId {
|
||||
u64 application_id{};
|
||||
AlbumFileDateTime date{};
|
||||
AlbumStorage storage{};
|
||||
ContentType type{};
|
||||
INSERT_PADDING_BYTES(0x5);
|
||||
u8 unknown{};
|
||||
|
||||
friend constexpr bool operator==(const AlbumFileId&, const AlbumFileId&) = default;
|
||||
};
|
||||
static_assert(sizeof(AlbumFileId) == 0x18, "AlbumFileId is an invalid size");
|
||||
|
||||
// This is nn::capsrv::AlbumEntry
|
||||
struct AlbumEntry {
|
||||
u64 entry_size{};
|
||||
AlbumFileId file_id{};
|
||||
};
|
||||
static_assert(sizeof(AlbumEntry) == 0x20, "AlbumEntry has incorrect size.");
|
||||
|
||||
// This is nn::capsrv::ApplicationAlbumEntry
|
||||
struct ApplicationAlbumEntry {
|
||||
u64 size{}; // Size of the entry
|
||||
u64 hash{}; // AES256 with hardcoded key over AlbumEntry
|
||||
AlbumFileDateTime datetime{};
|
||||
AlbumStorage storage{};
|
||||
ContentType content{};
|
||||
INSERT_PADDING_BYTES(5);
|
||||
u8 unknown{1}; // Set to 1 on official SW
|
||||
};
|
||||
static_assert(sizeof(ApplicationAlbumEntry) == 0x20, "ApplicationAlbumEntry has incorrect size.");
|
||||
|
||||
// This is nn::capsrv::ApplicationAlbumFileEntry
|
||||
struct ApplicationAlbumFileEntry {
|
||||
ApplicationAlbumEntry entry{};
|
||||
AlbumFileDateTime datetime{};
|
||||
u64 unknown{};
|
||||
};
|
||||
static_assert(sizeof(ApplicationAlbumFileEntry) == 0x30,
|
||||
"ApplicationAlbumFileEntry has incorrect size.");
|
||||
|
||||
struct ApplicationData {
|
||||
std::array<u8, 0x400> data{};
|
||||
u32 data_size{};
|
||||
};
|
||||
static_assert(sizeof(ApplicationData) == 0x404, "ApplicationData is an invalid size");
|
||||
|
||||
struct ScreenShotAttribute {
|
||||
u32 unknown_0{};
|
||||
AlbumImageOrientation orientation{};
|
||||
u32 unknown_1{};
|
||||
u32 unknown_2{};
|
||||
INSERT_PADDING_BYTES(0x30);
|
||||
};
|
||||
static_assert(sizeof(ScreenShotAttribute) == 0x40, "ScreenShotAttribute is an invalid size");
|
||||
|
||||
struct ScreenShotDecodeOption {
|
||||
ScreenShotDecoderFlag flags{};
|
||||
INSERT_PADDING_BYTES(0x18);
|
||||
};
|
||||
static_assert(sizeof(ScreenShotDecodeOption) == 0x20, "ScreenShotDecodeOption is an invalid size");
|
||||
|
||||
struct LoadAlbumScreenShotImageOutput {
|
||||
s64 width{};
|
||||
s64 height{};
|
||||
ScreenShotAttribute attribute{};
|
||||
INSERT_PADDING_BYTES(0x400);
|
||||
};
|
||||
static_assert(sizeof(LoadAlbumScreenShotImageOutput) == 0x450,
|
||||
"LoadAlbumScreenShotImageOutput is an invalid size");
|
||||
|
||||
struct LoadAlbumScreenShotImageOutputForApplication {
|
||||
s64 width{};
|
||||
s64 height{};
|
||||
ScreenShotAttribute attribute{};
|
||||
ApplicationData data{};
|
||||
INSERT_PADDING_BYTES(0xAC);
|
||||
};
|
||||
static_assert(sizeof(LoadAlbumScreenShotImageOutputForApplication) == 0x500,
|
||||
"LoadAlbumScreenShotImageOutput is an invalid size");
|
||||
|
||||
} // namespace Service::Capture
|
@ -2,45 +2,29 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/hle/service/caps/caps.h"
|
||||
#include "core/hle/service/caps/caps_manager.h"
|
||||
#include "core/hle/service/caps/caps_types.h"
|
||||
#include "core/hle/service/caps/caps_u.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
|
||||
namespace Service::Capture {
|
||||
|
||||
class IAlbumAccessorApplicationSession final
|
||||
: public ServiceFramework<IAlbumAccessorApplicationSession> {
|
||||
public:
|
||||
explicit IAlbumAccessorApplicationSession(Core::System& system_)
|
||||
: ServiceFramework{system_, "IAlbumAccessorApplicationSession"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{2001, nullptr, "OpenAlbumMovieReadStream"},
|
||||
{2002, nullptr, "CloseAlbumMovieReadStream"},
|
||||
{2003, nullptr, "GetAlbumMovieReadStreamMovieDataSize"},
|
||||
{2004, nullptr, "ReadMovieDataFromAlbumMovieReadStream"},
|
||||
{2005, nullptr, "GetAlbumMovieReadStreamBrokenReason"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
};
|
||||
|
||||
CAPS_U::CAPS_U(Core::System& system_) : ServiceFramework{system_, "caps:u"} {
|
||||
IAlbumApplicationService::IAlbumApplicationService(Core::System& system_,
|
||||
std::shared_ptr<AlbumManager> album_manager)
|
||||
: ServiceFramework{system_, "caps:u"}, manager{album_manager} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{32, &CAPS_U::SetShimLibraryVersion, "SetShimLibraryVersion"},
|
||||
{102, &CAPS_U::GetAlbumContentsFileListForApplication, "GetAlbumContentsFileListForApplication"},
|
||||
{103, nullptr, "DeleteAlbumContentsFileForApplication"},
|
||||
{104, nullptr, "GetAlbumContentsFileSizeForApplication"},
|
||||
{32, &IAlbumApplicationService::SetShimLibraryVersion, "SetShimLibraryVersion"},
|
||||
{102, &IAlbumApplicationService::GetAlbumFileList0AafeAruidDeprecated, "GetAlbumFileList0AafeAruidDeprecated"},
|
||||
{103, nullptr, "DeleteAlbumFileByAruid"},
|
||||
{104, nullptr, "GetAlbumFileSizeByAruid"},
|
||||
{105, nullptr, "DeleteAlbumFileByAruidForDebug"},
|
||||
{110, nullptr, "LoadAlbumContentsFileScreenShotImageForApplication"},
|
||||
{120, nullptr, "LoadAlbumContentsFileThumbnailImageForApplication"},
|
||||
{130, nullptr, "PrecheckToCreateContentsForApplication"},
|
||||
{110, nullptr, "LoadAlbumScreenShotImageByAruid"},
|
||||
{120, nullptr, "LoadAlbumScreenShotThumbnailImageByAruid"},
|
||||
{130, nullptr, "PrecheckToCreateContentsByAruid"},
|
||||
{140, nullptr, "GetAlbumFileList1AafeAruidDeprecated"},
|
||||
{141, nullptr, "GetAlbumFileList2AafeUidAruidDeprecated"},
|
||||
{142, &CAPS_U::GetAlbumFileList3AaeAruid, "GetAlbumFileList3AaeAruid"},
|
||||
{142, &IAlbumApplicationService::GetAlbumFileList3AaeAruid, "GetAlbumFileList3AaeAruid"},
|
||||
{143, nullptr, "GetAlbumFileList4AaeUidAruid"},
|
||||
{144, nullptr, "GetAllAlbumFileList3AaeAruid"},
|
||||
{60002, nullptr, "OpenAccessorSessionForApplication"},
|
||||
@ -50,9 +34,9 @@ CAPS_U::CAPS_U(Core::System& system_) : ServiceFramework{system_, "caps:u"} {
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
CAPS_U::~CAPS_U() = default;
|
||||
IAlbumApplicationService::~IAlbumApplicationService() = default;
|
||||
|
||||
void CAPS_U::SetShimLibraryVersion(HLERequestContext& ctx) {
|
||||
void IAlbumApplicationService::SetShimLibraryVersion(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto library_version{rp.Pop<u64>()};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
@ -64,37 +48,89 @@ void CAPS_U::SetShimLibraryVersion(HLERequestContext& ctx) {
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void CAPS_U::GetAlbumContentsFileListForApplication(HLERequestContext& ctx) {
|
||||
// Takes a type-0x6 output buffer containing an array of ApplicationAlbumFileEntry, a PID, an
|
||||
// u8 ContentType, two s64s, and an u64 AppletResourceUserId. Returns an output u64 for total
|
||||
// output entries (which is copied to a s32 by official SW).
|
||||
void IAlbumApplicationService::GetAlbumFileList0AafeAruidDeprecated(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto pid{rp.Pop<s32>()};
|
||||
const auto content_type{rp.PopEnum<ContentType>()};
|
||||
const auto start_posix_time{rp.Pop<s64>()};
|
||||
const auto end_posix_time{rp.Pop<s64>()};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
struct Parameters {
|
||||
ContentType content_type;
|
||||
INSERT_PADDING_BYTES(7);
|
||||
s64 start_posix_time;
|
||||
s64 end_posix_time;
|
||||
u64 applet_resource_user_id;
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 0x20, "Parameters has incorrect size.");
|
||||
|
||||
// TODO: Update this when we implement the album.
|
||||
// Currently we do not have a method of accessing album entries, set this to 0 for now.
|
||||
constexpr u32 total_entries_1{};
|
||||
constexpr u32 total_entries_2{};
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
|
||||
LOG_WARNING(
|
||||
Service_Capture,
|
||||
"(STUBBED) called. pid={}, content_type={}, start_posix_time={}, "
|
||||
"end_posix_time={}, applet_resource_user_id={}, total_entries_1={}, total_entries_2={}",
|
||||
pid, content_type, start_posix_time, end_posix_time, applet_resource_user_id,
|
||||
total_entries_1, total_entries_2);
|
||||
LOG_WARNING(Service_Capture,
|
||||
"(STUBBED) called. content_type={}, start_posix_time={}, end_posix_time={}, "
|
||||
"applet_resource_user_id={}",
|
||||
parameters.content_type, parameters.start_posix_time, parameters.end_posix_time,
|
||||
parameters.applet_resource_user_id);
|
||||
|
||||
Result result = ResultSuccess;
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
result = manager->IsAlbumMounted(AlbumStorage::Sd);
|
||||
}
|
||||
|
||||
std::vector<ApplicationAlbumFileEntry> entries;
|
||||
if (result.IsSuccess()) {
|
||||
result = manager->GetAlbumFileList(entries, parameters.content_type,
|
||||
parameters.start_posix_time, parameters.end_posix_time,
|
||||
parameters.applet_resource_user_id);
|
||||
}
|
||||
|
||||
if (!entries.empty()) {
|
||||
ctx.WriteBuffer(entries);
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(total_entries_1);
|
||||
rb.Push(total_entries_2);
|
||||
rb.Push(result);
|
||||
rb.Push<u64>(entries.size());
|
||||
}
|
||||
|
||||
void CAPS_U::GetAlbumFileList3AaeAruid(HLERequestContext& ctx) {
|
||||
GetAlbumContentsFileListForApplication(ctx);
|
||||
void IAlbumApplicationService::GetAlbumFileList3AaeAruid(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
ContentType content_type;
|
||||
INSERT_PADDING_BYTES(1);
|
||||
AlbumFileDateTime start_date_time;
|
||||
AlbumFileDateTime end_date_time;
|
||||
INSERT_PADDING_BYTES(6);
|
||||
u64 applet_resource_user_id;
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 0x20, "Parameters has incorrect size.");
|
||||
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
|
||||
LOG_WARNING(Service_Capture,
|
||||
"(STUBBED) called. content_type={}, start_date={}/{}/{}, "
|
||||
"end_date={}/{}/{}, applet_resource_user_id={}",
|
||||
parameters.content_type, parameters.start_date_time.year,
|
||||
parameters.start_date_time.month, parameters.start_date_time.day,
|
||||
parameters.end_date_time.year, parameters.end_date_time.month,
|
||||
parameters.end_date_time.day, parameters.applet_resource_user_id);
|
||||
|
||||
Result result = ResultSuccess;
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
result = manager->IsAlbumMounted(AlbumStorage::Sd);
|
||||
}
|
||||
|
||||
std::vector<ApplicationAlbumEntry> entries;
|
||||
if (result.IsSuccess()) {
|
||||
result =
|
||||
manager->GetAlbumFileList(entries, parameters.content_type, parameters.start_date_time,
|
||||
parameters.end_date_time, parameters.applet_resource_user_id);
|
||||
}
|
||||
|
||||
if (!entries.empty()) {
|
||||
ctx.WriteBuffer(entries);
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(result);
|
||||
rb.Push<u64>(entries.size());
|
||||
}
|
||||
|
||||
} // namespace Service::Capture
|
||||
|
@ -10,16 +10,20 @@ class System;
|
||||
}
|
||||
|
||||
namespace Service::Capture {
|
||||
class AlbumManager;
|
||||
|
||||
class CAPS_U final : public ServiceFramework<CAPS_U> {
|
||||
class IAlbumApplicationService final : public ServiceFramework<IAlbumApplicationService> {
|
||||
public:
|
||||
explicit CAPS_U(Core::System& system_);
|
||||
~CAPS_U() override;
|
||||
explicit IAlbumApplicationService(Core::System& system_,
|
||||
std::shared_ptr<AlbumManager> album_manager);
|
||||
~IAlbumApplicationService() override;
|
||||
|
||||
private:
|
||||
void SetShimLibraryVersion(HLERequestContext& ctx);
|
||||
void GetAlbumContentsFileListForApplication(HLERequestContext& ctx);
|
||||
void GetAlbumFileList0AafeAruidDeprecated(HLERequestContext& ctx);
|
||||
void GetAlbumFileList3AaeAruid(HLERequestContext& ctx);
|
||||
|
||||
std::shared_ptr<AlbumManager> manager = nullptr;
|
||||
};
|
||||
|
||||
} // namespace Service::Capture
|
||||
|
@ -1,74 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/core.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"
|
||||
#include "core/memory.h"
|
||||
|
||||
namespace Service::HID {
|
||||
constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C200;
|
||||
|
||||
Controller_ConsoleSixAxis::Controller_ConsoleSixAxis(Core::System& system_, u8* raw_shared_memory_)
|
||||
: ControllerBase{system_.HIDCore()}, system{system_} {
|
||||
console = hid_core.GetEmulatedConsole();
|
||||
static_assert(SHARED_MEMORY_OFFSET + sizeof(ConsoleSharedMemory) < shared_memory_size,
|
||||
"ConsoleSharedMemory is bigger than the shared memory");
|
||||
shared_memory = std::construct_at(
|
||||
reinterpret_cast<ConsoleSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET));
|
||||
}
|
||||
|
||||
Controller_ConsoleSixAxis::~Controller_ConsoleSixAxis() = default;
|
||||
|
||||
void Controller_ConsoleSixAxis::OnInit() {}
|
||||
|
||||
void Controller_ConsoleSixAxis::OnRelease() {}
|
||||
|
||||
void Controller_ConsoleSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
||||
if (!IsControllerActivated() || transfer_memory == 0) {
|
||||
seven_sixaxis_lifo.buffer_count = 0;
|
||||
seven_sixaxis_lifo.buffer_tail = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& last_entry = seven_sixaxis_lifo.ReadCurrentEntry().state;
|
||||
next_seven_sixaxis_state.sampling_number = last_entry.sampling_number + 1;
|
||||
|
||||
const auto motion_status = console->GetMotion();
|
||||
last_global_timestamp = core_timing.GetGlobalTimeNs().count();
|
||||
|
||||
// This value increments every time the switch goes to sleep
|
||||
next_seven_sixaxis_state.unknown = 1;
|
||||
next_seven_sixaxis_state.timestamp = last_global_timestamp - last_saved_timestamp;
|
||||
next_seven_sixaxis_state.accel = motion_status.accel;
|
||||
next_seven_sixaxis_state.gyro = motion_status.gyro;
|
||||
next_seven_sixaxis_state.quaternion = {
|
||||
{
|
||||
motion_status.quaternion.xyz.y,
|
||||
motion_status.quaternion.xyz.x,
|
||||
-motion_status.quaternion.w,
|
||||
},
|
||||
-motion_status.quaternion.xyz.z,
|
||||
};
|
||||
|
||||
shared_memory->sampling_number++;
|
||||
shared_memory->is_seven_six_axis_sensor_at_rest = motion_status.is_at_rest;
|
||||
shared_memory->verticalization_error = motion_status.verticalization_error;
|
||||
shared_memory->gyro_bias = motion_status.gyro_bias;
|
||||
|
||||
// Update seven six axis transfer memory
|
||||
seven_sixaxis_lifo.WriteNextEntry(next_seven_sixaxis_state);
|
||||
system.ApplicationMemory().WriteBlock(transfer_memory, &seven_sixaxis_lifo,
|
||||
sizeof(seven_sixaxis_lifo));
|
||||
}
|
||||
|
||||
void Controller_ConsoleSixAxis::SetTransferMemoryAddress(Common::ProcessAddress t_mem) {
|
||||
transfer_memory = t_mem;
|
||||
}
|
||||
|
||||
void Controller_ConsoleSixAxis::ResetTimestamp() {
|
||||
last_saved_timestamp = last_global_timestamp;
|
||||
}
|
||||
} // namespace Service::HID
|
@ -1,78 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "common/quaternion.h"
|
||||
#include "common/typed_address.h"
|
||||
#include "core/hle/service/hid/controllers/controller_base.h"
|
||||
#include "core/hle/service/hid/ring_lifo.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
} // namespace Core
|
||||
|
||||
namespace Core::HID {
|
||||
class EmulatedConsole;
|
||||
} // namespace Core::HID
|
||||
|
||||
namespace Service::HID {
|
||||
class Controller_ConsoleSixAxis final : public ControllerBase {
|
||||
public:
|
||||
explicit Controller_ConsoleSixAxis(Core::System& system_, u8* raw_shared_memory_);
|
||||
~Controller_ConsoleSixAxis() override;
|
||||
|
||||
// Called when the controller is initialized
|
||||
void OnInit() override;
|
||||
|
||||
// When the controller is released
|
||||
void OnRelease() override;
|
||||
|
||||
// When the controller is requesting an update for the shared memory
|
||||
void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
|
||||
|
||||
// Called on InitializeSevenSixAxisSensor
|
||||
void SetTransferMemoryAddress(Common::ProcessAddress t_mem);
|
||||
|
||||
// Called on ResetSevenSixAxisSensorTimestamp
|
||||
void ResetTimestamp();
|
||||
|
||||
private:
|
||||
struct SevenSixAxisState {
|
||||
INSERT_PADDING_WORDS(2); // unused
|
||||
u64 timestamp{};
|
||||
u64 sampling_number{};
|
||||
u64 unknown{};
|
||||
Common::Vec3f accel{};
|
||||
Common::Vec3f gyro{};
|
||||
Common::Quaternion<f32> quaternion{};
|
||||
};
|
||||
static_assert(sizeof(SevenSixAxisState) == 0x48, "SevenSixAxisState is an invalid size");
|
||||
|
||||
// This is nn::hid::detail::ConsoleSixAxisSensorSharedMemoryFormat
|
||||
struct ConsoleSharedMemory {
|
||||
u64 sampling_number{};
|
||||
bool is_seven_six_axis_sensor_at_rest{};
|
||||
INSERT_PADDING_BYTES(3); // padding
|
||||
f32 verticalization_error{};
|
||||
Common::Vec3f gyro_bias{};
|
||||
INSERT_PADDING_BYTES(4); // padding
|
||||
};
|
||||
static_assert(sizeof(ConsoleSharedMemory) == 0x20, "ConsoleSharedMemory is an invalid size");
|
||||
|
||||
Lifo<SevenSixAxisState, 0x21> seven_sixaxis_lifo{};
|
||||
static_assert(sizeof(seven_sixaxis_lifo) == 0xA70, "SevenSixAxisState is an invalid size");
|
||||
|
||||
SevenSixAxisState next_seven_sixaxis_state{};
|
||||
Common::ProcessAddress transfer_memory{};
|
||||
ConsoleSharedMemory* shared_memory = nullptr;
|
||||
Core::HID::EmulatedConsole* console = nullptr;
|
||||
|
||||
u64 last_saved_timestamp{};
|
||||
u64 last_global_timestamp{};
|
||||
|
||||
Core::System& system;
|
||||
};
|
||||
} // namespace Service::HID
|
@ -1,29 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/hle/service/hid/controllers/controller_base.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
ControllerBase::ControllerBase(Core::HID::HIDCore& hid_core_) : hid_core(hid_core_) {}
|
||||
ControllerBase::~ControllerBase() = default;
|
||||
|
||||
void ControllerBase::ActivateController() {
|
||||
if (is_activated) {
|
||||
return;
|
||||
}
|
||||
is_activated = true;
|
||||
OnInit();
|
||||
}
|
||||
|
||||
void ControllerBase::DeactivateController() {
|
||||
if (is_activated) {
|
||||
OnRelease();
|
||||
}
|
||||
is_activated = false;
|
||||
}
|
||||
|
||||
bool ControllerBase::IsControllerActivated() const {
|
||||
return is_activated;
|
||||
}
|
||||
} // namespace Service::HID
|
@ -1,48 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Core::Timing {
|
||||
class CoreTiming;
|
||||
}
|
||||
|
||||
namespace Core::HID {
|
||||
class HIDCore;
|
||||
}
|
||||
|
||||
namespace Service::HID {
|
||||
class ControllerBase {
|
||||
public:
|
||||
explicit ControllerBase(Core::HID::HIDCore& hid_core_);
|
||||
virtual ~ControllerBase();
|
||||
|
||||
// Called when the controller is initialized
|
||||
virtual void OnInit() = 0;
|
||||
|
||||
// When the controller is released
|
||||
virtual void OnRelease() = 0;
|
||||
|
||||
// When the controller is requesting an update for the shared memory
|
||||
virtual void OnUpdate(const Core::Timing::CoreTiming& core_timing) = 0;
|
||||
|
||||
// When the controller is requesting a motion update for the shared memory
|
||||
virtual void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing) {}
|
||||
|
||||
void ActivateController();
|
||||
|
||||
void DeactivateController();
|
||||
|
||||
bool IsControllerActivated() const;
|
||||
|
||||
static const std::size_t hid_entry_count = 17;
|
||||
static const std::size_t shared_memory_size = 0x40000;
|
||||
|
||||
protected:
|
||||
bool is_activated{false};
|
||||
|
||||
Core::HID::HIDCore& hid_core;
|
||||
};
|
||||
} // namespace Service::HID
|
@ -1,55 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <cstring>
|
||||
#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;
|
||||
|
||||
Controller_DebugPad::Controller_DebugPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_)
|
||||
: ControllerBase{hid_core_} {
|
||||
static_assert(SHARED_MEMORY_OFFSET + sizeof(DebugPadSharedMemory) < shared_memory_size,
|
||||
"DebugPadSharedMemory is bigger than the shared memory");
|
||||
shared_memory = std::construct_at(
|
||||
reinterpret_cast<DebugPadSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET));
|
||||
controller = hid_core.GetEmulatedController(Core::HID::NpadIdType::Other);
|
||||
}
|
||||
|
||||
Controller_DebugPad::~Controller_DebugPad() = default;
|
||||
|
||||
void Controller_DebugPad::OnInit() {}
|
||||
|
||||
void Controller_DebugPad::OnRelease() {}
|
||||
|
||||
void Controller_DebugPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
||||
if (!IsControllerActivated()) {
|
||||
shared_memory->debug_pad_lifo.buffer_count = 0;
|
||||
shared_memory->debug_pad_lifo.buffer_tail = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& last_entry = shared_memory->debug_pad_lifo.ReadCurrentEntry().state;
|
||||
next_state.sampling_number = last_entry.sampling_number + 1;
|
||||
|
||||
if (Settings::values.debug_pad_enabled) {
|
||||
next_state.attribute.connected.Assign(1);
|
||||
|
||||
const auto& button_state = controller->GetDebugPadButtons();
|
||||
const auto& stick_state = controller->GetSticks();
|
||||
|
||||
next_state.pad_state = button_state;
|
||||
next_state.l_stick = stick_state.left;
|
||||
next_state.r_stick = stick_state.right;
|
||||
}
|
||||
|
||||
shared_memory->debug_pad_lifo.WriteNextEntry(next_state);
|
||||
}
|
||||
|
||||
} // namespace Service::HID
|
@ -1,64 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/bit_field.h"
|
||||
#include "common/common_types.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::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
|
||||
~Controller_DebugPad() override;
|
||||
|
||||
// Called when the controller is initialized
|
||||
void OnInit() override;
|
||||
|
||||
// When the controller is released
|
||||
void OnRelease() override;
|
||||
|
||||
// When the controller is requesting an update for the shared memory
|
||||
void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
|
||||
|
||||
private:
|
||||
// This is nn::hid::DebugPadAttribute
|
||||
struct DebugPadAttribute {
|
||||
union {
|
||||
u32 raw{};
|
||||
BitField<0, 1, u32> connected;
|
||||
};
|
||||
};
|
||||
static_assert(sizeof(DebugPadAttribute) == 0x4, "DebugPadAttribute is an invalid size");
|
||||
|
||||
// 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(DebugPadState) == 0x20, "DebugPadState is an invalid state");
|
||||
|
||||
struct DebugPadSharedMemory {
|
||||
// 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");
|
||||
INSERT_PADDING_WORDS(0x4E);
|
||||
};
|
||||
static_assert(sizeof(DebugPadSharedMemory) == 0x400, "DebugPadSharedMemory is an invalid size");
|
||||
|
||||
DebugPadState next_state{};
|
||||
DebugPadSharedMemory* shared_memory = nullptr;
|
||||
Core::HID::EmulatedController* controller = nullptr;
|
||||
};
|
||||
} // namespace Service::HID
|
@ -1,359 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "common/math_util.h"
|
||||
#include "common/settings.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/frontend/emu_window.h"
|
||||
#include "core/hid/hid_core.h"
|
||||
#include "core/hle/service/hid/controllers/gesture.h"
|
||||
|
||||
namespace Service::HID {
|
||||
constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3BA00;
|
||||
|
||||
// HW is around 700, value is set to 400 to make it easier to trigger with mouse
|
||||
constexpr f32 swipe_threshold = 400.0f; // Threshold in pixels/s
|
||||
constexpr f32 angle_threshold = 0.015f; // Threshold in radians
|
||||
constexpr f32 pinch_threshold = 0.5f; // Threshold in pixels
|
||||
constexpr f32 press_delay = 0.5f; // Time in seconds
|
||||
constexpr f32 double_tap_delay = 0.35f; // Time in seconds
|
||||
|
||||
constexpr f32 Square(s32 num) {
|
||||
return static_cast<f32>(num * num);
|
||||
}
|
||||
|
||||
Controller_Gesture::Controller_Gesture(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_)
|
||||
: ControllerBase(hid_core_) {
|
||||
static_assert(SHARED_MEMORY_OFFSET + sizeof(GestureSharedMemory) < shared_memory_size,
|
||||
"GestureSharedMemory is bigger than the shared memory");
|
||||
shared_memory = std::construct_at(
|
||||
reinterpret_cast<GestureSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET));
|
||||
console = hid_core.GetEmulatedConsole();
|
||||
}
|
||||
Controller_Gesture::~Controller_Gesture() = default;
|
||||
|
||||
void Controller_Gesture::OnInit() {
|
||||
shared_memory->gesture_lifo.buffer_count = 0;
|
||||
shared_memory->gesture_lifo.buffer_tail = 0;
|
||||
force_update = true;
|
||||
}
|
||||
|
||||
void Controller_Gesture::OnRelease() {}
|
||||
|
||||
void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
||||
if (!IsControllerActivated()) {
|
||||
shared_memory->gesture_lifo.buffer_count = 0;
|
||||
shared_memory->gesture_lifo.buffer_tail = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
ReadTouchInput();
|
||||
|
||||
GestureProperties gesture = GetGestureProperties();
|
||||
f32 time_difference =
|
||||
static_cast<f32>(shared_memory->gesture_lifo.timestamp - last_update_timestamp) /
|
||||
(1000 * 1000 * 1000);
|
||||
|
||||
// Only update if necessary
|
||||
if (!ShouldUpdateGesture(gesture, time_difference)) {
|
||||
return;
|
||||
}
|
||||
|
||||
last_update_timestamp = shared_memory->gesture_lifo.timestamp;
|
||||
UpdateGestureSharedMemory(gesture, time_difference);
|
||||
}
|
||||
|
||||
void Controller_Gesture::ReadTouchInput() {
|
||||
if (!Settings::values.touchscreen.enabled) {
|
||||
fingers = {};
|
||||
return;
|
||||
}
|
||||
|
||||
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 = GetLastGestureEntry();
|
||||
if (force_update) {
|
||||
force_update = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Update if coordinates change
|
||||
for (size_t id = 0; id < MAX_POINTS; id++) {
|
||||
if (gesture.points[id] != last_gesture.points[id]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Update on press and hold event after 0.5 seconds
|
||||
if (last_entry.type == GestureType::Touch && last_entry.point_count == 1 &&
|
||||
time_difference > press_delay) {
|
||||
return enable_press_and_tap;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Controller_Gesture::UpdateGestureSharedMemory(GestureProperties& gesture,
|
||||
f32 time_difference) {
|
||||
GestureType type = GestureType::Idle;
|
||||
GestureAttribute attributes{};
|
||||
|
||||
const auto& last_entry = shared_memory->gesture_lifo.ReadCurrentEntry().state;
|
||||
|
||||
// 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) {
|
||||
NewGesture(gesture, type, attributes);
|
||||
} else {
|
||||
UpdateExistingGesture(gesture, type, time_difference);
|
||||
}
|
||||
} else {
|
||||
EndGesture(gesture, last_gesture, type, attributes, time_difference);
|
||||
}
|
||||
|
||||
// Apply attributes
|
||||
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;
|
||||
|
||||
shared_memory->gesture_lifo.WriteNextEntry(next_state);
|
||||
}
|
||||
|
||||
void Controller_Gesture::NewGesture(GestureProperties& gesture, GestureType& type,
|
||||
GestureAttribute& attributes) {
|
||||
const auto& last_entry = GetLastGestureEntry();
|
||||
|
||||
gesture.detection_count++;
|
||||
type = GestureType::Touch;
|
||||
|
||||
// New touch after cancel is not considered new
|
||||
if (last_entry.type != GestureType::Cancel) {
|
||||
attributes.is_new_touch.Assign(1);
|
||||
enable_press_and_tap = true;
|
||||
}
|
||||
}
|
||||
|
||||
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 = GestureType::Pan;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Number of fingers changed cancel the last event and clear data
|
||||
if (gesture.active_points != last_gesture.active_points) {
|
||||
type = GestureType::Cancel;
|
||||
enable_press_and_tap = false;
|
||||
gesture.active_points = 0;
|
||||
gesture.mid_point = {};
|
||||
gesture.points.fill({});
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate extra parameters of panning
|
||||
if (type == GestureType::Pan) {
|
||||
UpdatePanEvent(gesture, last_gesture, type, time_difference);
|
||||
return;
|
||||
}
|
||||
|
||||
// Promote to press type
|
||||
if (last_entry.type == GestureType::Touch) {
|
||||
type = GestureType::Press;
|
||||
}
|
||||
}
|
||||
|
||||
void Controller_Gesture::EndGesture(GestureProperties& gesture,
|
||||
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 GestureType::Touch:
|
||||
if (enable_press_and_tap) {
|
||||
SetTapEvent(gesture, last_gesture_props, type, attributes);
|
||||
return;
|
||||
}
|
||||
type = GestureType::Cancel;
|
||||
force_update = true;
|
||||
break;
|
||||
case GestureType::Press:
|
||||
case GestureType::Tap:
|
||||
case GestureType::Swipe:
|
||||
case GestureType::Pinch:
|
||||
case GestureType::Rotate:
|
||||
type = GestureType::Complete;
|
||||
force_update = true;
|
||||
break;
|
||||
case GestureType::Pan:
|
||||
EndPanEvent(gesture, last_gesture_props, type, time_difference);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (last_entry.type == GestureType::Complete || last_entry.type == GestureType::Cancel) {
|
||||
gesture.detection_count++;
|
||||
}
|
||||
}
|
||||
|
||||
void Controller_Gesture::SetTapEvent(GestureProperties& gesture,
|
||||
GestureProperties& last_gesture_props, GestureType& type,
|
||||
GestureAttribute& attributes) {
|
||||
type = GestureType::Tap;
|
||||
gesture = last_gesture_props;
|
||||
force_update = true;
|
||||
f32 tap_time_difference =
|
||||
static_cast<f32>(last_update_timestamp - last_tap_timestamp) / (1000 * 1000 * 1000);
|
||||
last_tap_timestamp = last_update_timestamp;
|
||||
if (tap_time_difference < double_tap_delay) {
|
||||
attributes.is_double_tap.Assign(1);
|
||||
}
|
||||
}
|
||||
|
||||
void Controller_Gesture::UpdatePanEvent(GestureProperties& gesture,
|
||||
GestureProperties& last_gesture_props, GestureType& type,
|
||||
f32 time_difference) {
|
||||
const auto& last_entry = GetLastGestureEntry();
|
||||
|
||||
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 = 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 = 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, GestureType& type,
|
||||
f32 time_difference) {
|
||||
const auto& last_entry = GetLastGestureEntry();
|
||||
next_state.vel_x =
|
||||
static_cast<f32>(last_entry.delta.x) / (last_pan_time_difference + time_difference);
|
||||
next_state.vel_y =
|
||||
static_cast<f32>(last_entry.delta.y) / (last_pan_time_difference + time_difference);
|
||||
const f32 curr_vel =
|
||||
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) {
|
||||
SetSwipeEvent(gesture, last_gesture_props, type);
|
||||
return;
|
||||
}
|
||||
|
||||
// End panning without swipe
|
||||
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, GestureType& type) {
|
||||
const auto& last_entry = GetLastGestureEntry();
|
||||
|
||||
type = GestureType::Swipe;
|
||||
gesture = last_gesture_props;
|
||||
force_update = true;
|
||||
next_state.delta = last_entry.delta;
|
||||
|
||||
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;
|
||||
}
|
||||
next_state.direction = GestureDirection::Left;
|
||||
return;
|
||||
}
|
||||
if (next_state.delta.y > 0) {
|
||||
next_state.direction = GestureDirection::Down;
|
||||
return;
|
||||
}
|
||||
next_state.direction = GestureDirection::Up;
|
||||
}
|
||||
|
||||
const Controller_Gesture::GestureState& Controller_Gesture::GetLastGestureEntry() const {
|
||||
return shared_memory->gesture_lifo.ReadCurrentEntry().state;
|
||||
}
|
||||
|
||||
Controller_Gesture::GestureProperties Controller_Gesture::GetGestureProperties() {
|
||||
GestureProperties gesture;
|
||||
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].position;
|
||||
gesture.points[id] = {
|
||||
.x = static_cast<s32>(active_x * Layout::ScreenUndocked::Width),
|
||||
.y = static_cast<s32>(active_y * Layout::ScreenUndocked::Height),
|
||||
};
|
||||
|
||||
// Hack: There is no touch in docked but games still allow it
|
||||
if (Settings::IsDockedMode()) {
|
||||
gesture.points[id] = {
|
||||
.x = static_cast<s32>(active_x * Layout::ScreenDocked::Width),
|
||||
.y = static_cast<s32>(active_y * Layout::ScreenDocked::Height),
|
||||
};
|
||||
}
|
||||
|
||||
gesture.mid_point.x += static_cast<s32>(gesture.points[id].x / gesture.active_points);
|
||||
gesture.mid_point.y += static_cast<s32>(gesture.points[id].y / gesture.active_points);
|
||||
}
|
||||
|
||||
for (size_t id = 0; id < gesture.active_points; ++id) {
|
||||
const f32 distance = std::sqrt(Square(gesture.mid_point.x - gesture.points[id].x) +
|
||||
Square(gesture.mid_point.y - gesture.points[id].y));
|
||||
gesture.average_distance += distance / static_cast<f32>(gesture.active_points);
|
||||
}
|
||||
|
||||
gesture.angle = std::atan2(static_cast<f32>(gesture.mid_point.y - gesture.points[0].y),
|
||||
static_cast<f32>(gesture.mid_point.x - gesture.points[0].x));
|
||||
|
||||
gesture.detection_count = last_gesture.detection_count;
|
||||
|
||||
return gesture;
|
||||
}
|
||||
|
||||
} // namespace Service::HID
|
@ -1,156 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include "common/bit_field.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/point.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::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
|
||||
~Controller_Gesture() override;
|
||||
|
||||
// Called when the controller is initialized
|
||||
void OnInit() override;
|
||||
|
||||
// When the controller is released
|
||||
void OnRelease() override;
|
||||
|
||||
// When the controller is requesting an update for the shared memory
|
||||
void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
|
||||
|
||||
private:
|
||||
static constexpr size_t MAX_FINGERS = 16;
|
||||
static constexpr size_t MAX_POINTS = 4;
|
||||
|
||||
// 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
|
||||
Touch, // A finger just touched the screen
|
||||
Press, // Set if last type is touch and the finger hasn't moved
|
||||
Tap, // Fast press then release
|
||||
Pan, // All points moving together across the screen
|
||||
Swipe, // Fast press movement and release of a single point
|
||||
Pinch, // All points moving away/closer to the midpoint
|
||||
Rotate, // All points rotating from the midpoint
|
||||
};
|
||||
|
||||
// This is nn::hid::GestureDirection
|
||||
enum class GestureDirection : u32 {
|
||||
None,
|
||||
Left,
|
||||
Up,
|
||||
Right,
|
||||
Down,
|
||||
};
|
||||
|
||||
// This is nn::hid::GestureAttribute
|
||||
struct GestureAttribute {
|
||||
union {
|
||||
u32 raw{};
|
||||
|
||||
BitField<4, 1, u32> is_new_touch;
|
||||
BitField<8, 1, u32> is_double_tap;
|
||||
};
|
||||
};
|
||||
static_assert(sizeof(GestureAttribute) == 4, "GestureAttribute is an invalid size");
|
||||
|
||||
// This is nn::hid::GestureState
|
||||
struct GestureState {
|
||||
s64 sampling_number{};
|
||||
s64 detection_count{};
|
||||
GestureType type{GestureType::Idle};
|
||||
GestureDirection direction{GestureDirection::None};
|
||||
Common::Point<s32> pos{};
|
||||
Common::Point<s32> delta{};
|
||||
f32 vel_x{};
|
||||
f32 vel_y{};
|
||||
GestureAttribute attributes{};
|
||||
f32 scale{};
|
||||
f32 rotation_angle{};
|
||||
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>, MAX_POINTS> points{};
|
||||
std::size_t active_points{};
|
||||
Common::Point<s32> mid_point{};
|
||||
s64 detection_count{};
|
||||
u64 delta_time{};
|
||||
f32 average_distance{};
|
||||
f32 angle{};
|
||||
};
|
||||
|
||||
struct GestureSharedMemory {
|
||||
// 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");
|
||||
INSERT_PADDING_WORDS(0x3E);
|
||||
};
|
||||
static_assert(sizeof(GestureSharedMemory) == 0x800, "GestureSharedMemory is an invalid size");
|
||||
|
||||
// Reads input from all available input engines
|
||||
void ReadTouchInput();
|
||||
|
||||
// Returns true if gesture state needs to be updated
|
||||
bool ShouldUpdateGesture(const GestureProperties& gesture, f32 time_difference);
|
||||
|
||||
// Updates the shared memory to the next state
|
||||
void UpdateGestureSharedMemory(GestureProperties& gesture, f32 time_difference);
|
||||
|
||||
// Initializes new gesture
|
||||
void NewGesture(GestureProperties& gesture, GestureType& type, GestureAttribute& attributes);
|
||||
|
||||
// Updates existing gesture state
|
||||
void UpdateExistingGesture(GestureProperties& gesture, GestureType& type, f32 time_difference);
|
||||
|
||||
// Terminates exiting gesture
|
||||
void EndGesture(GestureProperties& gesture, GestureProperties& last_gesture_props,
|
||||
GestureType& type, GestureAttribute& attributes, f32 time_difference);
|
||||
|
||||
// Set current event to a tap event
|
||||
void SetTapEvent(GestureProperties& gesture, GestureProperties& last_gesture_props,
|
||||
GestureType& type, GestureAttribute& attributes);
|
||||
|
||||
// Calculates and set the extra parameters related to a pan event
|
||||
void UpdatePanEvent(GestureProperties& gesture, GestureProperties& last_gesture_props,
|
||||
GestureType& type, f32 time_difference);
|
||||
|
||||
// Terminates the pan event
|
||||
void EndPanEvent(GestureProperties& gesture, GestureProperties& last_gesture_props,
|
||||
GestureType& type, f32 time_difference);
|
||||
|
||||
// Set current event to a swipe event
|
||||
void SetSwipeEvent(GestureProperties& gesture, GestureProperties& last_gesture_props,
|
||||
GestureType& type);
|
||||
|
||||
// Retrieves the last gesture entry, as indicated by shared memory indices.
|
||||
[[nodiscard]] const GestureState& GetLastGestureEntry() const;
|
||||
|
||||
// Returns the average distance, angle and middle point of the active fingers
|
||||
GestureProperties GetGestureProperties();
|
||||
|
||||
GestureState next_state{};
|
||||
GestureSharedMemory* shared_memory = nullptr;
|
||||
Core::HID::EmulatedConsole* console = nullptr;
|
||||
|
||||
std::array<Core::HID::TouchFinger, MAX_POINTS> fingers{};
|
||||
GestureProperties last_gesture{};
|
||||
s64 last_update_timestamp{};
|
||||
s64 last_tap_timestamp{};
|
||||
f32 last_pan_time_difference{};
|
||||
bool force_update{false};
|
||||
bool enable_press_and_tap{false};
|
||||
};
|
||||
} // namespace Service::HID
|
@ -1,52 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <cstring>
|
||||
#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;
|
||||
|
||||
Controller_Keyboard::Controller_Keyboard(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_)
|
||||
: ControllerBase{hid_core_} {
|
||||
static_assert(SHARED_MEMORY_OFFSET + sizeof(KeyboardSharedMemory) < shared_memory_size,
|
||||
"KeyboardSharedMemory is bigger than the shared memory");
|
||||
shared_memory = std::construct_at(
|
||||
reinterpret_cast<KeyboardSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET));
|
||||
emulated_devices = hid_core.GetEmulatedDevices();
|
||||
}
|
||||
|
||||
Controller_Keyboard::~Controller_Keyboard() = default;
|
||||
|
||||
void Controller_Keyboard::OnInit() {}
|
||||
|
||||
void Controller_Keyboard::OnRelease() {}
|
||||
|
||||
void Controller_Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
||||
if (!IsControllerActivated()) {
|
||||
shared_memory->keyboard_lifo.buffer_count = 0;
|
||||
shared_memory->keyboard_lifo.buffer_tail = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& last_entry = shared_memory->keyboard_lifo.ReadCurrentEntry().state;
|
||||
next_state.sampling_number = last_entry.sampling_number + 1;
|
||||
|
||||
if (Settings::values.keyboard_enabled) {
|
||||
const auto& keyboard_state = emulated_devices->GetKeyboard();
|
||||
const auto& keyboard_modifier_state = emulated_devices->GetKeyboardModifier();
|
||||
|
||||
next_state.key = keyboard_state;
|
||||
next_state.modifier = keyboard_modifier_state;
|
||||
next_state.attribute.is_connected.Assign(1);
|
||||
}
|
||||
|
||||
shared_memory->keyboard_lifo.WriteNextEntry(next_state);
|
||||
}
|
||||
|
||||
} // namespace Service::HID
|
@ -1,53 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.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::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
|
||||
~Controller_Keyboard() override;
|
||||
|
||||
// Called when the controller is initialized
|
||||
void OnInit() override;
|
||||
|
||||
// When the controller is released
|
||||
void OnRelease() override;
|
||||
|
||||
// When the controller is requesting an update for the shared memory
|
||||
void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
|
||||
|
||||
private:
|
||||
// This is nn::hid::detail::KeyboardState
|
||||
struct KeyboardState {
|
||||
s64 sampling_number{};
|
||||
Core::HID::KeyboardModifier modifier{};
|
||||
Core::HID::KeyboardAttribute attribute{};
|
||||
Core::HID::KeyboardKey key{};
|
||||
};
|
||||
static_assert(sizeof(KeyboardState) == 0x30, "KeyboardState is an invalid size");
|
||||
|
||||
struct KeyboardSharedMemory {
|
||||
// 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");
|
||||
INSERT_PADDING_WORDS(0xA);
|
||||
};
|
||||
static_assert(sizeof(KeyboardSharedMemory) == 0x400, "KeyboardSharedMemory is an invalid size");
|
||||
|
||||
KeyboardState next_state{};
|
||||
KeyboardSharedMemory* shared_memory = nullptr;
|
||||
Core::HID::EmulatedDevices* emulated_devices = nullptr;
|
||||
};
|
||||
} // namespace Service::HID
|
@ -1,60 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <cstring>
|
||||
#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::HID::HIDCore& hid_core_, u8* raw_shared_memory_)
|
||||
: ControllerBase{hid_core_} {
|
||||
static_assert(SHARED_MEMORY_OFFSET + sizeof(MouseSharedMemory) < shared_memory_size,
|
||||
"MouseSharedMemory is bigger than the shared memory");
|
||||
shared_memory = std::construct_at(
|
||||
reinterpret_cast<MouseSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET));
|
||||
emulated_devices = hid_core.GetEmulatedDevices();
|
||||
}
|
||||
|
||||
Controller_Mouse::~Controller_Mouse() = default;
|
||||
|
||||
void Controller_Mouse::OnInit() {}
|
||||
void Controller_Mouse::OnRelease() {}
|
||||
|
||||
void Controller_Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
||||
if (!IsControllerActivated()) {
|
||||
shared_memory->mouse_lifo.buffer_count = 0;
|
||||
shared_memory->mouse_lifo.buffer_tail = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
next_state = {};
|
||||
|
||||
const auto& last_entry = shared_memory->mouse_lifo.ReadCurrentEntry().state;
|
||||
next_state.sampling_number = last_entry.sampling_number + 1;
|
||||
|
||||
if (Settings::values.mouse_enabled) {
|
||||
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;
|
||||
|
||||
last_mouse_wheel_state = mouse_wheel_state;
|
||||
next_state.button = mouse_button_state;
|
||||
}
|
||||
|
||||
shared_memory->mouse_lifo.WriteNextEntry(next_state);
|
||||
}
|
||||
|
||||
} // namespace Service::HID
|
@ -1,45 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.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::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
|
||||
~Controller_Mouse() override;
|
||||
|
||||
// Called when the controller is initialized
|
||||
void OnInit() override;
|
||||
|
||||
// When the controller is released
|
||||
void OnRelease() override;
|
||||
|
||||
// When the controller is requesting an update for the shared memory
|
||||
void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
|
||||
|
||||
private:
|
||||
struct MouseSharedMemory {
|
||||
// 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");
|
||||
INSERT_PADDING_WORDS(0x2C);
|
||||
};
|
||||
static_assert(sizeof(MouseSharedMemory) == 0x400, "MouseSharedMemory is an invalid size");
|
||||
|
||||
Core::HID::MouseState next_state{};
|
||||
Core::HID::AnalogStickState last_mouse_wheel_state{};
|
||||
MouseSharedMemory* shared_memory = nullptr;
|
||||
Core::HID::EmulatedDevices* emulated_devices = nullptr;
|
||||
};
|
||||
} // namespace Service::HID
|
File diff suppressed because it is too large
Load Diff
@ -1,555 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include <span>
|
||||
|
||||
#include "common/bit_field.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/vector_math.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;
|
||||
class KReadableEvent;
|
||||
} // namespace Kernel
|
||||
|
||||
namespace Service::KernelHelpers {
|
||||
class ServiceContext;
|
||||
} // namespace Service::KernelHelpers
|
||||
|
||||
union Result;
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
class Controller_NPad final : public ControllerBase {
|
||||
public:
|
||||
explicit Controller_NPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_,
|
||||
KernelHelpers::ServiceContext& service_context_);
|
||||
~Controller_NPad() override;
|
||||
|
||||
// Called when the controller is initialized
|
||||
void OnInit() override;
|
||||
|
||||
// When the controller is released
|
||||
void OnRelease() override;
|
||||
|
||||
// When the controller is requesting an update for the shared memory
|
||||
void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
|
||||
|
||||
// When the controller is requesting a motion update for the shared memory
|
||||
void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing) override;
|
||||
|
||||
// This is nn::hid::NpadJoyHoldType
|
||||
enum class NpadJoyHoldType : u64 {
|
||||
Vertical = 0,
|
||||
Horizontal = 1,
|
||||
};
|
||||
|
||||
// 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,
|
||||
MaxActivationMode = 3,
|
||||
};
|
||||
|
||||
// This is nn::hid::NpadCommunicationMode
|
||||
enum class NpadCommunicationMode : u64 {
|
||||
Mode_5ms = 0,
|
||||
Mode_10ms = 1,
|
||||
Mode_15ms = 2,
|
||||
Default = 3,
|
||||
};
|
||||
|
||||
void SetSupportedStyleSet(Core::HID::NpadStyleTag style_set);
|
||||
Core::HID::NpadStyleTag GetSupportedStyleSet() const;
|
||||
|
||||
Result SetSupportedNpadIdTypes(std::span<const u8> data);
|
||||
void GetSupportedNpadIdTypes(u32* data, std::size_t max_length);
|
||||
std::size_t GetSupportedNpadIdTypesSize() const;
|
||||
|
||||
void SetHoldType(NpadJoyHoldType joy_hold_type);
|
||||
NpadJoyHoldType GetHoldType() const;
|
||||
|
||||
void SetNpadHandheldActivationMode(NpadHandheldActivationMode activation_mode);
|
||||
NpadHandheldActivationMode GetNpadHandheldActivationMode() const;
|
||||
|
||||
void SetNpadCommunicationMode(NpadCommunicationMode communication_mode_);
|
||||
NpadCommunicationMode GetNpadCommunicationMode() const;
|
||||
|
||||
bool SetNpadMode(Core::HID::NpadIdType& new_npad_id, Core::HID::NpadIdType npad_id,
|
||||
NpadJoyDeviceType npad_device_type, NpadJoyAssignmentMode assignment_mode);
|
||||
|
||||
bool VibrateControllerAtIndex(Core::HID::NpadIdType npad_id, std::size_t device_index,
|
||||
const Core::HID::VibrationValue& vibration_value);
|
||||
|
||||
void VibrateController(const Core::HID::VibrationDeviceHandle& vibration_device_handle,
|
||||
const Core::HID::VibrationValue& vibration_value);
|
||||
|
||||
void VibrateControllers(
|
||||
std::span<const Core::HID::VibrationDeviceHandle> vibration_device_handles,
|
||||
std::span<const Core::HID::VibrationValue> vibration_values);
|
||||
|
||||
Core::HID::VibrationValue GetLastVibration(
|
||||
const Core::HID::VibrationDeviceHandle& vibration_device_handle) const;
|
||||
|
||||
void InitializeVibrationDevice(const Core::HID::VibrationDeviceHandle& vibration_device_handle);
|
||||
|
||||
void InitializeVibrationDeviceAtIndex(Core::HID::NpadIdType npad_id, std::size_t device_index);
|
||||
|
||||
void SetPermitVibrationSession(bool permit_vibration_session);
|
||||
|
||||
bool IsVibrationDeviceMounted(
|
||||
const Core::HID::VibrationDeviceHandle& vibration_device_handle) 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(Core::HID::NpadStyleIndex controller, Core::HID::NpadIdType npad_id);
|
||||
// Adds a new controller at an index with connection status.
|
||||
void UpdateControllerAt(Core::HID::NpadStyleIndex controller, Core::HID::NpadIdType npad_id,
|
||||
bool connected);
|
||||
|
||||
Result DisconnectNpad(Core::HID::NpadIdType npad_id);
|
||||
|
||||
Result SetGyroscopeZeroDriftMode(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
|
||||
Core::HID::GyroscopeZeroDriftMode drift_mode);
|
||||
Result GetGyroscopeZeroDriftMode(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
|
||||
Core::HID::GyroscopeZeroDriftMode& drift_mode) const;
|
||||
Result IsSixAxisSensorAtRest(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
|
||||
bool& is_at_rest) const;
|
||||
Result IsFirmwareUpdateAvailableForSixAxisSensor(
|
||||
const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool& is_firmware_available) const;
|
||||
Result EnableSixAxisSensorUnalteredPassthrough(
|
||||
const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool is_enabled);
|
||||
Result IsSixAxisSensorUnalteredPassthroughEnabled(
|
||||
const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool& is_enabled) const;
|
||||
Result LoadSixAxisSensorCalibrationParameter(
|
||||
const Core::HID::SixAxisSensorHandle& sixaxis_handle,
|
||||
Core::HID::SixAxisSensorCalibrationParameter& calibration) const;
|
||||
Result GetSixAxisSensorIcInformation(
|
||||
const Core::HID::SixAxisSensorHandle& sixaxis_handle,
|
||||
Core::HID::SixAxisSensorIcInformation& ic_information) const;
|
||||
Result ResetIsSixAxisSensorDeviceNewlyAssigned(
|
||||
const Core::HID::SixAxisSensorHandle& sixaxis_handle);
|
||||
Result SetSixAxisEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
|
||||
bool sixaxis_status);
|
||||
Result IsSixAxisSensorFusionEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
|
||||
bool& is_fusion_enabled) const;
|
||||
Result SetSixAxisFusionEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
|
||||
bool is_fusion_enabled);
|
||||
Result SetSixAxisFusionParameters(
|
||||
const Core::HID::SixAxisSensorHandle& sixaxis_handle,
|
||||
Core::HID::SixAxisSensorFusionParameters sixaxis_fusion_parameters);
|
||||
Result GetSixAxisFusionParameters(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
|
||||
Core::HID::SixAxisSensorFusionParameters& parameters) const;
|
||||
Result GetLedPattern(Core::HID::NpadIdType npad_id, Core::HID::LedPattern& pattern) const;
|
||||
Result IsUnintendedHomeButtonInputProtectionEnabled(Core::HID::NpadIdType npad_id,
|
||||
bool& is_enabled) const;
|
||||
Result SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled,
|
||||
Core::HID::NpadIdType npad_id);
|
||||
void SetAnalogStickUseCenterClamp(bool use_center_clamp);
|
||||
void ClearAllConnectedControllers();
|
||||
void DisconnectAllConnectedControllers();
|
||||
void ConnectAllDisconnectedControllers();
|
||||
void ClearAllControllers();
|
||||
|
||||
Result MergeSingleJoyAsDualJoy(Core::HID::NpadIdType npad_id_1,
|
||||
Core::HID::NpadIdType npad_id_2);
|
||||
void StartLRAssignmentMode();
|
||||
void StopLRAssignmentMode();
|
||||
Result 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.
|
||||
Core::HID::NpadButton GetAndResetPressState();
|
||||
|
||||
void ApplyNpadSystemCommonPolicy();
|
||||
|
||||
static bool IsNpadIdValid(Core::HID::NpadIdType npad_id);
|
||||
static Result IsDeviceHandleValid(const Core::HID::VibrationDeviceHandle& device_handle);
|
||||
static Result VerifyValidSixAxisSensorHandle(
|
||||
const Core::HID::SixAxisSensorHandle& device_handle);
|
||||
|
||||
private:
|
||||
static constexpr std::size_t NPAD_COUNT = 10;
|
||||
|
||||
// This is nn::hid::detail::ColorAttribute
|
||||
enum class ColorAttribute : u32 {
|
||||
Ok = 0,
|
||||
ReadError = 1,
|
||||
NoController = 2,
|
||||
};
|
||||
static_assert(sizeof(ColorAttribute) == 4, "ColorAttribute is an invalid size");
|
||||
|
||||
// This is nn::hid::detail::NpadFullKeyColorState
|
||||
struct NpadFullKeyColorState {
|
||||
ColorAttribute attribute{ColorAttribute::NoController};
|
||||
Core::HID::NpadControllerColor fullkey{};
|
||||
};
|
||||
static_assert(sizeof(NpadFullKeyColorState) == 0xC, "NpadFullKeyColorState is an invalid size");
|
||||
|
||||
// This is nn::hid::detail::NpadJoyColorState
|
||||
struct NpadJoyColorState {
|
||||
ColorAttribute attribute{ColorAttribute::NoController};
|
||||
Core::HID::NpadControllerColor left{};
|
||||
Core::HID::NpadControllerColor right{};
|
||||
};
|
||||
static_assert(sizeof(NpadJoyColorState) == 0x14, "NpadJoyColorState is an invalid size");
|
||||
|
||||
// This is nn::hid::NpadAttribute
|
||||
struct NpadAttribute {
|
||||
union {
|
||||
u32 raw{};
|
||||
BitField<0, 1, u32> is_connected;
|
||||
BitField<1, 1, u32> is_wired;
|
||||
BitField<2, 1, u32> is_left_connected;
|
||||
BitField<3, 1, u32> is_left_wired;
|
||||
BitField<4, 1, u32> is_right_connected;
|
||||
BitField<5, 1, u32> is_right_wired;
|
||||
};
|
||||
};
|
||||
static_assert(sizeof(NpadAttribute) == 4, "NpadAttribute is an invalid size");
|
||||
|
||||
// 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(NPadGenericState) == 0x28, "NPadGenericState is an invalid size");
|
||||
|
||||
// This is nn::hid::SixAxisSensorAttribute
|
||||
struct SixAxisSensorAttribute {
|
||||
union {
|
||||
u32 raw{};
|
||||
BitField<0, 1, u32> is_connected;
|
||||
BitField<1, 1, u32> is_interpolated;
|
||||
};
|
||||
};
|
||||
static_assert(sizeof(SixAxisSensorAttribute) == 4, "SixAxisSensorAttribute is an invalid size");
|
||||
|
||||
// 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{};
|
||||
SixAxisSensorAttribute attribute{};
|
||||
INSERT_PADDING_BYTES(4); // Reserved
|
||||
};
|
||||
static_assert(sizeof(SixAxisSensorState) == 0x60, "SixAxisSensorState is an invalid size");
|
||||
|
||||
// This is nn::hid::server::NpadGcTriggerState
|
||||
struct NpadGcTriggerState {
|
||||
s64 sampling_number{};
|
||||
s32 l_analog{};
|
||||
s32 r_analog{};
|
||||
};
|
||||
static_assert(sizeof(NpadGcTriggerState) == 0x10, "NpadGcTriggerState is an invalid size");
|
||||
|
||||
// This is nn::hid::NpadSystemProperties
|
||||
struct NPadSystemProperties {
|
||||
union {
|
||||
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;
|
||||
BitField<3, 1, s64> is_powered_joy_dual;
|
||||
BitField<4, 1, s64> is_powered_joy_left;
|
||||
BitField<5, 1, s64> is_powered_joy_right;
|
||||
BitField<9, 1, s64> is_system_unsupported_button;
|
||||
BitField<10, 1, s64> is_system_ext_unsupported_button;
|
||||
BitField<11, 1, s64> is_vertical;
|
||||
BitField<12, 1, s64> is_horizontal;
|
||||
BitField<13, 1, s64> use_plus;
|
||||
BitField<14, 1, s64> use_minus;
|
||||
BitField<15, 1, s64> use_directional_buttons;
|
||||
};
|
||||
};
|
||||
static_assert(sizeof(NPadSystemProperties) == 0x8, "NPadSystemProperties is an invalid size");
|
||||
|
||||
// This is nn::hid::NpadSystemButtonProperties
|
||||
struct NpadSystemButtonProperties {
|
||||
union {
|
||||
s32 raw{};
|
||||
BitField<0, 1, s32> is_home_button_protection_enabled;
|
||||
};
|
||||
};
|
||||
static_assert(sizeof(NpadSystemButtonProperties) == 0x4,
|
||||
"NPadButtonProperties is an invalid size");
|
||||
|
||||
// This is nn::hid::system::DeviceType
|
||||
struct DeviceType {
|
||||
union {
|
||||
u32 raw{};
|
||||
BitField<0, 1, s32> fullkey;
|
||||
BitField<1, 1, s32> debug_pad;
|
||||
BitField<2, 1, s32> handheld_left;
|
||||
BitField<3, 1, s32> handheld_right;
|
||||
BitField<4, 1, s32> joycon_left;
|
||||
BitField<5, 1, s32> joycon_right;
|
||||
BitField<6, 1, s32> palma;
|
||||
BitField<7, 1, s32> lark_hvc_left;
|
||||
BitField<8, 1, s32> lark_hvc_right;
|
||||
BitField<9, 1, s32> lark_nes_left;
|
||||
BitField<10, 1, s32> lark_nes_right;
|
||||
BitField<11, 1, s32> handheld_lark_hvc_left;
|
||||
BitField<12, 1, s32> handheld_lark_hvc_right;
|
||||
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;
|
||||
};
|
||||
};
|
||||
|
||||
// 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,
|
||||
HandheldJoyConLeftOnly = 2,
|
||||
HandheldJoyConRightOnly = 3,
|
||||
HandheldJoyConLeftJoyConRight = 4,
|
||||
JoyDual = 5,
|
||||
JoyDualLeftOnly = 6,
|
||||
JoyDualRightOnly = 7,
|
||||
JoyLeftHorizontal = 8,
|
||||
JoyLeftVertical = 9,
|
||||
JoyRightHorizontal = 10,
|
||||
JoyRightVertical = 11,
|
||||
SwitchProController = 12,
|
||||
CompatibleProController = 13,
|
||||
CompatibleJoyCon = 14,
|
||||
LarkHvc1 = 15,
|
||||
LarkHvc2 = 16,
|
||||
LarkNesLeft = 17,
|
||||
LarkNesRight = 18,
|
||||
Lucia = 19,
|
||||
Verification = 20,
|
||||
Lagon = 21,
|
||||
};
|
||||
|
||||
// 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{Core::HID::NpadStyleSet::None};
|
||||
NpadJoyAssignmentMode assignment_mode{NpadJoyAssignmentMode::Dual};
|
||||
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{};
|
||||
NpadSystemButtonProperties button_properties{};
|
||||
Core::HID::NpadBatteryLevel battery_level_dual{};
|
||||
Core::HID::NpadBatteryLevel battery_level_left{};
|
||||
Core::HID::NpadBatteryLevel battery_level_right{};
|
||||
AppletFooterUiAttributes applet_footer_attributes{};
|
||||
AppletFooterUiType applet_footer_type{AppletFooterUiType::None};
|
||||
INSERT_PADDING_BYTES(0x5B); // Reserved
|
||||
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{};
|
||||
Core::HID::SixAxisSensorProperties sixaxis_fullkey_properties;
|
||||
Core::HID::SixAxisSensorProperties sixaxis_handheld_properties;
|
||||
Core::HID::SixAxisSensorProperties sixaxis_dual_left_properties;
|
||||
Core::HID::SixAxisSensorProperties sixaxis_dual_right_properties;
|
||||
Core::HID::SixAxisSensorProperties sixaxis_left_properties;
|
||||
Core::HID::SixAxisSensorProperties sixaxis_right_properties;
|
||||
INSERT_PADDING_BYTES(0xc06); // Unknown
|
||||
};
|
||||
static_assert(sizeof(NpadInternalState) == 0x5000, "NpadInternalState is an invalid size");
|
||||
|
||||
struct VibrationData {
|
||||
bool device_mounted{};
|
||||
Core::HID::VibrationValue latest_vibration_value{};
|
||||
std::chrono::steady_clock::time_point last_vibration_timepoint{};
|
||||
};
|
||||
|
||||
struct SixaxisParameters {
|
||||
bool is_fusion_enabled{true};
|
||||
bool unaltered_passtrough{false};
|
||||
Core::HID::SixAxisSensorFusionParameters fusion{};
|
||||
Core::HID::SixAxisSensorCalibrationParameter calibration{};
|
||||
Core::HID::SixAxisSensorIcInformation ic_information{};
|
||||
Core::HID::GyroscopeZeroDriftMode gyroscope_zero_drift_mode{
|
||||
Core::HID::GyroscopeZeroDriftMode::Standard};
|
||||
};
|
||||
|
||||
struct NpadControllerData {
|
||||
Kernel::KEvent* styleset_changed_event{};
|
||||
NpadInternalState* shared_memory = nullptr;
|
||||
Core::HID::EmulatedController* device = nullptr;
|
||||
|
||||
std::array<VibrationData, 2> vibration{};
|
||||
bool unintended_home_button_input_protection{};
|
||||
bool is_connected{};
|
||||
|
||||
// Dual joycons can have only one side connected
|
||||
bool is_dual_left_connected{true};
|
||||
bool is_dual_right_connected{true};
|
||||
|
||||
// Motion parameters
|
||||
bool sixaxis_at_rest{true};
|
||||
bool sixaxis_sensor_enabled{true};
|
||||
SixaxisParameters sixaxis_fullkey{};
|
||||
SixaxisParameters sixaxis_handheld{};
|
||||
SixaxisParameters sixaxis_dual_left{};
|
||||
SixaxisParameters sixaxis_dual_right{};
|
||||
SixaxisParameters sixaxis_left{};
|
||||
SixaxisParameters sixaxis_right{};
|
||||
SixaxisParameters sixaxis_unknown{};
|
||||
|
||||
// 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;
|
||||
|
||||
Core::HID::SixAxisSensorProperties& GetSixaxisProperties(
|
||||
const Core::HID::SixAxisSensorHandle& device_handle);
|
||||
const Core::HID::SixAxisSensorProperties& GetSixaxisProperties(
|
||||
const Core::HID::SixAxisSensorHandle& device_handle) const;
|
||||
SixaxisParameters& GetSixaxisState(const Core::HID::SixAxisSensorHandle& device_handle);
|
||||
const SixaxisParameters& GetSixaxisState(
|
||||
const Core::HID::SixAxisSensorHandle& device_handle) const;
|
||||
|
||||
std::atomic<u64> press_state{};
|
||||
|
||||
std::array<NpadControllerData, NPAD_COUNT> controller_data{};
|
||||
KernelHelpers::ServiceContext& service_context;
|
||||
std::mutex mutex;
|
||||
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};
|
||||
bool permit_vibration_session_enabled{false};
|
||||
bool analog_stick_use_center_clamp{false};
|
||||
bool is_in_lr_assignment_mode{false};
|
||||
bool is_controller_initialized{false};
|
||||
};
|
||||
} // namespace Service::HID
|
@ -1,229 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#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/kernel/k_event.h"
|
||||
#include "core/hle/kernel/k_readable_event.h"
|
||||
#include "core/hle/service/hid/controllers/palma.h"
|
||||
#include "core/hle/service/kernel_helpers.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
Controller_Palma::Controller_Palma(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_,
|
||||
KernelHelpers::ServiceContext& service_context_)
|
||||
: ControllerBase{hid_core_}, service_context{service_context_} {
|
||||
controller = hid_core.GetEmulatedController(Core::HID::NpadIdType::Other);
|
||||
operation_complete_event = service_context.CreateEvent("hid:PalmaOperationCompleteEvent");
|
||||
}
|
||||
|
||||
Controller_Palma::~Controller_Palma() = default;
|
||||
|
||||
void Controller_Palma::OnInit() {}
|
||||
|
||||
void Controller_Palma::OnRelease() {}
|
||||
|
||||
void Controller_Palma::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
||||
if (!IsControllerActivated()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Result Controller_Palma::GetPalmaConnectionHandle(Core::HID::NpadIdType npad_id,
|
||||
PalmaConnectionHandle& handle) {
|
||||
active_handle.npad_id = npad_id;
|
||||
handle = active_handle;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result Controller_Palma::InitializePalma(const PalmaConnectionHandle& handle) {
|
||||
if (handle.npad_id != active_handle.npad_id) {
|
||||
return InvalidPalmaHandle;
|
||||
}
|
||||
ActivateController();
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Kernel::KReadableEvent& Controller_Palma::AcquirePalmaOperationCompleteEvent(
|
||||
const PalmaConnectionHandle& handle) const {
|
||||
if (handle.npad_id != active_handle.npad_id) {
|
||||
LOG_ERROR(Service_HID, "Invalid npad id {}", handle.npad_id);
|
||||
}
|
||||
return operation_complete_event->GetReadableEvent();
|
||||
}
|
||||
|
||||
Result Controller_Palma::GetPalmaOperationInfo(const PalmaConnectionHandle& handle,
|
||||
PalmaOperationType& operation_type,
|
||||
PalmaOperationData& data) const {
|
||||
if (handle.npad_id != active_handle.npad_id) {
|
||||
return InvalidPalmaHandle;
|
||||
}
|
||||
operation_type = operation.operation;
|
||||
data = operation.data;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result Controller_Palma::PlayPalmaActivity(const PalmaConnectionHandle& handle,
|
||||
u64 palma_activity) {
|
||||
if (handle.npad_id != active_handle.npad_id) {
|
||||
return InvalidPalmaHandle;
|
||||
}
|
||||
operation.operation = PalmaOperationType::PlayActivity;
|
||||
operation.result = PalmaResultSuccess;
|
||||
operation.data = {};
|
||||
operation_complete_event->Signal();
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result Controller_Palma::SetPalmaFrModeType(const PalmaConnectionHandle& handle,
|
||||
PalmaFrModeType fr_mode_) {
|
||||
if (handle.npad_id != active_handle.npad_id) {
|
||||
return InvalidPalmaHandle;
|
||||
}
|
||||
fr_mode = fr_mode_;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result Controller_Palma::ReadPalmaStep(const PalmaConnectionHandle& handle) {
|
||||
if (handle.npad_id != active_handle.npad_id) {
|
||||
return InvalidPalmaHandle;
|
||||
}
|
||||
operation.operation = PalmaOperationType::ReadStep;
|
||||
operation.result = PalmaResultSuccess;
|
||||
operation.data = {};
|
||||
operation_complete_event->Signal();
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result Controller_Palma::EnablePalmaStep(const PalmaConnectionHandle& handle, bool is_enabled) {
|
||||
if (handle.npad_id != active_handle.npad_id) {
|
||||
return InvalidPalmaHandle;
|
||||
}
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result Controller_Palma::ResetPalmaStep(const PalmaConnectionHandle& handle) {
|
||||
if (handle.npad_id != active_handle.npad_id) {
|
||||
return InvalidPalmaHandle;
|
||||
}
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
void Controller_Palma::ReadPalmaApplicationSection() {}
|
||||
|
||||
void Controller_Palma::WritePalmaApplicationSection() {}
|
||||
|
||||
Result Controller_Palma::ReadPalmaUniqueCode(const PalmaConnectionHandle& handle) {
|
||||
if (handle.npad_id != active_handle.npad_id) {
|
||||
return InvalidPalmaHandle;
|
||||
}
|
||||
operation.operation = PalmaOperationType::ReadUniqueCode;
|
||||
operation.result = PalmaResultSuccess;
|
||||
operation.data = {};
|
||||
operation_complete_event->Signal();
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result Controller_Palma::SetPalmaUniqueCodeInvalid(const PalmaConnectionHandle& handle) {
|
||||
if (handle.npad_id != active_handle.npad_id) {
|
||||
return InvalidPalmaHandle;
|
||||
}
|
||||
operation.operation = PalmaOperationType::SetUniqueCodeInvalid;
|
||||
operation.result = PalmaResultSuccess;
|
||||
operation.data = {};
|
||||
operation_complete_event->Signal();
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
void Controller_Palma::WritePalmaActivityEntry() {}
|
||||
|
||||
Result Controller_Palma::WritePalmaRgbLedPatternEntry(const PalmaConnectionHandle& handle,
|
||||
u64 unknown) {
|
||||
if (handle.npad_id != active_handle.npad_id) {
|
||||
return InvalidPalmaHandle;
|
||||
}
|
||||
operation.operation = PalmaOperationType::WriteRgbLedPatternEntry;
|
||||
operation.result = PalmaResultSuccess;
|
||||
operation.data = {};
|
||||
operation_complete_event->Signal();
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result Controller_Palma::WritePalmaWaveEntry(const PalmaConnectionHandle& handle, PalmaWaveSet wave,
|
||||
Common::ProcessAddress t_mem, u64 size) {
|
||||
if (handle.npad_id != active_handle.npad_id) {
|
||||
return InvalidPalmaHandle;
|
||||
}
|
||||
operation.operation = PalmaOperationType::WriteWaveEntry;
|
||||
operation.result = PalmaResultSuccess;
|
||||
operation.data = {};
|
||||
operation_complete_event->Signal();
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result Controller_Palma::SetPalmaDataBaseIdentificationVersion(const PalmaConnectionHandle& handle,
|
||||
s32 database_id_version_) {
|
||||
if (handle.npad_id != active_handle.npad_id) {
|
||||
return InvalidPalmaHandle;
|
||||
}
|
||||
database_id_version = database_id_version_;
|
||||
operation.operation = PalmaOperationType::ReadDataBaseIdentificationVersion;
|
||||
operation.result = PalmaResultSuccess;
|
||||
operation.data[0] = {};
|
||||
operation_complete_event->Signal();
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result Controller_Palma::GetPalmaDataBaseIdentificationVersion(
|
||||
const PalmaConnectionHandle& handle) {
|
||||
if (handle.npad_id != active_handle.npad_id) {
|
||||
return InvalidPalmaHandle;
|
||||
}
|
||||
operation.operation = PalmaOperationType::ReadDataBaseIdentificationVersion;
|
||||
operation.result = PalmaResultSuccess;
|
||||
operation.data = {};
|
||||
operation.data[0] = static_cast<u8>(database_id_version);
|
||||
operation_complete_event->Signal();
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
void Controller_Palma::SuspendPalmaFeature() {}
|
||||
|
||||
Result Controller_Palma::GetPalmaOperationResult(const PalmaConnectionHandle& handle) const {
|
||||
if (handle.npad_id != active_handle.npad_id) {
|
||||
return InvalidPalmaHandle;
|
||||
}
|
||||
return operation.result;
|
||||
}
|
||||
void Controller_Palma::ReadPalmaPlayLog() {}
|
||||
|
||||
void Controller_Palma::ResetPalmaPlayLog() {}
|
||||
|
||||
void Controller_Palma::SetIsPalmaAllConnectable(bool is_all_connectable) {
|
||||
// If true controllers are able to be paired
|
||||
is_connectable = is_all_connectable;
|
||||
}
|
||||
|
||||
void Controller_Palma::SetIsPalmaPairedConnectable() {}
|
||||
|
||||
Result Controller_Palma::PairPalma(const PalmaConnectionHandle& handle) {
|
||||
if (handle.npad_id != active_handle.npad_id) {
|
||||
return InvalidPalmaHandle;
|
||||
}
|
||||
// TODO: Do something
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
void Controller_Palma::SetPalmaBoostMode(bool boost_mode) {}
|
||||
|
||||
void Controller_Palma::CancelWritePalmaWaveEntry() {}
|
||||
|
||||
void Controller_Palma::EnablePalmaBoostMode() {}
|
||||
|
||||
void Controller_Palma::GetPalmaBluetoothAddress() {}
|
||||
|
||||
void Controller_Palma::SetDisallowedPalmaConnection() {}
|
||||
|
||||
} // namespace Service::HID
|
@ -1,163 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/typed_address.h"
|
||||
#include "core/hle/service/hid/controllers/controller_base.h"
|
||||
#include "core/hle/service/hid/errors.h"
|
||||
|
||||
namespace Kernel {
|
||||
class KEvent;
|
||||
class KReadableEvent;
|
||||
} // namespace Kernel
|
||||
|
||||
namespace Service::KernelHelpers {
|
||||
class ServiceContext;
|
||||
}
|
||||
|
||||
namespace Core::HID {
|
||||
class EmulatedController;
|
||||
} // namespace Core::HID
|
||||
|
||||
namespace Service::HID {
|
||||
class Controller_Palma final : public ControllerBase {
|
||||
public:
|
||||
using PalmaOperationData = std::array<u8, 0x140>;
|
||||
|
||||
// This is nn::hid::PalmaOperationType
|
||||
enum class PalmaOperationType {
|
||||
PlayActivity,
|
||||
SetFrModeType,
|
||||
ReadStep,
|
||||
EnableStep,
|
||||
ResetStep,
|
||||
ReadApplicationSection,
|
||||
WriteApplicationSection,
|
||||
ReadUniqueCode,
|
||||
SetUniqueCodeInvalid,
|
||||
WriteActivityEntry,
|
||||
WriteRgbLedPatternEntry,
|
||||
WriteWaveEntry,
|
||||
ReadDataBaseIdentificationVersion,
|
||||
WriteDataBaseIdentificationVersion,
|
||||
SuspendFeature,
|
||||
ReadPlayLog,
|
||||
ResetPlayLog,
|
||||
};
|
||||
|
||||
// This is nn::hid::PalmaWaveSet
|
||||
enum class PalmaWaveSet : u64 {
|
||||
Small,
|
||||
Medium,
|
||||
Large,
|
||||
};
|
||||
|
||||
// This is nn::hid::PalmaFrModeType
|
||||
enum class PalmaFrModeType : u64 {
|
||||
Off,
|
||||
B01,
|
||||
B02,
|
||||
B03,
|
||||
Downloaded,
|
||||
};
|
||||
|
||||
// This is nn::hid::PalmaFeature
|
||||
enum class PalmaFeature : u64 {
|
||||
FrMode,
|
||||
RumbleFeedback,
|
||||
Step,
|
||||
MuteSwitch,
|
||||
};
|
||||
|
||||
// This is nn::hid::PalmaOperationInfo
|
||||
struct PalmaOperationInfo {
|
||||
PalmaOperationType operation{};
|
||||
Result result{PalmaResultSuccess};
|
||||
PalmaOperationData data{};
|
||||
};
|
||||
static_assert(sizeof(PalmaOperationInfo) == 0x148, "PalmaOperationInfo is an invalid size");
|
||||
|
||||
// This is nn::hid::PalmaActivityEntry
|
||||
struct PalmaActivityEntry {
|
||||
u32 rgb_led_pattern_index;
|
||||
INSERT_PADDING_BYTES(2);
|
||||
PalmaWaveSet wave_set;
|
||||
u32 wave_index;
|
||||
INSERT_PADDING_BYTES(12);
|
||||
};
|
||||
static_assert(sizeof(PalmaActivityEntry) == 0x20, "PalmaActivityEntry is an invalid size");
|
||||
|
||||
struct PalmaConnectionHandle {
|
||||
Core::HID::NpadIdType npad_id;
|
||||
INSERT_PADDING_BYTES(4); // Unknown
|
||||
};
|
||||
static_assert(sizeof(PalmaConnectionHandle) == 0x8,
|
||||
"PalmaConnectionHandle has incorrect size.");
|
||||
|
||||
explicit Controller_Palma(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_,
|
||||
KernelHelpers::ServiceContext& service_context_);
|
||||
~Controller_Palma() override;
|
||||
|
||||
// Called when the controller is initialized
|
||||
void OnInit() override;
|
||||
|
||||
// When the controller is released
|
||||
void OnRelease() override;
|
||||
|
||||
// When the controller is requesting an update for the shared memory
|
||||
void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
|
||||
|
||||
Result GetPalmaConnectionHandle(Core::HID::NpadIdType npad_id, PalmaConnectionHandle& handle);
|
||||
Result InitializePalma(const PalmaConnectionHandle& handle);
|
||||
Kernel::KReadableEvent& AcquirePalmaOperationCompleteEvent(
|
||||
const PalmaConnectionHandle& handle) const;
|
||||
Result GetPalmaOperationInfo(const PalmaConnectionHandle& handle,
|
||||
PalmaOperationType& operation_type,
|
||||
PalmaOperationData& data) const;
|
||||
Result PlayPalmaActivity(const PalmaConnectionHandle& handle, u64 palma_activity);
|
||||
Result SetPalmaFrModeType(const PalmaConnectionHandle& handle, PalmaFrModeType fr_mode_);
|
||||
Result ReadPalmaStep(const PalmaConnectionHandle& handle);
|
||||
Result EnablePalmaStep(const PalmaConnectionHandle& handle, bool is_enabled);
|
||||
Result ResetPalmaStep(const PalmaConnectionHandle& handle);
|
||||
Result ReadPalmaUniqueCode(const PalmaConnectionHandle& handle);
|
||||
Result SetPalmaUniqueCodeInvalid(const PalmaConnectionHandle& handle);
|
||||
Result WritePalmaRgbLedPatternEntry(const PalmaConnectionHandle& handle, u64 unknown);
|
||||
Result WritePalmaWaveEntry(const PalmaConnectionHandle& handle, PalmaWaveSet wave,
|
||||
Common::ProcessAddress t_mem, u64 size);
|
||||
Result SetPalmaDataBaseIdentificationVersion(const PalmaConnectionHandle& handle,
|
||||
s32 database_id_version_);
|
||||
Result GetPalmaDataBaseIdentificationVersion(const PalmaConnectionHandle& handle);
|
||||
Result GetPalmaOperationResult(const PalmaConnectionHandle& handle) const;
|
||||
void SetIsPalmaAllConnectable(bool is_all_connectable);
|
||||
Result PairPalma(const PalmaConnectionHandle& handle);
|
||||
void SetPalmaBoostMode(bool boost_mode);
|
||||
|
||||
private:
|
||||
void ReadPalmaApplicationSection();
|
||||
void WritePalmaApplicationSection();
|
||||
void WritePalmaActivityEntry();
|
||||
void SuspendPalmaFeature();
|
||||
void ReadPalmaPlayLog();
|
||||
void ResetPalmaPlayLog();
|
||||
void SetIsPalmaPairedConnectable();
|
||||
void CancelWritePalmaWaveEntry();
|
||||
void EnablePalmaBoostMode();
|
||||
void GetPalmaBluetoothAddress();
|
||||
void SetDisallowedPalmaConnection();
|
||||
|
||||
bool is_connectable{};
|
||||
s32 database_id_version{};
|
||||
PalmaOperationInfo operation{};
|
||||
PalmaFrModeType fr_mode{};
|
||||
PalmaConnectionHandle active_handle{};
|
||||
|
||||
Core::HID::EmulatedController* controller;
|
||||
|
||||
Kernel::KEvent* operation_complete_event;
|
||||
KernelHelpers::ServiceContext& service_context;
|
||||
};
|
||||
|
||||
} // namespace Service::HID
|
@ -1,42 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#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::HID::HIDCore& hid_core_, u8* raw_shared_memory_)
|
||||
: ControllerBase{hid_core_} {
|
||||
raw_shared_memory = raw_shared_memory_;
|
||||
}
|
||||
|
||||
Controller_Stubbed::~Controller_Stubbed() = default;
|
||||
|
||||
void Controller_Stubbed::OnInit() {}
|
||||
|
||||
void Controller_Stubbed::OnRelease() {}
|
||||
|
||||
void Controller_Stubbed::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
||||
if (!smart_update) {
|
||||
return;
|
||||
}
|
||||
|
||||
CommonHeader header{};
|
||||
header.timestamp = core_timing.GetGlobalTimeNs().count();
|
||||
header.total_entry_count = 17;
|
||||
header.entry_count = 0;
|
||||
header.last_entry_index = 0;
|
||||
|
||||
std::memcpy(raw_shared_memory + common_offset, &header, sizeof(CommonHeader));
|
||||
}
|
||||
|
||||
void Controller_Stubbed::SetCommonHeaderOffset(std::size_t off) {
|
||||
common_offset = off;
|
||||
smart_update = true;
|
||||
}
|
||||
|
||||
} // namespace Service::HID
|
@ -1,39 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/service/hid/controllers/controller_base.h"
|
||||
|
||||
namespace Service::HID {
|
||||
class Controller_Stubbed final : public ControllerBase {
|
||||
public:
|
||||
explicit Controller_Stubbed(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
|
||||
~Controller_Stubbed() override;
|
||||
|
||||
// Called when the controller is initialized
|
||||
void OnInit() override;
|
||||
|
||||
// When the controller is released
|
||||
void OnRelease() override;
|
||||
|
||||
// When the controller is requesting an update for the shared memory
|
||||
void OnUpdate(const Core::Timing::CoreTiming& core_timing) 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");
|
||||
|
||||
u8* raw_shared_memory = nullptr;
|
||||
bool smart_update{};
|
||||
std::size_t common_offset{};
|
||||
};
|
||||
} // namespace Service::HID
|
@ -1,124 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include "common/common_types.h"
|
||||
#include "common/settings.h"
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/frontend/emu_window.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::HID::HIDCore& hid_core_,
|
||||
u8* raw_shared_memory_)
|
||||
: ControllerBase{hid_core_} {
|
||||
static_assert(SHARED_MEMORY_OFFSET + sizeof(TouchSharedMemory) < shared_memory_size,
|
||||
"TouchSharedMemory is bigger than the shared memory");
|
||||
shared_memory = std::construct_at(
|
||||
reinterpret_cast<TouchSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET));
|
||||
console = hid_core.GetEmulatedConsole();
|
||||
}
|
||||
|
||||
Controller_Touchscreen::~Controller_Touchscreen() = default;
|
||||
|
||||
void Controller_Touchscreen::OnInit() {}
|
||||
|
||||
void Controller_Touchscreen::OnRelease() {}
|
||||
|
||||
void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
||||
shared_memory->touch_screen_lifo.timestamp = core_timing.GetGlobalTimeNs().count();
|
||||
|
||||
if (!IsControllerActivated()) {
|
||||
shared_memory->touch_screen_lifo.buffer_count = 0;
|
||||
shared_memory->touch_screen_lifo.buffer_tail = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
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.id = current_touch.id;
|
||||
|
||||
if (finger.attribute.start_touch) {
|
||||
finger.attribute.raw = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (finger.attribute.end_touch) {
|
||||
finger.attribute.raw = 0;
|
||||
finger.pressed = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!finger.pressed && current_touch.pressed) {
|
||||
// Ignore all touch fingers if disabled
|
||||
if (!Settings::values.touchscreen.enabled) {
|
||||
continue;
|
||||
}
|
||||
|
||||
finger.attribute.start_touch.Assign(1);
|
||||
finger.pressed = true;
|
||||
finger.position = current_touch.position;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (finger.pressed && !current_touch.pressed) {
|
||||
finger.attribute.raw = 0;
|
||||
finger.attribute.end_touch.Assign(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Only update position if touch is not on a special frame
|
||||
finger.position = current_touch.position;
|
||||
}
|
||||
|
||||
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 timestamp = static_cast<u64>(core_timing.GetGlobalTimeNs().count());
|
||||
const auto& last_entry = shared_memory->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 = next_state.states[id];
|
||||
if (id < active_fingers_count) {
|
||||
const auto& [active_x, active_y] = active_fingers[id].position;
|
||||
touch_entry.position = {
|
||||
.x = static_cast<u16>(active_x * Layout::ScreenUndocked::Width),
|
||||
.y = static_cast<u16>(active_y * Layout::ScreenUndocked::Height),
|
||||
};
|
||||
touch_entry.diameter_x = Settings::values.touchscreen.diameter_x;
|
||||
touch_entry.diameter_y = Settings::values.touchscreen.diameter_y;
|
||||
touch_entry.rotation_angle = Settings::values.touchscreen.rotation_angle;
|
||||
touch_entry.delta_time = timestamp - active_fingers[id].last_touch;
|
||||
fingers[active_fingers[id].id].last_touch = timestamp;
|
||||
touch_entry.finger = active_fingers[id].id;
|
||||
touch_entry.attribute.raw = active_fingers[id].attribute.raw;
|
||||
} else {
|
||||
// Clear touch entry
|
||||
touch_entry.attribute.raw = 0;
|
||||
touch_entry.position = {};
|
||||
touch_entry.diameter_x = 0;
|
||||
touch_entry.diameter_y = 0;
|
||||
touch_entry.rotation_angle = 0;
|
||||
touch_entry.delta_time = 0;
|
||||
touch_entry.finger = 0;
|
||||
}
|
||||
}
|
||||
|
||||
shared_memory->touch_screen_lifo.WriteNextEntry(next_state);
|
||||
}
|
||||
|
||||
} // namespace Service::HID
|
@ -1,57 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.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:
|
||||
explicit Controller_Touchscreen(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
|
||||
~Controller_Touchscreen() override;
|
||||
|
||||
// Called when the controller is initialized
|
||||
void OnInit() override;
|
||||
|
||||
// When the controller is released
|
||||
void OnRelease() override;
|
||||
|
||||
// When the controller is requesting an update for the shared memory
|
||||
void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
|
||||
|
||||
private:
|
||||
static constexpr std::size_t MAX_FINGERS = 16;
|
||||
|
||||
// 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(TouchScreenState) == 0x290, "TouchScreenState is an invalid size");
|
||||
|
||||
struct TouchSharedMemory {
|
||||
// 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");
|
||||
INSERT_PADDING_WORDS(0xF2);
|
||||
};
|
||||
static_assert(sizeof(TouchSharedMemory) == 0x3000, "TouchSharedMemory is an invalid size");
|
||||
|
||||
TouchScreenState next_state{};
|
||||
TouchSharedMemory* shared_memory = nullptr;
|
||||
Core::HID::EmulatedConsole* console = nullptr;
|
||||
|
||||
std::array<Core::HID::TouchFinger, MAX_FINGERS> fingers{};
|
||||
};
|
||||
} // namespace Service::HID
|
@ -1,40 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#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::HID::HIDCore& hid_core_, u8* raw_shared_memory_)
|
||||
: ControllerBase{hid_core_} {
|
||||
static_assert(SHARED_MEMORY_OFFSET + sizeof(XpadSharedMemory) < shared_memory_size,
|
||||
"XpadSharedMemory is bigger than the shared memory");
|
||||
shared_memory = std::construct_at(
|
||||
reinterpret_cast<XpadSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET));
|
||||
}
|
||||
Controller_XPad::~Controller_XPad() = default;
|
||||
|
||||
void Controller_XPad::OnInit() {}
|
||||
|
||||
void Controller_XPad::OnRelease() {}
|
||||
|
||||
void Controller_XPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
||||
if (!IsControllerActivated()) {
|
||||
shared_memory->basic_xpad_lifo.buffer_count = 0;
|
||||
shared_memory->basic_xpad_lifo.buffer_tail = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& last_entry = shared_memory->basic_xpad_lifo.ReadCurrentEntry().state;
|
||||
next_state.sampling_number = last_entry.sampling_number + 1;
|
||||
// TODO(ogniK): Update xpad states
|
||||
|
||||
shared_memory->basic_xpad_lifo.WriteNextEntry(next_state);
|
||||
}
|
||||
|
||||
} // namespace Service::HID
|
@ -1,112 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/bit_field.h"
|
||||
#include "common/common_types.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::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
|
||||
~Controller_XPad() override;
|
||||
|
||||
// Called when the controller is initialized
|
||||
void OnInit() override;
|
||||
|
||||
// When the controller is released
|
||||
void OnRelease() override;
|
||||
|
||||
// When the controller is requesting an update for the shared memory
|
||||
void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
|
||||
|
||||
private:
|
||||
// This is nn::hid::BasicXpadAttributeSet
|
||||
struct BasicXpadAttributeSet {
|
||||
union {
|
||||
u32 raw{};
|
||||
BitField<0, 1, u32> is_connected;
|
||||
BitField<1, 1, u32> is_wired;
|
||||
BitField<2, 1, u32> is_left_connected;
|
||||
BitField<3, 1, u32> is_left_wired;
|
||||
BitField<4, 1, u32> is_right_connected;
|
||||
BitField<5, 1, u32> is_right_wired;
|
||||
};
|
||||
};
|
||||
static_assert(sizeof(BasicXpadAttributeSet) == 4, "BasicXpadAttributeSet is an invalid size");
|
||||
|
||||
// This is nn::hid::BasicXpadButtonSet
|
||||
struct BasicXpadButtonSet {
|
||||
union {
|
||||
u32 raw{};
|
||||
// Button states
|
||||
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_stick;
|
||||
BitField<5, 1, u32> r_stick;
|
||||
BitField<6, 1, u32> l;
|
||||
BitField<7, 1, u32> r;
|
||||
BitField<8, 1, u32> zl;
|
||||
BitField<9, 1, u32> zr;
|
||||
BitField<10, 1, u32> plus;
|
||||
BitField<11, 1, u32> minus;
|
||||
|
||||
// D-Pad
|
||||
BitField<12, 1, u32> d_left;
|
||||
BitField<13, 1, u32> d_up;
|
||||
BitField<14, 1, u32> d_right;
|
||||
BitField<15, 1, u32> d_down;
|
||||
|
||||
// Left JoyStick
|
||||
BitField<16, 1, u32> l_stick_left;
|
||||
BitField<17, 1, u32> l_stick_up;
|
||||
BitField<18, 1, u32> l_stick_right;
|
||||
BitField<19, 1, u32> l_stick_down;
|
||||
|
||||
// Right JoyStick
|
||||
BitField<20, 1, u32> r_stick_left;
|
||||
BitField<21, 1, u32> r_stick_up;
|
||||
BitField<22, 1, u32> r_stick_right;
|
||||
BitField<23, 1, u32> r_stick_down;
|
||||
|
||||
// Not always active?
|
||||
BitField<24, 1, u32> left_sl;
|
||||
BitField<25, 1, u32> left_sr;
|
||||
|
||||
BitField<26, 1, u32> right_sl;
|
||||
BitField<27, 1, u32> right_sr;
|
||||
|
||||
BitField<28, 1, u32> palma;
|
||||
BitField<30, 1, u32> handheld_left_b;
|
||||
};
|
||||
};
|
||||
static_assert(sizeof(BasicXpadButtonSet) == 4, "BasicXpadButtonSet is an invalid size");
|
||||
|
||||
// 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(BasicXpadState) == 0x20, "BasicXpadState is an invalid size");
|
||||
|
||||
struct XpadSharedMemory {
|
||||
// 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");
|
||||
INSERT_PADDING_WORDS(0x4E);
|
||||
};
|
||||
static_assert(sizeof(XpadSharedMemory) == 0x400, "XpadSharedMemory is an invalid size");
|
||||
|
||||
BasicXpadState next_state{};
|
||||
XpadSharedMemory* shared_memory = nullptr;
|
||||
};
|
||||
} // namespace Service::HID
|
@ -1,31 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/result.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
constexpr Result PalmaResultSuccess{ErrorModule::HID, 0};
|
||||
constexpr Result NpadInvalidHandle{ErrorModule::HID, 100};
|
||||
constexpr Result NpadDeviceIndexOutOfRange{ErrorModule::HID, 107};
|
||||
constexpr Result VibrationInvalidStyleIndex{ErrorModule::HID, 122};
|
||||
constexpr Result VibrationInvalidNpadId{ErrorModule::HID, 123};
|
||||
constexpr Result VibrationDeviceIndexOutOfRange{ErrorModule::HID, 124};
|
||||
constexpr Result InvalidSixAxisFusionRange{ErrorModule::HID, 423};
|
||||
constexpr Result NpadIsDualJoycon{ErrorModule::HID, 601};
|
||||
constexpr Result NpadIsSameType{ErrorModule::HID, 602};
|
||||
constexpr Result InvalidNpadId{ErrorModule::HID, 709};
|
||||
constexpr Result NpadNotConnected{ErrorModule::HID, 710};
|
||||
constexpr Result InvalidArraySize{ErrorModule::HID, 715};
|
||||
constexpr Result InvalidPalmaHandle{ErrorModule::HID, 3302};
|
||||
|
||||
} // namespace Service::HID
|
||||
|
||||
namespace Service::IRS {
|
||||
|
||||
constexpr Result InvalidProcessorState{ErrorModule::Irsensor, 78};
|
||||
constexpr Result InvalidIrCameraHandle{ErrorModule::Irsensor, 204};
|
||||
|
||||
} // namespace Service::IRS
|
File diff suppressed because it is too large
Load Diff
@ -3,220 +3,14 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
|
||||
#include "core/hle/service/hid/controllers/controller_base.h"
|
||||
#include "core/hle/service/kernel_helpers.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Core::Timing {
|
||||
struct EventType;
|
||||
}
|
||||
|
||||
namespace Service::SM {
|
||||
class ServiceManager;
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
enum class HidController : std::size_t {
|
||||
DebugPad,
|
||||
Touchscreen,
|
||||
Mouse,
|
||||
Keyboard,
|
||||
XPad,
|
||||
HomeButton,
|
||||
SleepButton,
|
||||
CaptureButton,
|
||||
InputDetector,
|
||||
UniquePad,
|
||||
NPad,
|
||||
Gesture,
|
||||
ConsoleSixAxisSensor,
|
||||
DebugMouse,
|
||||
Palma,
|
||||
|
||||
MaxControllers,
|
||||
};
|
||||
|
||||
class IAppletResource final : public ServiceFramework<IAppletResource> {
|
||||
public:
|
||||
explicit IAppletResource(Core::System& system_,
|
||||
KernelHelpers::ServiceContext& service_context_);
|
||||
~IAppletResource() override;
|
||||
|
||||
void ActivateController(HidController controller);
|
||||
void DeactivateController(HidController controller);
|
||||
|
||||
template <typename T>
|
||||
T& GetController(HidController controller) {
|
||||
return static_cast<T&>(*controllers[static_cast<size_t>(controller)]);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const T& GetController(HidController controller) const {
|
||||
return static_cast<T&>(*controllers[static_cast<size_t>(controller)]);
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
void MakeController(HidController controller, u8* shared_memory) {
|
||||
if constexpr (std::is_constructible_v<T, Core::System&, u8*>) {
|
||||
controllers[static_cast<std::size_t>(controller)] =
|
||||
std::make_unique<T>(system, shared_memory);
|
||||
} else {
|
||||
controllers[static_cast<std::size_t>(controller)] =
|
||||
std::make_unique<T>(system.HIDCore(), shared_memory);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void MakeControllerWithServiceContext(HidController controller, u8* shared_memory) {
|
||||
controllers[static_cast<std::size_t>(controller)] =
|
||||
std::make_unique<T>(system.HIDCore(), shared_memory, service_context);
|
||||
}
|
||||
|
||||
void GetSharedMemoryHandle(HLERequestContext& ctx);
|
||||
void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
|
||||
void UpdateNpad(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> npad_update_event;
|
||||
std::shared_ptr<Core::Timing::EventType> default_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)>
|
||||
controllers{};
|
||||
};
|
||||
|
||||
class Hid final : public ServiceFramework<Hid> {
|
||||
public:
|
||||
explicit Hid(Core::System& system_, std::shared_ptr<IAppletResource> applet_resource_);
|
||||
~Hid() override;
|
||||
|
||||
std::shared_ptr<IAppletResource> GetAppletResource();
|
||||
|
||||
private:
|
||||
void CreateAppletResource(HLERequestContext& ctx);
|
||||
void ActivateDebugPad(HLERequestContext& ctx);
|
||||
void ActivateTouchScreen(HLERequestContext& ctx);
|
||||
void ActivateMouse(HLERequestContext& ctx);
|
||||
void ActivateKeyboard(HLERequestContext& ctx);
|
||||
void SendKeyboardLockKeyEvent(HLERequestContext& ctx);
|
||||
void ActivateXpad(HLERequestContext& ctx);
|
||||
void GetXpadIDs(HLERequestContext& ctx);
|
||||
void ActivateSixAxisSensor(HLERequestContext& ctx);
|
||||
void DeactivateSixAxisSensor(HLERequestContext& ctx);
|
||||
void StartSixAxisSensor(HLERequestContext& ctx);
|
||||
void StopSixAxisSensor(HLERequestContext& ctx);
|
||||
void IsSixAxisSensorFusionEnabled(HLERequestContext& ctx);
|
||||
void EnableSixAxisSensorFusion(HLERequestContext& ctx);
|
||||
void SetSixAxisSensorFusionParameters(HLERequestContext& ctx);
|
||||
void GetSixAxisSensorFusionParameters(HLERequestContext& ctx);
|
||||
void ResetSixAxisSensorFusionParameters(HLERequestContext& ctx);
|
||||
void SetGyroscopeZeroDriftMode(HLERequestContext& ctx);
|
||||
void GetGyroscopeZeroDriftMode(HLERequestContext& ctx);
|
||||
void ResetGyroscopeZeroDriftMode(HLERequestContext& ctx);
|
||||
void IsSixAxisSensorAtRest(HLERequestContext& ctx);
|
||||
void IsFirmwareUpdateAvailableForSixAxisSensor(HLERequestContext& ctx);
|
||||
void EnableSixAxisSensorUnalteredPassthrough(HLERequestContext& ctx);
|
||||
void IsSixAxisSensorUnalteredPassthroughEnabled(HLERequestContext& ctx);
|
||||
void LoadSixAxisSensorCalibrationParameter(HLERequestContext& ctx);
|
||||
void GetSixAxisSensorIcInformation(HLERequestContext& ctx);
|
||||
void ResetIsSixAxisSensorDeviceNewlyAssigned(HLERequestContext& ctx);
|
||||
void ActivateGesture(HLERequestContext& ctx);
|
||||
void SetSupportedNpadStyleSet(HLERequestContext& ctx);
|
||||
void GetSupportedNpadStyleSet(HLERequestContext& ctx);
|
||||
void SetSupportedNpadIdType(HLERequestContext& ctx);
|
||||
void ActivateNpad(HLERequestContext& ctx);
|
||||
void DeactivateNpad(HLERequestContext& ctx);
|
||||
void AcquireNpadStyleSetUpdateEventHandle(HLERequestContext& ctx);
|
||||
void DisconnectNpad(HLERequestContext& ctx);
|
||||
void GetPlayerLedPattern(HLERequestContext& ctx);
|
||||
void ActivateNpadWithRevision(HLERequestContext& ctx);
|
||||
void SetNpadJoyHoldType(HLERequestContext& ctx);
|
||||
void GetNpadJoyHoldType(HLERequestContext& ctx);
|
||||
void SetNpadJoyAssignmentModeSingleByDefault(HLERequestContext& ctx);
|
||||
void SetNpadJoyAssignmentModeSingle(HLERequestContext& ctx);
|
||||
void SetNpadJoyAssignmentModeDual(HLERequestContext& ctx);
|
||||
void MergeSingleJoyAsDualJoy(HLERequestContext& ctx);
|
||||
void StartLrAssignmentMode(HLERequestContext& ctx);
|
||||
void StopLrAssignmentMode(HLERequestContext& ctx);
|
||||
void SetNpadHandheldActivationMode(HLERequestContext& ctx);
|
||||
void GetNpadHandheldActivationMode(HLERequestContext& ctx);
|
||||
void SwapNpadAssignment(HLERequestContext& ctx);
|
||||
void IsUnintendedHomeButtonInputProtectionEnabled(HLERequestContext& ctx);
|
||||
void EnableUnintendedHomeButtonInputProtection(HLERequestContext& ctx);
|
||||
void SetNpadJoyAssignmentModeSingleWithDestination(HLERequestContext& ctx);
|
||||
void SetNpadAnalogStickUseCenterClamp(HLERequestContext& ctx);
|
||||
void SetNpadCaptureButtonAssignment(HLERequestContext& ctx);
|
||||
void ClearNpadCaptureButtonAssignment(HLERequestContext& ctx);
|
||||
void GetVibrationDeviceInfo(HLERequestContext& ctx);
|
||||
void SendVibrationValue(HLERequestContext& ctx);
|
||||
void GetActualVibrationValue(HLERequestContext& ctx);
|
||||
void CreateActiveVibrationDeviceList(HLERequestContext& ctx);
|
||||
void PermitVibration(HLERequestContext& ctx);
|
||||
void IsVibrationPermitted(HLERequestContext& ctx);
|
||||
void SendVibrationValues(HLERequestContext& ctx);
|
||||
void SendVibrationGcErmCommand(HLERequestContext& ctx);
|
||||
void GetActualVibrationGcErmCommand(HLERequestContext& ctx);
|
||||
void BeginPermitVibrationSession(HLERequestContext& ctx);
|
||||
void EndPermitVibrationSession(HLERequestContext& ctx);
|
||||
void IsVibrationDeviceMounted(HLERequestContext& ctx);
|
||||
void ActivateConsoleSixAxisSensor(HLERequestContext& ctx);
|
||||
void StartConsoleSixAxisSensor(HLERequestContext& ctx);
|
||||
void StopConsoleSixAxisSensor(HLERequestContext& ctx);
|
||||
void ActivateSevenSixAxisSensor(HLERequestContext& ctx);
|
||||
void StartSevenSixAxisSensor(HLERequestContext& ctx);
|
||||
void StopSevenSixAxisSensor(HLERequestContext& ctx);
|
||||
void InitializeSevenSixAxisSensor(HLERequestContext& ctx);
|
||||
void FinalizeSevenSixAxisSensor(HLERequestContext& ctx);
|
||||
void ResetSevenSixAxisSensorTimestamp(HLERequestContext& ctx);
|
||||
void IsUsbFullKeyControllerEnabled(HLERequestContext& ctx);
|
||||
void GetPalmaConnectionHandle(HLERequestContext& ctx);
|
||||
void InitializePalma(HLERequestContext& ctx);
|
||||
void AcquirePalmaOperationCompleteEvent(HLERequestContext& ctx);
|
||||
void GetPalmaOperationInfo(HLERequestContext& ctx);
|
||||
void PlayPalmaActivity(HLERequestContext& ctx);
|
||||
void SetPalmaFrModeType(HLERequestContext& ctx);
|
||||
void ReadPalmaStep(HLERequestContext& ctx);
|
||||
void EnablePalmaStep(HLERequestContext& ctx);
|
||||
void ResetPalmaStep(HLERequestContext& ctx);
|
||||
void ReadPalmaApplicationSection(HLERequestContext& ctx);
|
||||
void WritePalmaApplicationSection(HLERequestContext& ctx);
|
||||
void ReadPalmaUniqueCode(HLERequestContext& ctx);
|
||||
void SetPalmaUniqueCodeInvalid(HLERequestContext& ctx);
|
||||
void WritePalmaActivityEntry(HLERequestContext& ctx);
|
||||
void WritePalmaRgbLedPatternEntry(HLERequestContext& ctx);
|
||||
void WritePalmaWaveEntry(HLERequestContext& ctx);
|
||||
void SetPalmaDataBaseIdentificationVersion(HLERequestContext& ctx);
|
||||
void GetPalmaDataBaseIdentificationVersion(HLERequestContext& ctx);
|
||||
void SuspendPalmaFeature(HLERequestContext& ctx);
|
||||
void GetPalmaOperationResult(HLERequestContext& ctx);
|
||||
void ReadPalmaPlayLog(HLERequestContext& ctx);
|
||||
void ResetPalmaPlayLog(HLERequestContext& ctx);
|
||||
void SetIsPalmaAllConnectable(HLERequestContext& ctx);
|
||||
void SetIsPalmaPairedConnectable(HLERequestContext& ctx);
|
||||
void PairPalma(HLERequestContext& ctx);
|
||||
void SetPalmaBoostMode(HLERequestContext& ctx);
|
||||
void CancelWritePalmaWaveEntry(HLERequestContext& ctx);
|
||||
void EnablePalmaBoostMode(HLERequestContext& ctx);
|
||||
void GetPalmaBluetoothAddress(HLERequestContext& ctx);
|
||||
void SetDisallowedPalmaConnection(HLERequestContext& ctx);
|
||||
void SetNpadCommunicationMode(HLERequestContext& ctx);
|
||||
void GetNpadCommunicationMode(HLERequestContext& ctx);
|
||||
void SetTouchScreenConfiguration(HLERequestContext& ctx);
|
||||
void IsFirmwareUpdateNeededForNotification(HLERequestContext& ctx);
|
||||
|
||||
std::shared_ptr<IAppletResource> applet_resource;
|
||||
|
||||
KernelHelpers::ServiceContext service_context;
|
||||
};
|
||||
|
||||
void LoopProcess(Core::System& system);
|
||||
|
||||
} // namespace Service::HID
|
||||
|
650
src/core/hle/service/hid/hid_debug_server.cpp
Normal file
650
src/core/hle/service/hid/hid_debug_server.cpp
Normal file
@ -0,0 +1,650 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "core/hle/service/hid//hid_result.h"
|
||||
#include "core/hle/service/hid//hid_types.h"
|
||||
#include "core/hle/service/hid/hid_debug_server.h"
|
||||
#include "core/hle/service/hid/resource_manager.h"
|
||||
#include "core/hle/service/hid/resource_manager/debug_pad.h"
|
||||
#include "core/hle/service/hid/resource_manager/gesture.h"
|
||||
#include "core/hle/service/hid/resource_manager/keyboard.h"
|
||||
#include "core/hle/service/hid/resource_manager/mouse.h"
|
||||
#include "core/hle/service/hid/resource_manager/npad_resource/npad.h"
|
||||
#include "core/hle/service/hid/resource_manager/palma.h"
|
||||
#include "core/hle/service/hid/resource_manager/sixaxis.h"
|
||||
#include "core/hle/service/hid/resource_manager/touch_screen.h"
|
||||
#include "core/hle/service/hid/hid_firmware_settings.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
IHidDebugServer::IHidDebugServer(Core::System& system_, std::shared_ptr<ResourceManager> resource,
|
||||
std::shared_ptr<HidFirmwareSettings> settings)
|
||||
: ServiceFramework{system_, "hid:dbg"}, resource_manager{resource},
|
||||
firmware_settings{settings} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &IHidDebugServer::DeactivateDebugPad, "DeactivateDebugPad"},
|
||||
{1, &IHidDebugServer::SetDebugPadAutoPilotState, "SetDebugPadAutoPilotState"},
|
||||
{2, &IHidDebugServer::UnsetDebugPadAutoPilotState, "UnsetDebugPadAutoPilotState"},
|
||||
{10, &IHidDebugServer::DeactivateTouchScreen, "DeactivateTouchScreen"},
|
||||
{11, &IHidDebugServer::SetTouchScreenAutoPilotState, "SetTouchScreenAutoPilotState"},
|
||||
{12, &IHidDebugServer::UnsetTouchScreenAutoPilotState, "UnsetTouchScreenAutoPilotState"},
|
||||
{13, &IHidDebugServer::GetTouchScreenConfiguration, "GetTouchScreenConfiguration"},
|
||||
{14, &IHidDebugServer::ProcessTouchScreenAutoTune, "ProcessTouchScreenAutoTune"},
|
||||
{15, &IHidDebugServer::ForceStopTouchScreenManagement, "ForceStopTouchScreenManagement"},
|
||||
{16, &IHidDebugServer::ForceRestartTouchScreenManagement, "ForceRestartTouchScreenManagement"},
|
||||
{17, &IHidDebugServer::IsTouchScreenManaged, "IsTouchScreenManaged"},
|
||||
{20, &IHidDebugServer::DeactivateMouse, "DeactivateMouse"},
|
||||
{21, &IHidDebugServer::SetMouseAutoPilotState, "SetMouseAutoPilotState"},
|
||||
{22, &IHidDebugServer::UnsetMouseAutoPilotState, "UnsetMouseAutoPilotState"},
|
||||
{25, &IHidDebugServer::SetDebugMouseAutoPilotState, "SetDebugMouseAutoPilotState"},
|
||||
{26, &IHidDebugServer::UnsetDebugMouseAutoPilotState, "UnsetDebugMouseAutoPilotState"},
|
||||
{30, &IHidDebugServer::DeactivateKeyboard, "DeactivateKeyboard"},
|
||||
{31, &IHidDebugServer::SetKeyboardAutoPilotState, "SetKeyboardAutoPilotState"},
|
||||
{32, &IHidDebugServer::UnsetKeyboardAutoPilotState, "UnsetKeyboardAutoPilotState"},
|
||||
{50, &IHidDebugServer::DeactivateXpad, "DeactivateXpad"},
|
||||
{60, &IHidDebugServer::ClearNpadSystemCommonPolicy, "ClearNpadSystemCommonPolicy"},
|
||||
{61, &IHidDebugServer::DeactivateNpad, "DeactivateNpad"},
|
||||
{62, &IHidDebugServer::ForceDisconnectNpad, "ForceDisconnectNpad"},
|
||||
{91, &IHidDebugServer::DeactivateGesture, "DeactivateGesture"},
|
||||
{110, &IHidDebugServer::DeactivateHomeButton, "DeactivateHomeButton"},
|
||||
{111, &IHidDebugServer::SetHomeButtonAutoPilotState, "SetHomeButtonAutoPilotState"},
|
||||
{112, &IHidDebugServer::UnsetHomeButtonAutoPilotState, "UnsetHomeButtonAutoPilotState"},
|
||||
{120, &IHidDebugServer::DeactivateSleepButton, "DeactivateSleepButton"},
|
||||
{121, &IHidDebugServer::SetSleepButtonAutoPilotState, "SetSleepButtonAutoPilotState"},
|
||||
{122, &IHidDebugServer::UnsetSleepButtonAutoPilotState, "UnsetSleepButtonAutoPilotState"},
|
||||
{123, &IHidDebugServer::DeactivateInputDetector, "DeactivateInputDetector"},
|
||||
{130, &IHidDebugServer::DeactivateCaptureButton, "DeactivateCaptureButton"},
|
||||
{131, &IHidDebugServer::SetCaptureButtonAutoPilotState, "SetCaptureButtonAutoPilotState"},
|
||||
{132, &IHidDebugServer::UnsetCaptureButtonAutoPilotState, "UnsetCaptureButtonAutoPilotState"},
|
||||
{133, &IHidDebugServer::SetShiftAccelerometerCalibrationValue, "SetShiftAccelerometerCalibrationValue"},
|
||||
{134, &IHidDebugServer::GetShiftAccelerometerCalibrationValue, "GetShiftAccelerometerCalibrationValue"},
|
||||
{135, &IHidDebugServer::SetShiftGyroscopeCalibrationValue, "SetShiftGyroscopeCalibrationValue"},
|
||||
{136, &IHidDebugServer::GetShiftGyroscopeCalibrationValue, "GetShiftGyroscopeCalibrationValue"},
|
||||
{140, nullptr, "SetSixAxisSensorMode"},
|
||||
{140, nullptr, "DeactivateConsoleSixAxisSensor"},
|
||||
{141, nullptr, "GetConsoleSixAxisSensorSamplingFrequency"},
|
||||
{142, nullptr, "DeactivateSevenSixAxisSensor"},
|
||||
{143, nullptr, "GetConsoleSixAxisSensorCountStates"},
|
||||
{144, &IHidDebugServer::GetAccelerometerFsr, "GetAccelerometerFsr"},
|
||||
{145, &IHidDebugServer::SetAccelerometerFsr, "SetAccelerometerFsr"},
|
||||
{146, &IHidDebugServer::GetAccelerometerOdr, "GetAccelerometerOdr"},
|
||||
{147, &IHidDebugServer::SetAccelerometerOdr, "SetAccelerometerOdr"},
|
||||
{148, &IHidDebugServer::GetGyroscopeFsr, "GetGyroscopeFsr"},
|
||||
{149, &IHidDebugServer::SetGyroscopeFsr, "SetGyroscopeFsr"},
|
||||
{150, &IHidDebugServer::GetGyroscopeOdr, "GetGyroscopeOdr"},
|
||||
{151, &IHidDebugServer::SetGyroscopeOdr, "SetGyroscopeOdr"},
|
||||
{152, nullptr, "GetWhoAmI"},
|
||||
{201, nullptr, "ActivateFirmwareUpdate"},
|
||||
{202, nullptr, "DeactivateFirmwareUpdate"},
|
||||
{203, nullptr, "StartFirmwareUpdate"},
|
||||
{204, nullptr, "GetFirmwareUpdateStage"},
|
||||
{205, nullptr, "GetFirmwareVersion"},
|
||||
{206, nullptr, "GetDestinationFirmwareVersion"},
|
||||
{207, nullptr, "DiscardFirmwareInfoCacheForRevert"},
|
||||
{208, nullptr, "StartFirmwareUpdateForRevert"},
|
||||
{209, nullptr, "GetAvailableFirmwareVersionForRevert"},
|
||||
{210, nullptr, "IsFirmwareUpdatingDevice"},
|
||||
{211, nullptr, "StartFirmwareUpdateIndividual"},
|
||||
{215, nullptr, "SetUsbFirmwareForceUpdateEnabled"},
|
||||
{216, nullptr, "SetAllKuinaDevicesToFirmwareUpdateMode"},
|
||||
{221, nullptr, "UpdateControllerColor"},
|
||||
{222, nullptr, "ConnectUsbPadsAsync"},
|
||||
{223, nullptr, "DisconnectUsbPadsAsync"},
|
||||
{224, nullptr, "UpdateDesignInfo"},
|
||||
{225, nullptr, "GetUniquePadDriverState"},
|
||||
{226, nullptr, "GetSixAxisSensorDriverStates"},
|
||||
{227, nullptr, "GetRxPacketHistory"},
|
||||
{228, nullptr, "AcquireOperationEventHandle"},
|
||||
{229, nullptr, "ReadSerialFlash"},
|
||||
{230, nullptr, "WriteSerialFlash"},
|
||||
{231, nullptr, "GetOperationResult"},
|
||||
{232, nullptr, "EnableShipmentMode"},
|
||||
{233, nullptr, "ClearPairingInfo"},
|
||||
{234, nullptr, "GetUniquePadDeviceTypeSetInternal"},
|
||||
{235, nullptr, "EnableAnalogStickPower"},
|
||||
{236, nullptr, "RequestKuinaUartClockCal"},
|
||||
{237, nullptr, "GetKuinaUartClockCal"},
|
||||
{238, nullptr, "SetKuinaUartClockTrim"},
|
||||
{239, nullptr, "KuinaLoopbackTest"},
|
||||
{240, nullptr, "RequestBatteryVoltage"},
|
||||
{241, nullptr, "GetBatteryVoltage"},
|
||||
{242, nullptr, "GetUniquePadPowerInfo"},
|
||||
{243, nullptr, "RebootUniquePad"},
|
||||
{244, nullptr, "RequestKuinaFirmwareVersion"},
|
||||
{245, nullptr, "GetKuinaFirmwareVersion"},
|
||||
{246, nullptr, "GetVidPid"},
|
||||
{247, nullptr, "GetAnalogStickCalibrationValue"},
|
||||
{248, nullptr, "GetUniquePadIdsFull"},
|
||||
{249, nullptr, "ConnectUniquePad"},
|
||||
{250, nullptr, "IsVirtual"},
|
||||
{251, nullptr, "GetAnalogStickModuleParam"},
|
||||
{301, nullptr, "GetAbstractedPadHandles"},
|
||||
{302, nullptr, "GetAbstractedPadState"},
|
||||
{303, nullptr, "GetAbstractedPadsState"},
|
||||
{321, nullptr, "SetAutoPilotVirtualPadState"},
|
||||
{322, nullptr, "UnsetAutoPilotVirtualPadState"},
|
||||
{323, nullptr, "UnsetAllAutoPilotVirtualPadState"},
|
||||
{324, nullptr, "AttachHdlsWorkBuffer"},
|
||||
{325, nullptr, "ReleaseHdlsWorkBuffer"},
|
||||
{326, nullptr, "DumpHdlsNpadAssignmentState"},
|
||||
{327, nullptr, "DumpHdlsStates"},
|
||||
{328, nullptr, "ApplyHdlsNpadAssignmentState"},
|
||||
{329, nullptr, "ApplyHdlsStateList"},
|
||||
{330, nullptr, "AttachHdlsVirtualDevice"},
|
||||
{331, nullptr, "DetachHdlsVirtualDevice"},
|
||||
{332, nullptr, "SetHdlsState"},
|
||||
{350, nullptr, "AddRegisteredDevice"},
|
||||
{400, nullptr, "DisableExternalMcuOnNxDevice"},
|
||||
{401, nullptr, "DisableRailDeviceFiltering"},
|
||||
{402, nullptr, "EnableWiredPairing"},
|
||||
{403, nullptr, "EnableShipmentModeAutoClear"},
|
||||
{404, nullptr, "SetRailEnabled"},
|
||||
{500, nullptr, "SetFactoryInt"},
|
||||
{501, nullptr, "IsFactoryBootEnabled"},
|
||||
{550, nullptr, "SetAnalogStickModelDataTemporarily"},
|
||||
{551, nullptr, "GetAnalogStickModelData"},
|
||||
{552, nullptr, "ResetAnalogStickModelData"},
|
||||
{600, nullptr, "ConvertPadState"},
|
||||
{650, nullptr, "AddButtonPlayData"},
|
||||
{651, nullptr, "StartButtonPlayData"},
|
||||
{652, nullptr, "StopButtonPlayData"},
|
||||
{2000, nullptr, "DeactivateDigitizer"},
|
||||
{2001, nullptr, "SetDigitizerAutoPilotState"},
|
||||
{2002, nullptr, "UnsetDigitizerAutoPilotState"},
|
||||
{3000, &IHidDebugServer::ReloadFirmwareDebugSettings, "ReloadFirmwareDebugSettings"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
IHidDebugServer::~IHidDebugServer() = default;
|
||||
|
||||
void IHidDebugServer::DeactivateDebugPad(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
|
||||
Result result = ResultSuccess;
|
||||
|
||||
if (!firmware_settings->IsDeviceManaged()) {
|
||||
result = GetResourceManager()->GetDebugPad()->Deactivate();
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
void IHidDebugServer::SetDebugPadAutoPilotState(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto auto_pilot_state{rp.Pop<DebugPadAutoPilotState>()};
|
||||
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
|
||||
const Result result =
|
||||
GetResourceManager()->GetDebugPad()->SetAutoPilotState(auto_pilot_state);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
void IHidDebugServer::UnsetDebugPadAutoPilotState(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
|
||||
const Result result =
|
||||
GetResourceManager()->GetDebugPad()->UnsetAutoPilotState();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
void IHidDebugServer::DeactivateTouchScreen(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
|
||||
Result result = ResultSuccess;
|
||||
|
||||
if (!firmware_settings->IsDeviceManaged()) {
|
||||
result = GetResourceManager()->GetTouchScreen()->Deactivate();
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
void IHidDebugServer::SetTouchScreenAutoPilotState(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto touch_state_elements{ctx.GetReadBufferNumElements<TouchState>()};
|
||||
const auto touch_state_buffer{ctx.ReadBuffer()};
|
||||
|
||||
LOG_DEBUG(Service_HID, "called, touch_state_elements={}", touch_state_elements);
|
||||
|
||||
std::vector<TouchState> touch_states(touch_state_elements);
|
||||
memcpy(touch_states.data(), touch_state_buffer.data(), touch_state_buffer.size());
|
||||
const Result result = GetResourceManager()->GetTouchScreen()->SetAutoPilotState(touch_states);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
void IHidDebugServer::UnsetTouchScreenAutoPilotState(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
|
||||
const Result result = GetResourceManager()->GetTouchScreen()->UnsetAutoPilotState();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
void IHidDebugServer::GetTouchScreenConfiguration(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);
|
||||
|
||||
TouchScreenConfigurationForNx touch_screen_configuration{};
|
||||
const Result result =
|
||||
GetResourceManager()->GetTouchScreen()->GetConfiguration(applet_resource_user_id);
|
||||
|
||||
switch (touch_screen_configuration.mode) {
|
||||
case TouchScreenModeForNx::UseSystemSetting:
|
||||
case TouchScreenModeForNx::Finger:
|
||||
case TouchScreenModeForNx::Heat2:
|
||||
break;
|
||||
default:
|
||||
touch_screen_configuration.mode = TouchScreenModeForNx::UseSystemSetting;
|
||||
break;
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 6};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushRaw(touch_screen_configuration);
|
||||
}
|
||||
|
||||
void IHidDebugServer::ProcessTouchScreenAutoTune(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
|
||||
const Result result = GetResourceManager()->GetTouchScreen()->ProcessAutoTune();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
void IHidDebugServer::ForceStopTouchScreenManagement(HLERequestContext& ctx){
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
|
||||
Result result = ResultSuccess;
|
||||
auto touch_screen = GetResourceManager()->GetTouchScreen();
|
||||
|
||||
if (firmware_settings->IsDeviceManaged()) {
|
||||
if (firmware_settings->IsTouchI2cManaged()) {
|
||||
result=touch_screen->Something();
|
||||
if (result.IsSuccess()) {
|
||||
result = touch_screen->Somethingx2();
|
||||
}
|
||||
if (result.IsSuccess()) {
|
||||
result = touch_screen->DeactivateTouchScreen();
|
||||
}
|
||||
if (result.IsSuccess()) {
|
||||
result = touch_screen->DeactivateGesture();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
void IHidDebugServer::ForceRestartTouchScreenManagement(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
u32 basic_gesture_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>()};
|
||||
|
||||
LOG_DEBUG(Service_HID, "called, basic_gesture_id={}, applet_resource_user_id={}",
|
||||
parameters.basic_gesture_id, parameters.applet_resource_user_id);
|
||||
|
||||
Result result = ResultSuccess;
|
||||
auto touch_screen = GetResourceManager()->GetTouchScreen();
|
||||
|
||||
if (firmware_settings->IsDeviceManaged() && firmware_settings->IsTouchI2cManaged()) {
|
||||
result = touch_screen->ActivateGestureUnmanaged();
|
||||
if (result.IsSuccess()) {
|
||||
result = touch_screen->ActivateGesture(basic_gesture_id, applet_resource_user_id);
|
||||
}
|
||||
if (result.IsSuccess()) {
|
||||
result = touch_screen->ActivateTouchScreenUnmanaged();
|
||||
}
|
||||
if (result.IsSuccess()) {
|
||||
result = touch_screen->ActivateTouchScreen();
|
||||
}
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
void IHidDebugServer::IsTouchScreenManaged(HLERequestContext& ctx){
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
|
||||
bool is_managed{};
|
||||
bool is_bool{};
|
||||
bool is_baal{};
|
||||
Result result = GetResourceManager()->GetTouchScreen()->SomeFunction(is_bool);
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
GetResourceManager()->GetTouchScreen()->SomeFunction2(is_baal);
|
||||
}
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
is_managed = is_bool | is_baal;
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
void IHidDebugServer::DeactivateMouse(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
|
||||
Result result = ResultSuccess;
|
||||
|
||||
if (!firmware_settings->IsDeviceManaged()) {
|
||||
result = GetResourceManager()->GetMouse()->Deactivate();
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
void IHidDebugServer::SetMouseAutoPilotState(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto auto_pilot_state{rp.Pop<MouseAutoPilotState>()};
|
||||
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
|
||||
const Result result = GetResourceManager()->GetMouse()->SetAutoPilotState(auto_pilot_state);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
void IHidDebugServer::UnsetMouseAutoPilotState(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
|
||||
const Result result = GetResourceManager()->GetMouse()->UnsetAutoPilotState();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
void IHidDebugServer::SetDebugMouseAutoPilotState(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto auto_pilot_state{rp.Pop<MouseAutoPilotState>()};
|
||||
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
|
||||
const Result result = GetResourceManager()->GetDebugMouse()->SetAutoPilotState(auto_pilot_state);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
void IHidDebugServer::UnsetDebugMouseAutoPilotState(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
|
||||
const Result result = GetResourceManager()->GetDebugMouse()->UnsetAutoPilotState();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
void IHidDebugServer::DeactivateKeyboard(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
|
||||
Result result = ResultSuccess;
|
||||
|
||||
if (!firmware_settings->IsDeviceManaged()) {
|
||||
result = GetResourceManager()->GetKeyboard()->Deactivate();
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
void IHidDebugServer::SetKeyboardAutoPilotState(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto auto_pilot_state{rp.Pop<KeyboardAutoPilotState>()};
|
||||
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
|
||||
const Result result =
|
||||
GetResourceManager()->GetKeyboard()->SetAutoPilotState(auto_pilot_state);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
void IHidDebugServer::UnsetKeyboardAutoPilotState(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
|
||||
const Result result = GetResourceManager()->GetKeyboard()->UnsetAutoPilotState();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
void IHidDebugServer::DeactivateXpad(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto joy_xpad_id{rp.Pop<u32>()};
|
||||
|
||||
LOG_DEBUG(Service_HID, "called, joy_xpad_id={}", joy_xpad_id);
|
||||
|
||||
// This function has been stubbed since 10.0.0+
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IHidDebugServer::ClearNpadSystemCommonPolicy(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
|
||||
LOG_INFO(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
|
||||
|
||||
const auto npad = GetResourceManager()->GetNpad();
|
||||
const auto result = npad->ClearNpadSystemCommonPolicy(applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
void IHidDebugServer::DeactivateNpad(HLERequestContext& ctx) {}
|
||||
|
||||
void IHidDebugServer::ForceDisconnectNpad(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto npad_id{rp.PopEnum<NpadIdType>()};
|
||||
|
||||
LOG_INFO(Service_HID, "called, npad_id={}", npad_id);
|
||||
|
||||
GetResourceManager()->GetNpad()->ForceDisconnectNpad(NpadIdType::Player1);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IHidDebugServer::DeactivateGesture(HLERequestContext& ctx) {}
|
||||
void IHidDebugServer::DeactivateHomeButton(HLERequestContext& ctx) {}
|
||||
void IHidDebugServer::SetHomeButtonAutoPilotState(HLERequestContext& ctx) {}
|
||||
void IHidDebugServer::UnsetHomeButtonAutoPilotState(HLERequestContext& ctx) {}
|
||||
void IHidDebugServer::DeactivateSleepButton(HLERequestContext& ctx) {}
|
||||
void IHidDebugServer::SetSleepButtonAutoPilotState(HLERequestContext& ctx) {}
|
||||
void IHidDebugServer::UnsetSleepButtonAutoPilotState(HLERequestContext& ctx) {}
|
||||
void IHidDebugServer::DeactivateInputDetector(HLERequestContext& ctx) {}
|
||||
void IHidDebugServer::DeactivateCaptureButton(HLERequestContext& ctx) {}
|
||||
void IHidDebugServer::SetCaptureButtonAutoPilotState(HLERequestContext& ctx) {}
|
||||
void IHidDebugServer::UnsetCaptureButtonAutoPilotState(HLERequestContext& ctx) {}
|
||||
|
||||
void IHidDebugServer::SetShiftAccelerometerCalibrationValue(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
SixAxisSensorHandle sixaxis_handle;
|
||||
SixAxisSensorShiftAccelerometerCalibration accelerometer_calibration;
|
||||
INSERT_PADDING_WORDS_NOINIT(1);
|
||||
u64 applet_resource_user_id;
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
|
||||
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
|
||||
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);
|
||||
|
||||
Result result = ResultSuccess;
|
||||
std::array<u64, ARUID_MAX> aruid_list{};
|
||||
std::shared_ptr<SixAxisSensorState> state = nullptr;
|
||||
|
||||
const auto sixaxis = GetResourceManager()->GetSixAxis();
|
||||
sixaxis->GetAruidList(aruid_list);
|
||||
|
||||
for (const auto& aruid : aruid_list) {
|
||||
result = sixaxis->GetSensorState(state, aruid, parameters.sixaxis_handle);
|
||||
if (result.IsError()) {
|
||||
break;
|
||||
}
|
||||
state->SetShiftAccelerometerCalibrationValue(parameters.accelerometer_calibration);
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
void IHidDebugServer::GetShiftAccelerometerCalibrationValue(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
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>()};
|
||||
|
||||
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);
|
||||
|
||||
SixAxisSensorShiftAccelerometerCalibration accelerometer_calibration;
|
||||
std::shared_ptr<SixAxisSensorState> state = nullptr;
|
||||
const auto sixaxis = GetResourceManager()->GetSixAxis();
|
||||
const auto result = sixaxis->GetSensorState(state, parameters.applet_resource_user_id,
|
||||
parameters.sixaxis_handle);
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
accelerometer_calibration = state->GetShiftAccelerometerCalibrationValue();
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(result);
|
||||
rb.PushRaw(accelerometer_calibration);
|
||||
}
|
||||
|
||||
void IHidDebugServer::SetShiftGyroscopeCalibrationValue(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
SixAxisSensorHandle sixaxis_handle;
|
||||
SixAxisSensorShiftGyroscopeCalibration gyroscope_calibration;
|
||||
INSERT_PADDING_WORDS_NOINIT(1);
|
||||
u64 applet_resource_user_id;
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
|
||||
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
|
||||
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);
|
||||
|
||||
Result result = ResultSuccess;
|
||||
std::array<u64, ARUID_MAX> aruid_list{};
|
||||
std::shared_ptr<SixAxisSensorState> state = nullptr;
|
||||
|
||||
const auto sixaxis = GetResourceManager()->GetSixAxis();
|
||||
sixaxis->GetAruidList(aruid_list);
|
||||
|
||||
for (const auto& aruid : aruid_list) {
|
||||
result = sixaxis->GetSensorState(state, aruid, parameters.sixaxis_handle);
|
||||
if (result.IsError()) {
|
||||
break;
|
||||
}
|
||||
state->SetShiftGyroscopeCalibrationValue(parameters.gyroscope_calibration);
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
void IHidDebugServer::GetShiftGyroscopeCalibrationValue(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
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>()};
|
||||
|
||||
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);
|
||||
|
||||
SixAxisSensorShiftGyroscopeCalibration gyroscope_calibration;
|
||||
std::shared_ptr<SixAxisSensorState> state = nullptr;
|
||||
const auto sixaxis = GetResourceManager()->GetSixAxis();
|
||||
const auto result = sixaxis->GetSensorState(state, parameters.applet_resource_user_id,
|
||||
parameters.sixaxis_handle);
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
gyroscope_calibration = state->GetShiftGyroscopeCalibrationValue();
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(result);
|
||||
rb.PushRaw(gyroscope_calibration);
|
||||
}
|
||||
|
||||
void IHidDebugServer::GetAccelerometerFsr(HLERequestContext& ctx) {}
|
||||
void IHidDebugServer::SetAccelerometerFsr(HLERequestContext& ctx) {}
|
||||
void IHidDebugServer::GetAccelerometerOdr(HLERequestContext& ctx) {}
|
||||
void IHidDebugServer::SetAccelerometerOdr(HLERequestContext& ctx) {}
|
||||
void IHidDebugServer::GetGyroscopeFsr(HLERequestContext& ctx) {}
|
||||
void IHidDebugServer::SetGyroscopeFsr(HLERequestContext& ctx) {}
|
||||
void IHidDebugServer::GetGyroscopeOdr(HLERequestContext& ctx) {}
|
||||
void IHidDebugServer::SetGyroscopeOdr(HLERequestContext& ctx) {}
|
||||
|
||||
void IHidDebugServer::ReloadFirmwareDebugSettings(HLERequestContext& ctx) {
|
||||
firmware_settings->Reload();
|
||||
|
||||
LOG_INFO(Service_HID, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
std::shared_ptr<ResourceManager> IHidDebugServer::GetResourceManager() {
|
||||
resource_manager->VerifiyInitalization();
|
||||
return resource_manager;
|
||||
}
|
||||
|
||||
} // namespace Service::HID
|
78
src/core/hle/service/hid/hid_debug_server.h
Normal file
78
src/core/hle/service/hid/hid_debug_server.h
Normal file
@ -0,0 +1,78 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Service::HID {
|
||||
class ResourceManager;
|
||||
class HidFirmwareSettings;
|
||||
|
||||
class IHidDebugServer final : public ServiceFramework<IHidDebugServer> {
|
||||
public:
|
||||
explicit IHidDebugServer(Core::System& system_, std::shared_ptr<ResourceManager> resource,
|
||||
std::shared_ptr<HidFirmwareSettings> settings);
|
||||
~IHidDebugServer() override;
|
||||
|
||||
private:
|
||||
// Service calls
|
||||
void DeactivateDebugPad(HLERequestContext& ctx);
|
||||
void SetDebugPadAutoPilotState(HLERequestContext& ctx);
|
||||
void UnsetDebugPadAutoPilotState(HLERequestContext& ctx);
|
||||
void DeactivateTouchScreen(HLERequestContext& ctx);
|
||||
void SetTouchScreenAutoPilotState(HLERequestContext& ctx);
|
||||
void UnsetTouchScreenAutoPilotState(HLERequestContext& ctx);
|
||||
void GetTouchScreenConfiguration(HLERequestContext& ctx);
|
||||
void ProcessTouchScreenAutoTune(HLERequestContext& ctx);
|
||||
void ForceStopTouchScreenManagement(HLERequestContext& ctx);
|
||||
void ForceRestartTouchScreenManagement(HLERequestContext& ctx);
|
||||
void IsTouchScreenManaged(HLERequestContext& ctx);
|
||||
void DeactivateMouse(HLERequestContext& ctx);
|
||||
void SetMouseAutoPilotState(HLERequestContext& ctx);
|
||||
void UnsetMouseAutoPilotState(HLERequestContext& ctx);
|
||||
void SetDebugMouseAutoPilotState(HLERequestContext& ctx);
|
||||
void UnsetDebugMouseAutoPilotState(HLERequestContext& ctx);
|
||||
void DeactivateKeyboard(HLERequestContext& ctx);
|
||||
void SetKeyboardAutoPilotState(HLERequestContext& ctx);
|
||||
void UnsetKeyboardAutoPilotState(HLERequestContext& ctx);
|
||||
void DeactivateXpad(HLERequestContext& ctx);
|
||||
void ClearNpadSystemCommonPolicy(HLERequestContext& ctx);
|
||||
void DeactivateNpad(HLERequestContext& ctx);
|
||||
void ForceDisconnectNpad(HLERequestContext& ctx);
|
||||
void DeactivateGesture(HLERequestContext& ctx);
|
||||
void DeactivateHomeButton(HLERequestContext& ctx);
|
||||
void SetHomeButtonAutoPilotState(HLERequestContext& ctx);
|
||||
void UnsetHomeButtonAutoPilotState(HLERequestContext& ctx);
|
||||
void DeactivateSleepButton(HLERequestContext& ctx);
|
||||
void SetSleepButtonAutoPilotState(HLERequestContext& ctx);
|
||||
void UnsetSleepButtonAutoPilotState(HLERequestContext& ctx);
|
||||
void DeactivateInputDetector(HLERequestContext& ctx);
|
||||
void DeactivateCaptureButton(HLERequestContext& ctx);
|
||||
void SetCaptureButtonAutoPilotState(HLERequestContext& ctx);
|
||||
void UnsetCaptureButtonAutoPilotState(HLERequestContext& ctx);
|
||||
void SetShiftAccelerometerCalibrationValue(HLERequestContext& ctx);
|
||||
void GetShiftAccelerometerCalibrationValue(HLERequestContext& ctx);
|
||||
void SetShiftGyroscopeCalibrationValue(HLERequestContext& ctx);
|
||||
void GetShiftGyroscopeCalibrationValue(HLERequestContext& ctx);
|
||||
void GetAccelerometerFsr(HLERequestContext& ctx);
|
||||
void SetAccelerometerFsr(HLERequestContext& ctx);
|
||||
void GetAccelerometerOdr(HLERequestContext& ctx);
|
||||
void SetAccelerometerOdr(HLERequestContext& ctx);
|
||||
void GetGyroscopeFsr(HLERequestContext& ctx);
|
||||
void SetGyroscopeFsr(HLERequestContext& ctx);
|
||||
void GetGyroscopeOdr(HLERequestContext& ctx);
|
||||
void SetGyroscopeOdr(HLERequestContext& ctx);
|
||||
void ReloadFirmwareDebugSettings(HLERequestContext& ctx);
|
||||
|
||||
std::shared_ptr<ResourceManager> GetResourceManager();
|
||||
|
||||
std::shared_ptr<ResourceManager> resource_manager = nullptr;
|
||||
std::shared_ptr<HidFirmwareSettings> firmware_settings = nullptr;
|
||||
};
|
||||
|
||||
} // namespace Service::HID
|
148
src/core/hle/service/hid/hid_firmware_settings.cpp
Normal file
148
src/core/hle/service/hid/hid_firmware_settings.cpp
Normal file
@ -0,0 +1,148 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/hle/service/hid/hid_firmware_settings.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
HidFirmwareSettings::HidFirmwareSettings() {
|
||||
LoadSettings(true);
|
||||
}
|
||||
|
||||
void HidFirmwareSettings::Reload() {
|
||||
LoadSettings(true);
|
||||
}
|
||||
|
||||
void HidFirmwareSettings::LoadSettings(bool should_initialize) {
|
||||
// TODO: uncomment this code when we can talk between services
|
||||
|
||||
if (is_debug_settings_initalized && !should_initialize) {
|
||||
return;
|
||||
}
|
||||
|
||||
is_debugpad_enabled = true;
|
||||
// nn::settings::fwdbg::GetSettingsItemValue(&is_debugpad_enabled, 1, "hid_debug",
|
||||
// "enables_debugpad")
|
||||
|
||||
is_device_managed = true;
|
||||
// nn::settings::fwdbg::GetSettingsItemValue(&is_device_managed, 1, "hid_debug",
|
||||
// "manages_devices");
|
||||
|
||||
is_touch_i2c_managed = is_device_managed;
|
||||
if (is_device_managed) {
|
||||
// nn::settings::fwdbg::GetSettingsItemValue(&setting_hid_debug_manages_touch_ic_i2c, 1,
|
||||
// "hid_debug", "manages_touch_ic_i2c");
|
||||
}
|
||||
|
||||
is_future_devices_emulated = false;
|
||||
// nn::settings::fwdbg::GetSettingsItemValue(&setting_hid_debug_emulate_future_device, 1,
|
||||
// "hid_debug", "emulate_future_device");
|
||||
|
||||
is_mcu_hardware_error_emulated = false;
|
||||
// nn::settings::fwdbg::GetSettingsItemValue(&setting_hid_debug_emulate_mcu_hardware_error, 1,
|
||||
// "hid_debug", "emulate_mcu_hardware_error");
|
||||
|
||||
is_rail_enabled = true;
|
||||
// nn::settings::fwdbg::GetSettingsItemValue(&setting_hid_debug_enables_rail, 1, "hid_debug",
|
||||
// "enables_rail");
|
||||
|
||||
is_firmware_update_failure_emulated = false;
|
||||
// nn::settings::fwdbg::GetSettingsItemValue(setting_hid_debug_emulate_firmware_update_failure,
|
||||
// 1, "hid_debug", "emulate_firmware_update_failure");
|
||||
|
||||
is_firmware_update_failure = {};
|
||||
if (is_firmware_update_failure_emulated) {
|
||||
const std::size_t size = 0; // GetSettingsItemValueSize("hid_debug",
|
||||
// "firmware_update_failure"); if (size != 0) {
|
||||
[[maybe_unused]] const std::size_t setting_size =
|
||||
std::min(size, is_firmware_update_failure.size());
|
||||
// nn::settings::fwdbg::GetSettingsItemValue(&is_firmware_update_failure, setting_size,
|
||||
// "hid_debug", "firmware_update_failure");
|
||||
//}
|
||||
}
|
||||
|
||||
is_ble_disabled = false;
|
||||
// nn::settings::fwdbg::GetSettingsItemValue(&setting_hid_debug_ble_disabled, 1, "hid_debug",
|
||||
// "ble_disabled");
|
||||
|
||||
is_dscale_disabled = false;
|
||||
// nn::settings::fwdbg::GetSettingsItemValue(&setting_hid_debug_dscale_disabled, 1, "hid_debug",
|
||||
// "dscale_disabled");
|
||||
|
||||
is_handheld_forced = true;
|
||||
// nn::settings::fwdbg::GetSettingsItemValue(&force_handheld, 1, "hid_debug", "force_handheld");
|
||||
|
||||
features_per_id_disabled = {};
|
||||
// nn::settings::fwdbg::GetSettingsItemValue(&disabled_features_per_id,
|
||||
// is_features_per_id_disabled.size(), "hid_debug",
|
||||
// "disabled_features_per_id");
|
||||
|
||||
is_touch_firmware_auto_update_disabled = false;
|
||||
// nn::settings::fwdbg::GetSettingsItemValue(
|
||||
// &setting_hid_debug_touch_firmware_auto_update_disabled, 1, "hid_debug",
|
||||
// "touch_firmware_auto_update_disabled");
|
||||
|
||||
is_debug_settings_initalized = true;
|
||||
}
|
||||
|
||||
bool HidFirmwareSettings::IsDebugPadEnabled() {
|
||||
LoadSettings(false);
|
||||
return is_debugpad_enabled;
|
||||
}
|
||||
|
||||
bool HidFirmwareSettings::IsDeviceManaged() {
|
||||
LoadSettings(false);
|
||||
return is_device_managed;
|
||||
}
|
||||
|
||||
bool HidFirmwareSettings::IsEmulateFutureDevice() {
|
||||
LoadSettings(false);
|
||||
return is_future_devices_emulated;
|
||||
}
|
||||
|
||||
bool HidFirmwareSettings::IsTouchI2cManaged() {
|
||||
LoadSettings(false);
|
||||
return is_touch_i2c_managed;
|
||||
}
|
||||
|
||||
bool HidFirmwareSettings::IsHandheldForced() {
|
||||
LoadSettings(false);
|
||||
return is_handheld_forced;
|
||||
}
|
||||
|
||||
bool HidFirmwareSettings::IsRailEnabled() {
|
||||
LoadSettings(false);
|
||||
return is_rail_enabled;
|
||||
}
|
||||
|
||||
bool HidFirmwareSettings::IsHardwareErrorEmulated() {
|
||||
LoadSettings(false);
|
||||
return is_mcu_hardware_error_emulated;
|
||||
}
|
||||
|
||||
bool HidFirmwareSettings::IsBleDisabled() {
|
||||
LoadSettings(false);
|
||||
return is_ble_disabled;
|
||||
}
|
||||
|
||||
bool HidFirmwareSettings::IsDscaleDisabled() {
|
||||
LoadSettings(false);
|
||||
return is_dscale_disabled;
|
||||
}
|
||||
|
||||
bool HidFirmwareSettings::IsTouchAutoUpdateDisabled() {
|
||||
LoadSettings(false);
|
||||
return is_touch_firmware_auto_update_disabled;
|
||||
}
|
||||
|
||||
HidFirmwareSettings::FirmwareSetting HidFirmwareSettings::GetFirmwareUpdateFailure() {
|
||||
LoadSettings(false);
|
||||
return is_firmware_update_failure;
|
||||
}
|
||||
|
||||
HidFirmwareSettings::FeaturesPerId HidFirmwareSettings::FeaturesDisabledPerId() {
|
||||
LoadSettings(false);
|
||||
return features_per_id_disabled;
|
||||
}
|
||||
|
||||
} // namespace Service::HID
|
54
src/core/hle/service/hid/hid_firmware_settings.h
Normal file
54
src/core/hle/service/hid/hid_firmware_settings.h
Normal file
@ -0,0 +1,54 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
/// Loads firmware config from nn::settings::fwdbg
|
||||
class HidFirmwareSettings {
|
||||
public:
|
||||
using FirmwareSetting = std::array<u8, 4>;
|
||||
using FeaturesPerId = std::array<bool, 0xA8>;
|
||||
|
||||
HidFirmwareSettings();
|
||||
|
||||
void Reload();
|
||||
void LoadSettings(bool should_initialize);
|
||||
|
||||
bool IsDebugPadEnabled();
|
||||
bool IsDeviceManaged();
|
||||
bool IsEmulateFutureDevice();
|
||||
bool IsTouchI2cManaged();
|
||||
bool IsHandheldForced();
|
||||
bool IsRailEnabled();
|
||||
bool IsHardwareErrorEmulated();
|
||||
bool IsBleDisabled();
|
||||
bool IsDscaleDisabled();
|
||||
bool IsTouchAutoUpdateDisabled();
|
||||
|
||||
FirmwareSetting GetFirmwareUpdateFailure();
|
||||
FeaturesPerId FeaturesDisabledPerId();
|
||||
|
||||
private:
|
||||
bool is_debug_settings_initalized{};
|
||||
|
||||
// Debug settings
|
||||
bool is_debugpad_enabled{};
|
||||
bool is_device_managed{};
|
||||
bool is_touch_i2c_managed{};
|
||||
bool is_future_devices_emulated{};
|
||||
bool is_mcu_hardware_error_emulated{};
|
||||
bool is_rail_enabled{};
|
||||
bool is_firmware_update_failure_emulated{};
|
||||
bool is_ble_disabled{};
|
||||
bool is_dscale_disabled{};
|
||||
bool is_handheld_forced{};
|
||||
bool is_touch_firmware_auto_update_disabled{};
|
||||
FirmwareSetting is_firmware_update_failure{};
|
||||
FeaturesPerId features_per_id_disabled{};
|
||||
};
|
||||
|
||||
} // namespace Service::HID
|
41
src/core/hle/service/hid/hid_result.h
Normal file
41
src/core/hle/service/hid/hid_result.h
Normal file
@ -0,0 +1,41 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/result.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
constexpr Result ResultPalmaResultSuccess{ErrorModule::HID, 0};
|
||||
constexpr Result ResultNpadInvalidHandle{ErrorModule::HID, 100};
|
||||
constexpr Result ResultNpadDeviceIndexOutOfRange{ErrorModule::HID, 107};
|
||||
constexpr Result ResultVibrationInvalidStyleIndex{ErrorModule::HID, 122};
|
||||
constexpr Result ResultVibrationInvalidNpadId{ErrorModule::HID, 123};
|
||||
constexpr Result ResultVibrationVolumeOutOfRange{ErrorModule::HID, 126};
|
||||
constexpr Result ResultVibrationDeviceIndexOutOfRange{ErrorModule::HID, 124};
|
||||
constexpr Result ResultVibrationArraySizeMismatch{ErrorModule::HID, 131};
|
||||
|
||||
constexpr Result ResultInvalidSixAxisFusionRange{ErrorModule::HID, 423};
|
||||
constexpr Result ResultNpadIsDualJoycon{ErrorModule::HID, 601};
|
||||
constexpr Result ResultNpadIsSameType{ErrorModule::HID, 602};
|
||||
constexpr Result ResultInvalidNpadId{ErrorModule::HID, 709};
|
||||
constexpr Result ResultNpadNotConnected{ErrorModule::HID, 710};
|
||||
constexpr Result ResultInvalidArraySize{ErrorModule::HID, 715};
|
||||
constexpr Result ResultUndefinedStyleSet{ErrorModule::HID, 716};
|
||||
constexpr Result ResultInvalidStyleSet{ErrorModule::HID, 717};
|
||||
|
||||
constexpr Result ResultUnknown108{ErrorModule::HID, 108};
|
||||
|
||||
constexpr Result ResultInvalidPalmaNpadId{ErrorModule::HID, 3301};
|
||||
constexpr Result ResultInvalidPalmaHandle{ErrorModule::HID, 3302};
|
||||
constexpr Result ResultOperationFailed{ErrorModule::HID, 3304};
|
||||
|
||||
} // namespace Service::HID
|
||||
|
||||
namespace Service::XCD {
|
||||
|
||||
constexpr Result ResultUnknown1{ErrorModule::XCD, 1};
|
||||
constexpr Result ResultUnknown365{ErrorModule::XCD, 365};
|
||||
|
||||
} // namespace Service::XCD
|
2900
src/core/hle/service/hid/hid_server.cpp
Normal file
2900
src/core/hle/service/hid/hid_server.cpp
Normal file
File diff suppressed because it is too large
Load Diff
198
src/core/hle/service/hid/hid_server.h
Normal file
198
src/core/hle/service/hid/hid_server.h
Normal file
@ -0,0 +1,198 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Service::HID {
|
||||
struct VibrationDeviceHandle;
|
||||
struct VibrationValue;
|
||||
|
||||
class ResourceManager;
|
||||
class HidFirmwareSettings;
|
||||
|
||||
class IAppletResource final : public ServiceFramework<IAppletResource> {
|
||||
public:
|
||||
explicit IAppletResource(Core::System& system_);
|
||||
~IAppletResource() override;
|
||||
|
||||
private:
|
||||
void GetSharedMemoryHandle(HLERequestContext& ctx);
|
||||
};
|
||||
|
||||
class IActiveVibrationDeviceList final : public ServiceFramework<IActiveVibrationDeviceList> {
|
||||
public:
|
||||
explicit IActiveVibrationDeviceList(Core::System& system_,
|
||||
std::shared_ptr<ResourceManager> resource);
|
||||
~IActiveVibrationDeviceList() override;
|
||||
|
||||
private:
|
||||
void InitializeVibrationDevice(HLERequestContext& ctx);
|
||||
|
||||
std::shared_ptr<ResourceManager> resource_manager = nullptr;
|
||||
};
|
||||
|
||||
class IHidServer final : public ServiceFramework<IHidServer> {
|
||||
public:
|
||||
explicit IHidServer(Core::System& system_, std::shared_ptr<ResourceManager> resource,
|
||||
std::shared_ptr<HidFirmwareSettings> settings);
|
||||
~IHidServer() override;
|
||||
|
||||
private:
|
||||
void CreateAppletResource(HLERequestContext& ctx);
|
||||
void ActivateDebugPad(HLERequestContext& ctx);
|
||||
void ActivateTouchScreen(HLERequestContext& ctx);
|
||||
void ActivateMouse(HLERequestContext& ctx);
|
||||
void ActivateDebugMouse(HLERequestContext& ctx);
|
||||
void ActivateKeyboard(HLERequestContext& ctx);
|
||||
void SendKeyboardLockKeyEvent(HLERequestContext& ctx);
|
||||
void AcquireXpadIdEventHandle(HLERequestContext& ctx);
|
||||
void ReleaseXpadIdEventHandle(HLERequestContext& ctx);
|
||||
void ActivateXpad(HLERequestContext& ctx);
|
||||
void GetXpadIds(HLERequestContext& ctx);
|
||||
void ActivateJoyXpad(HLERequestContext& ctx);
|
||||
void GetJoyXpadLifoHandle(HLERequestContext& ctx);
|
||||
void GetJoyXpadIds(HLERequestContext& ctx);
|
||||
void ActivateSixAxisSensor(HLERequestContext& ctx);
|
||||
void DeactivateSixAxisSensor(HLERequestContext& ctx);
|
||||
void GetSixAxisSensorLifoHandle(HLERequestContext& ctx);
|
||||
void ActivateJoySixAxisSensor(HLERequestContext& ctx);
|
||||
void DeactivateJoySixAxisSensor(HLERequestContext& ctx);
|
||||
void GetJoySixAxisSensorLifoHandle(HLERequestContext& ctx);
|
||||
void StartSixAxisSensor(HLERequestContext& ctx);
|
||||
void StopSixAxisSensor(HLERequestContext& ctx);
|
||||
void IsSixAxisSensorFusionEnabled(HLERequestContext& ctx);
|
||||
void EnableSixAxisSensorFusion(HLERequestContext& ctx);
|
||||
void SetSixAxisSensorFusionParameters(HLERequestContext& ctx);
|
||||
void GetSixAxisSensorFusionParameters(HLERequestContext& ctx);
|
||||
void ResetSixAxisSensorFusionParameters(HLERequestContext& ctx);
|
||||
void SetAccelerometerParameters(HLERequestContext& ctx);
|
||||
void GetAccelerometerParameters(HLERequestContext& ctx);
|
||||
void ResetAccelerometerParameters(HLERequestContext& ctx);
|
||||
void SetAccelerometerPlayMode(HLERequestContext& ctx);
|
||||
void GetAccelerometerPlayMode(HLERequestContext& ctx);
|
||||
void ResetAccelerometerPlayMode(HLERequestContext& ctx);
|
||||
void SetGyroscopeZeroDriftMode(HLERequestContext& ctx);
|
||||
void GetGyroscopeZeroDriftMode(HLERequestContext& ctx);
|
||||
void ResetGyroscopeZeroDriftMode(HLERequestContext& ctx);
|
||||
void IsSixAxisSensorAtRest(HLERequestContext& ctx);
|
||||
void IsFirmwareUpdateAvailableForSixAxisSensor(HLERequestContext& ctx);
|
||||
void EnableSixAxisSensorUnalteredPassthrough(HLERequestContext& ctx);
|
||||
void IsSixAxisSensorUnalteredPassthroughEnabled(HLERequestContext& ctx);
|
||||
void StoreSixAxisSensorCalibrationParameter(HLERequestContext& ctx);
|
||||
void LoadSixAxisSensorCalibrationParameter(HLERequestContext& ctx);
|
||||
void GetSixAxisSensorIcInformation(HLERequestContext& ctx);
|
||||
void ResetIsSixAxisSensorDeviceNewlyAssigned(HLERequestContext& ctx);
|
||||
void ActivateGesture(HLERequestContext& ctx);
|
||||
void SetSupportedNpadStyleSet(HLERequestContext& ctx);
|
||||
void GetSupportedNpadStyleSet(HLERequestContext& ctx);
|
||||
void SetSupportedNpadIdType(HLERequestContext& ctx);
|
||||
void ActivateNpad(HLERequestContext& ctx);
|
||||
void DeactivateNpad(HLERequestContext& ctx);
|
||||
void AcquireNpadStyleSetUpdateEventHandle(HLERequestContext& ctx);
|
||||
void DisconnectNpad(HLERequestContext& ctx);
|
||||
void GetPlayerLedPattern(HLERequestContext& ctx);
|
||||
void ActivateNpadWithRevision(HLERequestContext& ctx);
|
||||
void SetNpadJoyHoldType(HLERequestContext& ctx);
|
||||
void GetNpadJoyHoldType(HLERequestContext& ctx);
|
||||
void SetNpadJoyAssignmentModeSingleByDefault(HLERequestContext& ctx);
|
||||
void SetNpadJoyAssignmentModeSingle(HLERequestContext& ctx);
|
||||
void SetNpadJoyAssignmentModeDual(HLERequestContext& ctx);
|
||||
void MergeSingleJoyAsDualJoy(HLERequestContext& ctx);
|
||||
void StartLrAssignmentMode(HLERequestContext& ctx);
|
||||
void StopLrAssignmentMode(HLERequestContext& ctx);
|
||||
void SetNpadHandheldActivationMode(HLERequestContext& ctx);
|
||||
void GetNpadHandheldActivationMode(HLERequestContext& ctx);
|
||||
void SwapNpadAssignment(HLERequestContext& ctx);
|
||||
void IsUnintendedHomeButtonInputProtectionEnabled(HLERequestContext& ctx);
|
||||
void EnableUnintendedHomeButtonInputProtection(HLERequestContext& ctx);
|
||||
void SetNpadJoyAssignmentModeSingleWithDestination(HLERequestContext& ctx);
|
||||
void SetNpadAnalogStickUseCenterClamp(HLERequestContext& ctx);
|
||||
void SetNpadCaptureButtonAssignment(HLERequestContext& ctx);
|
||||
void ClearNpadCaptureButtonAssignment(HLERequestContext& ctx);
|
||||
void GetVibrationDeviceInfo(HLERequestContext& ctx);
|
||||
void SendVibrationValue(HLERequestContext& ctx);
|
||||
void GetActualVibrationValue(HLERequestContext& ctx);
|
||||
void CreateActiveVibrationDeviceList(HLERequestContext& ctx);
|
||||
void PermitVibration(HLERequestContext& ctx);
|
||||
void IsVibrationPermitted(HLERequestContext& ctx);
|
||||
void SendVibrationValues(HLERequestContext& ctx);
|
||||
void SendVibrationGcErmCommand(HLERequestContext& ctx);
|
||||
void GetActualVibrationGcErmCommand(HLERequestContext& ctx);
|
||||
void BeginPermitVibrationSession(HLERequestContext& ctx);
|
||||
void EndPermitVibrationSession(HLERequestContext& ctx);
|
||||
void IsVibrationDeviceMounted(HLERequestContext& ctx);
|
||||
void SendVibrationValueInBool(HLERequestContext& ctx);
|
||||
void ActivateConsoleSixAxisSensor(HLERequestContext& ctx);
|
||||
void StartConsoleSixAxisSensor(HLERequestContext& ctx);
|
||||
void StopConsoleSixAxisSensor(HLERequestContext& ctx);
|
||||
void ActivateSevenSixAxisSensor(HLERequestContext& ctx);
|
||||
void StartSevenSixAxisSensor(HLERequestContext& ctx);
|
||||
void StopSevenSixAxisSensor(HLERequestContext& ctx);
|
||||
void InitializeSevenSixAxisSensor(HLERequestContext& ctx);
|
||||
void FinalizeSevenSixAxisSensor(HLERequestContext& ctx);
|
||||
void SetSevenSixAxisSensorFusionStrength(HLERequestContext& ctx);
|
||||
void GetSevenSixAxisSensorFusionStrength(HLERequestContext& ctx);
|
||||
void ResetSevenSixAxisSensorTimestamp(HLERequestContext& ctx);
|
||||
void IsUsbFullKeyControllerEnabled(HLERequestContext& ctx);
|
||||
void EnableUsbFullKeyController(HLERequestContext& ctx);
|
||||
void IsUsbFullKeyControllerConnected(HLERequestContext& ctx);
|
||||
void HasBattery(HLERequestContext& ctx);
|
||||
void HasLeftRightBattery(HLERequestContext& ctx);
|
||||
void GetNpadInterfaceType(HLERequestContext& ctx);
|
||||
void GetNpadLeftRightInterfaceType(HLERequestContext& ctx);
|
||||
void GetNpadOfHighestBatteryLevel(HLERequestContext& ctx);
|
||||
void GetNpadOfHighestBatteryLevelForJoyRight(HLERequestContext& ctx);
|
||||
void GetPalmaConnectionHandle(HLERequestContext& ctx);
|
||||
void InitializePalma(HLERequestContext& ctx);
|
||||
void AcquirePalmaOperationCompleteEvent(HLERequestContext& ctx);
|
||||
void GetPalmaOperationInfo(HLERequestContext& ctx);
|
||||
void PlayPalmaActivity(HLERequestContext& ctx);
|
||||
void SetPalmaFrModeType(HLERequestContext& ctx);
|
||||
void ReadPalmaStep(HLERequestContext& ctx);
|
||||
void EnablePalmaStep(HLERequestContext& ctx);
|
||||
void ResetPalmaStep(HLERequestContext& ctx);
|
||||
void ReadPalmaApplicationSection(HLERequestContext& ctx);
|
||||
void WritePalmaApplicationSection(HLERequestContext& ctx);
|
||||
void ReadPalmaUniqueCode(HLERequestContext& ctx);
|
||||
void SetPalmaUniqueCodeInvalid(HLERequestContext& ctx);
|
||||
void WritePalmaActivityEntry(HLERequestContext& ctx);
|
||||
void WritePalmaRgbLedPatternEntry(HLERequestContext& ctx);
|
||||
void WritePalmaWaveEntry(HLERequestContext& ctx);
|
||||
void SetPalmaDataBaseIdentificationVersion(HLERequestContext& ctx);
|
||||
void GetPalmaDataBaseIdentificationVersion(HLERequestContext& ctx);
|
||||
void SuspendPalmaFeature(HLERequestContext& ctx);
|
||||
void GetPalmaOperationResult(HLERequestContext& ctx);
|
||||
void ReadPalmaPlayLog(HLERequestContext& ctx);
|
||||
void ResetPalmaPlayLog(HLERequestContext& ctx);
|
||||
void SetIsPalmaAllConnectable(HLERequestContext& ctx);
|
||||
void SetIsPalmaPairedConnectable(HLERequestContext& ctx);
|
||||
void PairPalma(HLERequestContext& ctx);
|
||||
void SetPalmaBoostMode(HLERequestContext& ctx);
|
||||
void CancelWritePalmaWaveEntry(HLERequestContext& ctx);
|
||||
void EnablePalmaBoostMode(HLERequestContext& ctx);
|
||||
void GetPalmaBluetoothAddress(HLERequestContext& ctx);
|
||||
void SetDisallowedPalmaConnection(HLERequestContext& ctx);
|
||||
void SetNpadCommunicationMode(HLERequestContext& ctx);
|
||||
void GetNpadCommunicationMode(HLERequestContext& ctx);
|
||||
void SetTouchScreenConfiguration(HLERequestContext& ctx);
|
||||
void IsFirmwareUpdateNeededForNotification(HLERequestContext& ctx);
|
||||
void ActivateDigitizer(HLERequestContext& ctx);
|
||||
|
||||
private:
|
||||
Result SendVibrationValueImpl(const u64 aruid, const VibrationDeviceHandle& handle,
|
||||
const VibrationValue& value);
|
||||
|
||||
std::shared_ptr<ResourceManager> GetResourceManager();
|
||||
|
||||
std::shared_ptr<ResourceManager> resource_manager = nullptr;
|
||||
std::shared_ptr<IAppletResource> applet_resource = nullptr;
|
||||
std::shared_ptr<HidFirmwareSettings> firmware_settings = nullptr;
|
||||
};
|
||||
|
||||
} // namespace Service::HID
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user