diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 4de11d7967d..134a6d40338 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -82,7 +82,7 @@ jobs: max-size: 1000M - name: Configure - run: CI/before_script.macos.sh + run: CI/before_script.macos.sh -C - name: Build run: CI/macos/build.sh diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f779c52e445..edd7585cea1 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -344,7 +344,7 @@ Ubuntu_GCC_tests_coverage: PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip" before_script: - CI/install_debian_deps.sh gcc openmw-deps openmw-deps-dynamic openmw-coverage - - pipx install gcovr + - pipx install gcovr==8.3 coverage: /^\s*lines:\s*\d+.\d+\%/ artifacts: paths: [] @@ -429,7 +429,11 @@ Ubuntu_Clang: - mkdir -pv "${CCACHE_DIR}" - ccache -z -M "${CCACHE_SIZE}" - CI/before_script.linux.sh - - cp extern/.clang-tidy build/.clang-tidy + - mkdir -p build/extern build/apps/launcher build/apps/opencs build/apps/wizard + - cp extern/.clang-tidy build/extern/ + - cp extern/.clang-tidy build/apps/launcher/ + - cp extern/.clang-tidy build/apps/opencs/ + - cp extern/.clang-tidy build/apps/wizard/ - cd build - find . -name *.o -exec touch {} \; - cmake --build . -- -j $(nproc) ${BUILD_TARGETS} @@ -555,11 +559,12 @@ Ubuntu_GCC_integration_tests_asan: - ccache/ script: - CI/before_install.macos.sh + - brew install ccache - export CCACHE_BASEDIR="$(pwd)" - export CCACHE_DIR="$(pwd)/ccache" - mkdir -pv "${CCACHE_DIR}" - - CI/macos/ccache_prep.sh - - CI/before_script.macos.sh + - ccache -z -M "${CCACHE_SIZE}" + - CI/before_script.macos.sh -C - CI/macos/build.sh - cd build - for dmg in *.dmg; do mv "$dmg" "${dmg%.dmg}_${DMG_IDENTIFIER}_${CI_COMMIT_REF_NAME##*/}.dmg"; done @@ -578,7 +583,7 @@ Ubuntu_GCC_integration_tests_asan: s3cmd put "${dmg}" s3://openmw-artifacts/${artifactDirectory} done fi - - ../CI/macos/ccache_show_stats.sh + - ccache -svv artifacts: paths: - build/OpenMW-*.dmg diff --git a/CHANGELOG.md b/CHANGELOG.md index 830ab930949..c9c150d8338 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +0.51.0 +------ + + 0.50.0 ------ @@ -19,6 +23,7 @@ Bug #7979: Paralyzed NPCs battlecry Bug #7996: Instant magic effects are not always instant Bug #8012: Startcombat and Stopcombat do not affect music in the menu mode + Bug #8176: Error marker cloning is not thread-safe Bug #8245: The console command ShowVars does not list global mwscripts Bug #8265: Topics are linked incorrectly Bug #8303: On target spells cast by non-actors should fire underwater @@ -71,6 +76,11 @@ Bug #8650: Some plants turn invisible when being called types.Container.inventory(cont):isResolved() Bug #8680: Dead ancestor ghosts stop being dust when you rest near them Bug #8686: openmw-cs: Crash when smoothing terrain of a not-yet-created cell. + Bug #8710: Absorb Skill breaks on creatures + Bug #8720: Crash due to a malformed Lua UI element + Bug #8734: Shield sheathing does not work properly + Bug #8757: Crash in Lua coroutine when accessing player + Bug #8758: Lua UI crash on creating nested UI elements twice without destroying old parent element Feature #2522: Support quick item transfer Feature #3740: Gamepad GUI Mode Feature #3769: Allow GetSpellEffects on enchantments diff --git a/CI/before_install.macos.sh b/CI/before_install.macos.sh index 60d2d3a38c2..84cc99d03db 100755 --- a/CI/before_install.macos.sh +++ b/CI/before_install.macos.sh @@ -1,7 +1,12 @@ #!/bin/sh -ex +brew tap --repair +brew update --quiet + if [[ "${MACOS_AMD64}" ]]; then ./CI/macos/before_install.amd64.sh else ./CI/macos/before_install.arm64.sh fi + +command -v cmake >/dev/null 2>&1 || brew install cmake diff --git a/CI/before_script.macos.sh b/CI/before_script.macos.sh index 15be5eb4e00..67a7e7accfe 100755 --- a/CI/before_script.macos.sh +++ b/CI/before_script.macos.sh @@ -1,28 +1,91 @@ -#!/bin/sh -e +#!/bin/bash -e -# Silence a git warning -git config --global advice.detachedHead false +VERBOSE="" +USE_CCACHE="" +KEEP="" +USE_WERROR="" -rm -fr build -mkdir build +while [ $# -gt 0 ]; do + ARGSTR=$1 + shift + + if [ ${ARGSTR:0:1} != "-" ]; then + echo "Unknown argument $ARGSTR" + echo "Try '$0 -h'" + wrappedExit 1 + fi + + for (( i=1; i<${#ARGSTR}; i++ )); do + ARG=${ARGSTR:$i:1} + case $ARG in + V ) + VERBOSE=true ;; + + C ) + USE_CCACHE=true ;; + + k ) + KEEP=true ;; + + E ) + USE_WERROR=true ;; + + h ) + cat </dev/null 2>&1 && qmake -v | grep -F 'Using Qt version 6.' >/dev/null || /usr/local/bin/brew install qt@6" + +arch -x86_64 /usr/local/bin/brew install curl xquartz gd fontconfig freetype harfbuzz brotli openal-soft icu4c yaml-cpp sqlite curl -fSL -R -J https://gitlab.com/OpenMW/openmw-deps/-/raw/main/macos/openmw-deps-20240802.zip -o ~/openmw-deps.zip unzip -o ~/openmw-deps.zip -d /tmp > /dev/null diff --git a/CI/macos/before_install.arm64.sh b/CI/macos/before_install.arm64.sh index d1fb572f01a..60217093ec2 100755 --- a/CI/macos/before_install.arm64.sh +++ b/CI/macos/before_install.arm64.sh @@ -1,11 +1,8 @@ #!/bin/sh -ex -brew tap --repair -brew update --quiet +command -v qmake >/dev/null 2>&1 && qmake -v | grep -F "Using Qt version 6." >/dev/null || brew install qt@6 -command -v cmake >/dev/null 2>&1 || brew install cmake - -brew install curl xquartz gd fontconfig freetype harfbuzz brotli qt@6 ccache openal-soft icu4c yaml-cpp sqlite +brew install curl xquartz gd fontconfig freetype harfbuzz brotli openal-soft icu4c yaml-cpp sqlite curl -fSL -R -J https://gitlab.com/OpenMW/openmw-deps/-/raw/main/macos/openmw-deps-20240818-arm64.tar.xz -o ~/openmw-deps.tar.xz tar xf ~/openmw-deps.tar.xz -C /tmp > /dev/null diff --git a/CI/macos/ccache_prep.sh b/CI/macos/ccache_prep.sh deleted file mode 100755 index abd0103be0c..00000000000 --- a/CI/macos/ccache_prep.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh -ex - -if [[ "${MACOS_AMD64}" ]]; then - arch -x86_64 ccache -z -M "${CCACHE_SIZE}" -else - ccache -z -M "${CCACHE_SIZE}" -fi diff --git a/CI/macos/ccache_show_stats.sh b/CI/macos/ccache_show_stats.sh deleted file mode 100755 index d7cc48c25ef..00000000000 --- a/CI/macos/ccache_show_stats.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh -ex - -if [[ "${MACOS_AMD64}" ]]; then - arch -x86_64 ccache -svv -else - ccache -svv -fi diff --git a/CMakeLists.txt b/CMakeLists.txt index 834668e92aa..f72a7fd05f6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -80,9 +80,9 @@ endif() message(STATUS "Configuring OpenMW...") set(OPENMW_VERSION_MAJOR 0) -set(OPENMW_VERSION_MINOR 50) +set(OPENMW_VERSION_MINOR 51) set(OPENMW_VERSION_RELEASE 0) -set(OPENMW_LUA_API_REVISION 95) +set(OPENMW_LUA_API_REVISION 101) set(OPENMW_POSTPROCESSING_API_REVISION 3) set(OPENMW_VERSION_COMMITHASH "") @@ -270,6 +270,7 @@ set(USED_OSG_PLUGINS osgdb_bmp osgdb_dae osgdb_dds + osgdb_ktx osgdb_freetype osgdb_jpeg osgdb_osg @@ -452,7 +453,7 @@ if(HAVE_MULTIVIEW) add_definitions(-DOSG_HAS_MULTIVIEW) endif(HAVE_MULTIVIEW) -set(BOOST_COMPONENTS iostreams program_options system) +set(BOOST_COMPONENTS iostreams program_options) find_package(Boost 1.70.0 CONFIG REQUIRED COMPONENTS ${BOOST_COMPONENTS} OPTIONAL_COMPONENTS ${BOOST_OPTIONAL_COMPONENTS}) @@ -483,6 +484,7 @@ set(SOL_CONFIG_DIR ${OpenMW_SOURCE_DIR}/extern/sol_config) include_directories( BEFORE SYSTEM "." + ${SDL2_INCLUDE_DIR} ${MyGUI_INCLUDE_DIRS} ${OPENAL_INCLUDE_DIR} ${OPENGL_INCLUDE_DIR} @@ -493,7 +495,7 @@ include_directories( ${ICU_INCLUDE_DIRS} ) -link_directories(${COLLADA_DOM_LIBRARY_DIRS}) +link_directories(${SDL2_LIBRARY_DIRS} ${COLLADA_DOM_LIBRARY_DIRS}) if(MYGUI_STATIC) add_definitions(-DMYGUI_STATIC) @@ -615,7 +617,7 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" OR CMAKE_CXX_COMPILER_FRONTEND_VARIANT add_compile_options("/WX") endif() else () - add_compile_options("-Wall" "-Wextra" "-Wundef" "-Wextra-semi" "-Wno-unused-parameter" "-pedantic" "-Wno-long-long" "-Wnon-virtual-dtor" "-Wunused" "-Wshadow") + add_compile_options("-Wall" "-Wextra" "-Wundef" "-Wextra-semi" "-Wno-unused-parameter" "-Wno-long-long" "-Wnon-virtual-dtor" "-Wunused" "-Wshadow" "-Wno-overloaded-virtual" "-Wno-inconsistent-missing-override" "-Wno-deprecated-copy-with-user-provided-copy" "-Wno-extra-semi") if (CMAKE_CXX_COMPILER_ID STREQUAL Clang AND NOT APPLE) if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 3.6 OR CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 3.6) diff --git a/README.md b/README.md index f65f74e9d84..3b79c5ecefb 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ OpenMW is an open-source open-world RPG game engine that supports playing Morrow OpenMW also comes with OpenMW-CS, a replacement for Bethesda's Construction Set. -* Version: 0.50.0 +* Version: 0.51.0 * License: GPLv3 (see [LICENSE](https://gitlab.com/OpenMW/openmw/-/raw/master/LICENSE) for more information) * Website: https://www.openmw.org * IRC: #openmw on irc.libera.chat diff --git a/apps/bsatool/bsatool.cpp b/apps/bsatool/bsatool.cpp index b62a4382948..90685dfe1df 100644 --- a/apps/bsatool/bsatool.cpp +++ b/apps/bsatool/bsatool.cpp @@ -170,8 +170,8 @@ int list(std::unique_ptr& bsa, Arguments& info) // Long format std::ios::fmtflags f(std::cout.flags()); std::cout << std::setw(50) << std::left << file.name(); - std::cout << std::setw(8) << std::left << std::dec << file.fileSize; - std::cout << "@ 0x" << std::hex << file.offset << std::endl; + std::cout << std::setw(8) << std::left << std::dec << file.mFileSize; + std::cout << "@ 0x" << std::hex << file.mOffset << std::endl; std::cout.flags(f); } else diff --git a/apps/components_tests/CMakeLists.txt b/apps/components_tests/CMakeLists.txt index 75956813133..7e3fef263b8 100644 --- a/apps/components_tests/CMakeLists.txt +++ b/apps/components_tests/CMakeLists.txt @@ -84,10 +84,14 @@ file(GLOB UNITTEST_SRC_FILES esmterrain/testgridsampling.cpp resource/testobjectcache.cpp + resource/testresourcesystem.cpp vfs/testpathutil.cpp sceneutil/osgacontroller.cpp + + bsa/testbsafile.cpp + bsa/testcompressedbsafile.cpp ) source_group(apps\\components-tests FILES ${UNITTEST_SRC_FILES}) diff --git a/apps/components_tests/bsa/operators.hpp b/apps/components_tests/bsa/operators.hpp new file mode 100644 index 00000000000..a5098b38147 --- /dev/null +++ b/apps/components_tests/bsa/operators.hpp @@ -0,0 +1,40 @@ +#ifndef COMPONETS_TESTS_BSA_OPERATORS_H +#define COMPONETS_TESTS_BSA_OPERATORS_H + +#include + +#include +#include + +namespace Bsa +{ + inline auto makeTuple(const BSAFile::Hash& value) + { + return std::make_tuple(value.mLow, value.mHigh); + } + + inline auto makeTuple(const BSAFile::FileStruct& value) + { + return std::make_tuple( + value.mFileSize, value.mOffset, makeTuple(value.mHash), value.mNameOffset, value.mNameSize, value.name()); + } + + inline std::ostream& operator<<(std::ostream& stream, const BSAFile::Hash& value) + { + return stream << "Hash { .mLow = " << value.mLow << ", .mHigh = " << value.mHigh << "}"; + } + + inline std::ostream& operator<<(std::ostream& stream, const BSAFile::FileStruct& value) + { + return stream << "FileStruct { .mFileSize = " << value.mFileSize << ", .mOffset = " << value.mOffset + << ", .mHash = " << value.mHash << ", .mNameOffset = " << value.mNameOffset + << ", .mNameSize = " << value.mNameSize << ", .name() = " << value.name() << "}"; + } + + inline bool operator==(const BSAFile::FileStruct& lhs, const BSAFile::FileStruct& rhs) + { + return makeTuple(lhs) == makeTuple(rhs); + } +} + +#endif diff --git a/apps/components_tests/bsa/testbsafile.cpp b/apps/components_tests/bsa/testbsafile.cpp new file mode 100644 index 00000000000..365697e6ae9 --- /dev/null +++ b/apps/components_tests/bsa/testbsafile.cpp @@ -0,0 +1,356 @@ +#include "operators.hpp" + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Bsa +{ + namespace + { + using namespace ::testing; + + struct Free + { + void operator()(void* ptr) const { std::free(ptr); } + }; + + struct Buffer + { + std::unique_ptr mData; + std::size_t mCapacity; + }; + + struct Header + { + uint32_t mFormat; + uint32_t mDirSize; + uint32_t mFileCount; + }; + + struct Archive + { + Header mHeader; + std::vector mOffsets; + std::vector mStringBuffer; + std::vector mHashes; + std::size_t mTailSize; + }; + + struct TestBSAFile final : public BSAFile + { + void readHeader(std::istream& input) override { BSAFile::readHeader(input); } + + void writeHeader() override { throw std::logic_error("TestBSAFile::writeHeader is not implemented"); } + }; + + void writeArchive(const Archive& value, std::ostream& stream) + { + stream.write(reinterpret_cast(&value.mHeader), sizeof(value.mHeader)); + + if (!value.mOffsets.empty()) + stream.write(reinterpret_cast(value.mOffsets.data()), + value.mOffsets.size() * sizeof(std::uint32_t)); + + if (!value.mStringBuffer.empty()) + stream.write(reinterpret_cast(value.mStringBuffer.data()), value.mStringBuffer.size()); + + for (const BSAFile::Hash& hash : value.mHashes) + stream.write(reinterpret_cast(&hash), sizeof(BSAFile::Hash)); + + const std::size_t chunkSize = 4096; + std::vector chunk(chunkSize); + for (std::size_t i = 0; i < value.mTailSize; i += chunkSize) + stream.write(reinterpret_cast(chunk.data()), std::min(chunk.size(), value.mTailSize - i)); + } + + std::filesystem::path makeOutputPath() + { + const auto testInfo = UnitTest::GetInstance()->current_test_info(); + return TestingOpenMW::outputFilePath( + std::format("{}.{}.bsa", testInfo->test_suite_name(), testInfo->name())); + } + + Buffer makeBsaBuffer(std::uint32_t fileSize, std::uint32_t fileOffset) + { + std::ostringstream stream; + + const Header header{ + .mFormat = static_cast(BsaVersion::Uncompressed), + .mDirSize = 14, + .mFileCount = 1, + }; + + const BSAFile::Hash hash{ + .mLow = 0xaaaabbbb, + .mHigh = 0xccccdddd, + }; + + const Archive archive{ + .mHeader = header, + .mOffsets = { fileSize, fileOffset, 0 }, + .mStringBuffer = { 'a', '\0' }, + .mHashes = { hash }, + .mTailSize = 0, + }; + + writeArchive(archive, stream); + + const std::string data = std::move(stream).str(); + + const std::size_t capacity = static_cast(fileSize) + static_cast(fileOffset) + 34; + std::unique_ptr buffer(reinterpret_cast(std::malloc(capacity))); + + if (buffer == nullptr) + throw std::bad_alloc(); + + std::memcpy(buffer.get(), data.data(), data.size()); + + return Buffer{ .mData = std::move(buffer), .mCapacity = capacity }; + } + + TEST(BSAFileTest, shouldHandleEmpty) + { + const std::filesystem::path path = makeOutputPath(); + + { + std::ofstream stream; + stream.exceptions(std::ifstream::failbit | std::ifstream::badbit); + stream.open(path, std::ios::binary); + } + + BSAFile file; + EXPECT_THROW(file.open(path), std::runtime_error); + + EXPECT_THAT(file.getList(), IsEmpty()); + } + + TEST(BSAFileTest, shouldHandleZeroFiles) + { + const std::filesystem::path path = makeOutputPath(); + + { + std::ofstream stream; + stream.exceptions(std::ifstream::failbit | std::ifstream::badbit); + + stream.open(path, std::ios::binary); + + const Header header{ + .mFormat = static_cast(BsaVersion::Uncompressed), + .mDirSize = 0, + .mFileCount = 0, + }; + + const Archive archive{ + .mHeader = header, + .mOffsets = {}, + .mStringBuffer = {}, + .mHashes = {}, + .mTailSize = 0, + }; + + writeArchive(archive, stream); + } + + BSAFile file; + file.open(path); + + EXPECT_THAT(file.getList(), IsEmpty()); + } + + TEST(BSAFileTest, shouldHandleSingleFile) + { + const std::filesystem::path path = makeOutputPath(); + + { + std::ofstream stream; + stream.exceptions(std::ifstream::failbit | std::ifstream::badbit); + + stream.open(path, std::ios::binary); + + const Header header{ + .mFormat = static_cast(BsaVersion::Uncompressed), + .mDirSize = 14, + .mFileCount = 1, + }; + + const BSAFile::Hash hash{ + .mLow = 0xaaaabbbb, + .mHigh = 0xccccdddd, + }; + + const Archive archive{ + .mHeader = header, + .mOffsets = { 42, 0, 0 }, + .mStringBuffer = { 'a', '\0' }, + .mHashes = { hash }, + .mTailSize = 42, + }; + + writeArchive(archive, stream); + } + + BSAFile file; + file.open(path); + + std::vector namesBuffer = { 'a', '\0' }; + + EXPECT_THAT(file.getList(), + ElementsAre(BSAFile::FileStruct{ + .mFileSize = 42, + .mOffset = 34, + .mHash = BSAFile::Hash{ .mLow = 0xaaaabbbb, .mHigh = 0xccccdddd }, + .mNameOffset = 0, + .mNameSize = 1, + .mNamesBuffer = &namesBuffer, + })); + } + + TEST(BSAFileTest, shouldHandleTwoFiles) + { + const std::filesystem::path path = makeOutputPath(); + + { + std::ofstream stream; + stream.exceptions(std::ifstream::failbit | std::ifstream::badbit); + + stream.open(path, std::ios::binary); + + const std::uint32_t fileSize1 = 42; + const std::uint32_t fileSize2 = 13; + + const Header header{ + .mFormat = static_cast(BsaVersion::Uncompressed), + .mDirSize = 28, + .mFileCount = 2, + }; + + const BSAFile::Hash hash1{ + .mLow = 0xaaaabbbb, + .mHigh = 0xccccdddd, + }; + + const BSAFile::Hash hash2{ + .mLow = 0x11112222, + .mHigh = 0x33334444, + }; + + const Archive archive{ + .mHeader = header, + .mOffsets = { fileSize1, 0, fileSize2, fileSize1, 0, 2 }, + .mStringBuffer = { 'a', '\0', 'b', '\0' }, + .mHashes = { hash1, hash2 }, + .mTailSize = fileSize1 + fileSize2, + }; + + writeArchive(archive, stream); + } + + BSAFile file; + file.open(path); + + std::vector namesBuffer = { 'a', '\0', 'b', '\0' }; + + EXPECT_THAT(file.getList(), + ElementsAre( + BSAFile::FileStruct{ + .mFileSize = 42, + .mOffset = 56, + .mHash = BSAFile::Hash{ .mLow = 0xaaaabbbb, .mHigh = 0xccccdddd }, + .mNameOffset = 0, + .mNameSize = 1, + .mNamesBuffer = &namesBuffer, + }, + BSAFile::FileStruct{ + .mFileSize = 13, + .mOffset = 98, + .mHash = BSAFile::Hash{ .mLow = 0x11112222, .mHigh = 0x33334444 }, + .mNameOffset = 2, + .mNameSize = 1, + .mNamesBuffer = &namesBuffer, + })); + } + + TEST(BSAFileTest, shouldHandleSomewhatLargeFiles) + { + constexpr std::uint32_t maxUInt32 = std::numeric_limits::max(); + constexpr std::uint32_t fileSize = maxUInt32 / 4; + constexpr std::uint32_t fileOffset = maxUInt32 / 4 - 34; + const Buffer buffer = makeBsaBuffer(fileSize, fileOffset); + + TestBSAFile file; + // Use capacity assuming we never read beyond small header. + Files::IMemStream stream(buffer.mData.get(), buffer.mCapacity); + file.readHeader(stream); + + std::vector namesBuffer = { 'a', '\0' }; + + EXPECT_THAT(file.getList(), + ElementsAre(BSAFile::FileStruct{ + .mFileSize = maxUInt32 / 4, + .mOffset = maxUInt32 / 4, + .mHash = BSAFile::Hash{ .mLow = 0xaaaabbbb, .mHigh = 0xccccdddd }, + .mNameOffset = 0, + .mNameSize = 1, + .mNamesBuffer = &namesBuffer, + })); + } + +// std::streambuf in MSVC does not support buffers larger than 2**31 - 1: +// https://developercommunity.visualstudio.com/t/stdbasic-stringbuf-is-broken/290124 +#ifndef _MSC_VER + TEST(BSAFileTest, shouldHandleSingleFileAtTheEndOfLargeFile) + { + constexpr std::uint32_t maxUInt32 = std::numeric_limits::max(); + constexpr std::uint32_t fileSize = maxUInt32; + constexpr std::uint32_t fileOffset = maxUInt32 - 34; + const Buffer buffer = makeBsaBuffer(fileSize, fileOffset); + + TestBSAFile file; + // Use capacity assuming we never read beyond small header. + Files::IMemStream stream(buffer.mData.get(), buffer.mCapacity); + file.readHeader(stream); + + std::vector namesBuffer = { 'a', '\0' }; + + EXPECT_THAT(file.getList(), + ElementsAre(BSAFile::FileStruct{ + .mFileSize = maxUInt32, + .mOffset = maxUInt32, + .mHash = BSAFile::Hash{ .mLow = 0xaaaabbbb, .mHigh = 0xccccdddd }, + .mNameOffset = 0, + .mNameSize = 1, + .mNamesBuffer = &namesBuffer, + })); + } + + TEST(BSAFileTest, shouldThrowExceptionOnTooBigAbsoluteOffset) + { + constexpr std::uint32_t maxUInt32 = std::numeric_limits::max(); + constexpr std::uint32_t fileSize = maxUInt32; + constexpr std::uint32_t fileOffset = maxUInt32 - 34 + 1; + const Buffer buffer = makeBsaBuffer(fileSize, fileOffset); + + TestBSAFile file; + // Use capacity assuming we never read beyond small header. + Files::IMemStream stream(buffer.mData.get(), buffer.mCapacity); + EXPECT_THROW(file.readHeader(stream), std::runtime_error); + + EXPECT_THAT(file.getList(), IsEmpty()); + } +#endif + } +} diff --git a/apps/components_tests/bsa/testcompressedbsafile.cpp b/apps/components_tests/bsa/testcompressedbsafile.cpp new file mode 100644 index 00000000000..d6343ccaec9 --- /dev/null +++ b/apps/components_tests/bsa/testcompressedbsafile.cpp @@ -0,0 +1,360 @@ +#include "operators.hpp" + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +namespace Bsa +{ + namespace + { + using namespace ::testing; + + struct FileRecord + { + std::uint64_t mHash; + std::uint32_t mSize; + std::uint32_t mOffset; + std::string mName; + }; + + struct NonSSEFolderRecord + { + std::uint64_t mHash; + std::uint32_t mCount; + std::int32_t mOffset; + std::string mName; + std::vector mFiles; + }; + + struct Archive + { + CompressedBSAFile::Header mHeader; + std::vector mFolders; + }; + + void writeArchive(const Archive& value, std::ostream& stream) + { + stream.write(reinterpret_cast(&value.mHeader), sizeof(value.mHeader)); + + for (const NonSSEFolderRecord& folder : value.mFolders) + { + stream.write(reinterpret_cast(&folder.mHash), sizeof(folder.mHash)); + stream.write(reinterpret_cast(&folder.mCount), sizeof(folder.mCount)); + stream.write(reinterpret_cast(&folder.mOffset), sizeof(folder.mOffset)); + } + + for (const NonSSEFolderRecord& folder : value.mFolders) + { + const std::uint8_t folderNameSize = static_cast(folder.mName.size() + 1); + + stream.write(reinterpret_cast(&folderNameSize), sizeof(folderNameSize)); + stream.write(reinterpret_cast(folder.mName.data()), folder.mName.size()); + stream.put('\0'); + + for (const FileRecord& file : folder.mFiles) + { + stream.write(reinterpret_cast(&file.mHash), sizeof(file.mHash)); + stream.write(reinterpret_cast(&file.mSize), sizeof(file.mSize)); + stream.write(reinterpret_cast(&file.mOffset), sizeof(file.mOffset)); + } + } + + for (const NonSSEFolderRecord& folder : value.mFolders) + { + for (const FileRecord& file : folder.mFiles) + { + stream.write(reinterpret_cast(file.mName.data()), file.mName.size()); + stream.put('\0'); + } + } + } + + std::filesystem::path makeOutputPath() + { + const auto testInfo = UnitTest::GetInstance()->current_test_info(); + return TestingOpenMW::outputFilePath( + std::format("{}.{}.bsa", testInfo->test_suite_name(), testInfo->name())); + } + + TEST(CompressedBSAFileTest, shouldHandleEmpty) + { + const std::filesystem::path path = makeOutputPath(); + + { + std::ofstream stream; + stream.exceptions(std::ifstream::failbit | std::ifstream::badbit); + stream.open(path, std::ios::binary); + } + + CompressedBSAFile file; + EXPECT_THROW(file.open(path), std::runtime_error); + + EXPECT_THAT(file.getList(), IsEmpty()); + } + + TEST(CompressedBSAFileTest, shouldHandleSingleFile) + { + const std::filesystem::path path = makeOutputPath(); + + { + std::ofstream stream; + stream.exceptions(std::ifstream::failbit | std::ifstream::badbit); + + stream.open(path, std::ios::binary); + + const CompressedBSAFile::Header header{ + .mFormat = static_cast(BsaVersion::Compressed), + .mVersion = CompressedBSAFile::Version_TES4, + .mFoldersOffset = sizeof(CompressedBSAFile::Header), + .mFlags = CompressedBSAFile::ArchiveFlag_FolderNames | CompressedBSAFile::ArchiveFlag_FileNames, + .mFolderCount = 1, + .mFileCount = 1, + .mFolderNamesLength = 7, + .mFileNamesLength = 9, + .mFileFlags = 0, + }; + + const FileRecord file{ + .mHash = 0xfedcba9876543210, + .mSize = 42, + .mOffset = 0, + .mName = "filename", + }; + + const NonSSEFolderRecord folder{ + .mHash = 0xfedcba9876543210, + .mCount = 1, + .mOffset = 0, + .mName = "folder", + .mFiles = { file }, + }; + + const Archive archive{ + .mHeader = header, + .mFolders = { folder }, + }; + + writeArchive(archive, stream); + } + + CompressedBSAFile file; + file.open(path); + + std::vector namesBuffer; + constexpr std::string_view filePath = "folder\\filename"; + namesBuffer.assign(filePath.begin(), filePath.end()); + namesBuffer.push_back('\0'); + + EXPECT_THAT(file.getList(), + ElementsAre(BSAFile::FileStruct{ + .mFileSize = 42, + .mOffset = 0, + .mHash = BSAFile::Hash{ .mLow = 0, .mHigh = 0 }, + .mNameOffset = 0, + .mNameSize = 15, + .mNamesBuffer = &namesBuffer, + })); + } + + TEST(CompressedBSAFileTest, shouldHandleEmptyFileName) + { + const std::filesystem::path path = makeOutputPath(); + + { + std::ofstream stream; + stream.exceptions(std::ifstream::failbit | std::ifstream::badbit); + + stream.open(path, std::ios::binary); + + const CompressedBSAFile::Header header{ + .mFormat = static_cast(BsaVersion::Compressed), + .mVersion = CompressedBSAFile::Version_TES4, + .mFoldersOffset = sizeof(CompressedBSAFile::Header), + .mFlags = CompressedBSAFile::ArchiveFlag_FolderNames | CompressedBSAFile::ArchiveFlag_FileNames, + .mFolderCount = 1, + .mFileCount = 1, + .mFolderNamesLength = 7, + .mFileNamesLength = 1, + .mFileFlags = 0, + }; + + const FileRecord file{ + .mHash = 0xfedcba9876543210, + .mSize = 42, + .mOffset = 0, + .mName = "", + }; + + const NonSSEFolderRecord folder{ + .mHash = 0xfedcba9876543210, + .mCount = 1, + .mOffset = 0, + .mName = "folder", + .mFiles = { file }, + }; + + const Archive archive{ + .mHeader = header, + .mFolders = { folder }, + }; + + writeArchive(archive, stream); + } + + CompressedBSAFile file; + EXPECT_THROW(file.open(path), std::runtime_error); + } + + TEST(CompressedBSAFileTest, shouldHandleFoldersWithDuplicateHash) + { + const std::filesystem::path path = makeOutputPath(); + + { + std::ofstream stream; + stream.exceptions(std::ifstream::failbit | std::ifstream::badbit); + + stream.open(path, std::ios::binary); + + const CompressedBSAFile::Header header{ + .mFormat = static_cast(BsaVersion::Compressed), + .mVersion = CompressedBSAFile::Version_TES4, + .mFoldersOffset = sizeof(CompressedBSAFile::Header), + .mFlags = CompressedBSAFile::ArchiveFlag_FolderNames | CompressedBSAFile::ArchiveFlag_FileNames, + .mFolderCount = 2, + .mFileCount = 2, + .mFolderNamesLength = 16, + .mFileNamesLength = 18, + .mFileFlags = 0, + }; + + const FileRecord file{ + .mHash = 0xfedcba9876543210, + .mSize = 42, + .mOffset = 0, + .mName = "filename", + }; + + const NonSSEFolderRecord folder1{ + .mHash = 0xfedcba9876543210, + .mCount = 1, + .mOffset = 0, + .mName = "folder1", + .mFiles = { file }, + }; + + const NonSSEFolderRecord folder2{ + .mHash = 0xfedcba9876543210, + .mCount = 1, + .mOffset = 0, + .mName = "folder2", + .mFiles = { file }, + }; + + const Archive archive{ + .mHeader = header, + .mFolders = { folder1, folder2 }, + }; + + writeArchive(archive, stream); + } + + CompressedBSAFile file; + file.open(path); + + std::vector namesBuffer; + constexpr std::string_view filePath = "folder2\\filename"; + namesBuffer.assign(filePath.begin(), filePath.end()); + namesBuffer.push_back('\0'); + + EXPECT_THAT(file.getList(), + ElementsAre(BSAFile::FileStruct{ + .mFileSize = 42, + .mOffset = 0, + .mHash = BSAFile::Hash{ .mLow = 0, .mHigh = 0 }, + .mNameOffset = 0, + .mNameSize = 16, + .mNamesBuffer = &namesBuffer, + })); + } + + TEST(CompressedBSAFileTest, shouldHandleFilesWithDuplicateHash) + { + const std::filesystem::path path = makeOutputPath(); + + { + std::ofstream stream; + stream.exceptions(std::ifstream::failbit | std::ifstream::badbit); + + stream.open(path, std::ios::binary); + + const CompressedBSAFile::Header header{ + .mFormat = static_cast(BsaVersion::Compressed), + .mVersion = CompressedBSAFile::Version_TES4, + .mFoldersOffset = sizeof(CompressedBSAFile::Header), + .mFlags = CompressedBSAFile::ArchiveFlag_FolderNames | CompressedBSAFile::ArchiveFlag_FileNames, + .mFolderCount = 1, + .mFileCount = 2, + .mFolderNamesLength = 9, + .mFileNamesLength = 18, + .mFileFlags = 0, + }; + + const FileRecord file1{ + .mHash = 0xfedcba9876543210, + .mSize = 42, + .mOffset = 0, + .mName = "filename1", + }; + + const FileRecord file2{ + .mHash = 0xfedcba9876543210, + .mSize = 13, + .mOffset = 0, + .mName = "filename2", + }; + + const NonSSEFolderRecord folder{ + .mHash = 0xfedcba9876543210, + .mCount = 2, + .mOffset = 0, + .mName = "folder", + .mFiles = { file1, file2 }, + }; + + const Archive archive{ + .mHeader = header, + .mFolders = { folder }, + }; + + writeArchive(archive, stream); + } + + CompressedBSAFile file; + file.open(path); + + std::vector namesBuffer; + constexpr std::string_view filePath = "folder\\filename2"; + namesBuffer.assign(filePath.begin(), filePath.end()); + namesBuffer.push_back('\0'); + + EXPECT_THAT(file.getList(), + ElementsAre(BSAFile::FileStruct{ + .mFileSize = 13, + .mOffset = 0, + .mHash = BSAFile::Hash{ .mLow = 0, .mHigh = 0 }, + .mNameOffset = 0, + .mNameSize = 16, + .mNamesBuffer = &namesBuffer, + })); + } + } +} diff --git a/apps/components_tests/lua/testutilpackage.cpp b/apps/components_tests/lua/testutilpackage.cpp index 47041985f6f..11874a2ceaa 100644 --- a/apps/components_tests/lua/testutilpackage.cpp +++ b/apps/components_tests/lua/testutilpackage.cpp @@ -158,6 +158,13 @@ namespace EXPECT_EQ(get(lua, "darkRed:asHex()"), "a01112"); EXPECT_TRUE(get(lua, "green:asRgba() == util.vector4(0, 1, 0, 1)")); EXPECT_TRUE(get(lua, "red:asRgb() == util.vector3(1, 0, 0)")); + lua.safe_script("green = util.color.commaString('0,255,0')"); + EXPECT_EQ(get(lua, "tostring(green)"), "(0, 1, 0, 1)"); + lua.safe_script("red = util.color.commaString('255, 0, 0, 255')"); + EXPECT_EQ(get(lua, "tostring(red)"), "(1, 0, 0, 1)"); + lua.safe_script("blue = util.color.commaString('0, 0, 1000, 255')"); + EXPECT_EQ(get(lua, "tostring(blue)"), "(0, 0, 1, 1)"); + EXPECT_ERROR(lua.safe_script("white = util.color.commaString('aaa')"), "Invalid comma-separated color"); } TEST_F(LuaUtilPackageTest, Transform) diff --git a/apps/components_tests/resource/testresourcesystem.cpp b/apps/components_tests/resource/testresourcesystem.cpp new file mode 100644 index 00000000000..c863ba72e92 --- /dev/null +++ b/apps/components_tests/resource/testresourcesystem.cpp @@ -0,0 +1,32 @@ +#include +#include +#include +#include + +#include +#include + +#include + +namespace +{ + using namespace testing; + + TEST(ResourceResourceSystem, scenemanager_getinstance_should_be_thread_safe) + { + const VFS::Manager vfsManager; + const ToUTF8::Utf8Encoder encoder(ToUTF8::WINDOWS_1252); + Resource::ResourceSystem resourceSystem(&vfsManager, 1.0, &encoder.getStatelessEncoder()); + Resource::SceneManager* sceneManager = resourceSystem.getSceneManager(); + + constexpr VFS::Path::NormalizedView noSuchPath("meshes/whatever.nif"); + std::vector threads; + + for (int i = 0; i < 50; ++i) + { + threads.emplace_back([=]() { sceneManager->getInstance(noSuchPath); }); + } + for (std::thread& thread : threads) + thread.join(); + } +} diff --git a/apps/navmeshtool/main.cpp b/apps/navmeshtool/main.cpp index 6cfa7fc61da..a06433dd2d4 100644 --- a/apps/navmeshtool/main.cpp +++ b/apps/navmeshtool/main.cpp @@ -52,8 +52,8 @@ namespace NavMeshTool { - namespace - { +// namespace +// { namespace bpo = boost::program_options; using StringsVector = std::vector; @@ -255,9 +255,9 @@ namespace NavMeshTool return 0; } - } +// } } - +/* #ifdef ANDROID extern "C" int SDL_main(int argc, char* argv[]) #else @@ -266,3 +266,4 @@ int main(int argc, char* argv[]) { return Debug::wrapApplication(NavMeshTool::runNavMeshTool, argc, argv, NavMeshTool::applicationName); } +*/ diff --git a/apps/navmeshtool/navmesh.cpp b/apps/navmeshtool/navmesh.cpp index 6a4a708ef97..06936ef902c 100644 --- a/apps/navmeshtool/navmesh.cpp +++ b/apps/navmeshtool/navmesh.cpp @@ -53,6 +53,9 @@ namespace NavMeshTool Log(Debug::Info) << provided << "/" << expected << " (" << (static_cast(provided) / static_cast(expected) * 100) << "%) navmesh tiles are generated"; + + std::string message = std::to_string((static_cast(provided) / static_cast(expected) * 100)); + setenv("NAVMESHTOOL_MESSAGE", message.c_str(), true); } template diff --git a/apps/navmeshtool/navmesh.hpp b/apps/navmeshtool/navmesh.hpp index 4e607f4f2b0..cda1841f64b 100644 --- a/apps/navmeshtool/navmesh.hpp +++ b/apps/navmeshtool/navmesh.hpp @@ -24,6 +24,7 @@ namespace NavMeshTool Status generateAllNavMeshTiles(const DetourNavigator::AgentBounds& agentBounds, const DetourNavigator::Settings& settings, std::size_t threadsNumber, bool removeUnusedTiles, bool writeBinaryLog, WorldspaceData& cellsData, DetourNavigator::NavMeshDb&& db); + int runNavMeshTool(int argc, char *argv[]); } #endif diff --git a/apps/opencs/model/world/nestedtableproxymodel.cpp b/apps/opencs/model/world/nestedtableproxymodel.cpp index f542ce4defa..5278710e4a7 100644 --- a/apps/opencs/model/world/nestedtableproxymodel.cpp +++ b/apps/opencs/model/world/nestedtableproxymodel.cpp @@ -13,7 +13,9 @@ CSMWorld::NestedTableProxyModel::NestedTableProxyModel( { const int parentRow = parent.row(); - mId = std::string(parentModel->index(parentRow, 0).data().toString().toUtf8()); + const QByteArray utf8 = parentModel->index(parentRow, 0).data().toString().toUtf8(); + + mId = std::string(utf8.constData(), utf8.size()); QAbstractProxyModel::setSourceModel(parentModel); diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index 39b8ba321e1..ae815f207c2 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -362,8 +362,8 @@ void CSVWorld::CommandDelegate::setEditorData(QWidget* editor, const QModelIndex if (!n.isEmpty()) { if (!variant.isValid()) - variant = QVariant(editor->property(n).metaType(), (const void*)nullptr); - editor->setProperty(n, variant); + variant = QVariant(editor->property(n.constData()).metaType(), (const void*)nullptr); + editor->setProperty(n.constData(), variant); } } diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 9a5669c870e..ae3b43007ca 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -116,6 +116,10 @@ add_openmw_dir (mwbase inputmanager windowmanager statemanager luamanager ) +add_openmw_dir (. + ../navmeshtool/main ../navmeshtool/navmesh ../navmeshtool/worldspacedata + ) + # Main executable add_library(openmw-lib STATIC @@ -168,7 +172,7 @@ target_link_libraries(openmw-lib ${OPENAL_LIBRARY} ${FFmpeg_LIBRARIES} ${MyGUI_LIBRARIES} - SDL2::SDL2 + ${SDL2_LIBRARY} ${RecastNavigation_LIBRARIES} "osg-ffmpeg-videoplayer" "oics" diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 2ebfdeb8ae5..cdf761f806a 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -342,10 +342,10 @@ bool OMW::Engine::frame(unsigned frameNumber, float frametime) mViewer->eventTraversal(); mViewer->updateTraversal(); - // update GUI by world data + // update focus object for GUI { - ScopedProfile profile(frameStart, frameNumber, *timer, *stats); - mWorld->updateWindowManager(); + ScopedProfile profile(frameStart, frameNumber, *timer, *stats); + mWorld->updateFocusObject(); } // if there is a separate Lua thread, it starts the update now @@ -483,6 +483,10 @@ void OMW::Engine::setSkipMenu(bool skipMenu, bool newGame) mNewGame = newGame; } + +// To share the viewer with Android interfaces +osg::ref_ptr g_viewer; + void OMW::Engine::createWindow() { const int screen = Settings::video().mScreen; @@ -689,6 +693,9 @@ void OMW::Engine::createWindow() mViewer->getEventQueue()->getCurrentEventState()->setWindowRectangle( 0, 0, graphicsWindow->getTraits()->width, graphicsWindow->getTraits()->height); + + // To share the viewer with Android interfaces + g_viewer = mViewer; } void OMW::Engine::setWindowIcon() @@ -1071,6 +1078,8 @@ void OMW::Engine::go() mLuaWorker->join(); + g_viewer.release(); + // Save user settings Settings::Manager::saveUser(mCfgMgr.getUserConfigPath() / "settings.cfg"); Settings::ShaderManager::get().save(); diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 70e48e0cfc6..3b65442cd65 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -28,6 +28,9 @@ extern "C" __declspec(dllexport) DWORD AmdPowerXpressRequestHighPerformance = 0x #include #endif +// Android navmeshtool hack +#include "../navmeshtool/navmesh.hpp" + /** * \brief Parses application command line and calls \ref Cfg::ConfigurationManager * to parse configuration files. @@ -209,6 +212,8 @@ namespace }; } +Files::ConfigurationManager *g_cfgMgr; + int runApplication(int argc, char* argv[]) { Platform::init(); @@ -219,10 +224,22 @@ int runApplication(int argc, char* argv[]) osg::setNotifyHandler(new OSGLogHandler()); Files::ConfigurationManager cfgMgr; + g_cfgMgr = &cfgMgr; std::unique_ptr engine = std::make_unique(cfgMgr); engine->setRecastMaxLogLevel(Debug::getRecastMaxLogLevel()); + // Android navmeshtool hack + if ( getenv("OPENMW_GENERATE_NAVMESH_CACHE") ) + { + if(NavMeshTool::runNavMeshTool(argc, argv)) + Log(Debug::Error) << "runNavMeshTool failed"; + else + Log(Debug::Error) << "runNavMeshTool sucess"; + + return 0; + } + if (parseOptions(argc, argv, *engine, cfgMgr)) { if (!Misc::checkRequiredOSGPluginsArePresent()) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 3a7c84c3844..2e0e9a7b7d8 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -392,8 +392,12 @@ namespace MWBase /// Cycle to the next window to receive controller events virtual void cycleActiveControllerWindow(bool next) = 0; virtual void setActiveControllerWindow(MWGui::GuiMode mode, int activeIndex) = 0; - virtual bool getControllerTooltip() const = 0; - virtual void setControllerTooltip(bool enabled) = 0; + virtual bool getControllerTooltipVisible() const = 0; + virtual void setControllerTooltipVisible(bool visible) = 0; + virtual bool getControllerTooltipEnabled() const = 0; + virtual void setControllerTooltipEnabled(bool enabled) = 0; + /// Restore tooltip visibility if user has them enabled but they were hidden by mouse movement + virtual void restoreControllerTooltips() = 0; virtual void updateControllerButtonsOverlay() = 0; // Used in Lua bindings diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 983e2ef2289..e67e21c175c 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -257,10 +257,10 @@ namespace MWBase = 0; ///< @param changeEvent If false, do not trigger cell change flag or detect worldspace changes - virtual MWWorld::Ptr getFacedObject() = 0; + virtual MWWorld::Ptr getFocusObject() = 0; ///< Return pointer to the object the player is looking at, if it is within activation range - virtual float getDistanceToFacedObject() = 0; + virtual float getDistanceToFocusObject() = 0; virtual float getMaxActivationDistance() const = 0; diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 9fe7e92ffa0..d6df1bba5d4 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -124,7 +124,7 @@ namespace MWClass // make door glow if player activates it with telekinesis if (actor == MWMechanics::getPlayer() - && MWBase::Environment::get().getWorld()->getDistanceToFacedObject() + && MWBase::Environment::get().getWorld()->getDistanceToFocusObject() > MWBase::Environment::get().getWorld()->getMaxActivationDistance()) { MWRender::Animation* animation = MWBase::Environment::get().getWorld()->getAnimation(ptr); @@ -184,7 +184,7 @@ namespace MWClass if (ptr.getCellRef().getTeleport()) { if (actor == MWMechanics::getPlayer() - && MWBase::Environment::get().getWorld()->getDistanceToFacedObject() + && MWBase::Environment::get().getWorld()->getDistanceToFocusObject() > MWBase::Environment::get().getWorld()->getMaxActivationDistance()) { // player activated teleport door with telekinesis diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index 1c78b3dfef7..a8bf90ff03f 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -146,6 +146,7 @@ namespace MWClass { // Do not allow equip tools from inventory during attack if (MWBase::Environment::get().getMechanicsManager()->isAttackingOrSpell(npc) + && !MWBase::Environment::get().getMechanicsManager()->isCastingSpell(npc) && MWBase::Environment::get().getWindowManager()->isGuiMode()) return { 0, "#{sCantEquipWeapWarning}" }; diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index 110614bffd7..a46a2aefee3 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -144,6 +144,7 @@ namespace MWClass { // Do not allow equip tools from inventory during attack if (MWBase::Environment::get().getMechanicsManager()->isAttackingOrSpell(npc) + && !MWBase::Environment::get().getMechanicsManager()->isCastingSpell(npc) && MWBase::Environment::get().getWindowManager()->isGuiMode()) return { 0, "#{sCantEquipWeapWarning}" }; diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 863083ee942..197c3ff1b37 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -270,10 +270,25 @@ namespace MWClass std::pair Weapon::canBeEquipped(const MWWorld::ConstPtr& ptr, const MWWorld::Ptr& npc) const { + int type = ptr.get()->mBase->mData.mType; + // Do not allow equip weapons from inventory during attack if (npc.isInCell() && MWBase::Environment::get().getWindowManager()->isGuiMode() && MWBase::Environment::get().getMechanicsManager()->isAttackingOrSpell(npc)) - return { 0, "#{sCantEquipWeapWarning}" }; + { + int activeWeaponType = ESM::Weapon::None; + MWMechanics::getActiveWeapon(npc, &activeWeaponType); + if (activeWeaponType > ESM::Weapon::None || activeWeaponType == ESM::Weapon::HandToHand) + { + auto* activeWeapon = MWMechanics::getWeaponType(activeWeaponType); + bool isAmmo = MWMechanics::getWeaponType(type)->mWeaponClass == ESM::WeaponType::Class::Ammo; + bool activeWeapUsesAmmo = activeWeapon->mWeaponClass == ESM::WeaponType::Class::Ranged; + bool sameAmmoType = activeWeapon->mAmmoType == type; + // special case for ammo equipping + if ((activeWeapUsesAmmo && !sameAmmoType) || !isAmmo) + return { 0, "#{sCantEquipWeapWarning}" }; + } + } if (hasItemHealth(ptr) && getItemHealth(ptr) == 0) return { 0, "#{sInventoryMessage1}" }; @@ -283,7 +298,6 @@ namespace MWClass if (slots.first.empty()) return { 0, {} }; - int type = ptr.get()->mBase->mData.mType; if (MWMechanics::getWeaponType(type)->mFlags & ESM::WeaponType::TwoHanded) { return { 2, {} }; diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 56f18e9b0e4..e157f291e82 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -225,7 +225,7 @@ namespace MWGui if (!winMgr->isConsoleMode() && (mode != GM_Container) && (mode != GM_Inventory)) return; - MWWorld::Ptr object = MWBase::Environment::get().getWorld()->getFacedObject(); + MWWorld::Ptr object = MWBase::Environment::get().getWorld()->getFocusObject(); if (winMgr->isConsoleMode()) winMgr->setConsoleSelectedObject(object); diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 5fde06f75d7..726ff23996f 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -325,10 +325,10 @@ namespace MWGui // If we unequip weapon during attack, it can lead to unexpected behaviour if (MWBase::Environment::get().getMechanicsManager()->isAttackingOrSpell(mPtr)) { - bool isWeapon = item.mBase.getType() == ESM::Weapon::sRecordId; MWWorld::InventoryStore& invStore = mPtr.getClass().getInventoryStore(mPtr); - - if (isWeapon && invStore.isEquipped(item.mBase)) + MWWorld::ContainerStoreIterator weapIt = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); + bool weapActive = mPtr.getClass().getCreatureStats(mPtr).getDrawState() == MWMechanics::DrawState::Weapon; + if (weapActive && weapIt != invStore.end() && *weapIt == item.mBase) { MWBase::Environment::get().getWindowManager()->messageBox("#{sCantEquipWeapWarning}"); return; @@ -756,6 +756,8 @@ namespace MWGui void InventoryWindow::onFrame(float dt) { + updateEncumbranceBar(); + if (mUpdateNextFrame) { if (mTrading) @@ -766,7 +768,6 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->getTradeWindow()->updateOffer(); } - updateEncumbranceBar(); mDragAndDrop->update(); mItemView->update(); notifyContentChanged(); @@ -968,25 +969,25 @@ namespace MWGui mControllerButtons.mA = "#{OMWEngine:InventorySelect}"; mControllerButtons.mB = "#{Interface:Close}"; mControllerButtons.mX.clear(); - mControllerButtons.mR2 = "#{sCompanionShare}"; + mControllerButtons.mR2 = "#{Interface:Share}"; break; case MWGui::GM_Container: mControllerButtons.mA = "#{OMWEngine:InventorySelect}"; mControllerButtons.mB = "#{Interface:Close}"; mControllerButtons.mX = "#{Interface:TakeAll}"; - mControllerButtons.mR2 = "#{sContainer}"; + mControllerButtons.mR2 = "#{Interface:Container}"; break; case MWGui::GM_Barter: - mControllerButtons.mA = "#{sSell}"; + mControllerButtons.mA = "#{Interface:Sell}"; mControllerButtons.mB = "#{Interface:Cancel}"; - mControllerButtons.mX = "#{sOffer}"; - mControllerButtons.mR2 = "#{sBarter}"; + mControllerButtons.mX = "#{Interface:Offer}"; + mControllerButtons.mR2 = "#{Interface:Barter}"; break; case MWGui::GM_Inventory: default: - mControllerButtons.mA = "#{sEquip}"; + mControllerButtons.mA = "#{Interface:Equip}"; mControllerButtons.mB = "#{Interface:Back}"; - mControllerButtons.mX = "#{sDrop}"; + mControllerButtons.mX = "#{Interface:Drop}"; mControllerButtons.mR2.clear(); break; } diff --git a/apps/openmw/mwgui/itemview.cpp b/apps/openmw/mwgui/itemview.cpp index ba43082d429..8fdb0b387d5 100644 --- a/apps/openmw/mwgui/itemview.cpp +++ b/apps/openmw/mwgui/itemview.cpp @@ -82,7 +82,10 @@ namespace MWGui if (Settings::gui().mControllerMenus) { - mControllerFocus = std::clamp(mControllerFocus, 0, mItemCount - 1); + if (mItemCount > 0) + mControllerFocus = std::clamp(mControllerFocus, 0, mItemCount - 1); + else + mControllerFocus = -1; updateControllerFocus(-1, mControllerFocus); } @@ -190,7 +193,7 @@ namespace MWGui { mControllerActiveWindow = active; - MWBase::Environment::get().getWindowManager()->setControllerTooltip( + MWBase::Environment::get().getWindowManager()->setControllerTooltipVisible( active && Settings::gui().mControllerTooltips); if (active) @@ -205,6 +208,7 @@ namespace MWGui return; int prevFocus = mControllerFocus; + MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); switch (button) { @@ -218,27 +222,30 @@ namespace MWGui break; case SDL_CONTROLLER_BUTTON_RIGHTSTICK: // Toggle info tooltip - MWBase::Environment::get().getWindowManager()->setControllerTooltip( - !MWBase::Environment::get().getWindowManager()->getControllerTooltip()); + winMgr->setControllerTooltipEnabled(!winMgr->getControllerTooltipEnabled()); updateControllerFocus(-1, mControllerFocus); break; case SDL_CONTROLLER_BUTTON_DPAD_UP: + winMgr->restoreControllerTooltips(); if (mControllerFocus % mRows == 0) mControllerFocus = std::min(mControllerFocus + mRows - 1, mItemCount - 1); else mControllerFocus--; break; case SDL_CONTROLLER_BUTTON_DPAD_DOWN: + winMgr->restoreControllerTooltips(); if (mControllerFocus % mRows == mRows - 1 || mControllerFocus == mItemCount - 1) mControllerFocus -= mControllerFocus % mRows; else mControllerFocus++; break; case SDL_CONTROLLER_BUTTON_DPAD_LEFT: + winMgr->restoreControllerTooltips(); if (mControllerFocus >= mRows) mControllerFocus -= mRows; break; case SDL_CONTROLLER_BUTTON_DPAD_RIGHT: + winMgr->restoreControllerTooltips(); if (mControllerFocus + mRows < mItemCount) mControllerFocus += mRows; else if (mControllerFocus / mRows != (mItemCount - 1) / mRows) @@ -257,7 +264,7 @@ namespace MWGui void ItemView::updateControllerFocus(int prevFocus, int newFocus) { MWBase::Environment::get().getWindowManager()->setCursorVisible( - !MWBase::Environment::get().getWindowManager()->getControllerTooltip()); + !MWBase::Environment::get().getWindowManager()->getControllerTooltipVisible()); if (!mItemCount) return; @@ -285,7 +292,10 @@ namespace MWGui else mScrollView->setViewOffset(MyGUI::IntPoint(-42 * (column - 3), 0)); - if (MWBase::Environment::get().getWindowManager()->getControllerTooltip()) + MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); + winMgr->restoreControllerTooltips(); + + if (winMgr->getControllerTooltipVisible()) MWBase::Environment::get().getInputManager()->warpMouseToWidget(focused); } } diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 8d7cfac5869..c1fba27cfbf 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -226,7 +226,7 @@ namespace mControllerButtons.mA = "#{Interface:Select}"; mControllerButtons.mX = "#{OMWEngine:JournalQuests}"; - mControllerButtons.mY = "#{sTopics}"; + mControllerButtons.mY = "#{Interface:Topics}"; mQuestMode = false; mAllQuests = false; @@ -696,10 +696,23 @@ namespace MWGui::ControllerButtons* getControllerButtons() override { - mControllerButtons.mB = mOptionsMode || mStates.size() > 1 ? "#{sBack}" : "#{Interface:Close}"; - mControllerButtons.mL1 = mOptionsMode ? "" : "#{sPrev}"; - mControllerButtons.mR1 = mOptionsMode ? "" : "#{sNext}"; - mControllerButtons.mR3 = mOptionsMode && mQuestMode ? "#{OMWEngine:JournalShowAll}" : ""; + if (mOptionsMode || mStates.size() > 1) + mControllerButtons.mB = "#{Interface:Back}"; + else + mControllerButtons.mB = "#{Interface:Close}"; + + mControllerButtons.mL1.clear(); + mControllerButtons.mR1.clear(); + mControllerButtons.mR3.clear(); + if (!mOptionsMode) + { + mControllerButtons.mL1 = "#{Interface:Prev}"; + mControllerButtons.mR1 = "#{Interface:Next}"; + } + else if (mQuestMode) + { + mControllerButtons.mR3 = "#{OMWEngine:JournalShowAll}"; + } return &mControllerButtons; } diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index f80871d3ef3..c6dc54c8869 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -835,9 +835,10 @@ namespace MWGui if (Settings::gui().mControllerMenus) { mControllerButtons.mB = "#{Interface:Back}"; - mControllerButtons.mX = global ? "#{sLocal}" : "#{sWorld}"; - mControllerButtons.mY = "#{sCenter}"; - mControllerButtons.mDpad = Settings::map().mAllowZooming ? "" : "#{sMove}"; + mControllerButtons.mX = global ? "#{Interface:Local}" : "#{Interface:World}"; + mControllerButtons.mY = "#{Interface:Center}"; + if (!Settings::map().mAllowZooming) + mControllerButtons.mDpad = "#{Interface:Move}"; } } @@ -1228,7 +1229,7 @@ namespace MWGui mLocalMap->setVisible(!global); mButton->setCaptionWithReplacing(global ? "#{sLocal}" : "#{sWorld}"); - mControllerButtons.mX = global ? "#{sLocal}" : "#{sWorld}"; + mControllerButtons.mX = global ? "#{Interface:Local}" : "#{Interface:World}"; MWBase::Environment::get().getWindowManager()->updateControllerButtonsOverlay(); } @@ -1532,7 +1533,10 @@ namespace MWGui ControllerButtons* EditNoteDialog::getControllerButtons() { - mControllerButtons.mX = getDeleteButtonShown() ? "#{sDelete}" : ""; + if (getDeleteButtonShown()) + mControllerButtons.mX = "#{Interface:Delete}"; + else + mControllerButtons.mX.clear(); return &mControllerButtons; } diff --git a/apps/openmw/mwgui/merchantrepair.cpp b/apps/openmw/mwgui/merchantrepair.cpp index 5e0a889a0f4..20c17aa7011 100644 --- a/apps/openmw/mwgui/merchantrepair.cpp +++ b/apps/openmw/mwgui/merchantrepair.cpp @@ -32,7 +32,7 @@ namespace MWGui if (Settings::gui().mControllerMenus) { mDisableGamepadCursor = true; - mControllerButtons.mA = "#{sRepair}"; + mControllerButtons.mA = "#{Interface:Repair}"; mControllerButtons.mB = "#{Interface:Cancel}"; } } diff --git a/apps/openmw/mwgui/postprocessorhud.cpp b/apps/openmw/mwgui/postprocessorhud.cpp index 401770179d6..3141b2108ea 100644 --- a/apps/openmw/mwgui/postprocessorhud.cpp +++ b/apps/openmw/mwgui/postprocessorhud.cpp @@ -32,6 +32,9 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" + +#include + namespace MWGui { namespace diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index fe01a608941..ddcb843bf7b 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -111,9 +111,9 @@ namespace MWGui mControllerButtons.mLStick = "#{Interface:Mouse}"; mControllerButtons.mA = "#{Interface:Select}"; mControllerButtons.mB = "#{Interface:Back}"; - mControllerButtons.mY = "#{sSex}"; - mControllerButtons.mL1 = "#{sHair}"; - mControllerButtons.mR1 = "#{sFace}"; + mControllerButtons.mY = "#{Interface:Sex}"; + mControllerButtons.mL1 = "#{Interface:Hair}"; + mControllerButtons.mR1 = "#{Interface:Face}"; } updateRaces(); diff --git a/apps/openmw/mwgui/repair.cpp b/apps/openmw/mwgui/repair.cpp index 6064fcfd947..119376bbb27 100644 --- a/apps/openmw/mwgui/repair.cpp +++ b/apps/openmw/mwgui/repair.cpp @@ -40,7 +40,7 @@ namespace MWGui mToolIcon->eventMouseButtonClick += MyGUI::newDelegate(this, &Repair::onSelectItem); - mControllerButtons.mA = "#{sRepair}"; + mControllerButtons.mA = "#{Interface:Repair}"; mControllerButtons.mB = "#{Interface:Cancel}"; mControllerButtons.mY = "#{OMWEngine:RepairTool}"; } diff --git a/apps/openmw/mwgui/scrollwindow.cpp b/apps/openmw/mwgui/scrollwindow.cpp index de1ceaa5734..0113045c833 100644 --- a/apps/openmw/mwgui/scrollwindow.cpp +++ b/apps/openmw/mwgui/scrollwindow.cpp @@ -41,7 +41,7 @@ namespace MWGui mControllerScrollWidget = mTextView; mControllerButtons.mB = "#{Interface:Close}"; - mControllerButtons.mDpad = "#{sScrolldown}"; + mControllerButtons.mDpad = "#{Interface:ScrollDown}"; center(); } diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index d292c84a74d..7d649d37bef 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/inputmanager.hpp" @@ -141,6 +142,8 @@ namespace } } +extern Files::ConfigurationManager *g_cfgMgr; + namespace MWGui { void SettingsWindow::configureWidgets(MyGUI::Widget* widget, bool init) diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index 7ace1603503..a1e5fecd1eb 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -151,8 +151,8 @@ namespace MWGui mSpellButtons[0].first->setStateSelected(true); MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); - winMgr->setControllerTooltip(Settings::gui().mControllerTooltips); - if (winMgr->getControllerTooltip()) + winMgr->setControllerTooltipVisible(Settings::gui().mControllerTooltips); + if (winMgr->getControllerTooltipVisible()) MWBase::Environment::get().getInputManager()->warpMouseToWidget(mSpellButtons[0].first); } } @@ -230,6 +230,8 @@ namespace MWGui bool SpellBuyingWindow::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) { + MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); + if (arg.button == SDL_CONTROLLER_BUTTON_A) { if (mControllerFocus < mSpellButtons.size()) @@ -242,11 +244,12 @@ namespace MWGui else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSTICK) { // Toggle info tooltip - MWBase::Environment::get().getWindowManager()->setControllerTooltip( - !MWBase::Environment::get().getWindowManager()->getControllerTooltip()); + winMgr->setControllerTooltipEnabled(!winMgr->getControllerTooltipEnabled()); } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) { + winMgr->restoreControllerTooltips(); + if (mSpellButtons.size() <= 1) return true; @@ -256,6 +259,8 @@ namespace MWGui } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) { + winMgr->restoreControllerTooltips(); + if (mSpellButtons.size() <= 1) return true; @@ -279,7 +284,7 @@ namespace MWGui } // Warp the mouse to the selected spell to show the tooltip - if (MWBase::Environment::get().getWindowManager()->getControllerTooltip()) + if (MWBase::Environment::get().getWindowManager()->getControllerTooltipVisible()) MWBase::Environment::get().getInputManager()->warpMouseToWidget(mSpellButtons[mControllerFocus].first); } diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 6d27b4e4d2a..bd4728928bd 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -850,7 +850,7 @@ namespace MWGui if (mAvailableButtons.size() > 0) { mAvailableButtons[0]->setStateSelected(true); - if (MWBase::Environment::get().getWindowManager()->getControllerTooltip()) + if (MWBase::Environment::get().getWindowManager()->getControllerTooltipVisible()) MWBase::Environment::get().getInputManager()->warpMouseToWidget(mAvailableButtons[0]); } } @@ -1058,7 +1058,7 @@ namespace MWGui else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSTICK) { // Toggle info tooltip - winMgr->setControllerTooltip(!mRightColumn && !winMgr->getControllerTooltip()); + winMgr->setControllerTooltipEnabled(!winMgr->getControllerTooltipEnabled()); } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) { @@ -1102,7 +1102,7 @@ namespace MWGui if (mAvailableFocus >= 0 && mAvailableFocus < static_cast(mAvailableButtons.size())) mAvailableButtons[mAvailableFocus]->setStateSelected(true); - winMgr->setControllerTooltip(Settings::gui().mControllerTooltips); + winMgr->setControllerTooltipVisible(Settings::gui().mControllerTooltips); } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT && !mRightColumn && mEffectButtons.size() > 0) { @@ -1112,7 +1112,7 @@ namespace MWGui if (mEffectFocus >= 0 && mEffectFocus < static_cast(mEffectButtons.size())) mEffectButtons[mEffectFocus].first->setStateSelected(true); - winMgr->setControllerTooltip(false); + winMgr->setControllerTooltipVisible(false); } else return true; @@ -1129,7 +1129,7 @@ namespace MWGui if (!mRightColumn && mAvailableFocus >= 0 && mAvailableFocus < static_cast(mAvailableButtons.size())) { // Warp the mouse to the selected spell to show the tooltip - if (winMgr->getControllerTooltip()) + if (winMgr->getControllerTooltipVisible()) MWBase::Environment::get().getInputManager()->warpMouseToWidget(mAvailableButtons[mAvailableFocus]); } diff --git a/apps/openmw/mwgui/spellview.cpp b/apps/openmw/mwgui/spellview.cpp index ac923586dd6..8c64c92ce67 100644 --- a/apps/openmw/mwgui/spellview.cpp +++ b/apps/openmw/mwgui/spellview.cpp @@ -350,6 +350,7 @@ namespace MWGui return; int prevFocus = mControllerFocus; + MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); switch (button) { @@ -363,19 +364,22 @@ namespace MWGui break; case SDL_CONTROLLER_BUTTON_RIGHTSTICK: // Toggle info tooltip - MWBase::Environment::get().getWindowManager()->setControllerTooltip( - !MWBase::Environment::get().getWindowManager()->getControllerTooltip()); + winMgr->setControllerTooltipEnabled(!winMgr->getControllerTooltipEnabled()); break; case SDL_CONTROLLER_BUTTON_DPAD_UP: + winMgr->restoreControllerTooltips(); mControllerFocus--; break; case SDL_CONTROLLER_BUTTON_DPAD_DOWN: + winMgr->restoreControllerTooltips(); mControllerFocus++; break; case SDL_CONTROLLER_BUTTON_DPAD_LEFT: + winMgr->restoreControllerTooltips(); mControllerFocus = std::max(0, mControllerFocus - 10); break; case SDL_CONTROLLER_BUTTON_DPAD_RIGHT: + winMgr->restoreControllerTooltips(); mControllerFocus = std::min(mControllerFocus + 10, static_cast(mButtons.size()) - 1); break; case SDL_CONTROLLER_BUTTON_LEFTSHOULDER: @@ -451,7 +455,10 @@ namespace MWGui mScrollView->setViewOffset(MyGUI::IntPoint(0, -lineHeight * (line - 5))); } - if (MWBase::Environment::get().getWindowManager()->getControllerTooltip()) + MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); + winMgr->restoreControllerTooltips(); + + if (winMgr->getControllerTooltipVisible()) MWBase::Environment::get().getInputManager()->warpMouseToWidget(focused); } } diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index 3b088ae518b..01b4a94e934 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -328,7 +328,7 @@ namespace MWGui MyGUI::Window* window = mMainWidget->castType(); window->setCoord(x, active ? y : viewSize.height + 1, width, height); - MWBase::Environment::get().getWindowManager()->setControllerTooltip( + MWBase::Environment::get().getWindowManager()->setControllerTooltipVisible( active && Settings::gui().mControllerTooltips); } diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index 73b526a44bc..656adcb4b72 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -85,7 +85,7 @@ namespace MWGui { setPinButtonVisible(false); mControllerButtons.mLStick = "#{Interface:Mouse}"; - mControllerButtons.mRStick = "#{sScrolldown}"; + mControllerButtons.mRStick = "#{Interface:ScrollDown}"; mControllerButtons.mB = "#{Interface:Back}"; } diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 7fd048a778c..3abd2383448 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -95,7 +95,7 @@ namespace MWGui if (guiMode) { - if (!winMgr->getCursorVisible() && !winMgr->getControllerTooltip()) + if (!winMgr->getCursorVisible() && !winMgr->getControllerTooltipVisible()) return; const MyGUI::IntPoint& mousePos = MyGUI::InputManager::getInstance().getMousePosition(); diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index bc57cb2c087..d238db70c9e 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -190,7 +190,7 @@ namespace MWGui mControllerButtons.mA = "#{Interface:Buy}"; mControllerButtons.mB = "#{Interface:Cancel}"; - mControllerButtons.mX = "#{sOffer}"; + mControllerButtons.mX = "#{Interface:Offer}"; mControllerButtons.mR3 = "#{Interface:Info}"; mControllerButtons.mL2 = "#{Interface:Inventory}"; } diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index b5d9fd317bb..e83c327125e 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -41,7 +41,7 @@ namespace MWGui if (Settings::gui().mControllerMenus) { mDisableGamepadCursor = true; - mControllerButtons.mA = "#{sTravel}"; + mControllerButtons.mA = "#{Interface:Travel}"; mControllerButtons.mB = "#{Interface:Cancel}"; } } diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 7d5fb0503e5..8663ea10710 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -330,8 +330,17 @@ namespace MWGui ControllerButtons* WaitDialog::getControllerButtons() { - mControllerButtons.mA = mSleeping ? "#{sRest}" : "#{sWait}"; - mControllerButtons.mX = mSleeping && mUntilHealedButton->getVisible() ? "#{sUntilHealed}" : ""; + mControllerButtons.mX.clear(); + if (mSleeping) + { + mControllerButtons.mA = "#{Interface:Rest}"; + if (mUntilHealedButton->getVisible()) + mControllerButtons.mX = "#{Interface:UntilHealed}"; + } + else + { + mControllerButtons.mA = "#{Interface:Wait}"; + } return &mControllerButtons; } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 960933ed51e..15b5b20258f 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -519,6 +519,8 @@ namespace MWGui auto inventoryTabsOverlay = std::make_unique(); mInventoryTabsOverlay = inventoryTabsOverlay.get(); mWindows.push_back(std::move(inventoryTabsOverlay)); + + mControllerTooltipEnabled = Settings::gui().mControllerTooltips; mActiveControllerWindows[GM_Inventory] = 1; // Start on Inventory page mInputBlocker = MyGUI::Gui::getInstance().createWidget( @@ -1496,7 +1498,7 @@ namespace MWGui if (Settings::gui().mControllerMenus) { if (mGuiModes.empty()) - setControllerTooltip(false); + setControllerTooltipVisible(false); else reapplyActiveControllerWindow(); } @@ -2640,12 +2642,29 @@ namespace MWGui return height; } - void WindowManager::setControllerTooltip(bool enabled) + void WindowManager::setControllerTooltipVisible(bool visible) + { + if (!Settings::gui().mControllerMenus) + return; + + mControllerTooltipVisible = visible; + } + + void WindowManager::setControllerTooltipEnabled(bool enabled) { if (!Settings::gui().mControllerMenus) return; - mControllerTooltip = enabled; + mControllerTooltipEnabled = enabled; + // When user toggles the setting, also update visibility + mControllerTooltipVisible = enabled; + } + + void WindowManager::restoreControllerTooltips() + { + // Restore tooltip visibility if user has them enabled but they were hidden by mouse movement + if (mControllerTooltipEnabled && !mControllerTooltipVisible) + setControllerTooltipVisible(true); } void WindowManager::updateControllerButtonsOverlay() diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index a62432e6872..a9acaffcf08 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -395,8 +395,11 @@ namespace MWGui int getControllerMenuHeight() override; void cycleActiveControllerWindow(bool next) override; void setActiveControllerWindow(GuiMode mode, int activeIndex) override; - bool getControllerTooltip() const override { return mControllerTooltip; } - void setControllerTooltip(bool enabled) override; + bool getControllerTooltipVisible() const override { return mControllerTooltipVisible; } + void setControllerTooltipVisible(bool visible) override; + bool getControllerTooltipEnabled() const override { return mControllerTooltipEnabled; } + void setControllerTooltipEnabled(bool enabled) override; + void restoreControllerTooltips() override; void updateControllerButtonsOverlay() override; // Used in Lua bindings @@ -511,7 +514,10 @@ namespace MWGui std::vector mGuiModes; // The active window for controller mode for each GUI mode. std::map mActiveControllerWindows; - bool mControllerTooltip = false; + // Current tooltip visibility state (can be disabled by mouse movement) + bool mControllerTooltipVisible = false; + // User preference for tooltips (persists across mouse/controller switches) + bool mControllerTooltipEnabled = false; void reapplyActiveControllerWindow(); diff --git a/apps/openmw/mwinput/controllermanager.cpp b/apps/openmw/mwinput/controllermanager.cpp index c0a7dbbae05..c1f73ae7c94 100644 --- a/apps/openmw/mwinput/controllermanager.cpp +++ b/apps/openmw/mwinput/controllermanager.cpp @@ -215,6 +215,12 @@ namespace MWInput void ControllerManager::axisMoved(int deviceID, const SDL_ControllerAxisEvent& arg) { + if (mBindingsManager->isDetectingBindingState()) + { + mBindingsManager->controllerAxisMoved(deviceID, arg); + return; + } + if (!Settings::input().mEnableController || MWBase::Environment::get().getInputManager()->controlsDisabled()) return; @@ -259,7 +265,7 @@ namespace MWInput { // When the inventory tooltip is visible, we don't actually want the A button to // act like a mouse button; it should act normally. - if (treatAsMouse && arg.button == SDL_CONTROLLER_BUTTON_A && winMgr->getControllerTooltip()) + if (treatAsMouse && arg.button == SDL_CONTROLLER_BUTTON_A && winMgr->getControllerTooltipVisible()) treatAsMouse = false; mGamepadGuiCursorEnabled = topWin->isGamepadCursorAllowed(); @@ -368,9 +374,9 @@ namespace MWInput && (arg.axis == SDL_CONTROLLER_AXIS_LEFTX || arg.axis == SDL_CONTROLLER_AXIS_LEFTY)) { // Treat the left stick like a cursor, which is the default behavior. - if (winMgr->getControllerTooltip()) + if (winMgr->getControllerTooltipVisible()) { - winMgr->setControllerTooltip(false); + winMgr->setControllerTooltipVisible(false); winMgr->setCursorVisible(true); } else if (mGamepadGuiCursorEnabled) diff --git a/apps/openmw/mwinput/mousemanager.cpp b/apps/openmw/mwinput/mousemanager.cpp index b17b92e1180..ced69fbe790 100644 --- a/apps/openmw/mwinput/mousemanager.cpp +++ b/apps/openmw/mwinput/mousemanager.cpp @@ -32,6 +32,8 @@ namespace MWInput , mMouseWheel(0) , mMouseLookEnabled(false) , mGuiCursorEnabled(true) + , mLastWarpX(-1) + , mLastWarpY(-1) , mMouseMoveX(0) , mMouseMoveY(0) { @@ -72,13 +74,22 @@ namespace MWInput static_cast(mGuiCursorX), static_cast(mGuiCursorY), mMouseWheel); winMgr->setCursorActive(true); + + // Check if this movement is from our recent mouse warp + bool isFromWarp = (mLastWarpX >= 0 && mLastWarpY >= 0 && std::abs(mGuiCursorX - mLastWarpX) < 0.5f + && std::abs(mGuiCursorY - mLastWarpY) < 0.5f); + if (Settings::gui().mControllerMenus && !winMgr->getCursorVisible() - && (std::abs(arg.xrel) > 1 || std::abs(arg.yrel) > 1)) + && (std::abs(arg.xrel) > 1 || std::abs(arg.yrel) > 1) && !isFromWarp) { // Unhide the cursor if it was hidden to show a controller tooltip. - winMgr->setControllerTooltip(false); + winMgr->setControllerTooltipVisible(false); winMgr->setCursorVisible(true); } + + // Clear warp tracking after processing + mLastWarpX = -1; + mLastWarpY = -1; } if (mMouseLookEnabled && !input->controlsDisabled()) @@ -280,6 +291,9 @@ namespace MWInput { mGuiCursorX = widgetX; mGuiCursorY = widgetY; + // Remember where we warped to so we can ignore movement from this warp + mLastWarpX = widgetX; + mLastWarpY = widgetY; warpMouse(); } } diff --git a/apps/openmw/mwinput/mousemanager.hpp b/apps/openmw/mwinput/mousemanager.hpp index 0a9c4eccd7d..323703b56f3 100644 --- a/apps/openmw/mwinput/mousemanager.hpp +++ b/apps/openmw/mwinput/mousemanager.hpp @@ -49,6 +49,8 @@ namespace MWInput int mMouseWheel; bool mMouseLookEnabled; bool mGuiCursorEnabled; + float mLastWarpX; + float mLastWarpY; int mMouseMoveX; int mMouseMoveY; diff --git a/apps/openmw/mwlua/cellbindings.cpp b/apps/openmw/mwlua/cellbindings.cpp index 4e4542d89fd..1efcbb89e55 100644 --- a/apps/openmw/mwlua/cellbindings.cpp +++ b/apps/openmw/mwlua/cellbindings.cpp @@ -40,7 +40,10 @@ #include #include +#include + #include "../mwbase/environment.hpp" +#include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/worldmodel.hpp" @@ -85,12 +88,15 @@ namespace MWLua }; cellT["name"] = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->getNameId(); }); - cellT["id"] - = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->getId().serializeText(); }); - cellT["region"] = sol::readonly_property( - [](const CellT& c) -> std::string { return c.mStore->getCell()->getRegion().serializeText(); }); - cellT["worldSpaceId"] = sol::readonly_property( - [](const CellT& c) -> std::string { return c.mStore->getCell()->getWorldSpace().serializeText(); }); + cellT["displayName"] = sol::readonly_property([](const CellT& c) -> std::string_view { + const auto& storage = MWBase::Environment::get().getWindowManager()->getTranslationDataStorage(); + return storage.translateCellName(c.mStore->getCell()->getNameId()); + }); + cellT["id"] = sol::readonly_property([](const CellT& c) -> ESM::RefId { return c.mStore->getCell()->getId(); }); + cellT["region"] + = sol::readonly_property([](const CellT& c) -> ESM::RefId { return c.mStore->getCell()->getRegion(); }); + cellT["worldSpaceId"] + = sol::readonly_property([](const CellT& c) -> ESM::RefId { return c.mStore->getCell()->getWorldSpace(); }); cellT["gridX"] = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->getGridX(); }); cellT["gridY"] = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->getGridY(); }); cellT["hasWater"] = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->hasWater(); }); diff --git a/apps/openmw/mwlua/luamanagerimp.cpp b/apps/openmw/mwlua/luamanagerimp.cpp index 0b760ccdf01..7aef11caa42 100644 --- a/apps/openmw/mwlua/luamanagerimp.cpp +++ b/apps/openmw/mwlua/luamanagerimp.cpp @@ -42,6 +42,20 @@ namespace MWLua { + namespace + { + struct BoolScopeGuard + { + bool& mValue; + BoolScopeGuard(bool& value) + : mValue(value) + { + mValue = true; + } + + ~BoolScopeGuard() { mValue = false; } + }; + } static LuaUtil::LuaStateSettings createLuaStateSettings() { @@ -208,21 +222,23 @@ namespace MWLua // Run event handlers for events that were sent before `finalizeEventBatch`. mLuaEvents.callEventHandlers(); - // Run queued callbacks - for (CallbackWithData& c : mQueuedCallbacks) - c.mCallback.tryCall(c.mArg); - mQueuedCallbacks.clear(); + mLua.protectedCall([&](LuaUtil::LuaView& lua) { + // Run queued callbacks + for (CallbackWithData& c : mQueuedCallbacks) + c.mCallback.tryCall(c.mArg); + mQueuedCallbacks.clear(); - // Run engine handlers - mEngineEvents.callEngineHandlers(); - bool isPaused = timeManager.isPaused(); + // Run engine handlers + mEngineEvents.callEngineHandlers(); + bool isPaused = timeManager.isPaused(); - float frameDuration = MWBase::Environment::get().getFrameDuration(); - for (LocalScripts* scripts : mActiveLocalScripts) - scripts->update(isPaused ? 0 : frameDuration); - mGlobalScripts.update(isPaused ? 0 : frameDuration); + float frameDuration = MWBase::Environment::get().getFrameDuration(); + for (LocalScripts* scripts : mActiveLocalScripts) + scripts->update(isPaused ? 0 : frameDuration); + mGlobalScripts.update(isPaused ? 0 : frameDuration); - mLua.protectedCall([&](LuaUtil::LuaView& lua) { mScriptTracker.unloadInactiveScripts(lua); }); + mScriptTracker.unloadInactiveScripts(lua); + }); } void LuaManager::objectTeleported(const MWWorld::Ptr& ptr) @@ -264,31 +280,33 @@ namespace MWLua // can teleport the player to the starting location before the first frame is rendered. mGlobalScripts.newGameStarted(); } + BoolScopeGuard updateGuard(mRunningSynchronizedUpdates); - // We apply input events in `synchronizedUpdate` rather than in `update` in order to reduce input latency. - mProcessingInputEvents = true; + MWBase::WindowManager* windowManager = MWBase::Environment::get().getWindowManager(); PlayerScripts* playerScripts = mPlayer.isEmpty() ? nullptr : dynamic_cast(mPlayer.getRefData().getLuaScripts()); - MWBase::WindowManager* windowManager = MWBase::Environment::get().getWindowManager(); - - for (const auto& event : mMenuInputEvents) - mMenuScripts.processInputEvent(event); - mMenuInputEvents.clear(); - if (playerScripts && !windowManager->containsMode(MWGui::GM_MainMenu)) + // We apply input events in `synchronizedUpdate` rather than in `update` in order to reduce input latency. { - for (const auto& event : mInputEvents) - playerScripts->processInputEvent(event); + BoolScopeGuard processingGuard(mProcessingInputEvents); + + for (const auto& event : mMenuInputEvents) + mMenuScripts.processInputEvent(event); + mMenuInputEvents.clear(); + if (playerScripts && !windowManager->containsMode(MWGui::GM_MainMenu)) + { + for (const auto& event : mInputEvents) + playerScripts->processInputEvent(event); + } + mInputEvents.clear(); + mLuaEvents.callMenuEventHandlers(); + double frameDuration = MWBase::Environment::get().getWorld()->getTimeManager()->isPaused() + ? 0.0 + : MWBase::Environment::get().getFrameDuration(); + mInputActions.update(frameDuration); + mMenuScripts.onFrame(frameDuration); + if (playerScripts) + playerScripts->onFrame(frameDuration); } - mInputEvents.clear(); - mLuaEvents.callMenuEventHandlers(); - double frameDuration = MWBase::Environment::get().getWorld()->getTimeManager()->isPaused() - ? 0.0 - : MWBase::Environment::get().getFrameDuration(); - mInputActions.update(frameDuration); - mMenuScripts.onFrame(frameDuration); - if (playerScripts) - playerScripts->onFrame(frameDuration); - mProcessingInputEvents = false; for (const auto& [message, mode] : mUIMessages) windowManager->messageBox(message, mode); @@ -316,7 +334,7 @@ namespace MWLua void LuaManager::applyDelayedActions() { - mApplyingDelayedActions = true; + BoolScopeGuard applyingGuard(mApplyingDelayedActions); for (DelayedAction& action : mActionQueue) action.apply(); mActionQueue.clear(); @@ -324,7 +342,6 @@ namespace MWLua if (mTeleportPlayerAction) mTeleportPlayerAction->apply(); mTeleportPlayerAction.reset(); - mApplyingDelayedActions = false; } void LuaManager::clear() diff --git a/apps/openmw/mwlua/luamanagerimp.hpp b/apps/openmw/mwlua/luamanagerimp.hpp index 42b18d236ff..80c3163c80e 100644 --- a/apps/openmw/mwlua/luamanagerimp.hpp +++ b/apps/openmw/mwlua/luamanagerimp.hpp @@ -125,7 +125,7 @@ namespace MWLua // Some changes to the game world can not be done from the scripting thread (because it runs in parallel with // OSG Cull), so we need to queue it and apply from the main thread. - void addAction(std::function action, std::string_view name = ""); + void addAction(std::function action, std::string_view name = {}); void addTeleportPlayerAction(std::function action); // Saving @@ -174,6 +174,8 @@ namespace MWLua void sendLocalEvent( const MWWorld::Ptr& target, const std::string& name, const std::optional& data = std::nullopt); + bool isSynchronizedUpdateRunning() const { return mRunningSynchronizedUpdates; } + private: void initConfiguration(); LocalScripts* createLocalScripts(const MWWorld::Ptr& ptr, @@ -187,6 +189,7 @@ namespace MWLua bool mApplyingDelayedActions = false; bool mNewGameStarted = false; bool mReloadAllScriptsRequested = false; + bool mRunningSynchronizedUpdates = false; LuaUtil::ScriptsConfiguration mConfiguration; LuaUtil::LuaState mLua; LuaUi::ResourceManager mUiResourceManager; diff --git a/apps/openmw/mwlua/menuscripts.cpp b/apps/openmw/mwlua/menuscripts.cpp index 6387a3dce15..c9134201d30 100644 --- a/apps/openmw/mwlua/menuscripts.cpp +++ b/apps/openmw/mwlua/menuscripts.cpp @@ -8,6 +8,7 @@ #include "../mwstate/character.hpp" #include "context.hpp" +#include "luamanagerimp.hpp" namespace MWLua { @@ -72,7 +73,9 @@ namespace MWLua return sol::nullopt; }; - api["saveGame"] = [](std::string_view description, sol::optional slotName) { + api["saveGame"] = [context](std::string_view description, sol::optional slotName) { + if (!context.mLuaManager->isSynchronizedUpdateRunning()) + throw std::runtime_error("menu.saveGame can only be used during engine or event handler processing"); MWBase::StateManager* manager = MWBase::Environment::get().getStateManager(); const MWState::Character* character = manager->getCurrentCharacter(); const MWState::Slot* slot = nullptr; diff --git a/apps/openmw/mwlua/nearbybindings.cpp b/apps/openmw/mwlua/nearbybindings.cpp index b31a934a543..2436dd887e4 100644 --- a/apps/openmw/mwlua/nearbybindings.cpp +++ b/apps/openmw/mwlua/nearbybindings.cpp @@ -26,18 +26,27 @@ namespace { std::vector ignore; - if (const auto& ignoreObj = options.get>("ignore")) + if (const auto& ignoreObj = options.get>("ignore")) { - ignore.push_back(ignoreObj->ptr()); - } - else if (const auto& ignoreTable = options.get>("ignore")) - { - ignoreTable->for_each([&](const auto& _, const sol::object& value) { - if (value.is()) + if (ignoreObj->is()) + ignore.push_back(ignoreObj->as().ptr()); + else if (ignoreObj->is()) + { + for (const MWLua::ObjectId& id : *ignoreObj->as().mIds) { - ignore.push_back(value.as().ptr()); + ignore.push_back(MWLua::LObject(id).ptr()); } - }); + } + else + { + // ignoreObj->as throws if the type doesn't match, but an unchecked value.as crashes... + ignoreObj->as().for_each([&](sol::object _, sol::object value) { + if (value.is()) + ignore.push_back(value.as().ptr()); + else + throw std::runtime_error("Table value is not a GameObject"); + }); + } } return ignore; diff --git a/apps/openmw/mwlua/objectbindings.cpp b/apps/openmw/mwlua/objectbindings.cpp index 2a0aa87d15c..ace9722bbe4 100644 --- a/apps/openmw/mwlua/objectbindings.cpp +++ b/apps/openmw/mwlua/objectbindings.cpp @@ -330,10 +330,9 @@ namespace MWLua return LuaUtil::Box{ bb.center(), bb._max - bb.center() }; }; - objectT["type"] - = sol::readonly_property([types = getTypeToPackageTable(context.sol())](const ObjectT& o) mutable { - return types[getLiveCellRefType(o.ptr().mRef)]; - }); + objectT["type"] = sol::readonly_property( + [types = getTypeToPackageTable(context.sol())]( + const ObjectT& o) -> sol::object { return types[getLiveCellRefType(o.ptr().mRef)]; }); objectT["count"] = sol::readonly_property([](const ObjectT& o) { return o.ptr().getCellRef().getCount(); }); objectT[sol::meta_function::equal_to] = [](const ObjectT& a, const ObjectT& b) { return a.id() == b.id(); }; diff --git a/apps/openmw/mwlua/regionbindings.cpp b/apps/openmw/mwlua/regionbindings.cpp index 1f0e85a5e30..e9920a25cd5 100644 --- a/apps/openmw/mwlua/regionbindings.cpp +++ b/apps/openmw/mwlua/regionbindings.cpp @@ -46,7 +46,7 @@ namespace MWLua regionT["mapColor"] = sol::readonly_property( [](const ESM::Region& rec) -> Misc::Color { return Misc::Color::fromRGB(rec.mMapColor); }); regionT["sleepList"] - = sol::readonly_property([](const ESM::Region& rec) { return LuaUtil::serializeRefId(rec.mSleepList); }); + = sol::readonly_property([](const ESM::Region& rec) -> ESM::RefId { return rec.mSleepList; }); regionT["weatherProbabilities"] = sol::readonly_property([lua = lua.lua_state()](const ESM::Region& rec) { sol::table res(lua, sol::create); diff --git a/apps/openmw/mwlua/types/activator.cpp b/apps/openmw/mwlua/types/activator.cpp index a3662568994..1245dd70263 100644 --- a/apps/openmw/mwlua/types/activator.cpp +++ b/apps/openmw/mwlua/types/activator.cpp @@ -52,8 +52,7 @@ namespace MWLua = sol::readonly_property([](const ESM::Activator& rec) -> std::string { return rec.mId.serializeText(); }); record["name"] = sol::readonly_property([](const ESM::Activator& rec) -> std::string { return rec.mName; }); addModelProperty(record); - record["mwscript"] = sol::readonly_property([](const ESM::Activator& rec) -> sol::optional { - return LuaUtil::serializeRefId(rec.mScript); - }); + record["mwscript"] + = sol::readonly_property([](const ESM::Activator& rec) -> ESM::RefId { return rec.mScript; }); } } diff --git a/apps/openmw/mwlua/types/actor.cpp b/apps/openmw/mwlua/types/actor.cpp index 839f57e621c..33e88c4ea2a 100644 --- a/apps/openmw/mwlua/types/actor.cpp +++ b/apps/openmw/mwlua/types/actor.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include "apps/openmw/mwbase/environment.hpp" @@ -396,8 +397,8 @@ namespace MWLua const int actorsProcessingRange = Settings::game().mActorsProcessingRange; const osg::Vec3f playerPos = player.getRefData().getPosition().asVec3(); - const float dist = (playerPos - target.getRefData().getPosition().asVec3()).length(); - return dist <= actorsProcessingRange; + const float dist = (playerPos - target.getRefData().getPosition().asVec3()).length2(); + return dist <= (actorsProcessingRange * actorsProcessingRange); }; actor["isDead"] = [](const Object& o) { @@ -427,7 +428,7 @@ namespace MWLua { for (auto& [key, value] : damageLua.value()) { - damageCpp[key.as()] = value.as(); + damageCpp[key.as()] = value.as(); } } std::string sourceTypeStr = options.get_or("sourceType", "unspecified"); diff --git a/apps/openmw/mwlua/types/apparatus.cpp b/apps/openmw/mwlua/types/apparatus.cpp index c9953d87ad4..72dcbf4b307 100644 --- a/apps/openmw/mwlua/types/apparatus.cpp +++ b/apps/openmw/mwlua/types/apparatus.cpp @@ -42,9 +42,8 @@ namespace MWLua = sol::readonly_property([](const ESM::Apparatus& rec) -> std::string { return rec.mId.serializeText(); }); record["name"] = sol::readonly_property([](const ESM::Apparatus& rec) -> std::string { return rec.mName; }); addModelProperty(record); - record["mwscript"] = sol::readonly_property([](const ESM::Apparatus& rec) -> sol::optional { - return LuaUtil::serializeRefId(rec.mScript); - }); + record["mwscript"] + = sol::readonly_property([](const ESM::Apparatus& rec) -> ESM::RefId { return rec.mScript; }); record["icon"] = sol::readonly_property([vfs](const ESM::Apparatus& rec) -> std::string { return Misc::ResourceHelpers::correctIconPath(rec.mIcon, vfs); }); @@ -54,4 +53,4 @@ namespace MWLua record["quality"] = sol::readonly_property([](const ESM::Apparatus& rec) -> float { return rec.mData.mQuality; }); } -} +} \ No newline at end of file diff --git a/apps/openmw/mwlua/types/armor.cpp b/apps/openmw/mwlua/types/armor.cpp index 0acb517dbe6..8668d0cc134 100644 --- a/apps/openmw/mwlua/types/armor.cpp +++ b/apps/openmw/mwlua/types/armor.cpp @@ -102,10 +102,8 @@ namespace MWLua record["icon"] = sol::readonly_property([vfs](const ESM::Armor& rec) -> std::string { return Misc::ResourceHelpers::correctIconPath(rec.mIcon, vfs); }); - record["enchant"] = sol::readonly_property( - [](const ESM::Armor& rec) -> sol::optional { return LuaUtil::serializeRefId(rec.mEnchant); }); - record["mwscript"] = sol::readonly_property( - [](const ESM::Armor& rec) -> sol::optional { return LuaUtil::serializeRefId(rec.mScript); }); + record["enchant"] = sol::readonly_property([](const ESM::Armor& rec) -> ESM::RefId { return rec.mEnchant; }); + record["mwscript"] = sol::readonly_property([](const ESM::Armor& rec) -> ESM::RefId { return rec.mScript; }); record["weight"] = sol::readonly_property([](const ESM::Armor& rec) -> float { return rec.mData.mWeight; }); record["value"] = sol::readonly_property([](const ESM::Armor& rec) -> int { return rec.mData.mValue; }); record["type"] = sol::readonly_property([](const ESM::Armor& rec) -> int { return rec.mData.mType; }); diff --git a/apps/openmw/mwlua/types/book.cpp b/apps/openmw/mwlua/types/book.cpp index 006fbd80928..ebcc7a06fdf 100644 --- a/apps/openmw/mwlua/types/book.cpp +++ b/apps/openmw/mwlua/types/book.cpp @@ -106,21 +106,18 @@ namespace MWLua = sol::readonly_property([](const ESM::Book& rec) -> std::string { return rec.mId.serializeText(); }); record["name"] = sol::readonly_property([](const ESM::Book& rec) -> std::string { return rec.mName; }); addModelProperty(record); - record["mwscript"] = sol::readonly_property( - [](const ESM::Book& rec) -> sol::optional { return LuaUtil::serializeRefId(rec.mScript); }); + record["mwscript"] = sol::readonly_property([](const ESM::Book& rec) -> ESM::RefId { return rec.mScript; }); record["icon"] = sol::readonly_property([vfs](const ESM::Book& rec) -> std::string { return Misc::ResourceHelpers::correctIconPath(rec.mIcon, vfs); }); record["text"] = sol::readonly_property([](const ESM::Book& rec) -> std::string { return rec.mText; }); - record["enchant"] = sol::readonly_property( - [](const ESM::Book& rec) -> sol::optional { return LuaUtil::serializeRefId(rec.mEnchant); }); + record["enchant"] = sol::readonly_property([](const ESM::Book& rec) -> ESM::RefId { return rec.mEnchant; }); record["isScroll"] = sol::readonly_property([](const ESM::Book& rec) -> bool { return rec.mData.mIsScroll; }); record["value"] = sol::readonly_property([](const ESM::Book& rec) -> int { return rec.mData.mValue; }); record["weight"] = sol::readonly_property([](const ESM::Book& rec) -> float { return rec.mData.mWeight; }); record["enchantCapacity"] = sol::readonly_property([](const ESM::Book& rec) -> float { return rec.mData.mEnchant * 0.1f; }); - record["skill"] = sol::readonly_property([](const ESM::Book& rec) -> sol::optional { - return LuaUtil::serializeRefId(ESM::Skill::indexToRefId(rec.mData.mSkillId)); - }); + record["skill"] = sol::readonly_property( + [](const ESM::Book& rec) -> ESM::RefId { return ESM::Skill::indexToRefId(rec.mData.mSkillId); }); } -} +} \ No newline at end of file diff --git a/apps/openmw/mwlua/types/clothing.cpp b/apps/openmw/mwlua/types/clothing.cpp index 0085f05198c..40c22468254 100644 --- a/apps/openmw/mwlua/types/clothing.cpp +++ b/apps/openmw/mwlua/types/clothing.cpp @@ -97,12 +97,8 @@ namespace MWLua record["icon"] = sol::readonly_property([vfs](const ESM::Clothing& rec) -> std::string { return Misc::ResourceHelpers::correctIconPath(rec.mIcon, vfs); }); - record["enchant"] = sol::readonly_property([](const ESM::Clothing& rec) -> sol::optional { - return LuaUtil::serializeRefId(rec.mEnchant); - }); - record["mwscript"] = sol::readonly_property([](const ESM::Clothing& rec) -> sol::optional { - return LuaUtil::serializeRefId(rec.mScript); - }); + record["enchant"] = sol::readonly_property([](const ESM::Clothing& rec) -> ESM::RefId { return rec.mEnchant; }); + record["mwscript"] = sol::readonly_property([](const ESM::Clothing& rec) -> ESM::RefId { return rec.mScript; }); record["weight"] = sol::readonly_property([](const ESM::Clothing& rec) -> float { return rec.mData.mWeight; }); record["value"] = sol::readonly_property([](const ESM::Clothing& rec) -> int { return rec.mData.mValue; }); record["type"] = sol::readonly_property([](const ESM::Clothing& rec) -> int { return rec.mData.mType; }); diff --git a/apps/openmw/mwlua/types/container.cpp b/apps/openmw/mwlua/types/container.cpp index 9d3821ca48c..8e37ac275b3 100644 --- a/apps/openmw/mwlua/types/container.cpp +++ b/apps/openmw/mwlua/types/container.cpp @@ -52,9 +52,8 @@ namespace MWLua = sol::readonly_property([](const ESM::Container& rec) -> std::string { return rec.mId.serializeText(); }); record["name"] = sol::readonly_property([](const ESM::Container& rec) -> std::string { return rec.mName; }); addModelProperty(record); - record["mwscript"] = sol::readonly_property([](const ESM::Container& rec) -> sol::optional { - return LuaUtil::serializeRefId(rec.mScript); - }); + record["mwscript"] + = sol::readonly_property([](const ESM::Container& rec) -> ESM::RefId { return rec.mScript; }); record["weight"] = sol::readonly_property([](const ESM::Container& rec) -> float { return rec.mWeight; }); record["isOrganic"] = sol::readonly_property( [](const ESM::Container& rec) -> bool { return rec.mFlags & ESM::Container::Organic; }); diff --git a/apps/openmw/mwlua/types/creature.cpp b/apps/openmw/mwlua/types/creature.cpp index a9a1be9eee7..81dfd612e45 100644 --- a/apps/openmw/mwlua/types/creature.cpp +++ b/apps/openmw/mwlua/types/creature.cpp @@ -40,9 +40,7 @@ namespace MWLua = sol::readonly_property([](const ESM::Creature& rec) -> std::string { return rec.mId.serializeText(); }); record["name"] = sol::readonly_property([](const ESM::Creature& rec) -> std::string { return rec.mName; }); addModelProperty(record); - record["mwscript"] = sol::readonly_property([](const ESM::Creature& rec) -> sol::optional { - return LuaUtil::serializeRefId(rec.mScript); - }); + record["mwscript"] = sol::readonly_property([](const ESM::Creature& rec) -> ESM::RefId { return rec.mScript; }); record["baseCreature"] = sol::readonly_property( [](const ESM::Creature& rec) -> std::string { return rec.mOriginal.serializeText(); }); record["soulValue"] = sol::readonly_property([](const ESM::Creature& rec) -> int { return rec.mData.mSoul; }); @@ -78,4 +76,4 @@ namespace MWLua addActorServicesBindings(record, context); } -} +} \ No newline at end of file diff --git a/apps/openmw/mwlua/types/door.cpp b/apps/openmw/mwlua/types/door.cpp index 61dcc66a454..e1414fea37d 100644 --- a/apps/openmw/mwlua/types/door.cpp +++ b/apps/openmw/mwlua/types/door.cpp @@ -30,7 +30,6 @@ namespace sol namespace MWLua { - static const MWWorld::Ptr& doorPtr(const Object& o) { return verifyType(ESM::REC_DOOR, o.ptr()); @@ -110,8 +109,7 @@ namespace MWLua = sol::readonly_property([](const ESM::Door& rec) -> std::string { return rec.mId.serializeText(); }); record["name"] = sol::readonly_property([](const ESM::Door& rec) -> std::string { return rec.mName; }); addModelProperty(record); - record["mwscript"] = sol::readonly_property( - [](const ESM::Door& rec) -> sol::optional { return LuaUtil::serializeRefId(rec.mScript); }); + record["mwscript"] = sol::readonly_property([](const ESM::Door& rec) -> ESM::RefId { return rec.mScript; }); record["openSound"] = sol::readonly_property( [](const ESM::Door& rec) -> std::string { return rec.mOpenSound.serializeText(); }); record["closeSound"] = sol::readonly_property( @@ -154,4 +152,4 @@ namespace MWLua record["closeSound"] = sol::readonly_property( [](const ESM4::Door& rec) -> std::string { return ESM::RefId(rec.mCloseSound).serializeText(); }); } -} +} \ No newline at end of file diff --git a/apps/openmw/mwlua/types/ingredient.cpp b/apps/openmw/mwlua/types/ingredient.cpp index 8e52a82b190..ed017da9d19 100644 --- a/apps/openmw/mwlua/types/ingredient.cpp +++ b/apps/openmw/mwlua/types/ingredient.cpp @@ -34,9 +34,8 @@ namespace MWLua = sol::readonly_property([](const ESM::Ingredient& rec) -> std::string { return rec.mId.serializeText(); }); record["name"] = sol::readonly_property([](const ESM::Ingredient& rec) -> std::string { return rec.mName; }); addModelProperty(record); - record["mwscript"] = sol::readonly_property([](const ESM::Ingredient& rec) -> sol::optional { - return LuaUtil::serializeRefId(rec.mScript); - }); + record["mwscript"] + = sol::readonly_property([](const ESM::Ingredient& rec) -> ESM::RefId { return rec.mScript; }); record["icon"] = sol::readonly_property([vfs](const ESM::Ingredient& rec) -> std::string { return Misc::ResourceHelpers::correctIconPath(rec.mIcon, vfs); }); @@ -64,4 +63,4 @@ namespace MWLua return res; }); } -} +} \ No newline at end of file diff --git a/apps/openmw/mwlua/types/light.cpp b/apps/openmw/mwlua/types/light.cpp index 171db177a49..0a9befd9ebe 100644 --- a/apps/openmw/mwlua/types/light.cpp +++ b/apps/openmw/mwlua/types/light.cpp @@ -105,8 +105,7 @@ namespace MWLua }); record["sound"] = sol::readonly_property([](const ESM::Light& rec) -> std::string { return rec.mSound.serializeText(); }); - record["mwscript"] = sol::readonly_property( - [](const ESM::Light& rec) -> sol::optional { return LuaUtil::serializeRefId(rec.mScript); }); + record["mwscript"] = sol::readonly_property([](const ESM::Light& rec) -> ESM::RefId { return rec.mScript; }); record["weight"] = sol::readonly_property([](const ESM::Light& rec) -> float { return rec.mData.mWeight; }); record["value"] = sol::readonly_property([](const ESM::Light& rec) -> int { return rec.mData.mValue; }); record["duration"] = sol::readonly_property([](const ESM::Light& rec) -> int { return rec.mData.mTime; }); diff --git a/apps/openmw/mwlua/types/lockpick.cpp b/apps/openmw/mwlua/types/lockpick.cpp index 3f41c65df26..b8aab6c9822 100644 --- a/apps/openmw/mwlua/types/lockpick.cpp +++ b/apps/openmw/mwlua/types/lockpick.cpp @@ -33,9 +33,7 @@ namespace MWLua = sol::readonly_property([](const ESM::Lockpick& rec) -> std::string { return rec.mId.serializeText(); }); record["name"] = sol::readonly_property([](const ESM::Lockpick& rec) -> std::string { return rec.mName; }); addModelProperty(record); - record["mwscript"] = sol::readonly_property([](const ESM::Lockpick& rec) -> sol::optional { - return LuaUtil::serializeRefId(rec.mScript); - }); + record["mwscript"] = sol::readonly_property([](const ESM::Lockpick& rec) -> ESM::RefId { return rec.mScript; }); record["icon"] = sol::readonly_property([vfs](const ESM::Lockpick& rec) -> std::string { return Misc::ResourceHelpers::correctIconPath(rec.mIcon, vfs); }); @@ -46,4 +44,4 @@ namespace MWLua record["quality"] = sol::readonly_property([](const ESM::Lockpick& rec) -> float { return rec.mData.mQuality; }); } -} +} \ No newline at end of file diff --git a/apps/openmw/mwlua/types/misc.cpp b/apps/openmw/mwlua/types/misc.cpp index ef89464a2cd..c486b9c8ab8 100644 --- a/apps/openmw/mwlua/types/misc.cpp +++ b/apps/openmw/mwlua/types/misc.cpp @@ -71,10 +71,8 @@ namespace MWLua object.ptr().getCellRef().setSoul(creature); }; - miscellaneous["getSoul"] = [](const Object& object) -> sol::optional { - ESM::RefId soul = object.ptr().getCellRef().getSoul(); - return LuaUtil::serializeRefId(soul); - }; + miscellaneous["getSoul"] + = [](const Object& object) -> ESM::RefId { return object.ptr().getCellRef().getSoul(); }; miscellaneous["soul"] = miscellaneous["getSoul"]; // for compatibility; should be removed later sol::usertype record = context.sol().new_usertype("ESM3_Miscellaneous"); @@ -84,9 +82,8 @@ namespace MWLua [](const ESM::Miscellaneous& rec) -> std::string { return rec.mId.serializeText(); }); record["name"] = sol::readonly_property([](const ESM::Miscellaneous& rec) -> std::string { return rec.mName; }); addModelProperty(record); - record["mwscript"] = sol::readonly_property([](const ESM::Miscellaneous& rec) -> sol::optional { - return LuaUtil::serializeRefId(rec.mScript); - }); + record["mwscript"] + = sol::readonly_property([](const ESM::Miscellaneous& rec) -> ESM::RefId { return rec.mScript; }); record["icon"] = sol::readonly_property([vfs](const ESM::Miscellaneous& rec) -> std::string { return Misc::ResourceHelpers::correctIconPath(rec.mIcon, vfs); }); @@ -96,4 +93,4 @@ namespace MWLua record["weight"] = sol::readonly_property([](const ESM::Miscellaneous& rec) -> float { return rec.mData.mWeight; }); } -} +} \ No newline at end of file diff --git a/apps/openmw/mwlua/types/npc.cpp b/apps/openmw/mwlua/types/npc.cpp index 15022b79c79..b71ad28fc05 100644 --- a/apps/openmw/mwlua/types/npc.cpp +++ b/apps/openmw/mwlua/types/npc.cpp @@ -208,16 +208,15 @@ namespace MWLua = sol::readonly_property([](const ESM::NPC& rec) -> std::string { return rec.mRace.serializeText(); }); record["class"] = sol::readonly_property([](const ESM::NPC& rec) -> std::string { return rec.mClass.serializeText(); }); - record["mwscript"] = sol::readonly_property( - [](const ESM::NPC& rec) -> sol::optional { return LuaUtil::serializeRefId(rec.mScript); }); + record["mwscript"] = sol::readonly_property([](const ESM::NPC& rec) -> ESM::RefId { return rec.mScript; }); record["hair"] = sol::readonly_property([](const ESM::NPC& rec) -> std::string { return rec.mHair.serializeText(); }); record["baseDisposition"] = sol::readonly_property([](const ESM::NPC& rec) -> int { return (int)rec.mNpdt.mDisposition; }); record["head"] = sol::readonly_property([](const ESM::NPC& rec) -> std::string { return rec.mHead.serializeText(); }); - record["primaryFaction"] = sol::readonly_property( - [](const ESM::NPC& rec) -> sol::optional { return LuaUtil::serializeRefId(rec.mFaction); }); + record["primaryFaction"] + = sol::readonly_property([](const ESM::NPC& rec) -> ESM::RefId { return rec.mFaction; }); record["primaryFactionRank"] = sol::readonly_property([](const ESM::NPC& rec, sol::this_state s) -> int { if (rec.mFaction.empty()) return 0; diff --git a/apps/openmw/mwlua/types/potion.cpp b/apps/openmw/mwlua/types/potion.cpp index 4d04c8bb13b..435bce9c9ba 100644 --- a/apps/openmw/mwlua/types/potion.cpp +++ b/apps/openmw/mwlua/types/potion.cpp @@ -82,8 +82,7 @@ namespace MWLua record["icon"] = sol::readonly_property([vfs](const ESM::Potion& rec) -> std::string { return Misc::ResourceHelpers::correctIconPath(rec.mIcon, vfs); }); - record["mwscript"] = sol::readonly_property( - [](const ESM::Potion& rec) -> sol::optional { return LuaUtil::serializeRefId(rec.mScript); }); + record["mwscript"] = sol::readonly_property([](const ESM::Potion& rec) -> ESM::RefId { return rec.mScript; }); record["weight"] = sol::readonly_property([](const ESM::Potion& rec) -> float { return rec.mData.mWeight; }); record["value"] = sol::readonly_property([](const ESM::Potion& rec) -> int { return rec.mData.mValue; }); record["effects"] = sol::readonly_property([lua = lua.lua_state()](const ESM::Potion& rec) -> sol::table { @@ -93,4 +92,4 @@ namespace MWLua return res; }); } -} +} \ No newline at end of file diff --git a/apps/openmw/mwlua/types/probe.cpp b/apps/openmw/mwlua/types/probe.cpp index 4467f6617a7..d8f499acdc1 100644 --- a/apps/openmw/mwlua/types/probe.cpp +++ b/apps/openmw/mwlua/types/probe.cpp @@ -33,8 +33,7 @@ namespace MWLua = sol::readonly_property([](const ESM::Probe& rec) -> std::string { return rec.mId.serializeText(); }); record["name"] = sol::readonly_property([](const ESM::Probe& rec) -> std::string { return rec.mName; }); addModelProperty(record); - record["mwscript"] = sol::readonly_property( - [](const ESM::Probe& rec) -> sol::optional { return LuaUtil::serializeRefId(rec.mScript); }); + record["mwscript"] = sol::readonly_property([](const ESM::Probe& rec) -> ESM::RefId { return rec.mScript; }); record["icon"] = sol::readonly_property([vfs](const ESM::Probe& rec) -> std::string { return Misc::ResourceHelpers::correctIconPath(rec.mIcon, vfs); }); @@ -43,4 +42,4 @@ namespace MWLua record["weight"] = sol::readonly_property([](const ESM::Probe& rec) -> float { return rec.mData.mWeight; }); record["quality"] = sol::readonly_property([](const ESM::Probe& rec) -> float { return rec.mData.mQuality; }); } -} +} \ No newline at end of file diff --git a/apps/openmw/mwlua/types/repair.cpp b/apps/openmw/mwlua/types/repair.cpp index af95d187a8f..9ab62196636 100644 --- a/apps/openmw/mwlua/types/repair.cpp +++ b/apps/openmw/mwlua/types/repair.cpp @@ -33,8 +33,7 @@ namespace MWLua = sol::readonly_property([](const ESM::Repair& rec) -> std::string { return rec.mId.serializeText(); }); record["name"] = sol::readonly_property([](const ESM::Repair& rec) -> std::string { return rec.mName; }); addModelProperty(record); - record["mwscript"] = sol::readonly_property( - [](const ESM::Repair& rec) -> sol::optional { return LuaUtil::serializeRefId(rec.mScript); }); + record["mwscript"] = sol::readonly_property([](const ESM::Repair& rec) -> ESM::RefId { return rec.mScript; }); record["icon"] = sol::readonly_property([vfs](const ESM::Repair& rec) -> std::string { return Misc::ResourceHelpers::correctIconPath(rec.mIcon, vfs); }); @@ -43,4 +42,4 @@ namespace MWLua record["weight"] = sol::readonly_property([](const ESM::Repair& rec) -> float { return rec.mData.mWeight; }); record["quality"] = sol::readonly_property([](const ESM::Repair& rec) -> float { return rec.mData.mQuality; }); } -} +} \ No newline at end of file diff --git a/apps/openmw/mwlua/types/weapon.cpp b/apps/openmw/mwlua/types/weapon.cpp index 7fbfd5fb411..96477bc0bbd 100644 --- a/apps/openmw/mwlua/types/weapon.cpp +++ b/apps/openmw/mwlua/types/weapon.cpp @@ -135,10 +135,8 @@ namespace MWLua record["icon"] = sol::readonly_property([vfs](const ESM::Weapon& rec) -> std::string { return Misc::ResourceHelpers::correctIconPath(rec.mIcon, vfs); }); - record["enchant"] = sol::readonly_property( - [](const ESM::Weapon& rec) -> sol::optional { return LuaUtil::serializeRefId(rec.mEnchant); }); - record["mwscript"] = sol::readonly_property( - [](const ESM::Weapon& rec) -> sol::optional { return LuaUtil::serializeRefId(rec.mScript); }); + record["enchant"] = sol::readonly_property([](const ESM::Weapon& rec) -> ESM::RefId { return rec.mEnchant; }); + record["mwscript"] = sol::readonly_property([](const ESM::Weapon& rec) -> ESM::RefId { return rec.mScript; }); record["isMagical"] = sol::readonly_property( [](const ESM::Weapon& rec) -> bool { return rec.mData.mFlags & ESM::Weapon::Magical; }); record["isSilver"] = sol::readonly_property( diff --git a/apps/openmw/mwlua/uibindings.cpp b/apps/openmw/mwlua/uibindings.cpp index 7c708fefa99..05d3910f42b 100644 --- a/apps/openmw/mwlua/uibindings.cpp +++ b/apps/openmw/mwlua/uibindings.cpp @@ -22,21 +22,6 @@ namespace MWLua { namespace { - template - void wrapAction(const std::shared_ptr& element, Fn&& fn) - { - try - { - fn(); - } - catch (...) - { - // prevent any actions on a potentially corrupted widget - element->mRoot = nullptr; - throw; - } - } - const std::unordered_map modeToName{ { MWGui::GM_Inventory, "Interface" }, { MWGui::GM_Container, "Container" }, @@ -92,6 +77,7 @@ namespace MWLua luaManager->addAction([state] { MWBase::Environment::get().getWindowManager()->setHudVisibility(state); }); }; api["_isHudVisible"] = []() -> bool { return MWBase::Environment::get().getWindowManager()->isHudVisible(); }; + api["_getDefaultFontSize"] = []() -> int { return Settings::gui().mFontSize; }; api["showMessage"] = [luaManager = context.mLuaManager](std::string_view message, const sol::optional& options) { MWGui::ShowInDialogueMode mode = MWGui::ShowInDialogueMode_IfPossible; @@ -142,7 +128,7 @@ namespace MWLua api["create"] = [luaManager = context.mLuaManager, menu](const sol::table& layout) { auto element = LuaUi::Element::make(layout, menu); - luaManager->addAction([element] { wrapAction(element, [&] { element->create(); }); }, "Create UI"); + luaManager->addAction([element] { element->create(); }, "Create UI"); return element; }; @@ -327,14 +313,13 @@ namespace MWLua if (element->mState != LuaUi::Element::Created) return; element->mState = LuaUi::Element::Update; - luaManager->addAction([element] { wrapAction(element, [&] { element->update(); }); }, "Update UI"); + luaManager->addAction([element] { element->update(); }, "Update UI"); }; uiElement["destroy"] = [luaManager = context.mLuaManager](const std::shared_ptr& element) { if (element->mState == LuaUi::Element::Destroyed) return; element->mState = LuaUi::Element::Destroy; - luaManager->addAction( - [element] { wrapAction(element, [&] { LuaUi::Element::erase(element.get()); }); }, "Destroy UI"); + luaManager->addAction([element] { LuaUi::Element::erase(element.get()); }, "Destroy UI"); }; auto uiLayer = context.sol().new_usertype("UiLayer"); diff --git a/apps/openmw/mwlua/weatherbindings.cpp b/apps/openmw/mwlua/weatherbindings.cpp index 09c930d889d..e405d456c84 100644 --- a/apps/openmw/mwlua/weatherbindings.cpp +++ b/apps/openmw/mwlua/weatherbindings.cpp @@ -161,6 +161,8 @@ namespace MWLua weatherT["cloudsMaximumPercent"] = sol::property([](const MWWorld::Weather& w) { return w.mCloudsMaximumPercent; }, [](MWWorld::Weather& w, const FiniteFloat cloudsMaximumPercent) { + if (cloudsMaximumPercent <= 0.f) + throw std::runtime_error("Value must be greater than 0"); w.mCloudsMaximumPercent = cloudsMaximumPercent; }); weatherT["isStorm"] = sol::property([](const MWWorld::Weather& w) { return w.mIsStorm; }, @@ -172,7 +174,11 @@ namespace MWLua weatherT["rainSpeed"] = sol::property([](const MWWorld::Weather& w) { return w.mRainSpeed; }, [](MWWorld::Weather& w, const FiniteFloat rainSpeed) { w.mRainSpeed = rainSpeed; }); weatherT["rainEntranceSpeed"] = sol::property([](const MWWorld::Weather& w) { return w.mRainEntranceSpeed; }, - [](MWWorld::Weather& w, const FiniteFloat rainEntranceSpeed) { w.mRainEntranceSpeed = rainEntranceSpeed; }); + [](MWWorld::Weather& w, const FiniteFloat rainEntranceSpeed) { + if (rainEntranceSpeed <= 0.f) + throw std::runtime_error("Value must be greater than 0"); + w.mRainEntranceSpeed = rainEntranceSpeed; + }); weatherT["rainEffect"] = sol::property( [](const MWWorld::Weather& w) -> sol::optional { if (w.mRainEffect.empty()) @@ -193,7 +199,7 @@ namespace MWLua weatherT["rainMinHeight"] = sol::property([](const MWWorld::Weather& w) { return w.mRainMinHeight; }, [](MWWorld::Weather& w, const FiniteFloat rainMinHeight) { w.mRainMinHeight = rainMinHeight; }); weatherT["rainLoopSoundID"] - = sol::property([](const MWWorld::Weather& w) { return LuaUtil::serializeRefId(w.mRainLoopSoundID); }, + = sol::property([](const MWWorld::Weather& w) -> ESM::RefId { return w.mRainLoopSoundID; }, [](MWWorld::Weather& w, sol::optional rainLoopSoundID) { w.mRainLoopSoundID = ESM::RefId::deserializeText(rainLoopSoundID.value_or("")); }); @@ -203,7 +209,7 @@ namespace MWLua w.mSunDiscSunsetColor = sunDiscSunsetColor.toVec(); }); weatherT["ambientLoopSoundID"] - = sol::property([](const MWWorld::Weather& w) { return LuaUtil::serializeRefId(w.mAmbientLoopSoundID); }, + = sol::property([](const MWWorld::Weather& w) -> ESM::RefId { return w.mAmbientLoopSoundID; }, [](MWWorld::Weather& w, sol::optional ambientLoopSoundId) { w.mAmbientLoopSoundID = ESM::RefId::deserializeText(ambientLoopSoundId.value_or("")); }); diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index bd84776c00f..86cfd96e0be 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1072,23 +1072,17 @@ namespace MWMechanics std::string_view action = evt.substr(groupname.size() + 2); if (action == "equip attach") { - if (mUpperBodyState == UpperBodyState::Equipping) - { - if (groupname == "shield") - mAnimation->showCarriedLeft(true); - else - mAnimation->showWeapons(true); - } + if (groupname == "shield") + mAnimation->showCarriedLeft(true); + else if (mUpperBodyState == UpperBodyState::Equipping) + mAnimation->showWeapons(true); } else if (action == "unequip detach") { - if (mUpperBodyState == UpperBodyState::Unequipping) - { - if (groupname == "shield") - mAnimation->showCarriedLeft(false); - else - mAnimation->showWeapons(false); - } + if (groupname == "shield") + mAnimation->showCarriedLeft(false); + else if (mUpperBodyState == UpperBodyState::Unequipping) + mAnimation->showWeapons(false); } else if (action == "chop hit" || action == "slash hit" || action == "thrust hit" || action == "hit") { @@ -1392,7 +1386,7 @@ namespace MWMechanics // We can not play un-equip animation if weapon changed since last update if (!weaponChanged) { - // Note: we do not disable unequipping animation automatically to avoid body desync + // Note: we do not disable the weapon unequipping animation automatically to avoid body desync weapgroup = getWeaponAnimation(mWeaponType); int unequipMask = MWRender::BlendMask_All; mUpperBodyState = UpperBodyState::Unequipping; @@ -1401,6 +1395,7 @@ namespace MWMechanics && !(mWeaponType == ESM::Weapon::None && weaptype == ESM::Weapon::Spell)) { unequipMask = unequipMask | ~MWRender::BlendMask_LeftArm; + mAnimation->disable("shield"); playBlendedAnimation("shield", Priority_Block, MWRender::BlendMask_LeftArm, true, 1.0f, "unequip start", "unequip stop", 0.0f, 0); } @@ -1458,6 +1453,7 @@ namespace MWMechanics if (useShieldAnims && weaptype != ESM::Weapon::Spell) { equipMask = equipMask | ~MWRender::BlendMask_LeftArm; + mAnimation->disable("shield"); playBlendedAnimation("shield", Priority_Block, MWRender::BlendMask_LeftArm, true, 1.0f, "equip start", "equip stop", 0.0f, 0); } @@ -1745,7 +1741,7 @@ namespace MWMechanics { // TODO: this will only work for the player, and needs to be fixed if NPCs should ever use // lockpicks/probes. - MWWorld::Ptr target = world->getFacedObject(); + MWWorld::Ptr target = world->getFocusObject(); if (!target.isEmpty()) { diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index 7c0c6749868..cd25a4f4ea9 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -1,6 +1,8 @@ #include "combat.hpp" +#include + #include #include @@ -504,15 +506,19 @@ namespace MWMechanics } MWBase::SoundManager* sndMgr = MWBase::Environment::get().getSoundManager(); + auto& prng = MWBase::Environment::get().getWorld()->getPrng(); if (isWerewolf) { - auto& prng = MWBase::Environment::get().getWorld()->getPrng(); const ESM::Sound* sound = store.get().searchRandom("WolfHit", prng); if (sound) sndMgr->playSound3D(victim, sound->mId, 1.0f, 1.0f); } else if (!healthdmg) - sndMgr->playSound3D(victim, ESM::RefId::stringRefId("Hand To Hand Hit"), 1.0f, 1.0f); + { + static const std::array sounds + = { ESM::RefId::stringRefId("Hand To Hand Hit"), ESM::RefId::stringRefId("Hand To Hand Hit 2") }; + sndMgr->playSound3D(victim, sounds[Misc::Rng::rollDice(sounds.size(), prng)], 1.0f, 1.0f); + } } void applyFatigueLoss(const MWWorld::Ptr& attacker, const MWWorld::Ptr& weapon, float attackStrength) diff --git a/apps/openmw/mwmechanics/disease.hpp b/apps/openmw/mwmechanics/disease.hpp index 262f8139168..4e36e47ca02 100644 --- a/apps/openmw/mwmechanics/disease.hpp +++ b/apps/openmw/mwmechanics/disease.hpp @@ -21,11 +21,11 @@ namespace MWMechanics { /// Call when \a actor has got in contact with \a carrier (e.g. hit by him, or loots him) - /// @param actor The actor that will potentially catch diseases. Currently only the player can catch diseases. + /// @param actor The actor that will potentially catch diseases. Actors cannot catch diseases from the player. /// @param carrier The disease carrier. inline void diseaseContact(const MWWorld::Ptr& actor, const MWWorld::Ptr& carrier) { - if (!carrier.getClass().isActor() || actor != getPlayer()) + if (!carrier.getClass().isActor() || carrier == getPlayer()) return; float fDiseaseXferChance = MWBase::Environment::get() @@ -71,13 +71,16 @@ namespace MWMechanics creatureStats.getActiveSpells().addSpell(spell, actor, false); MWBase::Environment::get().getWorld()->applyLoopingParticles(actor); - std::string msg = MWBase::Environment::get() - .getESMStore() - ->get() - .find("sMagicContractDisease") - ->mValue.getString(); - msg = Misc::StringUtils::format(msg, spell->mName); - MWBase::Environment::get().getWindowManager()->messageBox(msg); + if (actor == getPlayer()) + { + std::string msg = MWBase::Environment::get() + .getESMStore() + ->get() + .find("sMagicContractDisease") + ->mValue.getString(); + msg = Misc::StringUtils::format(msg, spell->mName); + MWBase::Environment::get().getWindowManager()->messageBox(msg); + } } } } diff --git a/apps/openmw/mwmechanics/spelleffects.cpp b/apps/openmw/mwmechanics/spelleffects.cpp index c2a7924c77e..6c8bc292ec7 100644 --- a/apps/openmw/mwmechanics/spelleffects.cpp +++ b/apps/openmw/mwmechanics/spelleffects.cpp @@ -44,18 +44,16 @@ namespace return effect.mMinMagnitude + Misc::Rng::rollDice(effect.mMaxMagnitude - effect.mMinMagnitude + 1, prng); } - void modifyAiSetting(const MWWorld::Ptr& target, const ESM::ActiveEffect& effect, - ESM::MagicEffect::Effects creatureEffect, MWMechanics::AiSetting setting, float magnitude, bool& invalid) + ESM::ActiveEffect::Flags modifyAiSetting(const MWWorld::Ptr& target, const ESM::ActiveEffect& effect, + ESM::MagicEffect::Effects creatureEffect, MWMechanics::AiSetting setting, float magnitude) { if (target == MWMechanics::getPlayer() || (effect.mEffectId == creatureEffect) == target.getClass().isNpc()) - invalid = true; - else - { - auto& creatureStats = target.getClass().getCreatureStats(target); - auto stat = creatureStats.getAiSetting(setting); - stat.setModifier(static_cast(stat.getModifier() + magnitude)); - creatureStats.setAiSetting(setting, stat); - } + return ESM::ActiveEffect::Flag_Invalid; + auto& creatureStats = target.getClass().getCreatureStats(target); + auto stat = creatureStats.getAiSetting(setting); + stat.setModifier(static_cast(stat.getModifier() + magnitude)); + creatureStats.setAiSetting(setting, stat); + return ESM::ActiveEffect::Flag_Applied; } void adjustDynamicStat(const MWWorld::Ptr& target, int index, float magnitude, bool allowDecreaseBelowZero = false, @@ -420,12 +418,12 @@ namespace namespace MWMechanics { - void applyMagicEffect(const MWWorld::Ptr& target, const MWWorld::Ptr& caster, - const ActiveSpells::ActiveSpellParams& spellParams, ESM::ActiveEffect& effect, bool& invalid, - bool& receivedMagicDamage, bool& affectedHealth, bool& recalculateMagicka) + ESM::ActiveEffect::Flags applyMagicEffect(const MWWorld::Ptr& target, const MWWorld::Ptr& caster, + const ActiveSpells::ActiveSpellParams& spellParams, ESM::ActiveEffect& effect, bool& receivedMagicDamage, + bool& affectedHealth, bool& recalculateMagicka) { const auto world = MWBase::Environment::get().getWorld(); - bool godmode = target == getPlayer() && world->getGodModeState(); + const bool godmode = target == getPlayer() && world->getGodModeState(); switch (effect.mEffectId) { case ESM::MagicEffect::CureCommonDisease: @@ -469,7 +467,7 @@ namespace MWMechanics case ESM::MagicEffect::AlmsiviIntervention: case ESM::MagicEffect::DivineIntervention: if (target != getPlayer()) - invalid = true; + return ESM::ActiveEffect::Flag_Invalid; else if (world->isTeleportingEnabled()) { std::string_view marker @@ -494,7 +492,7 @@ namespace MWMechanics break; case ESM::MagicEffect::Mark: if (target != getPlayer()) - invalid = true; + return ESM::ActiveEffect::Flag_Invalid; else if (world->isTeleportingEnabled()) world->getPlayer().markPosition(target.getCell(), target.getRefData().getPosition()); else if (caster == getPlayer()) @@ -502,7 +500,7 @@ namespace MWMechanics break; case ESM::MagicEffect::Recall: if (target != getPlayer()) - invalid = true; + return ESM::ActiveEffect::Flag_Invalid; else if (world->isTeleportingEnabled()) { MWWorld::CellStore* markedCell = nullptr; @@ -528,7 +526,7 @@ namespace MWMechanics case ESM::MagicEffect::CommandHumanoid: if (caster.isEmpty() || !caster.getClass().isActor() || target == getPlayer() || (effect.mEffectId == ESM::MagicEffect::CommandCreature) == target.getClass().isNpc()) - invalid = true; + return ESM::ActiveEffect::Flag_Invalid; else if (effect.mMagnitude >= target.getClass().getCreatureStats(target).getLevel()) { MWMechanics::AiFollow package(caster, true); @@ -536,41 +534,37 @@ namespace MWMechanics } break; case ESM::MagicEffect::ExtraSpell: - if (target.getClass().hasInventoryStore(target)) + if (!target.getClass().hasInventoryStore(target)) + return ESM::ActiveEffect::Flag_Invalid; + if (target != getPlayer()) { - if (target != getPlayer()) + auto& store = target.getClass().getInventoryStore(target); + for (int slot = 0; slot < MWWorld::InventoryStore::Slots; ++slot) { - auto& store = target.getClass().getInventoryStore(target); - for (int slot = 0; slot < MWWorld::InventoryStore::Slots; ++slot) + // Unequip everything except weapons, torches, and pants + switch (slot) { - // Unequip everything except weapons, torches, and pants - switch (slot) + case MWWorld::InventoryStore::Slot_Ammunition: + case MWWorld::InventoryStore::Slot_CarriedRight: + case MWWorld::InventoryStore::Slot_Pants: + continue; + case MWWorld::InventoryStore::Slot_CarriedLeft: { - case MWWorld::InventoryStore::Slot_Ammunition: - case MWWorld::InventoryStore::Slot_CarriedRight: - case MWWorld::InventoryStore::Slot_Pants: + auto carried = store.getSlot(slot); + if (carried == store.end() || carried.getType() != MWWorld::ContainerStore::Type_Armor) continue; - case MWWorld::InventoryStore::Slot_CarriedLeft: - { - auto carried = store.getSlot(slot); - if (carried == store.end() - || carried.getType() != MWWorld::ContainerStore::Type_Armor) - continue; - [[fallthrough]]; - } - default: - store.unequipSlot(slot); + [[fallthrough]]; } + default: + store.unequipSlot(slot); } } } - else - invalid = true; break; case ESM::MagicEffect::TurnUndead: if (target.getClass().isNpc() || target.get()->mBase->mData.mType != ESM::Creature::Undead) - invalid = true; + return ESM::ActiveEffect::Flag_Invalid; else { auto& creatureStats = target.getClass().getCreatureStats(target); @@ -581,32 +575,33 @@ namespace MWMechanics break; case ESM::MagicEffect::FrenzyCreature: case ESM::MagicEffect::FrenzyHumanoid: - modifyAiSetting( - target, effect, ESM::MagicEffect::FrenzyCreature, AiSetting::Fight, effect.mMagnitude, invalid); - break; + return modifyAiSetting( + target, effect, ESM::MagicEffect::FrenzyCreature, AiSetting::Fight, effect.mMagnitude); case ESM::MagicEffect::CalmCreature: case ESM::MagicEffect::CalmHumanoid: - modifyAiSetting( - target, effect, ESM::MagicEffect::CalmCreature, AiSetting::Fight, -effect.mMagnitude, invalid); - if (!invalid && effect.mMagnitude > 0) + { + ESM::ActiveEffect::Flags applied = modifyAiSetting( + target, effect, ESM::MagicEffect::CalmCreature, AiSetting::Fight, -effect.mMagnitude); + if (applied != ESM::ActiveEffect::Flag_Applied) + return applied; + if (effect.mMagnitude > 0) { auto& creatureStats = target.getClass().getCreatureStats(target); creatureStats.getAiSequence().stopCombat(); } break; + } case ESM::MagicEffect::DemoralizeCreature: case ESM::MagicEffect::DemoralizeHumanoid: - modifyAiSetting( - target, effect, ESM::MagicEffect::DemoralizeCreature, AiSetting::Flee, effect.mMagnitude, invalid); - break; + return modifyAiSetting( + target, effect, ESM::MagicEffect::DemoralizeCreature, AiSetting::Flee, effect.mMagnitude); case ESM::MagicEffect::RallyCreature: case ESM::MagicEffect::RallyHumanoid: - modifyAiSetting( - target, effect, ESM::MagicEffect::RallyCreature, AiSetting::Flee, -effect.mMagnitude, invalid); - break; + return modifyAiSetting( + target, effect, ESM::MagicEffect::RallyCreature, AiSetting::Flee, -effect.mMagnitude); case ESM::MagicEffect::Charm: if (!target.getClass().isNpc()) - invalid = true; + return ESM::ActiveEffect::Flag_Invalid; break; case ESM::MagicEffect::Sound: if (target == getPlayer()) @@ -643,16 +638,12 @@ namespace MWMechanics case ESM::MagicEffect::SummonCreature04: case ESM::MagicEffect::SummonCreature05: if (!target.isInCell()) - invalid = true; - else - effect.mArg = summonCreature(effect.mEffectId, target); + return ESM::ActiveEffect::Flag_Invalid; + effect.mArg = summonCreature(effect.mEffectId, target); break; case ESM::MagicEffect::BoundGloves: if (!target.getClass().hasInventoryStore(target)) - { - invalid = true; - break; - } + return ESM::ActiveEffect::Flag_Invalid; addBoundItem(ESM::RefId::stringRefId(world->getStore() .get() .find("sMagicBoundRightGauntletID") @@ -672,10 +663,7 @@ namespace MWMechanics case ESM::MagicEffect::BoundShield: { if (!target.getClass().hasInventoryStore(target)) - { - invalid = true; - break; - } + return ESM::ActiveEffect::Flag_Invalid; const std::string& item = sBoundItemsMap.at(effect.mEffectId); const MWWorld::Store& gmst = world->getStore().get(); const ESM::RefId itemId = ESM::RefId::stringRefId(gmst.find(item)->mValue.getString()); @@ -714,9 +702,7 @@ namespace MWMechanics damageAttribute(target, effect, effect.mMagnitude); break; case ESM::MagicEffect::DamageSkill: - if (!target.getClass().isNpc()) - invalid = true; - else if (!godmode) + if (!godmode && target.getClass().isNpc()) { // Damage Skill abilities reduce base skill :todd: if (spellParams.hasFlag(ESM::ActiveSpells::Flag_AffectsBaseValues)) @@ -734,9 +720,7 @@ namespace MWMechanics restoreAttribute(target, effect, effect.mMagnitude); break; case ESM::MagicEffect::RestoreSkill: - if (!target.getClass().isNpc()) - invalid = true; - else + if (target.getClass().isNpc()) restoreSkill(target, effect, effect.mMagnitude); break; case ESM::MagicEffect::RestoreHealth: @@ -766,7 +750,9 @@ namespace MWMechanics case ESM::MagicEffect::DrainHealth: case ESM::MagicEffect::DrainMagicka: case ESM::MagicEffect::DrainFatigue: - if (!godmode) + if (godmode) + return ESM::ActiveEffect::Flag_Remove; + else { int index = effect.mEffectId - ESM::MagicEffect::DrainHealth; // Unlike Absorb and Damage effects Drain effects can bring stats below zero @@ -785,8 +771,9 @@ namespace MWMechanics target, effect.mEffectId - ESM::MagicEffect::FortifyHealth, effect.mMagnitude, false, true); break; case ESM::MagicEffect::DrainAttribute: - if (!godmode) - damageAttribute(target, effect, effect.mMagnitude); + if (godmode) + return ESM::ActiveEffect::Flag_Remove; + damageAttribute(target, effect, effect.mMagnitude); break; case ESM::MagicEffect::FortifyAttribute: // Abilities affect base stats, but not for drain @@ -802,23 +789,23 @@ namespace MWMechanics fortifyAttribute(target, effect, effect.mMagnitude); break; case ESM::MagicEffect::DrainSkill: - if (!target.getClass().isNpc()) - invalid = true; - else if (!godmode) - damageSkill(target, effect, effect.mMagnitude); + if (godmode || !target.getClass().isNpc()) + return ESM::ActiveEffect::Flag_Remove; + damageSkill(target, effect, effect.mMagnitude); break; case ESM::MagicEffect::FortifySkill: - if (!target.getClass().isNpc()) - invalid = true; - else if (spellParams.hasFlag(ESM::ActiveSpells::Flag_AffectsBaseValues)) + if (target.getClass().isNpc()) { - // Abilities affect base stats, but not for drain - auto& npcStats = target.getClass().getNpcStats(target); - auto& skill = npcStats.getSkill(effect.getSkillOrAttribute()); - skill.setBase(skill.getBase() + effect.mMagnitude); + if (spellParams.hasFlag(ESM::ActiveSpells::Flag_AffectsBaseValues)) + { + // Abilities affect base stats, but not for drain + auto& npcStats = target.getClass().getNpcStats(target); + auto& skill = npcStats.getSkill(effect.getSkillOrAttribute()); + skill.setBase(skill.getBase() + effect.mMagnitude); + } + else + fortifySkill(target, effect, effect.mMagnitude); } - else - fortifySkill(target, effect, effect.mMagnitude); break; case ESM::MagicEffect::FortifyMaximumMagicka: recalculateMagicka = true; @@ -826,7 +813,9 @@ namespace MWMechanics case ESM::MagicEffect::AbsorbHealth: case ESM::MagicEffect::AbsorbMagicka: case ESM::MagicEffect::AbsorbFatigue: - if (!godmode) + if (godmode) + return ESM::ActiveEffect::Flag_Remove; + else { int index = effect.mEffectId - ESM::MagicEffect::AbsorbHealth; adjustDynamicStat(target, index, -effect.mMagnitude); @@ -837,7 +826,9 @@ namespace MWMechanics } break; case ESM::MagicEffect::AbsorbAttribute: - if (!godmode) + if (godmode) + return ESM::ActiveEffect::Flag_Remove; + else { damageAttribute(target, effect, effect.mMagnitude); if (!caster.isEmpty()) @@ -845,22 +836,20 @@ namespace MWMechanics } break; case ESM::MagicEffect::AbsorbSkill: - if (!target.getClass().isNpc()) - invalid = true; - else if (!godmode) + if (godmode) + return ESM::ActiveEffect::Flag_Remove; + else { - damageSkill(target, effect, effect.mMagnitude); - if (!caster.isEmpty()) + if (target.getClass().isNpc()) + damageSkill(target, effect, effect.mMagnitude); + if (!caster.isEmpty() && caster.getClass().isNpc()) fortifySkill(caster, effect, effect.mMagnitude); } break; case ESM::MagicEffect::DisintegrateArmor: { if (!target.getClass().hasInventoryStore(target)) - { - invalid = true; - break; - } + return ESM::ActiveEffect::Flag_Invalid; if (godmode) break; static const std::array priorities{ @@ -883,18 +872,18 @@ namespace MWMechanics } case ESM::MagicEffect::DisintegrateWeapon: if (!target.getClass().hasInventoryStore(target)) - { - invalid = true; - break; - } + return ESM::ActiveEffect::Flag_Invalid; if (!godmode) disintegrateSlot(target, MWWorld::InventoryStore::Slot_CarriedRight, effect.mMagnitude); break; } + return ESM::ActiveEffect::Flag_Applied; } bool shouldRemoveEffect(const MWWorld::Ptr& target, const ESM::ActiveEffect& effect) { + if (effect.mFlags & ESM::ActiveEffect::Flag_Invalid) + return true; const auto world = MWBase::Environment::get().getWorld(); switch (effect.mEffectId) { @@ -936,7 +925,7 @@ namespace MWMechanics ActiveSpells::ActiveSpellParams& spellParams, ESM::ActiveEffect& effect, float dt, bool playNonLooping) { const auto world = MWBase::Environment::get().getWorld(); - bool invalid = false; + int32_t applied = ESM::ActiveEffect::Flag_Remove; bool receivedMagicDamage = false; bool recalculateMagicka = false; bool affectedHealth = false; @@ -946,8 +935,8 @@ namespace MWMechanics for (auto& otherEffect : spellParams.getEffects()) { if (isCorprusEffect(otherEffect)) - applyMagicEffect(target, caster, spellParams, otherEffect, invalid, receivedMagicDamage, - affectedHealth, recalculateMagicka); + applyMagicEffect(target, caster, spellParams, otherEffect, receivedMagicDamage, affectedHealth, + recalculateMagicka); } if (target == getPlayer()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicCorprusWorsens}"); @@ -989,7 +978,7 @@ namespace MWMechanics } } else - invalid = true; + applied |= ESM::ActiveEffect::Flag_Invalid; } else if (effect.mEffectId == ESM::MagicEffect::Open) { @@ -1021,11 +1010,11 @@ namespace MWMechanics } } else - invalid = true; + applied |= ESM::ActiveEffect::Flag_Invalid; } else if (!target.getClass().isActor()) { - invalid = true; + applied |= ESM::ActiveEffect::Flag_Invalid; } else { @@ -1041,7 +1030,7 @@ namespace MWMechanics auto& stats = target.getClass().getCreatureStats(target); auto& magnitudes = stats.getMagicEffects(); if (!spellParams.hasFlag(ESM::ActiveSpells::Flag_AffectsBaseValues) - && !(effect.mFlags & ESM::ActiveEffect::Flag_Applied)) + && !(effect.mFlags & ESM::ActiveEffect::Flag_Remove)) { MagicApplicationResult::Type result = applyProtections(target, caster, spellParams, effect, magicEffect); @@ -1051,7 +1040,7 @@ namespace MWMechanics float oldMagnitude = 0.f; if (effect.mFlags & ESM::ActiveEffect::Flag_Applied) oldMagnitude = effect.mMagnitude; - else + else if (!(effect.mFlags & ESM::ActiveEffect::Flag_Remove)) { bool isTemporary = spellParams.hasFlag(ESM::ActiveSpells::Flag_Temporary); bool isEquipment = spellParams.hasFlag(ESM::ActiveSpells::Flag_Equipment); @@ -1086,25 +1075,27 @@ namespace MWMechanics } } if (effect.mEffectId == ESM::MagicEffect::Corprus) + { spellParams.worsen(); + applied |= ESM::ActiveEffect::Flag_Applied; + } else - applyMagicEffect(target, caster, spellParams, effect, invalid, receivedMagicDamage, affectedHealth, - recalculateMagicka); + applied |= applyMagicEffect( + target, caster, spellParams, effect, receivedMagicDamage, affectedHealth, recalculateMagicka); effect.mMagnitude = magnitude; magnitudes.add(EffectKey(effect.mEffectId, effect.getSkillOrAttribute()), EffectParam(effect.mMagnitude - oldMagnitude)); } effect.mTimeLeft -= dt; - if (invalid) + if (applied & ESM::ActiveEffect::Flag_Invalid) { effect.mTimeLeft = 0; - effect.mFlags |= ESM::ActiveEffect::Flag_Remove; auto anim = world->getAnimation(target); if (anim) anim->removeEffect(ESM::MagicEffect::indexToName(effect.mEffectId)); + // Note that we can't return REMOVED here because the effect still needs to be detectable } - else - effect.mFlags |= ESM::ActiveEffect::Flag_Applied | ESM::ActiveEffect::Flag_Remove; + effect.mFlags |= applied; if (recalculateMagicka) target.getClass().getCreatureStats(target).recalculateMagicka(); return { MagicApplicationResult::Type::APPLIED, receivedMagicDamage, affectedHealth }; @@ -1115,7 +1106,6 @@ namespace MWMechanics { const auto world = MWBase::Environment::get().getWorld(); auto& magnitudes = target.getClass().getCreatureStats(target).getMagicEffects(); - bool invalid; switch (effect.mEffectId) { case ESM::MagicEffect::CommandCreature: @@ -1143,18 +1133,16 @@ namespace MWMechanics break; case ESM::MagicEffect::FrenzyCreature: case ESM::MagicEffect::FrenzyHumanoid: - modifyAiSetting( - target, effect, ESM::MagicEffect::FrenzyCreature, AiSetting::Fight, -effect.mMagnitude, invalid); + modifyAiSetting(target, effect, ESM::MagicEffect::FrenzyCreature, AiSetting::Fight, -effect.mMagnitude); break; case ESM::MagicEffect::CalmCreature: case ESM::MagicEffect::CalmHumanoid: - modifyAiSetting( - target, effect, ESM::MagicEffect::CalmCreature, AiSetting::Fight, effect.mMagnitude, invalid); + modifyAiSetting(target, effect, ESM::MagicEffect::CalmCreature, AiSetting::Fight, effect.mMagnitude); break; case ESM::MagicEffect::DemoralizeCreature: case ESM::MagicEffect::DemoralizeHumanoid: modifyAiSetting( - target, effect, ESM::MagicEffect::DemoralizeCreature, AiSetting::Flee, -effect.mMagnitude, invalid); + target, effect, ESM::MagicEffect::DemoralizeCreature, AiSetting::Flee, -effect.mMagnitude); break; case ESM::MagicEffect::NightEye: { @@ -1173,8 +1161,7 @@ namespace MWMechanics break; case ESM::MagicEffect::RallyCreature: case ESM::MagicEffect::RallyHumanoid: - modifyAiSetting( - target, effect, ESM::MagicEffect::RallyCreature, AiSetting::Flee, effect.mMagnitude, invalid); + modifyAiSetting(target, effect, ESM::MagicEffect::RallyCreature, AiSetting::Flee, effect.mMagnitude); break; case ESM::MagicEffect::Sound: if (magnitudes.getOrDefault(effect.mEffectId).getModifier() <= 0.f && target == getPlayer()) @@ -1274,18 +1261,22 @@ namespace MWMechanics fortifyAttribute(target, effect, -effect.mMagnitude); break; case ESM::MagicEffect::DrainSkill: - restoreSkill(target, effect, effect.mMagnitude); + if (target.getClass().isNpc()) + restoreSkill(target, effect, effect.mMagnitude); break; case ESM::MagicEffect::FortifySkill: - // Abilities affect base stats, but not for drain - if (spellParams.hasFlag(ESM::ActiveSpells::Flag_AffectsBaseValues)) + if (target.getClass().isNpc()) { - auto& npcStats = target.getClass().getNpcStats(target); - auto& skill = npcStats.getSkill(effect.getSkillOrAttribute()); - skill.setBase(skill.getBase() - effect.mMagnitude); + // Abilities affect base stats, but not for drain + if (spellParams.hasFlag(ESM::ActiveSpells::Flag_AffectsBaseValues)) + { + auto& npcStats = target.getClass().getNpcStats(target); + auto& skill = npcStats.getSkill(effect.getSkillOrAttribute()); + skill.setBase(skill.getBase() - effect.mMagnitude); + } + else + fortifySkill(target, effect, -effect.mMagnitude); } - else - fortifySkill(target, effect, -effect.mMagnitude); break; case ESM::MagicEffect::FortifyMaximumMagicka: target.getClass().getCreatureStats(target).recalculateMagicka(); @@ -1300,9 +1291,10 @@ namespace MWMechanics break; case ESM::MagicEffect::AbsorbSkill: { + if (target.getClass().isNpc()) + restoreSkill(target, effect, effect.mMagnitude); const auto caster = world->searchPtrViaActorId(spellParams.getCasterActorId()); - restoreSkill(target, effect, effect.mMagnitude); - if (!caster.isEmpty()) + if (!caster.isEmpty() && caster.getClass().isNpc()) fortifySkill(caster, effect, -effect.mMagnitude); } break; diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 9181996a4e6..789e613afc1 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -344,7 +344,7 @@ namespace MWRender auto primaryFBO = postProcessor->getPrimaryFbo(frameId); primaryFBO->apply(*state); - postProcessor->getFbo(PostProcessor::FBO_OpaqueDepth, frameId)->apply(*state); + // postProcessor->getFbo(PostProcessor::FBO_OpaqueDepth, frameId)->apply(*state); // depth accumulation pass osg::ref_ptr restore = bin->getStateSet(); diff --git a/apps/openmw/mwrender/postprocessor.cpp b/apps/openmw/mwrender/postprocessor.cpp index a06b9a83def..60925bd3374 100644 --- a/apps/openmw/mwrender/postprocessor.cpp +++ b/apps/openmw/mwrender/postprocessor.cpp @@ -196,10 +196,6 @@ namespace MWRender if (!ext->glDisablei && ext->glDisableIndexedEXT) ext->glDisablei = ext->glDisableIndexedEXT; -#ifdef ANDROID - ext->glDisablei = nullptr; -#endif - if (ext->glDisablei) mNormalsSupported = true; else @@ -300,7 +296,7 @@ namespace MWRender mCanvases[frameId]->setCalculateAvgLum(mHDR); mCanvases[frameId]->setTextureScene(getTexture(Tex_Scene, frameId)); - mCanvases[frameId]->setTextureDepth(getTexture(Tex_OpaqueDepth, frameId)); + mCanvases[frameId]->setTextureDepth(getTexture(Tex_Depth/*Tex_OpaqueDepth*/, frameId)); mCanvases[frameId]->setTextureDistortion(getTexture(Tex_Distortion, frameId)); mTransparentDepthPostPass->mFbo[frameId] = mFbos[frameId][FBO_Primary]; @@ -412,11 +408,15 @@ namespace MWRender if (mNormalsSupported) { +// Crashing with gl4es, use OSG define instead +/* auto& shaderManager = MWBase::Environment::get().getResourceSystem()->getSceneManager()->getShaderManager(); auto defines = shaderManager.getGlobalDefines(); defines["disableNormals"] = mNormals ? "0" : "1"; shaderManager.setGlobalDefines(defines); +*/ + mRendering.setWriteNormals(mNormals); } mRendering.getLightRoot()->setCollectPPLights(mPassLights); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 67d1cfb587c..c9f08918d57 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -213,6 +213,7 @@ namespace MWRender : mFogStart(0.f) , mFogEnd(0.f) , mWireframe(false) + , mWriteNormals(false) { } @@ -231,6 +232,12 @@ namespace MWRender } else stateset->removeAttribute(osg::StateAttribute::POLYGONMODE); + + stateset->setDefine("FORCE_PPL", (Settings::shaders().mForcePerPixelLighting == true) ? "1" : "0", osg::StateAttribute::ON); + stateset->setDefine("CLASSIC_FALLOFF", (Settings::shaders().mClassicFalloff == true) ? "1" : "0", osg::StateAttribute::ON); + stateset->setDefine("MAX_LIGHTS", std::to_string(Settings::shaders().mMaxLights), osg::StateAttribute::ON); + + stateset->setDefine("WRITE_NORMALS", (mWriteNormals) ? "1" : "0", osg::StateAttribute::ON); } void apply(osg::StateSet* stateset, osg::NodeVisitor*) override @@ -242,6 +249,8 @@ namespace MWRender fog->setColor(mFogColor); fog->setStart(mFogStart); fog->setEnd(mFogEnd); + + stateset->setDefine("WRITE_NORMALS", (mWriteNormals) ? "1" : "0", osg::StateAttribute::ON); } void setAmbientColor(const osg::Vec4f& col) { mAmbientColor = col; } @@ -263,12 +272,15 @@ namespace MWRender bool getWireframe() const { return mWireframe; } + void setWriteNormals(float enabled) {mWriteNormals = enabled; } + private: osg::Vec4f mAmbientColor; osg::Vec4f mFogColor; float mFogStart; float mFogEnd; bool mWireframe; + bool mWriteNormals; }; class PreloadCommonAssetsWorkItem : public SceneUtil::WorkItem @@ -460,6 +472,10 @@ namespace MWRender globalDefines["reverseZ"] = reverseZ ? "1" : "0"; + + globalDefines["shadowMapSize"] = std::to_string(Settings::shadows().mShadowMapResolution); + globalDefines["PCFSamples"] = std::to_string(Settings::shadows().mPercentageCloserFiltering); + // It is unnecessary to stop/start the viewer as no frames are being rendered yet. mResourceSystem->getSceneManager()->getShaderManager().setGlobalDefines(globalDefines); @@ -510,8 +526,8 @@ namespace MWRender mPostProcessor = new PostProcessor(*this, viewer, mRootNode, resourceSystem->getVFS()); resourceSystem->getSceneManager()->setOpaqueDepthTex( - mPostProcessor->getTexture(PostProcessor::Tex_OpaqueDepth, 0), - mPostProcessor->getTexture(PostProcessor::Tex_OpaqueDepth, 1)); + mPostProcessor->getTexture(PostProcessor::Tex_Depth/*Tex_OpaqueDepth*/, 0), + mPostProcessor->getTexture(PostProcessor::Tex_Depth/*Tex_OpaqueDepth*/, 1)); resourceSystem->getSceneManager()->setSupportsNormalsRT(mPostProcessor->getSupportsNormalsRT()); resourceSystem->getSceneManager()->setWeatherParticleOcclusion(Settings::shaders().mWeatherParticleOcclusion); @@ -1541,17 +1557,21 @@ namespace MWRender else if (it->first == "Shaders" && (it->second == "force per pixel lighting" || it->second == "classic falloff")) { +/* mViewer->stopThreading(); auto defines = mResourceSystem->getSceneManager()->getShaderManager().getGlobalDefines(); defines["forcePPL"] = Settings::shaders().mForcePerPixelLighting ? "1" : "0"; defines["classicFalloff"] = Settings::shaders().mClassicFalloff ? "1" : "0"; mResourceSystem->getSceneManager()->getShaderManager().setGlobalDefines(defines); +*/ if (MWMechanics::getPlayer().isInCell() && it->second == "classic falloff") configureAmbient(*MWMechanics::getPlayer().getCell()->getCell()); - mViewer->startThreading(); + mStateUpdater->reset(); + +// mViewer->startThreading(); } else if (it->first == "Shaders" && (it->second == "light bounds multiplier" || it->second == "maximum light distance" @@ -1567,12 +1587,12 @@ namespace MWRender mViewer->stopThreading(); lightManager->updateMaxLights(Settings::shaders().mMaxLights); - +/* auto defines = mResourceSystem->getSceneManager()->getShaderManager().getGlobalDefines(); for (const auto& [name, key] : lightManager->getLightDefines()) defines[name] = key; mResourceSystem->getSceneManager()->getShaderManager().setGlobalDefines(defines); - +*/ mStateUpdater->reset(); mViewer->startThreading(); @@ -1824,4 +1844,9 @@ namespace MWRender { mNavMesh->setMode(value); } + + void RenderingManager::setWriteNormals(bool enabled) + { + mStateUpdater->setWriteNormals(enabled); + } } diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 4723c59b8a9..622cd410563 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -276,6 +276,8 @@ namespace MWRender void setNavMeshMode(Settings::NavMeshRenderMode value); + void setWriteNormals(bool enabled); + private: void updateTextureFiltering(); void updateAmbient(); diff --git a/apps/openmw/mwrender/transparentpass.cpp b/apps/openmw/mwrender/transparentpass.cpp index ce53b1c2193..6f36dbef6ad 100644 --- a/apps/openmw/mwrender/transparentpass.cpp +++ b/apps/openmw/mwrender/transparentpass.cpp @@ -43,6 +43,11 @@ namespace MWRender for (unsigned int unit = 1; unit < 8; ++unit) mStateSet->setTextureMode(unit, GL_TEXTURE_2D, modeOff); + + mDepth = new SceneUtil::AutoDepth; + mDepth->setWriteMask(false); + + // setPostPass(mPostPass); } void TransparentDepthBinCallback::drawImplementation( @@ -92,20 +97,27 @@ namespace MWRender else { opaqueFbo->apply(state, osg::FrameBufferObject::DRAW_FRAMEBUFFER); - ext->glBlitFramebuffer(0, 0, tex->getTextureWidth(), tex->getTextureHeight(), 0, 0, tex->getTextureWidth(), - tex->getTextureHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST); + //ext->glBlitFramebuffer(0, 0, tex->getTextureWidth(), tex->getTextureHeight(), 0, 0, tex->getTextureWidth(), + // tex->getTextureHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST); + glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); } msaaFbo ? msaaFbo->apply(state, osg::FrameBufferObject::DRAW_FRAMEBUFFER) : fbo->apply(state, osg::FrameBufferObject::DRAW_FRAMEBUFFER); + if (mPostPass) + bin->getStateSet()->setAttributeAndModes(mDepth, osg::StateAttribute::ON); + // draws scene into primary attachments bin->drawImplementation(renderInfo, previous); + if (mPostPass) + bin->getStateSet()->setAttributeAndModes(mDepth, osg::StateAttribute::OFF); + if (!mPostPass) return; - opaqueFbo->apply(state, osg::FrameBufferObject::DRAW_FRAMEBUFFER); + //opaqueFbo->apply(state, osg::FrameBufferObject::DRAW_FRAMEBUFFER); // draw transparent post-pass to populate a postprocess friendly depth texture with alpha-clipped geometry @@ -140,4 +152,11 @@ namespace MWRender : fbo->apply(state, osg::FrameBufferObject::DRAW_FRAMEBUFFER); state.checkGLErrors("after TransparentDepthBinCallback::drawImplementation"); } + + void TransparentDepthBinCallback::setPostPass(bool enable) + { + mPostPass = enable; + + // osgUtil::RenderBin::getRenderBinPrototype("DepthSortedBin")->getStateSet()->setAttributeAndModes(mDepth, (mPostPass) ? osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE : osg::StateAttribute::OFF); + } } diff --git a/apps/openmw/mwrender/transparentpass.hpp b/apps/openmw/mwrender/transparentpass.hpp index 9d727cf08d2..0b74b84947d 100644 --- a/apps/openmw/mwrender/transparentpass.hpp +++ b/apps/openmw/mwrender/transparentpass.hpp @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -35,9 +36,12 @@ namespace MWRender std::array, 2> mMultiviewResolve; + void setPostPass(bool enable); + private: osg::ref_ptr mStateSet; bool mPostPass; + osg::ref_ptr mDepth; }; } diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 15119093320..3880f8e6401 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -626,7 +626,7 @@ namespace MWScript { for (const auto& effect : spell.getEffects()) { - if (effect.mFlags & ESM::ActiveEffect::Flag_Applied && effect.mEffectId == key) + if (effect.mFlags & ESM::ActiveEffect::Flag_Remove && effect.mEffectId == key) { runtime.push(1); return; diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 34aa3eaa460..d6cdf99bffe 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -659,15 +659,13 @@ void MWState::StateManager::loadGame(const Character* character, const std::file { const char* release; // Report the last version still capable of reading this save - if (e.getFormatVersion() <= ESM::OpenMW0_48SaveGameFormatVersion) + if (e.getFormatVersion() < ESM::OpenMW0_49MinSaveGameFormatVersion) release = "OpenMW 0.48.0"; - else if (e.getFormatVersion() <= ESM::OpenMW0_49SaveGameFormatVersion) - release = "OpenMW 0.49.0"; else { // Insert additional else if statements above to cover future releases - static_assert(ESM::MinSupportedSaveGameFormatVersion <= ESM::OpenMW0_50SaveGameFormatVersion); - release = "OpenMW 0.50.0"; + static_assert(ESM::MinSupportedSaveGameFormatVersion <= ESM::OpenMW0_49MinSaveGameFormatVersion); + release = "OpenMW 0.51.0"; } auto l10n = MWBase::Environment::get().getL10nManager()->getContext("OMWEngine"); std::string error = l10n->formatMessage("LoadingRequiresOldVersionError", { "version" }, { release }); diff --git a/apps/openmw/mwworld/actiontrap.cpp b/apps/openmw/mwworld/actiontrap.cpp index 5a0e3c7b868..f256ff4af4e 100644 --- a/apps/openmw/mwworld/actiontrap.cpp +++ b/apps/openmw/mwworld/actiontrap.cpp @@ -18,7 +18,7 @@ namespace MWWorld // Using activation distance as the trap range. if (actor == MWBase::Environment::get().getWorld()->getPlayerPtr() - && MWBase::Environment::get().getWorld()->getDistanceToFacedObject() + && MWBase::Environment::get().getWorld()->getDistanceToFocusObject() > trapRange) // player activated object outside range of trap { MWMechanics::CastSpell cast(mTrapSource, mTrapSource); diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index b776f27f06b..fca3a30a2c9 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -193,7 +193,7 @@ namespace MWWorld if (playerStats.isParalyzed() || playerStats.getKnockedDown() || playerStats.isDead()) return; - MWWorld::Ptr toActivate = MWBase::Environment::get().getWorld()->getFacedObject(); + MWWorld::Ptr toActivate = MWBase::Environment::get().getWorld()->getFocusObject(); if (toActivate.isEmpty()) return; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 957ab98f24f..5caeea45ddd 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -261,7 +261,7 @@ namespace MWWorld , mActivationDistanceOverride(activationDistanceOverride) , mStartCell(startCell) , mSwimHeightScale(0.f) - , mDistanceToFacedObject(-1.f) + , mDistanceToFocusObject(-1.f) , mTeleportEnabled(true) , mLevitationEnabled(true) , mGoToJail(false) @@ -999,33 +999,33 @@ namespace MWWorld return static_cast(iMaxActivateDist); } - MWWorld::Ptr World::getFacedObject() + MWWorld::Ptr World::getFocusObject() { - MWWorld::Ptr facedObject; + MWWorld::Ptr focusObject; if (MWBase::Environment::get().getStateManager()->getState() == MWBase::StateManager::State_NoGame) - return facedObject; + return focusObject; if (MWBase::Environment::get().getWindowManager()->isGuiMode() && MWBase::Environment::get().getWindowManager()->isConsoleMode()) - facedObject = getFacedObject(getMaxActivationDistance() * 50, false); + focusObject = getFocusObject(getMaxActivationDistance() * 50, false); else { float activationDistance = getActivationDistancePlusTelekinesis(); - facedObject = getFacedObject(activationDistance, true); + focusObject = getFocusObject(activationDistance, true); - if (!facedObject.isEmpty() && !facedObject.getClass().allowTelekinesis(facedObject) - && mDistanceToFacedObject > getMaxActivationDistance() + if (!focusObject.isEmpty() && !focusObject.getClass().allowTelekinesis(focusObject) + && mDistanceToFocusObject > getMaxActivationDistance() && !MWBase::Environment::get().getWindowManager()->isGuiMode()) return nullptr; } - return facedObject; + return focusObject; } - float World::getDistanceToFacedObject() + float World::getDistanceToFocusObject() { - return mDistanceToFacedObject; + return mDistanceToFocusObject; } osg::Matrixf World::getActorHeadTransform(const MWWorld::ConstPtr& actor) const @@ -1772,12 +1772,12 @@ namespace MWWorld MWBase::Environment::get().getSoundManager()->setListenerPosDir(listenerPos, forward, up, underwater); } - void World::updateWindowManager() + void World::updateFocusObject() { try { // inform the GUI about focused object - MWWorld::Ptr object = getFacedObject(); + MWWorld::Ptr object = getFocusObject(); // retrieve the object's top point's screen position so we know where to place the floating label if (!object.isEmpty()) @@ -1798,15 +1798,15 @@ namespace MWWorld } catch (std::exception& e) { - Log(Debug::Error) << "Error updating window manager: " << e.what(); + Log(Debug::Error) << "Error updating focus object: " << e.what(); } } - MWWorld::Ptr World::getFacedObject(float maxDistance, bool ignorePlayer) + MWWorld::Ptr World::getFocusObject(float maxDistance, bool ignorePlayer) { const float camDist = mRendering->getCamera()->getCameraDistance(); maxDistance += camDist; - MWWorld::Ptr facedObject; + MWWorld::Ptr focusObject; MWRender::RenderingManager::RayResult rayToObject; if (MWBase::Environment::get().getWindowManager()->isGuiMode()) @@ -1818,14 +1818,14 @@ namespace MWWorld else rayToObject = mRendering->castCameraToViewportRay(0.5f, 0.5f, maxDistance, ignorePlayer); - facedObject = rayToObject.mHitObject; - if (facedObject.isEmpty() && rayToObject.mHitRefnum.isSet()) - facedObject = MWBase::Environment::get().getWorldModel()->getPtr(rayToObject.mHitRefnum); + focusObject = rayToObject.mHitObject; + if (focusObject.isEmpty() && rayToObject.mHitRefnum.isSet()) + focusObject = MWBase::Environment::get().getWorldModel()->getPtr(rayToObject.mHitRefnum); if (rayToObject.mHit) - mDistanceToFacedObject = (rayToObject.mRatio * maxDistance) - camDist; + mDistanceToFocusObject = (rayToObject.mRatio * maxDistance) - camDist; else - mDistanceToFacedObject = -1; - return facedObject; + mDistanceToFocusObject = -1; + return focusObject; } bool World::castRenderingRay(MWPhysics::RayCastingResult& res, const osg::Vec3f& from, const osg::Vec3f& to, @@ -2997,7 +2997,7 @@ namespace MWWorld else { if (casterIsPlayer) - target = getFacedObject(); + target = getFocusObject(); if (target.isEmpty() || !target.getClass().hasToolTip(target)) { diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 4b99f3c687c..b5dbc19de9e 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -121,7 +121,7 @@ namespace MWWorld float mSwimHeightScale; - float mDistanceToFacedObject; + float mDistanceToFocusObject; bool mTeleportEnabled; bool mLevitationEnabled; @@ -152,7 +152,7 @@ namespace MWWorld void preloadSpells(); - MWWorld::Ptr getFacedObject(float maxDistance, bool ignorePlayer = true); + MWWorld::Ptr getFocusObject(float maxDistance, bool ignorePlayer = true); void PCDropped(const Ptr& item); @@ -349,10 +349,10 @@ namespace MWWorld bool changeEvent = true) override; ///< @param changeEvent If false, do not trigger cell change flag or detect worldspace changes - MWWorld::Ptr getFacedObject() override; + MWWorld::Ptr getFocusObject() override; ///< Return pointer to the object the player is looking at, if it is within activation range - float getDistanceToFacedObject() override; + float getDistanceToFocusObject() override; /// @note No-op for items in containers. Use ContainerStore::removeItem instead. void deleteObject(const Ptr& ptr) override; @@ -419,7 +419,7 @@ namespace MWWorld void updatePhysics( float duration, bool paused, osg::Timer_t frameStart, unsigned int frameNumber, osg::Stats& stats); - void updateWindowManager(); + void updateFocusObject(); MWWorld::Ptr placeObject( const MWWorld::Ptr& object, float cursorX, float cursorY, int amount, bool copy = true) override; diff --git a/apps/openmw/profile.hpp b/apps/openmw/profile.hpp index da9128197c6..da8ef46e214 100644 --- a/apps/openmw/profile.hpp +++ b/apps/openmw/profile.hpp @@ -37,7 +37,7 @@ namespace OMW PhysicsWorker, World, Gui, - WindowManager, + Focus, Lua, Number, }; @@ -73,7 +73,7 @@ namespace OMW inline const UserStats UserStatsValue::sValue{ "World", "world" }; template <> - inline const UserStats UserStatsValue::sValue{ "Gui", "gui" }; + inline const UserStats UserStatsValue::sValue{ "GUI", "gui" }; template <> inline const UserStats UserStatsValue::sValue{ "Lua", "lua" }; @@ -82,7 +82,7 @@ namespace OMW inline const UserStats UserStatsValue::sValue{ "LuaSync", "luasyncupdate" }; template <> - inline const UserStats UserStatsValue::sValue{ "WindowManager", "windowmanager" }; + inline const UserStats UserStatsValue::sValue{ "Focus", "focusobject" }; template struct ForEachUserStatsValue diff --git a/apps/openmw_tests/mwscript/testscripts.cpp b/apps/openmw_tests/mwscript/testscripts.cpp index b9e422daed8..561a7bc3fa5 100644 --- a/apps/openmw_tests/mwscript/testscripts.cpp +++ b/apps/openmw_tests/mwscript/testscripts.cpp @@ -1,4 +1,6 @@ #include + +#include #include #include "testutils.hpp" @@ -126,6 +128,34 @@ player -> addSpell "fire_bite", 645 PositionCell "Rabenfels, Taverne" 4480.000 3968.000 15820.000 0 +End)mwscript"; + + const std::string sScript5 = R"mwscript(Begin messagebox_format_script + +float fVal + +set fVal to 12.34 + +MessageBox "hello world" +MessageBox "%.0f" fVal +MessageBox "%.f" fVal +MessageBox "a %03.0f b" fVal +MessageBox "%+04.0f" fVal +MessageBox "%+4.0f" fVal +MessageBox "%+ 4.0f" fVal +MessageBox "%0+ 4.0f" fVal +MessageBox "%0+ #4.0f" fVal +MessageBox "%- 5.0f" fVal + +MessageBox "%g" fVal +MessageBox "%.3g" fVal +MessageBox "%.5g" fVal +MessageBox "%#.5g" fVal +MessageBox "%-5g" fVal +MessageBox "%- 5g" fVal + +MessageBox "%.1b" fVal + End)mwscript"; const std::string sIssue587 = R"mwscript(Begin stalresetScript @@ -579,6 +609,47 @@ End)mwscript"; EXPECT_FALSE(!compile(sScript4)); } + TEST_F(MWScriptTest, mwscript_test_messagebox_format) + { + if (const auto script = compile(sScript5)) + { + TestInterpreterContext context; + run(*script, context); + using std::string_view_literals::operator""sv; + constexpr std::array expected{ + "hello world"sv, + "12"sv, + "12"sv, + "a 012 b"sv, + "+012"sv, + " +12"sv, + " +12"sv, + "+012"sv, + "+12."sv, + " 12 "sv, + + "12.34"sv, + "12.3"sv, + "12.34"sv, + "12.340"sv, + "12.34"sv, + " 12.34"sv, + + "b"sv, + }; + const std::vector& output = context.getMessages(); + EXPECT_EQ(expected.size(), output.size()); + for (std::size_t i = 0; i < output.size(); i++) + { + EXPECT_EQ(expected[i], output[i]); + } + } + else + { + FAIL(); + } + } + TEST_F(MWScriptTest, mwscript_test_587) { EXPECT_FALSE(!compile(sIssue587)); diff --git a/apps/openmw_tests/mwscript/testutils.hpp b/apps/openmw_tests/mwscript/testutils.hpp index ba22156f561..8ad571b6ee2 100644 --- a/apps/openmw_tests/mwscript/testutils.hpp +++ b/apps/openmw_tests/mwscript/testutils.hpp @@ -145,8 +145,11 @@ namespace { LocalVariables mLocals; std::map mMembers; + std::vector mMessages; public: + const std::vector& getMessages() { return mMessages; } + ESM::RefId getTarget() const override { return ESM::RefId(); } int getLocalShort(int index) const override { return mLocals.getShort(index); } @@ -161,7 +164,10 @@ namespace void setLocalFloat(int index, float value) override { mLocals.setFloat(index, value); } - void messageBox(std::string_view message, const std::vector& buttons) override {} + void messageBox(std::string_view message, const std::vector& buttons) override + { + mMessages.emplace_back(message); + } void report(const std::string& message) override {} diff --git a/cmake/FindSDL2.cmake b/cmake/FindSDL2.cmake new file mode 100644 index 00000000000..4f2be8c421a --- /dev/null +++ b/cmake/FindSDL2.cmake @@ -0,0 +1,129 @@ +# Locate SDL2 library +# This module defines +# SDL2_LIBRARY, the SDL2 library, with no other libraries +# SDL2_LIBRARIES, the SDL library and required components with compiler flags +# SDL2_FOUND, if false, do not try to link to SDL2 +# SDL2_INCLUDE_DIR, where to find SDL.h +# SDL2_VERSION, the version of the found library +# +# This module accepts the following env variables +# SDL2DIR - Can be set to ./configure --prefix=$SDL2DIR used in building SDL2. l.e.galup 9-20-02 +# This module responds to the the flag: +# SDL2_BUILDING_LIBRARY +# If this is defined, then no SDL2_main will be linked in because +# only applications need main(). +# Otherwise, it is assumed you are building an application and this +# module will attempt to locate and set the the proper link flags +# as part of the returned SDL2_LIBRARIES variable. +# +# Don't forget to include SDL2main.h and SDL2main.m your project for the +# OS X framework based version. (Other versions link to -lSDL2main which +# this module will try to find on your behalf.) Also for OS X, this +# module will automatically add the -framework Cocoa on your behalf. +# +# +# Modified by Eric Wing. +# Added code to assist with automated building by using environmental variables +# and providing a more controlled/consistent search behavior. +# Added new modifications to recognize OS X frameworks and +# additional Unix paths (FreeBSD, etc). +# Also corrected the header search path to follow "proper" SDL2 guidelines. +# Added a search for SDL2main which is needed by some platforms. +# Added a search for threads which is needed by some platforms. +# Added needed compile switches for MinGW. +# +# On OSX, this will prefer the Framework version (if found) over others. +# People will have to manually change the cache values of +# SDL2_LIBRARY to override this selection or set the CMake environment +# CMAKE_INCLUDE_PATH to modify the search paths. +# +# Note that the header path has changed from SDL2/SDL.h to just SDL.h +# This needed to change because "proper" SDL2 convention +# is #include "SDL.h", not . This is done for portability +# reasons because not all systems place things in SDL2/ (see FreeBSD). +# +# Ported by Johnny Patterson. This is a literal port for SDL2 of the FindSDL.cmake +# module with the minor edit of changing "SDL" to "SDL2" where necessary. This +# was not created for redistribution, and exists temporarily pending official +# SDL2 CMake modules. + +#============================================================================= +# Copyright 2003-2009 Kitware, Inc. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + + +if (CMAKE_SIZEOF_VOID_P EQUAL 8) + set(_sdl_lib_suffix lib/x64) +else() + set(_sdl_lib_suffix lib/x86) +endif() + +libfind_pkg_detect(SDL2 sdl2 + FIND_PATH SDL.h + HINTS $ENV{SDL2DIR} + PATH_SUFFIXES include SDL2 include/SDL2 + FIND_LIBRARY SDL2 + HINTS $ENV{SDL2DIR} + PATH_SUFFIXES lib ${_sdl_lib_suffix} +) +libfind_version_n_header(SDL2 NAMES SDL_version.h DEFINES SDL_MAJOR_VERSION SDL_MINOR_VERSION SDL_PATCHLEVEL) + +IF(NOT SDL2_BUILDING_LIBRARY AND NOT APPLE) + # Non-OS X framework versions expect you to also dynamically link to + # SDL2main. This is mainly for Windows and OS X. Other (Unix) platforms + # seem to provide SDL2main for compatibility even though they don't + # necessarily need it. + libfind_pkg_detect(SDL2MAIN sdl2 + FIND_LIBRARY SDL2main + HINTS $ENV{SDL2DIR} + PATH_SUFFIXES lib ${_sdl_lib_suffix} + ) + set(SDL2MAIN_FIND_QUIETLY TRUE) + libfind_process(SDL2MAIN) + list(APPEND SDL2_PROCESS_LIBS SDL2MAIN_LIBRARY) +ENDIF() + + +set(SDL2_TARGET_SPECIFIC) + +if (APPLE) + # For OS X, SDL2 uses Cocoa as a backend so it must link to Cocoa. + list(APPEND SDL2_TARGET_SPECIFIC "-framework Cocoa") +else() + # SDL2 may require threads on your system. + # The Apple build may not need an explicit flag because one of the + # frameworks may already provide it. + # But for non-OSX systems, I will use the CMake Threads package. + libfind_package(SDL2 Threads) + list(APPEND SDL2_TARGET_SPECIFIC ${CMAKE_THREAD_LIBS_INIT}) +endif() + +# MinGW needs an additional library, mwindows +# It's total link flags should look like -lmingw32 -lSDL2main -lSDL2 -lmwindows +# (Actually on second look, I think it only needs one of the m* libraries.) +if(MINGW) + list(APPEND SDL2_TARGET_SPECIFIC mingw32) +endif() + +if(WIN32) + list(APPEND SDL2_TARGET_SPECIFIC winmm imm32 version msimg32) +endif() + +set(SDL2_PROCESS_LIBS SDL2_TARGET_SPECIFIC) + +libfind_process(SDL2) + +if (SDL2_STATIC AND UNIX AND NOT APPLE) + execute_process(COMMAND sdl2-config --static-libs OUTPUT_VARIABLE SDL2_STATIC_FLAGS) + string(REGEX REPLACE "(\r?\n)+$" "" SDL2_STATIC_FLAGS "${SDL2_STATIC_FLAGS}") + set(SDL2_LIBRARIES ${SDL2_STATIC_FLAGS}) +endif() diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index f23d54eb568..106f430c1c7 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -321,7 +321,7 @@ ENDIF() add_component_dir (files linuxpath androidpath windowspath macospath fixedpath multidircollection collections configurationmanager constrainedfilestream memorystream hash configfileparser openfile constrainedfilestreambuf conversion - istreamptr streamwithbuffer + istreamptr streamwithbuffer utils ) if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" AND NOT CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC") @@ -592,11 +592,10 @@ target_link_libraries(components ${OSG_LIBRARIES} ${OPENTHREADS_LIBRARIES} - Boost::system Boost::program_options Boost::iostreams - SDL2::SDL2 + ${SDL2_LIBRARIES} ${OPENGL_gl_LIBRARY} ${MyGUI_LIBRARIES} ${LUA_LIBRARIES} diff --git a/components/bsa/ba2dx10file.cpp b/components/bsa/ba2dx10file.cpp index d4f14926c6a..c16a3bacd25 100644 --- a/components/bsa/ba2dx10file.cpp +++ b/components/bsa/ba2dx10file.cpp @@ -4,13 +4,15 @@ #include #include #include -#include +#include +#include #include #include #include #include +#include #include #include "ba2file.hpp" @@ -73,19 +75,11 @@ namespace Bsa } /// Read header information from the input source - void BA2DX10File::readHeader() + void BA2DX10File::readHeader(std::istream& input) { assert(!mIsLoaded); - std::ifstream input(mFilepath, std::ios_base::binary); - - // Total archive size - std::streamoff fsize = 0; - if (input.seekg(0, std::ios_base::end)) - { - fsize = input.tellg(); - input.seekg(0); - } + const std::streamsize fsize = Files::getStreamSizeLeft(input); if (fsize < 24) // header is 24 bytes fail("File too small to be a valid BSA archive"); @@ -135,23 +129,22 @@ namespace Bsa std::vector fileName; uint16_t fileNameSize; input.read(reinterpret_cast(&fileNameSize), sizeof(uint16_t)); - fileName.resize(fileNameSize); - input.read(fileName.data(), fileName.size()); - fileName.push_back('\0'); + fileName.resize(fileNameSize + 1); + input.read(fileName.data(), fileNameSize); mFileNames.push_back(std::move(fileName)); - mFiles[i].setNameInfos(0, &mFileNames.back()); + mFiles[i].mNameOffset = 0; + mFiles[i].mNameSize = fileNameSize; + mFiles[i].mNamesBuffer = &mFileNames.back(); } - - mIsLoaded = true; } - std::optional BA2DX10File::getFileRecord(const std::string& str) const + std::optional BA2DX10File::getFileRecord(std::string_view str) const { for (const auto c : str) { if (((static_cast(c) >> 7U) & 1U) != 0U) { - fail("File record " + str + " contains unicode characters, refusing to load."); + fail(std::format("File record {} contains unicode characters, refusing to load.", str)); } } @@ -161,7 +154,7 @@ namespace Bsa // Force-convert the path into something UNIX can handle first // to make sure std::filesystem::path doesn't think the entire path is the filename on Linux // and subsequently purge it to determine the file folder. - std::string path = str; + std::string path(str); std::replace(path.begin(), path.end(), '\\', '/'); #endif diff --git a/components/bsa/ba2dx10file.hpp b/components/bsa/ba2dx10file.hpp index c902a4ccb0f..aed727dc1a2 100644 --- a/components/bsa/ba2dx10file.hpp +++ b/components/bsa/ba2dx10file.hpp @@ -41,7 +41,7 @@ namespace Bsa std::list> mFileNames; - std::optional getFileRecord(const std::string& str) const; + std::optional getFileRecord(std::string_view str) const; Files::IStreamPtr getFile(const FileRecord& fileRecord); @@ -57,7 +57,7 @@ namespace Bsa virtual ~BA2DX10File(); /// Read header information from the input source - void readHeader() override; + void readHeader(std::istream& stream) override; Files::IStreamPtr getFile(const char* filePath); Files::IStreamPtr getFile(const FileStruct* fileStruct); diff --git a/components/bsa/ba2gnrlfile.cpp b/components/bsa/ba2gnrlfile.cpp index dcef09296e8..30e9b1eb0aa 100644 --- a/components/bsa/ba2gnrlfile.cpp +++ b/components/bsa/ba2gnrlfile.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -10,6 +11,7 @@ #include #include #include +#include #include #include "ba2file.hpp" @@ -61,26 +63,18 @@ namespace Bsa mFolders[dirHash][{ nameHash, extHash }] = file; FileStruct fileStruct{}; - fileStruct.fileSize = file.size; - fileStruct.offset = file.offset; + fileStruct.mFileSize = file.size; + fileStruct.mOffset = file.offset; mFiles.push_back(fileStruct); } } /// Read header information from the input source - void BA2GNRLFile::readHeader() + void BA2GNRLFile::readHeader(std::istream& input) { assert(!mIsLoaded); - std::ifstream input(mFilepath, std::ios_base::binary); - - // Total archive size - std::streamoff fsize = 0; - if (input.seekg(0, std::ios_base::end)) - { - fsize = input.tellg(); - input.seekg(0); - } + const std::streamsize fsize = Files::getStreamSizeLeft(input); if (fsize < 24) // header is 24 bytes fail("File too small to be a valid BSA archive"); @@ -126,23 +120,22 @@ namespace Bsa std::vector fileName; uint16_t fileNameSize; input.read(reinterpret_cast(&fileNameSize), sizeof(uint16_t)); - fileName.resize(fileNameSize); - input.read(fileName.data(), fileName.size()); - fileName.push_back('\0'); + fileName.resize(fileNameSize + 1); + input.read(fileName.data(), fileNameSize); mFileNames.push_back(std::move(fileName)); - mFiles[i].setNameInfos(0, &mFileNames.back()); + mFiles[i].mNameOffset = 0; + mFiles[i].mNameSize = fileNameSize; + mFiles[i].mNamesBuffer = &mFileNames.back(); } - - mIsLoaded = true; } - BA2GNRLFile::FileRecord BA2GNRLFile::getFileRecord(const std::string& str) const + BA2GNRLFile::FileRecord BA2GNRLFile::getFileRecord(std::string_view str) const { for (const auto c : str) { if (((static_cast(c) >> 7U) & 1U) != 0U) { - fail("File record " + str + " contains unicode characters, refusing to load."); + fail(std::format("File record {} contains unicode characters, refusing to load.", str)); } } @@ -152,7 +145,7 @@ namespace Bsa // Force-convert the path into something UNIX can handle first // to make sure std::filesystem::path doesn't think the entire path is the filename on Linux // and subsequently purge it to determine the file folder. - std::string path = str; + std::string path(str); std::replace(path.begin(), path.end(), '\\', '/'); #endif diff --git a/components/bsa/ba2gnrlfile.hpp b/components/bsa/ba2gnrlfile.hpp index 080ba3a8df3..371fe3d0722 100644 --- a/components/bsa/ba2gnrlfile.hpp +++ b/components/bsa/ba2gnrlfile.hpp @@ -29,7 +29,7 @@ namespace Bsa std::list> mFileNames; - FileRecord getFileRecord(const std::string& str) const; + FileRecord getFileRecord(std::string_view str) const; Files::IStreamPtr getFile(const FileRecord& fileRecord); @@ -45,7 +45,7 @@ namespace Bsa virtual ~BA2GNRLFile(); /// Read header information from the input source - void readHeader() override; + void readHeader(std::istream& input) override; Files::IStreamPtr getFile(const char* filePath); Files::IStreamPtr getFile(const FileStruct* fileStruct); diff --git a/components/bsa/bsafile.cpp b/components/bsa/bsafile.cpp index 948b9dac8d7..979ea4376a2 100644 --- a/components/bsa/bsafile.cpp +++ b/components/bsa/bsafile.cpp @@ -25,12 +25,17 @@ #include #include +#include #include #include +#include #include +#include +#include #include #include +#include using namespace Bsa; @@ -54,7 +59,7 @@ BSAFile::Hash getHash(const std::string& name) sum ^= (((unsigned)(name[i])) << (off & 0x1F)); off += 8; } - hash.low = sum; + hash.mLow = sum; for (sum = off = 0; i < name.size(); i++) { @@ -64,12 +69,12 @@ BSAFile::Hash getHash(const std::string& name) sum = (sum << (32 - n)) | (sum >> n); // binary "rotate right" off += 8; } - hash.high = sum; + hash.mHigh = sum; return hash; } /// Read header information from the input source -void BSAFile::readHeader() +void BSAFile::readHeader(std::istream& input) { /* * The layout of a BSA archive is as follows: @@ -103,27 +108,24 @@ void BSAFile::readHeader() */ assert(!mIsLoaded); - std::ifstream input(mFilepath, std::ios_base::binary); - // Total archive size - std::streamoff fsize = 0; - if (input.seekg(0, std::ios_base::end)) - { - fsize = input.tellg(); - input.seekg(0); - } + const std::streamsize fsize = Files::getStreamSizeLeft(input); if (fsize < 12) fail("File too small to be a valid BSA archive"); // Get essential header numbers - size_t dirsize, filenum; + std::streamsize dirsize; + std::streamsize filenum; { // First 12 bytes uint32_t head[3]; input.read(reinterpret_cast(head), 12); + if (input.fail()) + fail(std::format("Failed to read head: {}", std::generic_category().message(errno))); + if (head[0] != 0x100) fail("Unrecognized BSA header"); @@ -138,62 +140,83 @@ void BSAFile::readHeader() // Each file must take up at least 21 bytes of data in the bsa. So // if files*21 overflows the file size then we are guaranteed that // the archive is corrupt. - if ((filenum * 21 > unsigned(fsize - 12)) || (dirsize + 8 * filenum > unsigned(fsize - 12))) + if (filenum * 21 > fsize - 12 || dirsize + 8 * filenum > fsize - 12) fail("Directory information larger than entire archive"); // Read the offset info into a temporary buffer std::vector offsets(3 * filenum); input.read(reinterpret_cast(offsets.data()), 12 * filenum); + if (input.fail()) + fail(std::format("Failed to read offsets: {}", std::generic_category().message(errno))); + // Read the string table mStringBuf.resize(dirsize - 12 * filenum); input.read(mStringBuf.data(), mStringBuf.size()); + if (input.fail()) + fail(std::format("Failed to read string table: {}", std::generic_category().message(errno))); + // Check our position assert(input.tellg() == std::streampos(12 + dirsize)); std::vector hashes(filenum); static_assert(sizeof(Hash) == 8); input.read(reinterpret_cast(hashes.data()), 8 * filenum); + if (input.fail()) + fail(std::format("Failed to read hashes: {}", std::generic_category().message(errno))); + // Calculate the offset of the data buffer. All file offsets are // relative to this. 12 header bytes + directory + hash table // (skipped) - size_t fileDataOffset = 12 + dirsize + 8 * filenum; + const std::streamsize fileDataOffset = 12 + dirsize + 8 * filenum; // Set up the the FileStruct table - mFiles.resize(filenum); + mFiles.reserve(filenum); size_t endOfNameBuffer = 0; - for (size_t i = 0; i < filenum; i++) + for (std::streamsize i = 0; i < filenum; i++) { - FileStruct& fs = mFiles[i]; - fs.fileSize = offsets[i * 2]; - fs.offset = static_cast(offsets[i * 2 + 1] + fileDataOffset); - auto namesOffset = offsets[2 * filenum + i]; - fs.setNameInfos(namesOffset, &mStringBuf); - fs.hash = hashes[i]; - - if (namesOffset >= mStringBuf.size()) - { + const uint32_t fileSize = offsets[i * 2]; + const std::streamsize offset = static_cast(offsets[i * 2 + 1]) + fileDataOffset; + + if (fileSize + offset > fsize) + fail(std::format("Archive contains offsets outside itself: {} + {} > {}", fileSize, offset, fsize)); + + if (offset > std::numeric_limits::max()) + fail(std::format( + "Absolute file {} offset is too large: {} > {}", i, offset, std::numeric_limits::max())); + + const uint32_t nameOffset = offsets[2 * filenum + i]; + + if (nameOffset >= mStringBuf.size()) fail("Archive contains names offset outside itself"); - } - const void* end = std::memchr(fs.name(), '\0', mStringBuf.size() - namesOffset); - if (!end) - { + + const char* const begin = mStringBuf.data() + nameOffset; + const char* const end = reinterpret_cast(std::memchr(begin, '\0', mStringBuf.size() - nameOffset)); + + if (end == nullptr) fail("Archive contains non-zero terminated string"); - } - endOfNameBuffer = std::max(endOfNameBuffer, namesOffset + std::strlen(fs.name()) + 1); - assert(endOfNameBuffer <= mStringBuf.size()); + const std::size_t nameSize = end - begin; + + FileStruct fs; + + fs.mFileSize = fileSize; + fs.mOffset = static_cast(offset); + fs.mHash = hashes[i]; + fs.mNameOffset = nameOffset; + fs.mNameSize = static_cast(nameSize); + fs.mNamesBuffer = &mStringBuf; + + mFiles.push_back(fs); - if (fs.offset + fs.fileSize > fsize) - fail("Archive contains offsets outside itself"); + endOfNameBuffer = std::max(endOfNameBuffer, nameOffset + nameSize + 1); + assert(endOfNameBuffer <= mStringBuf.size()); } mStringBuf.resize(endOfNameBuffer); std::sort(mFiles.begin(), mFiles.end(), - [](const FileStruct& left, const FileStruct& right) { return left.offset < right.offset; }); - - mIsLoaded = true; + [](const FileStruct& left, const FileStruct& right) { return left.mOffset < right.mOffset; }); } /// Write header information to the output sink @@ -203,7 +226,7 @@ void Bsa::BSAFile::writeHeader() uint32_t head[3]; head[0] = 0x100; - auto fileDataOffset = mFiles.empty() ? 12 : mFiles.front().offset; + auto fileDataOffset = mFiles.empty() ? 12 : mFiles.front().mOffset; head[1] = static_cast(fileDataOffset - 12 - 8 * mFiles.size()); output.seekp(0, std::ios_base::end); @@ -213,7 +236,7 @@ void Bsa::BSAFile::writeHeader() output.write(reinterpret_cast(head), 12); std::sort(mFiles.begin(), mFiles.end(), [](const FileStruct& left, const FileStruct& right) { - return std::make_pair(left.hash.low, left.hash.high) < std::make_pair(right.hash.low, right.hash.high); + return std::make_pair(left.mHash.mLow, left.mHash.mHigh) < std::make_pair(right.mHash.mLow, right.mHash.mHigh); }); size_t filenum = mFiles.size(); @@ -222,10 +245,10 @@ void Bsa::BSAFile::writeHeader() for (size_t i = 0; i < filenum; i++) { auto& f = mFiles[i]; - offsets[i * 2] = f.fileSize; - offsets[i * 2 + 1] = f.offset - fileDataOffset; - offsets[2 * filenum + i] = f.namesOffset; - hashes[i] = f.hash; + offsets[i * 2] = f.mFileSize; + offsets[i * 2 + 1] = f.mOffset - fileDataOffset; + offsets[2 * filenum + i] = f.mNameOffset; + hashes[i] = f.mHash; } output.write(reinterpret_cast(offsets.data()), sizeof(uint32_t) * offsets.size()); output.write(reinterpret_cast(mStringBuf.data()), mStringBuf.size()); @@ -241,7 +264,11 @@ void BSAFile::open(const std::filesystem::path& file) mFilepath = file; if (std::filesystem::exists(file)) - readHeader(); + { + std::ifstream input(mFilepath, std::ios_base::binary); + readHeader(input); + mIsLoaded = true; + } else { { @@ -265,7 +292,7 @@ void Bsa::BSAFile::close() Files::IStreamPtr Bsa::BSAFile::getFile(const FileStruct* file) { - return Files::openConstrainedFileStream(mFilepath, file->offset, file->fileSize); + return Files::openConstrainedFileStream(mFilepath, file->mOffset, file->mFileSize); } void Bsa::BSAFile::addFile(const std::string& filename, std::istream& file) @@ -281,37 +308,41 @@ void Bsa::BSAFile::addFile(const std::string& filename, std::istream& file) FileStruct newFile; file.seekg(0, std::ios::end); - newFile.fileSize = static_cast(file.tellg()); - newFile.setNameInfos(mStringBuf.size(), &mStringBuf); - newFile.hash = getHash(filename); + newFile.mFileSize = static_cast(file.tellg()); + newFile.mHash = getHash(filename); if (mFiles.empty()) - newFile.offset = static_cast(newStartOfDataBuffer); + newFile.mOffset = static_cast(newStartOfDataBuffer); else { std::vector buffer; - while (mFiles.front().offset < newStartOfDataBuffer) + while (mFiles.front().mOffset < newStartOfDataBuffer) { FileStruct& firstFile = mFiles.front(); - buffer.resize(firstFile.fileSize); + buffer.resize(firstFile.mFileSize); - stream.seekg(firstFile.offset, std::ios::beg); - stream.read(buffer.data(), firstFile.fileSize); + stream.seekg(firstFile.mOffset, std::ios::beg); + stream.read(buffer.data(), firstFile.mFileSize); stream.seekp(0, std::ios::end); - firstFile.offset = static_cast(stream.tellp()); + firstFile.mOffset = static_cast(stream.tellp()); - stream.write(buffer.data(), firstFile.fileSize); + stream.write(buffer.data(), firstFile.mFileSize); // ensure sort order is preserved std::rotate(mFiles.begin(), mFiles.begin() + 1, mFiles.end()); } stream.seekp(0, std::ios::end); - newFile.offset = static_cast(stream.tellp()); + newFile.mOffset = static_cast(stream.tellp()); } + newFile.mNameOffset = mStringBuf.size(); + newFile.mNameSize = filename.size(); + newFile.mNamesBuffer = &mStringBuf; + mStringBuf.insert(mStringBuf.end(), filename.begin(), filename.end()); mStringBuf.push_back('\0'); + mFiles.push_back(newFile); mHasChanged = true; diff --git a/components/bsa/bsafile.hpp b/components/bsa/bsafile.hpp index 7b910208d80..bc25e1f5dac 100644 --- a/components/bsa/bsafile.hpp +++ b/components/bsa/bsafile.hpp @@ -26,6 +26,7 @@ #include #include +#include #include #include @@ -54,30 +55,25 @@ namespace Bsa #pragma pack(1) struct Hash { - uint32_t low, high; + uint32_t mLow; + uint32_t mHigh; }; #pragma pack(pop) /// Represents one file entry in the archive struct FileStruct { - void setNameInfos(size_t index, std::vector* stringBuf) - { - namesOffset = static_cast(index); - namesBuffer = stringBuf; - } - // File size and offset in file. We store the offset from the // beginning of the file, not the offset into the data buffer // (which is what is stored in the archive.) - uint32_t fileSize, offset; - Hash hash; - - // Zero-terminated file name - const char* name() const { return &(*namesBuffer)[namesOffset]; } - - uint32_t namesOffset = 0; - std::vector* namesBuffer = nullptr; + uint32_t mFileSize = 0; + uint32_t mOffset = 0; + Hash mHash{}; + uint32_t mNameOffset = 0; + uint32_t mNameSize = 0; + std::vector* mNamesBuffer = nullptr; + + std::string_view name() const { return std::string_view(mNamesBuffer->data() + mNameOffset, mNameSize); } }; typedef std::vector FileList; @@ -100,7 +96,7 @@ namespace Bsa [[noreturn]] void fail(const std::string& msg) const; /// Read header information from the input source - virtual void readHeader(); + virtual void readHeader(std::istream& input); virtual void writeHeader(); public: @@ -151,7 +147,6 @@ namespace Bsa // checks version of BSA from file header static BsaVersion detectVersion(const std::filesystem::path& filePath); }; - } #endif diff --git a/components/bsa/compressedbsafile.cpp b/components/bsa/compressedbsafile.cpp index 655a4d28447..8ad72211057 100644 --- a/components/bsa/compressedbsafile.cpp +++ b/components/bsa/compressedbsafile.cpp @@ -26,14 +26,18 @@ #include #include +#include #include -#include +#include +#include +#include #include #include #include #include +#include #include #include "memorystream.hpp" @@ -41,19 +45,11 @@ namespace Bsa { /// Read header information from the input source - void CompressedBSAFile::readHeader() + void CompressedBSAFile::readHeader(std::istream& input) { assert(!mIsLoaded); - std::ifstream input(mFilepath, std::ios_base::binary); - - // Total archive size - std::streamoff fsize = 0; - if (input.seekg(0, std::ios_base::end)) - { - fsize = input.tellg(); - input.seekg(0); - } + const std::streamsize fsize = Files::getStreamSizeLeft(input); if (fsize < 36) // Header is 36 bytes fail("File too small to be a valid BSA archive"); @@ -69,8 +65,8 @@ namespace Bsa mHeader.mFlags &= (~ArchiveFlag_EmbeddedNames); input.seekg(mHeader.mFoldersOffset); - if (input.bad()) - fail("Invalid compressed BSA folder record offset"); + if (input.fail()) + fail("Failed to read compressed BSA folder record offset: " + std::generic_category().message(errno)); struct FlatFolderRecord { @@ -81,9 +77,12 @@ namespace Bsa }; std::vector>> folders; - folders.resize(mHeader.mFolderCount); - for (auto& [folder, filelist] : folders) + folders.reserve(mHeader.mFolderCount); + + for (std::uint32_t i = 0; i < mHeader.mFolderCount; ++i) { + FlatFolderRecord folder; + input.read(reinterpret_cast(&folder.mHash), 8); input.read(reinterpret_cast(&folder.mCount), 4); if (mHeader.mVersion == Version_SSE) // SSE @@ -96,10 +95,13 @@ namespace Bsa { input.read(reinterpret_cast(&folder.mOffset), 4); } - } - if (input.bad()) - fail("Failed to read compressed BSA folder records: input error"); + if (input.fail()) + fail(std::format( + "Failed to read compressed BSA folder record: {}", std::generic_category().message(errno))); + + folders.emplace_back(std::move(folder), std::vector()); + } // file record blocks if ((mHeader.mFlags & ArchiveFlag_FolderNames) == 0) @@ -126,20 +128,29 @@ namespace Bsa mHeader.mFolderNamesLength -= size; } - filelist.resize(folder.mCount); - for (auto& file : filelist) + filelist.reserve(folder.mCount); + + for (std::uint32_t i = 0; i < folder.mCount; ++i) { + FileRecord file; + input.read(reinterpret_cast(&file.mHash), 8); input.read(reinterpret_cast(&file.mSize), 4); input.read(reinterpret_cast(&file.mOffset), 4); + + if (input.fail()) + fail(std::format("Failed to read compressed BSA folder file record: {}", + std::generic_category().message(errno))); + + filelist.push_back(std::move(file)); } } if (mHeader.mFolderNamesLength != 0) input.ignore(mHeader.mFolderNamesLength); - if (input.bad()) - fail("Failed to read compressed BSA file records: input error"); + if (input.fail()) + fail(std::format("Failed to read compressed BSA file records: {}", std::generic_category().message(errno))); if ((mHeader.mFlags & ArchiveFlag_FileNames) != 0) { @@ -168,36 +179,42 @@ namespace Bsa if (mHeader.mFileNamesLength != 0) input.ignore(mHeader.mFileNamesLength); - if (input.bad()) - fail("Failed to read compressed BSA filenames: input error"); + if (input.fail()) + fail(std::format("Failed to read compressed BSA filenames: {}", std::generic_category().message(errno))); for (auto& [folder, filelist] : folders) { std::map fileMap; - for (const auto& file : filelist) + + for (auto& file : filelist) fileMap[file.mHash] = std::move(file); - auto& folderMap = mFolders[folder.mHash]; - folderMap = FolderRecord{ folder.mCount, folder.mOffset, std::move(fileMap) }; - for (auto& [hash, fileRec] : folderMap.mFiles) + + mFolders[folder.mHash] = FolderRecord{ folder.mCount, folder.mOffset, folder.mName, std::move(fileMap) }; + } + + for (auto& [folderHash, folderRecord] : mFolders) + { + for (auto& [fileHash, fileRecord] : folderRecord.mFiles) { FileStruct fileStruct{}; - fileStruct.fileSize = fileRec.mSize & (~FileSizeFlag_Compression); - fileStruct.offset = fileRec.mOffset; - fileStruct.setNameInfos(0, &fileRec.mName); - mFiles.emplace_back(fileStruct); + fileStruct.mFileSize = fileRecord.mSize & (~FileSizeFlag_Compression); + fileStruct.mOffset = fileRecord.mOffset; + fileStruct.mNameOffset = 0; + fileStruct.mNameSize + = fileRecord.mName.empty() ? 0 : static_cast(fileRecord.mName.size() - 1); + fileStruct.mNamesBuffer = &fileRecord.mName; + mFiles.push_back(fileStruct); } } - - mIsLoaded = true; } - CompressedBSAFile::FileRecord CompressedBSAFile::getFileRecord(const std::string& str) const + CompressedBSAFile::FileRecord CompressedBSAFile::getFileRecord(std::string_view str) const { for (const auto c : str) { if (((static_cast(c) >> 7U) & 1U) != 0U) { - fail("File record " + str + " contains unicode characters, refusing to load."); + fail(std::format("File record {} contains unicode characters, refusing to load.", str)); } } @@ -207,7 +224,7 @@ namespace Bsa // Force-convert the path into something UNIX can handle first // to make sure std::filesystem::path doesn't think the entire path is the filename on Linux // and subsequently purge it to determine the file folder. - std::string path = str; + std::string path(str); std::replace(path.begin(), path.end(), '\\', '/'); #endif diff --git a/components/bsa/compressedbsafile.hpp b/components/bsa/compressedbsafile.hpp index 1e359ea3fee..6eae44cec13 100644 --- a/components/bsa/compressedbsafile.hpp +++ b/components/bsa/compressedbsafile.hpp @@ -36,7 +36,7 @@ namespace Bsa { class CompressedBSAFile : private BSAFile { - private: + public: enum ArchiveFlags { ArchiveFlag_FolderNames = 0x0001, @@ -89,8 +89,6 @@ namespace Bsa std::uint32_t mFileFlags; }; - Header mHeader; - struct FileRecord { std::uint64_t mHash; @@ -103,12 +101,15 @@ namespace Bsa { std::uint32_t mCount; std::int64_t mOffset; + std::string mName; std::map mFiles; }; + private: + Header mHeader; std::map mFolders; - FileRecord getFileRecord(const std::string& str) const; + FileRecord getFileRecord(std::string_view str) const; /// \brief Normalizes given filename or folder and generates format-compatible hash. static std::uint64_t generateHash(const std::filesystem::path& stem, std::string extension); @@ -124,7 +125,7 @@ namespace Bsa virtual ~CompressedBSAFile() = default; /// Read header information from the input source - void readHeader() override; + void readHeader(std::istream& input) override; Files::IStreamPtr getFile(const char* filePath); Files::IStreamPtr getFile(const FileStruct* fileStruct); diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp index 90bdac16102..6ea4f9c66ae 100644 --- a/components/compiler/lineparser.cpp +++ b/components/compiler/lineparser.cpp @@ -481,7 +481,7 @@ namespace Compiler } void GetArgumentsFromMessageFormat::visitedPlaceholder( - Placeholder placeholder, char /*padding*/, int /*width*/, int /*precision*/, Notation /*notation*/) + Placeholder placeholder, int /*flags*/, int /*width*/, int /*precision*/, Notation /*notation*/) { switch (placeholder) { diff --git a/components/compiler/lineparser.hpp b/components/compiler/lineparser.hpp index 68b3198ff26..67ad8e7603e 100644 --- a/components/compiler/lineparser.hpp +++ b/components/compiler/lineparser.hpp @@ -88,7 +88,7 @@ namespace Compiler protected: void visitedPlaceholder( - Placeholder placeholder, char padding, int width, int precision, Notation notation) override; + Placeholder placeholder, int flags, int width, int precision, Notation notation) override; void visitedCharacter(char c) override {} public: diff --git a/components/esm3/activespells.hpp b/components/esm3/activespells.hpp index 19e1f53be52..3058e8e4dec 100644 --- a/components/esm3/activespells.hpp +++ b/components/esm3/activespells.hpp @@ -26,7 +26,8 @@ namespace ESM Flag_Remove = 1 << 1, Flag_Ignore_Resistances = 1 << 2, Flag_Ignore_Reflect = 1 << 3, - Flag_Ignore_SpellAbsorption = 1 << 4 + Flag_Ignore_SpellAbsorption = 1 << 4, + Flag_Invalid = 1 << 5 }; int32_t mEffectId; diff --git a/components/esm3/formatversion.hpp b/components/esm3/formatversion.hpp index c205f2fbb72..f25cdca4bf6 100644 --- a/components/esm3/formatversion.hpp +++ b/components/esm3/formatversion.hpp @@ -31,9 +31,7 @@ namespace ESM inline constexpr FormatVersion CurrentSaveGameFormatVersion = 34; inline constexpr FormatVersion MinSupportedSaveGameFormatVersion = 5; - inline constexpr FormatVersion OpenMW0_48SaveGameFormatVersion = 21; - inline constexpr FormatVersion OpenMW0_49SaveGameFormatVersion = 34; - inline constexpr FormatVersion OpenMW0_50SaveGameFormatVersion = CurrentSaveGameFormatVersion; + inline constexpr FormatVersion OpenMW0_49MinSaveGameFormatVersion = 5; } #endif diff --git a/components/files/qtconversion.cpp b/components/files/qtconversion.cpp index d56832cb78d..36dab522a67 100644 --- a/components/files/qtconversion.cpp +++ b/components/files/qtconversion.cpp @@ -1,8 +1,9 @@ - #include "qtconversion.hpp" #include +#include + QString Files::pathToQString(const std::filesystem::path& path) { const auto tmp = path.u8string(); @@ -17,12 +18,10 @@ QString Files::pathToQString(std::filesystem::path&& path) std::filesystem::path Files::pathFromQString(QStringView path) { - const auto tmp = path.toUtf8(); - return std::filesystem::path{ Misc::StringUtils::stringToU8String(tmp) }; + return std::filesystem::path(std::u16string_view(path.utf16(), path.size())); } std::filesystem::path Files::pathFromQString(QString&& path) { - const auto tmp = path.toUtf8(); - return std::filesystem::path{ Misc::StringUtils::stringToU8String(tmp) }; + return std::filesystem::path(path.toStdU16String()); } diff --git a/components/files/utils.hpp b/components/files/utils.hpp new file mode 100644 index 00000000000..732a7d39cde --- /dev/null +++ b/components/files/utils.hpp @@ -0,0 +1,38 @@ +#ifndef COMPONENTS_FILES_UTILS_H +#define COMPONENTS_FILES_UTILS_H + +#include +#include +#include +#include +#include + +namespace Files +{ + inline std::streamsize getStreamSizeLeft(std::istream& stream) + { + const auto begin = stream.tellg(); + if (stream.fail()) + throw std::runtime_error( + std::format("Failed to get current file position: {}", std::generic_category().message(errno))); + + stream.seekg(0, std::ios_base::end); + if (stream.fail()) + throw std::runtime_error( + std::format("Failed to seek end file position: {}", std::generic_category().message(errno))); + + const auto end = stream.tellg(); + if (stream.fail()) + throw std::runtime_error( + std::format("Failed to get current file position: {}", std::generic_category().message(errno))); + + stream.seekg(begin); + if (stream.fail()) + throw std::runtime_error( + std::format("Failed to seek original file position: {}", std::generic_category().message(errno))); + + return end - begin; + } +} + +#endif diff --git a/components/fx/technique.cpp b/components/fx/technique.cpp index 945a3cf1b1b..75b166a5e86 100644 --- a/components/fx/technique.cpp +++ b/components/fx/technique.cpp @@ -241,7 +241,7 @@ namespace Fx else if (key == "author") mAuthor = parseString(); else if (key == "glsl_version") - mGLSLVersion = std::max(mGLSLVersion, parseInteger()); + mGLSLVersion = std::min(mGLSLVersion, parseInteger()); else if (key == "flags") mFlags = parseFlags(); else if (key == "hdr") diff --git a/components/interpreter/miscopcodes.hpp b/components/interpreter/miscopcodes.hpp index 0b49b3c2486..05791617a66 100644 --- a/components/interpreter/miscopcodes.hpp +++ b/components/interpreter/miscopcodes.hpp @@ -2,8 +2,7 @@ #define INTERPRETER_MISCOPCODES_H_INCLUDED #include -#include -#include +#include #include #include @@ -23,78 +22,84 @@ namespace Interpreter protected: void visitedPlaceholder( - Placeholder placeholder, char padding, int width, int precision, Notation notation) override + Placeholder placeholder, int flags, int width, int precision, Notation notation) override { - std::ostringstream out; - out.fill(padding); - if (width != -1) - out.width(width); - if (precision != -1) - out.precision(precision); - - switch (placeholder) + std::string formatString; + + if (placeholder == StringPlaceholder) { - case StringPlaceholder: + int index = mRuntime[0].mInteger; + mRuntime.pop(); + + std::string_view value = mRuntime.getStringLiteral(index); + if (precision >= 0) + value = value.substr(0, static_cast(precision)); + if (width < 0) + mFormattedMessage += value; + else { - int index = mRuntime[0].mInteger; - mRuntime.pop(); - - out << mRuntime.getStringLiteral(index); - mFormattedMessage += out.str(); + formatString = "{:"; + if (flags & PrependZero) + formatString += '0'; + if (flags & AlignLeft) + formatString += '<'; + else + formatString += '>'; + formatString += "{}}"; + std::vformat_to( + std::back_inserter(mFormattedMessage), formatString, std::make_format_args(value, width)); } - break; - case IntegerPlaceholder: + } + else + { + formatString = "{:"; + if (flags & AlignLeft) + formatString += '<'; + if (flags & PositiveSign) + formatString += '+'; + else if (flags & PositiveSpace) + formatString += ' '; + if (flags & AlternateForm) + formatString += '#'; + if (flags & PrependZero) + formatString += '0'; + if (width >= 0) + formatString += "{}"; + if (placeholder == FloatPlaceholder) { - Type_Integer value = mRuntime[0].mInteger; - mRuntime.pop(); - - out << value; - mFormattedMessage += out.str(); + if (precision >= 0) + formatString += ".{}"; + formatString += static_cast(notation); } - break; - case FloatPlaceholder: + else + precision = -1; + formatString += '}'; + const auto appendMessage = [&](auto value) { + if (width >= 0 && precision >= 0) + std::vformat_to(std::back_inserter(mFormattedMessage), formatString, + std::make_format_args(value, width, precision)); + else if (width >= 0) + std::vformat_to( + std::back_inserter(mFormattedMessage), formatString, std::make_format_args(value, width)); + else if (precision >= 0) + std::vformat_to(std::back_inserter(mFormattedMessage), formatString, + std::make_format_args(value, precision)); + else + std::vformat_to( + std::back_inserter(mFormattedMessage), formatString, std::make_format_args(value)); + }; + if (placeholder == FloatPlaceholder) { float value = mRuntime[0].mFloat; mRuntime.pop(); - - if (notation == Notation::Fixed) - { - out << std::fixed << value; - mFormattedMessage += out.str(); - } - else if (notation == Notation::Shortest) - { - out << value; - std::string standard = out.str(); - - out.str(std::string()); - out.clear(); - - out << std::scientific << value; - std::string scientific = out.str(); - - mFormattedMessage += standard.length() < scientific.length() ? standard : scientific; - } - // TODO switch to std::format so the precision argument applies to these two - else if (notation == Notation::HexLower) - { - out << std::hexfloat << value; - mFormattedMessage += out.str(); - } - else if (notation == Notation::HexUpper) - { - out << std::uppercase << std::hexfloat << value; - mFormattedMessage += out.str(); - } - else - { - out << std::scientific << value; - mFormattedMessage += out.str(); - } + appendMessage(value); + } + else + { + Type_Integer value = mRuntime[0].mInteger; + mRuntime.pop(); + appendMessage(value); } - break; - default: - break; } } diff --git a/components/lua/luastate.hpp b/components/lua/luastate.hpp index 178d19aef2d..1a432ec749c 100644 --- a/components/lua/luastate.hpp +++ b/components/lua/luastate.hpp @@ -50,7 +50,8 @@ namespace LuaUtil } public: - friend class LuaState; + template + friend int invokeProtectedCall(lua_State*, Function&&); // Returns underlying sol::state. sol::state_view& sol() { return mSol; } @@ -67,6 +68,45 @@ namespace LuaUtil return res; } + // Pushing to the stack from outside a Lua context crashes the engine if no memory can be allocated to grow the + // stack + template + [[nodiscard]] int invokeProtectedCall(lua_State* luaState, Function&& function) + { + if (!lua_checkstack(luaState, 2)) + return LUA_ERRMEM; + lua_pushcfunction(luaState, [](lua_State* state) { + void* f = lua_touserdata(state, 1); + LuaView view(state); + (*static_cast(f))(view); + return 0; + }); + lua_pushlightuserdata(luaState, &function); + return lua_pcall(luaState, 1, 0, 0); + } + + template + void protectedCall(lua_State* luaState, Lambda&& f) + { + int result = invokeProtectedCall(luaState, std::forward(f)); + switch (result) + { + case LUA_OK: + break; + case LUA_ERRMEM: + throw std::runtime_error("Lua error: out of memory"); + case LUA_ERRRUN: + { + sol::optional error = sol::stack::check_get(luaState); + if (error) + throw std::runtime_error(*error); + } + [[fallthrough]]; + default: + throw std::runtime_error("Lua error: " + std::to_string(result)); + } + } + // Holds Lua state. // Provides additional features: // - Load scripts from the virtual filesystem; @@ -87,43 +127,10 @@ namespace LuaUtil LuaState(const LuaState&) = delete; LuaState(LuaState&&) = delete; - // Pushing to the stack from outside a Lua context crashes the engine if no memory can be allocated to grow the - // stack - template - [[nodiscard]] int invokeProtectedCall(Function&& function) const - { - if (!lua_checkstack(mSol.lua_state(), 2)) - return LUA_ERRMEM; - lua_pushcfunction(mSol.lua_state(), [](lua_State* state) { - void* f = lua_touserdata(state, 1); - LuaView view(state); - (*static_cast(f))(view); - return 0; - }); - lua_pushlightuserdata(mSol.lua_state(), &function); - return lua_pcall(mSol.lua_state(), 1, 0, 0); - } - template void protectedCall(Lambda&& f) const { - int result = invokeProtectedCall(std::forward(f)); - switch (result) - { - case LUA_OK: - break; - case LUA_ERRMEM: - throw std::runtime_error("Lua error: out of memory"); - case LUA_ERRRUN: - { - sol::optional error = sol::stack::check_get(mSol.lua_state()); - if (error) - throw std::runtime_error(*error); - } - [[fallthrough]]; - default: - throw std::runtime_error("Lua error: " + std::to_string(result)); - } + LuaUtil::protectedCall(mSol.lua_state(), std::forward(f)); } // Note that constructing a sol::state_view is only safe from a Lua context. Use protectedCall to get one diff --git a/components/lua/scriptscontainer.cpp b/components/lua/scriptscontainer.cpp index f5b5605e374..6f58e72dd08 100644 --- a/components/lua/scriptscontainer.cpp +++ b/components/lua/scriptscontainer.cpp @@ -47,7 +47,7 @@ namespace LuaUtil } } - void ScriptsContainer::printError(int scriptId, std::string_view msg, const std::exception& e) + void ScriptsContainer::printError(int scriptId, std::string_view msg, const std::exception& e) const { Log(Debug::Error) << mNamePrefix << "[" << scriptPath(scriptId) << "] " << msg << ": " << e.what(); } @@ -408,7 +408,17 @@ namespace LuaUtil void ScriptsContainer::save(ESM::LuaScripts& data) { - if (UnloadedData* unloadedData = std::get_if(&mData)) + if (const UnloadedData* unloadedData = std::get_if(&mData)) + { + data.mScripts = unloadedData->mScripts; + return; + } + mLua.protectedCall([&](LuaView& view) { save(view, data); }); + } + + void ScriptsContainer::save(LuaView&, ESM::LuaScripts& data) + { + if (const UnloadedData* unloadedData = std::get_if(&mData)) { data.mScripts = unloadedData->mScripts; return; @@ -614,12 +624,12 @@ namespace LuaUtil return data; } - ScriptsContainer::UnloadedData& ScriptsContainer::ensureUnloaded(LuaView&) + ScriptsContainer::UnloadedData& ScriptsContainer::ensureUnloaded(LuaView& view) { if (UnloadedData* data = std::get_if(&mData)) return *data; UnloadedData data; - save(data); + save(view, data); mAPI.erase("openmw.interfaces"); UnloadedData& out = mData.emplace(std::move(data)); for (auto& [_, handlers] : mEngineHandlers) @@ -751,9 +761,11 @@ namespace LuaUtil void ScriptsContainer::processTimers(double simulationTime, double gameTime) { - LoadedData& data = ensureLoaded(); - updateTimerQueue(data.mSimulationTimersQueue, simulationTime); - updateTimerQueue(data.mGameTimersQueue, gameTime); + mLua.protectedCall([&](LuaView& view) { + LoadedData& data = ensureLoaded(); + updateTimerQueue(data.mSimulationTimersQueue, simulationTime); + updateTimerQueue(data.mGameTimersQueue, gameTime); + }); } static constexpr float instructionCountAvgCoef = 1.0f / 30; // averaging over approximately 30 frames diff --git a/components/lua/scriptscontainer.hpp b/components/lua/scriptscontainer.hpp index 8eaaf2955f4..fe036bae8ee 100644 --- a/components/lua/scriptscontainer.hpp +++ b/components/lua/scriptscontainer.hpp @@ -271,7 +271,7 @@ namespace LuaUtil // Returns script by id (throws an exception if doesn't exist) Script& getScript(int scriptId); - void printError(int scriptId, std::string_view msg, const std::exception& e); + void printError(int scriptId, std::string_view msg, const std::exception& e) const; const VFS::Path::Normalized& scriptPath(int scriptId) const { @@ -286,6 +286,7 @@ namespace LuaUtil static void removeHandler(std::vector& list, int scriptId); void insertInterface(int scriptId, const Script& script); void removeInterface(int scriptId, const Script& script); + void save(LuaView&, ESM::LuaScripts&); ScriptIdsWithInitializationData mAutoStartScripts; const UserdataSerializer* mSerializer = nullptr; diff --git a/components/lua/util.hpp b/components/lua/util.hpp index 2b84d9d60ca..d3cb7648314 100644 --- a/components/lua/util.hpp +++ b/components/lua/util.hpp @@ -2,7 +2,6 @@ #define COMPONENTS_LUA_UTIL_H #include -#include #include @@ -20,13 +19,15 @@ namespace LuaUtil { return i + 1; } +} - inline sol::optional serializeRefId(ESM::RefId id) - { - if (id.empty()) - return sol::nullopt; - return id.serializeText(); - } +// ADL-based customization point for sol2 to automatically convert ESM::RefId +// Empty RefIds are converted to nil, non-empty ones are serialized to strings +inline int sol_lua_push(sol::types, lua_State* state, const ESM::RefId& id) +{ + if (id.empty()) + return sol::stack::push(state, sol::lua_nil); + return sol::stack::push(state, id.serializeText()); } #endif diff --git a/components/lua/utilpackage.cpp b/components/lua/utilpackage.cpp index 0117934deff..c4a8230def5 100644 --- a/components/lua/utilpackage.cpp +++ b/components/lua/utilpackage.cpp @@ -8,6 +8,9 @@ #include #include +#include + +#include #include "luastate.hpp" #include "util.hpp" @@ -243,6 +246,28 @@ namespace LuaUtil color["rgba"] = [](float r, float g, float b, float a) { return Misc::Color(r, g, b, a); }; color["rgb"] = [](float r, float g, float b) { return Misc::Color(r, g, b, 1); }; color["hex"] = [](std::string_view hex) { return Misc::Color::fromHex(hex); }; + color["commaString"] = [](std::string_view str) { + int wrongChars = std::count_if( + str.begin(), str.end(), [](unsigned char c) { return !std::isdigit(c) && c != ' ' && c != ','; }); + + if (wrongChars != 0) + { + throw std::runtime_error("Invalid comma-separated color: " + std::string(str)); + } + + std::vector rgba; + Misc::StringUtils::split(str, rgba, ","); + if (rgba.size() != 3 && rgba.size() != 4) + { + throw std::runtime_error("Invalid comma-separated color: " + std::string(str)); + } + + if (rgba.size() == 3) + rgba.push_back("255"); + + return Misc::Color(MyGUI::utility::parseInt(rgba[0]) / 255.f, MyGUI::utility::parseInt(rgba[1]) / 255.f, + MyGUI::utility::parseInt(rgba[2]) / 255.f, MyGUI::utility::parseInt(rgba[3]) / 255.f); + }; util["color"] = LuaUtil::makeReadOnly(color); // Lua bindings for Transform diff --git a/components/lua_ui/element.cpp b/components/lua_ui/element.cpp index ce6d57e1542..e54993cfc7f 100644 --- a/components/lua_ui/element.cpp +++ b/components/lua_ui/element.cpp @@ -296,6 +296,7 @@ namespace LuaUi children.erase(it); parent->setChildren(children); mRoot = nullptr; + mState = New; throw; } parent->setChildren(children); diff --git a/components/lua_ui/textedit.cpp b/components/lua_ui/textedit.cpp index 9bd241884a8..43f7c09cce3 100644 --- a/components/lua_ui/textedit.cpp +++ b/components/lua_ui/textedit.cpp @@ -46,7 +46,9 @@ namespace LuaUi void LuaTextEdit::textChange(MyGUI::EditBox*) { - triggerEvent("textChanged", sol::make_object(lua(), mEditBox->getCaption().asUTF8())); + protectedCall([this](LuaUtil::LuaView& view) { + triggerEvent("textChanged", sol::make_object(view.sol(), mEditBox->getCaption().asUTF8())); + }); } void LuaTextEdit::updateCoord() diff --git a/components/lua_ui/widget.cpp b/components/lua_ui/widget.cpp index a126fd9f7ba..ec951f36107 100644 --- a/components/lua_ui/widget.cpp +++ b/components/lua_ui/widget.cpp @@ -105,7 +105,7 @@ namespace LuaUi if (ext->mParent) { auto children = ext->mParent->children(); - std::erase(children, this); + std::erase(children, ext); ext->mParent->setChildren(children); } ext->detachFromParent(); @@ -169,27 +169,22 @@ namespace LuaUi return result; } - sol::table WidgetExtension::makeTable() const - { - return sol::table(lua(), sol::create); - } - - sol::object WidgetExtension::keyEvent(MyGUI::KeyCode code) const + sol::object WidgetExtension::keyEvent(LuaUtil::LuaView& view, MyGUI::KeyCode code) const { auto keySym = SDL_Keysym(); keySym.sym = SDLUtil::myGuiKeyToSdl(code); keySym.scancode = SDL_GetScancodeFromKey(keySym.sym); keySym.mod = SDL_GetModState(); - return sol::make_object(lua(), keySym); + return sol::make_object(view.sol(), keySym); } sol::object WidgetExtension::mouseEvent( - int left, int top, MyGUI::MouseButton button = MyGUI::MouseButton::None) const + LuaUtil::LuaView& view, int left, int top, MyGUI::MouseButton button = MyGUI::MouseButton::None) const { osg::Vec2f position(left, top); MyGUI::IntPoint absolutePosition = mWidget->getAbsolutePosition(); osg::Vec2f offset = position - osg::Vec2f(absolutePosition.left, absolutePosition.top); - sol::table table = makeTable(); + sol::table table = view.newTable(); int sdlButton = SDLUtil::myGuiMouseButtonToSdl(button); table["position"] = position; table["offset"] = offset; @@ -372,31 +367,39 @@ namespace LuaUi void WidgetExtension::keyPress(MyGUI::Widget*, MyGUI::KeyCode code, MyGUI::Char ch) { - if (code == MyGUI::KeyCode::None) - { - propagateEvent("textInput", [ch](auto w) { - MyGUI::UString uString; - uString.push_back(static_cast(ch)); - return sol::make_object(w->lua(), uString.asUTF8()); - }); - } - else - propagateEvent("keyPress", [code](auto w) { return w->keyEvent(code); }); + protectedCall([=, this](LuaUtil::LuaView& view) { + if (code == MyGUI::KeyCode::None) + { + propagateEvent("textInput", [&](auto w) { + MyGUI::UString uString; + uString.push_back(static_cast(ch)); + return sol::make_object(view.sol(), uString.asUTF8()); + }); + } + else + propagateEvent("keyPress", [&](auto w) { return w->keyEvent(view, code); }); + }); } void WidgetExtension::keyRelease(MyGUI::Widget*, MyGUI::KeyCode code) { - propagateEvent("keyRelease", [code](auto w) { return w->keyEvent(code); }); + protectedCall([=, this](LuaUtil::LuaView& view) { + propagateEvent("keyRelease", [&](auto w) { return w->keyEvent(view, code); }); + }); } void WidgetExtension::mouseMove(MyGUI::Widget*, int left, int top) { - propagateEvent("mouseMove", [left, top](auto w) { return w->mouseEvent(left, top); }); + protectedCall([=, this](LuaUtil::LuaView& view) { + propagateEvent("mouseMove", [&](auto w) { return w->mouseEvent(view, left, top); }); + }); } void WidgetExtension::mouseDrag(MyGUI::Widget*, int left, int top, MyGUI::MouseButton button) { - propagateEvent("mouseMove", [left, top, button](auto w) { return w->mouseEvent(left, top, button); }); + protectedCall([=, this](LuaUtil::LuaView& view) { + propagateEvent("mouseMove", [&](auto w) { return w->mouseEvent(view, left, top, button); }); + }); } void WidgetExtension::mouseClick(MyGUI::Widget* /*widget*/) @@ -411,12 +414,16 @@ namespace LuaUi void WidgetExtension::mousePress(MyGUI::Widget*, int left, int top, MyGUI::MouseButton button) { - propagateEvent("mousePress", [left, top, button](auto w) { return w->mouseEvent(left, top, button); }); + protectedCall([=, this](LuaUtil::LuaView& view) { + propagateEvent("mousePress", [&](auto w) { return w->mouseEvent(view, left, top, button); }); + }); } void WidgetExtension::mouseRelease(MyGUI::Widget*, int left, int top, MyGUI::MouseButton button) { - propagateEvent("mouseRelease", [left, top, button](auto w) { return w->mouseEvent(left, top, button); }); + protectedCall([=, this](LuaUtil::LuaView& view) { + propagateEvent("mouseRelease", [&](auto w) { return w->mouseEvent(view, left, top, button); }); + }); } void WidgetExtension::focusGain(MyGUI::Widget*, MyGUI::Widget*) diff --git a/components/lua_ui/widget.hpp b/components/lua_ui/widget.hpp index 5fcf86d110a..c20f70587ea 100644 --- a/components/lua_ui/widget.hpp +++ b/components/lua_ui/widget.hpp @@ -83,9 +83,8 @@ namespace LuaUi void registerEvents(MyGUI::Widget* w); void clearEvents(MyGUI::Widget* w); - sol::table makeTable() const; - sol::object keyEvent(MyGUI::KeyCode) const; - sol::object mouseEvent(int left, int top, MyGUI::MouseButton button) const; + sol::object keyEvent(LuaUtil::LuaView& view, MyGUI::KeyCode) const; + sol::object mouseEvent(LuaUtil::LuaView& view, int left, int top, MyGUI::MouseButton button) const; MyGUI::IntSize parentSize() const; virtual MyGUI::IntSize childScalingSize() const; @@ -104,7 +103,11 @@ namespace LuaUi virtual void updateProperties(); virtual void updateChildren() {} - lua_State* lua() const { return mLua; } + template + void protectedCall(Lambda&& f) const + { + LuaUtil::protectedCall(mLua, std::forward(f)); + } void triggerEvent(std::string_view name, sol::object argument) const; template diff --git a/components/lua_ui/window.cpp b/components/lua_ui/window.cpp index a06da149727..ca8244394b6 100644 --- a/components/lua_ui/window.cpp +++ b/components/lua_ui/window.cpp @@ -78,9 +78,11 @@ namespace LuaUi mPreviousMouse.left = left; mPreviousMouse.top = top; - sol::table table = makeTable(); - table["position"] = osg::Vec2f(mCoord.left, mCoord.top); - table["size"] = osg::Vec2f(mCoord.width, mCoord.height); - triggerEvent("windowDrag", table); + protectedCall([this](LuaUtil::LuaView& view) { + sol::table table = view.newTable(); + table["position"] = osg::Vec2f(mCoord.left, mCoord.top); + table["size"] = osg::Vec2f(mCoord.width, mCoord.height); + triggerEvent("windowDrag", table); + }); } } diff --git a/components/misc/messageformatparser.cpp b/components/misc/messageformatparser.cpp index 649d0184d3d..67ac07011cf 100644 --- a/components/misc/messageformatparser.cpp +++ b/components/misc/messageformatparser.cpp @@ -27,58 +27,71 @@ namespace Misc { for (std::size_t i = 0; i < m.size(); ++i) { + if (m[i] != '%') + { + visitedCharacter(m[i]); + continue; + } + if (++i == m.size()) + break; if (m[i] == '%') { - if (++i < m.size()) - { - if (m[i] == '%') - visitedCharacter('%'); - else - { - char pad = ' '; - if (m[i] == '0' || m[i] == ' ') - { - pad = m[i]; - ++i; - } + visitedCharacter('%'); + continue; + } - int width = parseNumber(i, m, -1); + int flags = None; + while (i < m.size()) + { + if (m[i] == '-') + flags |= AlignLeft; + else if (m[i] == '+') + flags |= PositiveSign; + else if (m[i] == ' ') + flags |= PositiveSpace; + else if (m[i] == '0') + flags |= PrependZero; + else if (m[i] == '#') + flags |= AlternateForm; + else + break; + ++i; + } - if (i < m.size()) - { - int precision = -1; - if (m[i] == '.') - { - ++i; - precision = parseNumber(i, m, 0); - } + int width = parseNumber(i, m, -1); - if (i < m.size()) - { - if (m[i] == 'S' || m[i] == 's') - visitedPlaceholder(StringPlaceholder, pad, width, precision, Notation::Fixed); - else if (m[i] == 'd' || m[i] == 'i') - visitedPlaceholder(IntegerPlaceholder, pad, width, precision, Notation::Fixed); - else if (m[i] == 'f' || m[i] == 'F') - visitedPlaceholder(FloatPlaceholder, pad, width, precision, Notation::Fixed); - else if (m[i] == 'e' || m[i] == 'E') - visitedPlaceholder(FloatPlaceholder, pad, width, precision, Notation::Scientific); - else if (m[i] == 'g' || m[i] == 'G') - visitedPlaceholder(FloatPlaceholder, pad, width, precision, Notation::Shortest); - else if (m[i] == 'a') - visitedPlaceholder(FloatPlaceholder, pad, width, precision, Notation::HexLower); - else if (m[i] == 'A') - visitedPlaceholder(FloatPlaceholder, pad, width, precision, Notation::HexUpper); - else - visitedCharacter(m[i]); - } - } - } - } - } - else + if (i < m.size()) { - visitedCharacter(m[i]); + int precision = -1; + if (m[i] == '.') + { + ++i; + precision = parseNumber(i, m, 0); + } + + if (i < m.size()) + { + if (m[i] == 'S' || m[i] == 's') + visitedPlaceholder(StringPlaceholder, flags, width, precision, Notation::Fixed); + else if (m[i] == 'd' || m[i] == 'i') + visitedPlaceholder(IntegerPlaceholder, flags, width, precision, Notation::Fixed); + else if (m[i] == 'f' || m[i] == 'F') + visitedPlaceholder(FloatPlaceholder, flags, width, precision, Notation::Fixed); + else if (m[i] == 'e') + visitedPlaceholder(FloatPlaceholder, flags, width, precision, Notation::ScientificLower); + else if (m[i] == 'E') + visitedPlaceholder(FloatPlaceholder, flags, width, precision, Notation::ScientificUpper); + else if (m[i] == 'g') + visitedPlaceholder(FloatPlaceholder, flags, width, precision, Notation::ShortestLower); + else if (m[i] == 'G') + visitedPlaceholder(FloatPlaceholder, flags, width, precision, Notation::ShortestUpper); + else if (m[i] == 'a') + visitedPlaceholder(FloatPlaceholder, flags, width, precision, Notation::HexLower); + else if (m[i] == 'A') + visitedPlaceholder(FloatPlaceholder, flags, width, precision, Notation::HexUpper); + else + visitedCharacter(m[i]); + } } } } diff --git a/components/misc/messageformatparser.hpp b/components/misc/messageformatparser.hpp index eeef29234d5..99a42d27394 100644 --- a/components/misc/messageformatparser.hpp +++ b/components/misc/messageformatparser.hpp @@ -15,17 +15,28 @@ namespace Misc FloatPlaceholder }; - enum class Notation + enum Flags { - Fixed, - Scientific, - Shortest, - HexUpper, - HexLower + None = 0, + PositiveSpace = 1, + PositiveSign = 2, + AlignLeft = 4, + PrependZero = 8, + AlternateForm = 16 }; - virtual void visitedPlaceholder( - Placeholder placeholder, char padding, int width, int precision, Notation notation) + enum class Notation : char + { + Fixed = 'f', + ScientificUpper = 'E', + ScientificLower = 'e', + ShortestUpper = 'G', + ShortestLower = 'g', + HexUpper = 'A', + HexLower = 'a' + }; + + virtual void visitedPlaceholder(Placeholder placeholder, int flags, int width, int precision, Notation notation) = 0; virtual void visitedCharacter(char c) = 0; diff --git a/components/nif/physics.cpp b/components/nif/physics.cpp index 6368537e60e..f855edb30a0 100644 --- a/components/nif/physics.cpp +++ b/components/nif/physics.cpp @@ -770,6 +770,11 @@ namespace Nif filter.read(nif); } + void bhkListShape::post(Reader& nif) + { + postRecordList(nif, mSubshapes); + } + void bhkCompressedMeshShape::read(NIFStream* nif) { mTarget.read(nif); diff --git a/components/nif/physics.hpp b/components/nif/physics.hpp index 286c8cc3536..d3ac22b4b84 100644 --- a/components/nif/physics.hpp +++ b/components/nif/physics.hpp @@ -730,6 +730,7 @@ namespace Nif std::vector mHavokFilters; void read(NIFStream* nif) override; + void post(Reader& nif) override; }; struct bhkCompressedMeshShape : public bhkShape diff --git a/components/resource/imagemanager.cpp b/components/resource/imagemanager.cpp index b7a19b4d521..f2655f3b1d0 100644 --- a/components/resource/imagemanager.cpp +++ b/components/resource/imagemanager.cpp @@ -16,6 +16,7 @@ USE_OSGPLUGIN(png) USE_OSGPLUGIN(tga) USE_OSGPLUGIN(dds) +USE_OSGPLUGIN(ktx) USE_OSGPLUGIN(jpeg) USE_OSGPLUGIN(bmp) USE_OSGPLUGIN(osg) diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 84ba08c0b37..ffa6abe58e6 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -446,15 +446,6 @@ namespace Resource Resource::NifFileManager* nifFileManager, Resource::BgsmFileManager* bgsmFileManager, double expiryDelay) : ResourceManager(vfs, expiryDelay) , mShaderManager(new Shader::ShaderManager) - , mForceShaders(false) - , mClampLighting(true) - , mAutoUseNormalMaps(false) - , mAutoUseSpecularMaps(false) - , mApplyLightingToEnvMaps(false) - , mLightingMethod(SceneUtil::LightingMethod::FFP) - , mConvertAlphaTestToAlphaToCoverage(false) - , mAdjustCoverageForAlphaTest(false) - , mSupportsNormalsRT(false) , mSharedStateManager(new SharedStateManager) , mImageManager(imageManager) , mNifFileManager(nifFileManager) @@ -462,8 +453,8 @@ namespace Resource , mMinFilter(osg::Texture::LINEAR_MIPMAP_LINEAR) , mMagFilter(osg::Texture::LINEAR) , mMaxAnisotropy(1) - , mUnRefImageDataAfterApply(false) , mParticleSystemMask(~0u) + , mLightingMethod(SceneUtil::LightingMethod::FFP) { } @@ -988,8 +979,7 @@ namespace Resource osg::ref_ptr SceneManager::cloneErrorMarker() { - if (!mErrorMarker) - mErrorMarker = loadErrorMarker(); + std::call_once(mErrorMarkerFlag, [this] { mErrorMarker = loadErrorMarker(); }); return static_cast(mErrorMarker->clone(osg::CopyOp::DEEP_COPY_ALL)); } diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index 370383975d1..df37a6165a7 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -237,42 +237,43 @@ namespace Resource osg::ref_ptr loadErrorMarker(); osg::ref_ptr cloneErrorMarker(); + mutable std::mutex mSharedStateMutex; + std::unique_ptr mShaderManager; - bool mForceShaders; - bool mClampLighting; - bool mAutoUseNormalMaps; std::string mNormalMapPattern; std::string mNormalHeightMapPattern; - bool mAutoUseSpecularMaps; std::string mSpecularMapPattern; - bool mApplyLightingToEnvMaps; - SceneUtil::LightingMethod mLightingMethod; - SceneUtil::LightManager::SupportedMethods mSupportedLightingMethods; - bool mConvertAlphaTestToAlphaToCoverage; - bool mAdjustCoverageForAlphaTest; - bool mSupportsNormalsRT; std::array, 2> mOpaqueDepthTex; - bool mWeatherParticleOcclusion = false; osg::ref_ptr mSharedStateManager; - mutable std::mutex mSharedStateMutex; Resource::ImageManager* mImageManager; Resource::NifFileManager* mNifFileManager; Resource::BgsmFileManager* mBgsmFileManager; + osg::ref_ptr mIncrementalCompileOperation; + mutable osg::ref_ptr mErrorMarker; + mutable std::once_flag mErrorMarkerFlag; osg::Texture::FilterMode mMinFilter; osg::Texture::FilterMode mMagFilter; int mMaxAnisotropy; - bool mUnRefImageDataAfterApply; - - osg::ref_ptr mIncrementalCompileOperation; unsigned int mParticleSystemMask; - mutable osg::ref_ptr mErrorMarker; + SceneUtil::LightingMethod mLightingMethod; + SceneUtil::LightManager::SupportedMethods mSupportedLightingMethods; + bool mForceShaders = false; + bool mClampLighting = true; + bool mAutoUseNormalMaps = false; + bool mAutoUseSpecularMaps = false; + bool mApplyLightingToEnvMaps = false; + bool mConvertAlphaTestToAlphaToCoverage = false; + bool mAdjustCoverageForAlphaTest = false; + bool mSupportsNormalsRT = false; + bool mWeatherParticleOcclusion = false; + bool mUnRefImageDataAfterApply = false; - SceneManager(const SceneManager&); - void operator=(const SceneManager&); + SceneManager(const SceneManager&) = delete; + void operator=(const SceneManager&) = delete; }; } diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index 178ea087c0f..7b041df6b36 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -717,6 +717,7 @@ namespace SceneUtil if (!mInitLayout) { +/* mDummyProgram->apply(state); auto handle = mDummyProgram->getPCP(state)->getHandle(); auto* ext = state.get(); @@ -726,8 +727,10 @@ namespace SceneUtil // wait until the UBO binding is created if (activeUniformBlocks > 0) +*/ { - initSharedLayout(ext, handle, frame); + //initSharedLayout(ext, handle, frame); + mTemplate->configureLayout(0, 16, 32, 16384, 0); mInitLayout = true; } } diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 7ee4fb9511a..b874e25fa28 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -90,8 +90,19 @@ static const char fragmentShaderSource_withBaseTexture_twoShadowMaps[] = "} \n"; #endif -std::string debugVertexShaderSource = "void main(void){gl_Position = gl_Vertex; gl_TexCoord[0]=gl_MultiTexCoord0;}"; +//std::string debugVertexShaderSource = "void main(void){gl_Position = gl_Vertex; gl_TexCoord[0]=gl_MultiTexCoord0;}"; +std::string debugVertexShaderSource = + "#version 120 \n" + " \n" + "void main(void) \n" + "{ \n" + " gl_Position = gl_Vertex; \n" + " gl_TexCoord[0]=gl_MultiTexCoord0; \n" + "} \n"; + std::string debugFragmentShaderSource = + "#version 120 \n" + " \n" "uniform sampler2D texture; \n" " \n" "void main(void) \n" @@ -128,8 +139,21 @@ std::string debugFragmentShaderSource = #endif "} \n"; -std::string debugFrustumVertexShaderSource = "varying float depth; uniform mat4 transform; void main(void){gl_Position = transform * gl_Vertex; depth = gl_Position.z / gl_Position.w;}"; +//std::string debugFrustumVertexShaderSource = "varying float depth; uniform mat4 transform; void main(void){gl_Position = transform * gl_Vertex; depth = gl_Position.z / gl_Position.w;}"; +std::string debugFrustumVertexShaderSource = + "#version 120 \n" + " \n" + "varying float depth; \n" + "uniform mat4 transform; \n" + "void main(void) \n" + "{ \n" + " gl_Position = transform * gl_Vertex; \n" + " depth = gl_Position.z / gl_Position.w; \n" + "} \n"; + std::string debugFrustumFragmentShaderSource = + "#version 120 \n" + " \n" "varying float depth; \n" " \n" "void main(void) \n" @@ -553,7 +577,7 @@ MWShadowTechnique::ShadowData::ShadowData(MWShadowTechnique::ViewDependentData* { _texture->setInternalFormat(GL_DEPTH_COMPONENT); _texture->setShadowComparison(true); - _texture->setShadowTextureMode(osg::Texture2D::LUMINANCE); + // _texture->setShadowTextureMode(osg::Texture2D::LUMINANCE); } _texture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR); diff --git a/components/settings/categories/shadows.hpp b/components/settings/categories/shadows.hpp index b6349dfd440..5732471e63b 100644 --- a/components/settings/categories/shadows.hpp +++ b/components/settings/categories/shadows.hpp @@ -42,6 +42,7 @@ namespace Settings SettingValue mTerrainShadows{ mIndex, "Shadows", "terrain shadows" }; SettingValue mObjectShadows{ mIndex, "Shadows", "object shadows" }; SettingValue mEnableIndoorShadows{ mIndex, "Shadows", "enable indoor shadows" }; + SettingValue mPercentageCloserFiltering{ mIndex, "Shadows", "percentage closer filtering" }; }; } diff --git a/components/shader/shadervisitor.cpp b/components/shader/shadervisitor.cpp index 0e6b5e79c63..2430a4f269e 100644 --- a/components/shader/shadervisitor.cpp +++ b/components/shader/shadervisitor.cpp @@ -720,7 +720,10 @@ namespace Shader defineMap["endLight"] = "0"; if (simpleLighting || dynamic_cast(&node)) + { defineMap["forcePPL"] = "0"; + writableStateSet->setDefine("FORCE_PPL", "0", osg::StateAttribute::ON | osg::StateAttribute::PROTECTED); + } bool particleOcclusion = false; node.getUserValue("particleOcclusion", particleOcclusion); diff --git a/components/sqlite3/request.hpp b/components/sqlite3/request.hpp index d4737a41f92..b77e1a5ce81 100644 --- a/components/sqlite3/request.hpp +++ b/components/sqlite3/request.hpp @@ -6,6 +6,7 @@ #include +#include #include #include #include @@ -19,6 +20,12 @@ namespace Sqlite3 { + template + concept StrongTypedef = requires(T v) + { + v.mValue; + }; + inline void bindParameter(sqlite3& db, sqlite3_stmt& stmt, int index, int value) { if (const int ec = sqlite3_bind_int(&stmt, index, value); ec != SQLITE_OK) @@ -93,11 +100,11 @@ namespace Sqlite3 { if (type != SQLITE_NULL) throw std::logic_error("Type of column " + std::to_string(index) + " is " + sqliteTypeToString(type) - + " that does not match expected output type: SQLITE_INTEGER or SQLITE_FLOAT"); + + " that does not match expected output type: SQLITE_NULL"); value = nullptr; } - template + template inline auto copyColumn(sqlite3& /*db*/, sqlite3_stmt& statement, int index, int type, T& value) { switch (type) @@ -105,6 +112,19 @@ namespace Sqlite3 case SQLITE_INTEGER: value = static_cast(sqlite3_column_int64(&statement, index)); return; + case SQLITE_NULL: + value = std::decay_t{}; + return; + } + throw std::logic_error("Type of column " + std::to_string(index) + " is " + sqliteTypeToString(type) + + " that does not match expected output type: SQLITE_INTEGER or SQLITE_NULL"); + } + + template + inline auto copyColumn(sqlite3& /*db*/, sqlite3_stmt& statement, int index, int type, T& value) + { + switch (type) + { case SQLITE_FLOAT: value = static_cast(sqlite3_column_double(&statement, index)); return; @@ -113,7 +133,13 @@ namespace Sqlite3 return; } throw std::logic_error("Type of column " + std::to_string(index) + " is " + sqliteTypeToString(type) - + " that does not match expected output type: SQLITE_INTEGER or SQLITE_FLOAT or SQLITE_NULL"); + + " that does not match expected output type: SQLITE_FLOAT or SQLITE_NULL"); + } + + template + inline auto copyColumn(sqlite3& db, sqlite3_stmt& statement, int index, int type, T& value) + { + return copyColumn(db, statement, index, type, value.mValue); } inline void copyColumn(sqlite3& db, sqlite3_stmt& statement, int index, int type, std::string& value) diff --git a/components/vfs/qtconversion.cpp b/components/vfs/qtconversion.cpp index 472e3dd0b49..fc8a0fb78e1 100644 --- a/components/vfs/qtconversion.cpp +++ b/components/vfs/qtconversion.cpp @@ -1,8 +1,9 @@ - #include "qtconversion.hpp" #include +#include + QString VFS::Path::normalizedToQString(NormalizedView path) { return QString::fromUtf8(path.value().data(), path.value().size()); @@ -15,12 +16,12 @@ QString VFS::Path::normalizedToQString(Normalized&& path) VFS::Path::Normalized VFS::Path::normalizedFromQString(QStringView path) { - const auto tmp = path.toUtf8(); - return Normalized{ tmp }; + const QByteArray tmp = path.toUtf8(); + return Normalized(std::string_view(tmp.constData(), tmp.size())); } VFS::Path::Normalized VFS::Path::normalizedFromQString(QString&& path) { - const auto tmp = path.toUtf8(); - return Normalized{ tmp }; + const QByteArray tmp = std::move(path).toUtf8(); + return Normalized(std::string_view(tmp.constData(), tmp.size())); } diff --git a/docs/source/manuals/openmw-cs/record-filters.rst b/docs/source/manuals/openmw-cs/record-filters.rst index 19eee2542c8..460b59f9ca1 100644 --- a/docs/source/manuals/openmw-cs/record-filters.rst +++ b/docs/source/manuals/openmw-cs/record-filters.rst @@ -241,7 +241,7 @@ Logical Expressions In this particular case only one argument can evaluate to ``true``, but one can write expressions where multiple arguments can be ``true`` at a time. -``or(, , ..., )`` +``and(, , ..., )`` Logical conjunction, evaluates to ``true`` if and only if all arguments evaluate to ``true`` as well, otherwise the expression evaluates to ``false``. diff --git a/docs/source/reference/lua-scripting/events.rst b/docs/source/reference/lua-scripting/events.rst index 810739caeb8..b49e2937443 100644 --- a/docs/source/reference/lua-scripting/events.rst +++ b/docs/source/reference/lua-scripting/events.rst @@ -218,7 +218,7 @@ Lock a container or door .. code-block:: Lua - core.sendGlobalEvent('Lock', {taret = selected, magnitude = 50}) + core.sendGlobalEvent('Lock', {target = selected, magnitude = 50}) **Unlock** @@ -226,4 +226,4 @@ Unlock a container or door .. code-block:: Lua - core.sendGlobalEvent('Unlock', {taret = selected}) + core.sendGlobalEvent('Unlock', {target = selected}) diff --git a/docs/source/reference/modding/extended.rst b/docs/source/reference/modding/extended.rst index 8b5c30fdd0a..3746a9db707 100644 --- a/docs/source/reference/modding/extended.rst +++ b/docs/source/reference/modding/extended.rst @@ -165,6 +165,7 @@ The minimum you need is the ``xbase_anim_sh.nif`` file from the `Weapon Sheathin [Game] weapon sheathing = true + use additional anim sources = true The ``xbase_anim_sh.nif`` contains default placement points for different weapon types. That way you'll get Gothic-style weapon sheathing for all biped actors (without quivers and scabbards). @@ -204,6 +205,28 @@ It is important to make sure the names of empty nodes start with ``"Bip01 "``, o An example of a mod which uses this feature is `Weapon Sheathing`_. +Shield sheathing support +------------------------ + +The minimum you need is the ``xbase_anim_sh.nif`` file from the `Weapon Sheathing`_ mod and this line in your settings.cfg: + +.. code-block:: ini + :caption: settings.cfg + + [Game] + shield sheathing = true + use additional anim sources = true + +The ``xbase_anim_sh.nif`` contains default placement points for shields (a ``"Bip01 AttachShield"`` node). +You also may use meshes with ``_sh`` suffix (with ``Bip01 Sheath`` node) to tweak how particular shield looks in the sheathed mode. A stub sheath means that the shield should be excluded from this feature. +When a two-handed weapon is equipped, a shield is hidden when this feature is enabled. +This feature also supports shield equipping and unequipping animations. It is a ``Shield`` group (with ``Equip Start``, ``Equip Attach``, ``Equip Stop``, ``Unequip Start``, ``Unequip Attach`` and ``Unequip Stop`` keys). +Note that equip and unequip animation blocks should not overlap each other and weapon equip/unequip animations. +Basically, you need to avoid situations when you play an animation block where you need both to attach and detach the shield. + +An example of a mod which uses this feature is `Weapon Sheathing`_. + + Skeleton extensions ------------------- diff --git a/docs/source/reference/modding/paths.rst b/docs/source/reference/modding/paths.rst index 2fdedaa90ea..d5765b8ce51 100644 --- a/docs/source/reference/modding/paths.rst +++ b/docs/source/reference/modding/paths.rst @@ -70,6 +70,31 @@ Screenshots .. note:: Flatpak sets ``$XDG_DATA_HOME`` to ``$HOME/.var/app/$FLATPAK_ID/data``, so screenshots will be at ``$HOME/.var/app/org.openmw.OpenMW/data/openmw/screenshots`` if you use the Flatpak. +Override directory (data-local) +------------------------------- + +This is the directory in which OpenMW-CS saves generated content files. +Additionally, this is always the last-loaded data directory in OpenMW, overriding any which came before it. +This can be useful, for instance, for placing automatically-generated plugins created by external tools or to be very certain that particular assets are always overridden regardless of load order. +You may define your own, custom ``data-local`` directory by using it as a key in ``openmw.cfg``, e.g. ``data-local=C:/Games/OpenMW/data``. + ++--------------+----------------------------------------------------------------------------------------------------+ +| OS | Location | ++==============+====================================================================================================+ +| Linux | ``$XDG_DATA_HOME/openmw/data`` or ``$HOME/.local/share/openmw/data`` | ++--------------+----------------------------------------------------------------------------------------------------+ +| Mac | ``$HOME/Library/Application\ Support/openmw/data`` | ++--------------+---------------+------------------------------------------------------------------------------------+ +| Windows | File Explorer | ``Documents\My Games\OpenMW\data`` | +| +---------------+------------------------------------------------------------------------------------+ +| | PowerShell | ``Join-Path ([environment]::GetFolderPath("mydocuments")) "My Games\OpenMW\data"`` | +| +---------------+------------------------------------------------------------------------------------+ +| | Example | ``C:\Users\Username\Documents\My Games\OpenMW\data`` | ++--------------+---------------+------------------------------------------------------------------------------------+ + +.. note:: + Flatpak sets ``$XDG_DATA_HOME`` to ``$HOME/.var/app/$FLATPAK_ID/data``, so data-local will be set to ``$HOME/.var/app/org.openmw.OpenMW/data/openmw/data`` if you use the Flatpak. + Custom configuration directories ================================ diff --git a/extern/oics/CMakeLists.txt b/extern/oics/CMakeLists.txt index 2d34f3f3e66..64b7c3383fe 100644 --- a/extern/oics/CMakeLists.txt +++ b/extern/oics/CMakeLists.txt @@ -20,8 +20,6 @@ else() target_link_libraries(oics local_tinyxml) endif() -target_link_libraries(oics SDL2::SDL2) - if (MSVC AND PRECOMPILE_HEADERS_WITH_MSVC) target_precompile_headers(oics PUBLIC ) endif() diff --git a/extern/osg-ffmpeg-videoplayer/CMakeLists.txt b/extern/osg-ffmpeg-videoplayer/CMakeLists.txt index 8ff608bf046..b8f2e59bced 100644 --- a/extern/osg-ffmpeg-videoplayer/CMakeLists.txt +++ b/extern/osg-ffmpeg-videoplayer/CMakeLists.txt @@ -14,7 +14,6 @@ include_directories(${FFmpeg_INCLUDE_DIRS}) add_library(${OSG_FFMPEG_VIDEOPLAYER_LIBRARY} STATIC ${OSG_FFMPEG_VIDEOPLAYER_SOURCE_FILES}) target_link_libraries(${OSG_FFMPEG_VIDEOPLAYER_LIBRARY} ${FFmpeg_LIBRARIES}) target_link_libraries(${OSG_FFMPEG_VIDEOPLAYER_LIBRARY} ${OSG_LIBRARIES}) -target_link_libraries(${OSG_FFMPEG_VIDEOPLAYER_LIBRARY} SDL2::SDL2) link_directories(${CMAKE_CURRENT_BINARY_DIR}) diff --git a/files/data-mw/l10n/Interface/gmst.yaml b/files/data-mw/l10n/Interface/gmst.yaml index cef128fdb6c..0ab886a83ed 100644 --- a/files/data-mw/l10n/Interface/gmst.yaml +++ b/files/data-mw/l10n/Interface/gmst.yaml @@ -1,27 +1,48 @@ Ask: "sAsk" Back: "sBack" +Barter: "sBarter" Buy: "sBuy" Cancel: "sCancel" +Center: "sCenter" # This has a trailing space in Russian and French games Close: "sClose" +Container: "sContainer" # This has a trailing space in the Russian game Create: "sCreate" +Delete: "sDelete" DisposeOfCorpse: "sDisposeofCorpse" Done: "sDone" +Drop: "sDrop" # This has a trailing space in the Russian game +Equip: "sEquip" # This has a trailing space in the Russian game +Face: "sFace" Goodbye: "sGoodbye" +Hair: "sHair" Info: "sInfo" Inventory: "sInventory" Item: "sItem" +Local: "sLocal" MagicEffects: "sMagicEffects" -# NB: sMouse exists but it is not localized in the Russian game and should not be used to translate Mouse +# Mouse/Move: sMouse and sMove exist but they are not localised in the Russian game and should not be used Next: "sNext" No: "sNo" None: "sNone" Off: "sOff" +Offer: "sOffer" OK: "sOK" On: "sOn" Prev: "sPrev" +Repair: "sRepair" +Rest: "sRest" +ScrollDown: "sScrolldown" ScrollUp: "sScrollup" Select: "sSelect" +Sell: "sSell" +Sex: "sSex" +Share: "sCompanionShare" Soul: "sSoulGem" Take: "sTake" TakeAll: "sTakeAll" +Topics: "sTopics" +Travel: "sTravel" +UntilHealed: "sUntilHealed" +Wait: "sWait" +World: "sWorld" Yes: "sYes" diff --git a/files/data/CMakeLists.txt b/files/data/CMakeLists.txt index da7d97454e3..540e1767505 100644 --- a/files/data/CMakeLists.txt +++ b/files/data/CMakeLists.txt @@ -75,10 +75,14 @@ set(BUILTIN_DATA_FILES l10n/OMWCamera/sv.yaml l10n/OMWCamera/fr.yaml l10n/OMWCamera/pl.yaml + + l10n/OMWCombat/de.yaml l10n/OMWCombat/en.yaml + l10n/OMWCombat/fr.yaml l10n/OMWCombat/ru.yaml l10n/OMWCombat/sv.yaml l10n/OMWCombat/pl.yaml + l10n/OMWControls/de.yaml l10n/OMWControls/en.yaml l10n/OMWControls/fr.yaml diff --git a/files/data/l10n/Interface/de.yaml b/files/data/l10n/Interface/de.yaml index 0413292169c..81244aeb8d4 100644 --- a/files/data/l10n/Interface/de.yaml +++ b/files/data/l10n/Interface/de.yaml @@ -1,12 +1,17 @@ Ask: "Fragen" Back: "Zurück" +Barter: "Handeln" Buy: "Kaufen" Cancel: "Abbruch" +Center: "Zentrieren" Close: "Schließen" +Container: "Behälter" Copy: "Kopieren" Create: "Herstellen" +Delete: "Entfernen" DisposeOfCorpse: "Leiche beseitigen" Done: "Fertig" +Drop: "Ablegen" DurationDay: "{days} d " DurationHour: "{hours} h " DurationMinute: "{minutes} min " @@ -26,12 +31,17 @@ DurationYear: |- one{{years} Jahr } other{{years} Jahre } } +Equip: "Verwenden" +Face: "Gesicht" Goodbye: "Lebt wohl!" +Hair: "Haar" Info: "Info" Inventory: "Inventar" Item: "Gegenstand" +Local: "Lokal" MagicEffects: "Magischer Effekt" Mouse: "Maus" +Move: "Bewegen" Next: "Weiter" No: "Nein" # This one is a bit tricky since it can be translated to @@ -41,13 +51,25 @@ No: "Nein" None: "Keine" NotAvailableShort: "N/A" Off: "Aus" +Offer: "Angebot" OK: "OK" On: "An" Prev: "Zurück" +Repair: "Reparieren" Reset: "Zurücksetzen" +Rest: "Rasten" +ScrollDown: "Nach unten scrollen" ScrollUp: "Nach oben scrollen" Select: "Auswählen" +Sell: "Verkaufen" +Sex: "Geschlecht" +Share: "Teilen" Soul: "Seele" Take: "Nehmen" TakeAll: "Alles nehmen" +Topics: "Themen" +Travel: "Reisen" +UntilHealed: "Bis geheilt" +Wait: "Warten" +World: "Welt" Yes: "Ja" diff --git a/files/data/l10n/Interface/en.yaml b/files/data/l10n/Interface/en.yaml index 0a97542c355..cd5ee9df0d8 100644 --- a/files/data/l10n/Interface/en.yaml +++ b/files/data/l10n/Interface/en.yaml @@ -1,12 +1,17 @@ Ask: "Ask" Back: "Back" +Barter: "Barter" Buy: "Buy" Cancel: "Cancel" +Center: "Center" Close: "Close" +Container: "Container" Copy: "Copy" Create: "Create" +Delete: "Delete" DisposeOfCorpse: "Dispose of Corpse" Done: "Done" +Drop: "Drop" DurationDay: "{days} d " DurationHour: "{hours} h " DurationMinute: "{minutes} min " @@ -21,24 +26,41 @@ DurationYear: |- one{{years} yr } other{{years} yrs } } +Equip: "Equip" +Face: "Face" Goodbye: "Goodbye" +Hair: "Hair" Info: "Info" Inventory: "Inventory" Item: "Item" +Local: "Local" MagicEffects: "Magic Effects" Mouse: "Mouse" +Move: "Move" Next: "Next" No: "No" None: "None" NotAvailableShort: "N/A" Off: "Off" +Offer: "Offer" OK: "OK" On: "On" Prev: "Prev" +Repair: "Repair" Reset: "Reset" +Rest: "Rest" +ScrollDown: "Scroll Down" ScrollUp: "Scroll Up" Select: "Select" +Sell: "Sell" +Sex: "Sex" +Share: "Share" Soul: "Soul" Take: "Take" TakeAll: "Take All" +Topics: "Topics" +Travel: "Travel" +UntilHealed: "Until Healed" +Wait: "Wait" +World: "World" Yes: "Yes" diff --git a/files/data/l10n/Interface/fr.yaml b/files/data/l10n/Interface/fr.yaml index df5d950e5d9..d6f17150a34 100644 --- a/files/data/l10n/Interface/fr.yaml +++ b/files/data/l10n/Interface/fr.yaml @@ -1,12 +1,17 @@ Ask: "Demander" Back: "En arrière" +Barter: "Marchander" Buy: "Acheter" Cancel: "Annuler" +Center: "Centrer" Close: "Fermer" +Container: "Contenant" Copy: "Copier" Create: "Créer" DisposeOfCorpse: "Supprimer cadavre" +Delete: "Effacer" Done: "Fait" +Drop: "Lâcher" DurationDay: |- {days, plural, one{{days} jour } @@ -21,24 +26,41 @@ DurationYear: |- one{{years} an } other{{years} ans } } +Equip: "S'équiper" +Face: "Face" Goodbye: "Au revoir" +Hair: "Cheveux" Info: "Info" Inventory: "Inventaire" Item: "Objet" +Local: "Local" MagicEffects: "Effets magiques" Mouse: "Souris" +Move: "Déplacement" Next: "Suivant" No: "Non" None: "Aucun" NotAvailableShort: "N/A" Off: "Inactif" +Offer: "Proposer" OK: "Valider" On: "Actif" Prev: "Précédent" +Repair: "Réparer" Reset: "Réinitialiser" +Rest: "Repos" +ScrollDown: "Défilement bas" ScrollUp: "Défilement haut" Select: "Sélectionner" +Sell: "Vendre" +Sex: "Sexe" +Share: "Répartir" Soul: "Ame" Take: "Prendre" TakeAll: "Tout prendre" +Topics: "Sujets" +Travel: "Voyager" +UntilHealed: "Récup. totale" +Wait: "Attendre" +World: "Monde" Yes: "Oui" diff --git a/files/data/l10n/Interface/pl.yaml b/files/data/l10n/Interface/pl.yaml index cb71ed6fcd8..2968c482dc6 100644 --- a/files/data/l10n/Interface/pl.yaml +++ b/files/data/l10n/Interface/pl.yaml @@ -1,12 +1,17 @@ Ask: "Zapytaj" Back: "Wstecz" +Barter: "Handel" Buy: "Kup" Cancel: "Anuluj" +Center: "Centruj" Close: "Zamknij" +Container: "Pojemnik" Copy: "Kopiuj" Create: "Utwórz" +Delete: "Usuń" DisposeOfCorpse: "Usuń zwłoki" Done: "Koniec" +Drop: "Upuść" DurationDay: "{days} d. " DurationHour: "{hours} godz. " DurationMinute: "{minutes} min " @@ -19,24 +24,41 @@ DurationYear: |- few{{years} lata } many{{years} lat } } +Equip: "Załóż" +Face: "Twarz" Goodbye: "Do widzenia" +Hair: "Włosy" Info: "Info" Inventory: "Ekwipunek" Item: "Przedmiot" +Local: "Okolica" MagicEffects: "Magiczne efekty" Mouse: "Mysz" +Move: "Przenieś" Next: "Nast." No: "Nie" None: "Brak" NotAvailableShort: "N/D" Off: "Wył." +Offer: "Zaoferuj" OK: "OK" On: "Wł." Prev: "Poprz." +Repair: "Naprawa" Reset: "Przywróć" +Rest: "Odpocznij" +ScrollDown: "Przewiń w dół" ScrollUp: "Przewiń w górę" Select: "Wybierz" +Sell: "Sprzedaj" +Sex: "Płeć" +Share: "Podział" Soul: "Dusza" Take: "Weź" TakeAll: "Weź wszystko" +Topics: "Tematy" +Travel: "Podróż" +UntilHealed: "Do wyzdr." +Wait: "Czekaj" +World: "Świat" Yes: "Tak" diff --git a/files/data/l10n/Interface/ru.yaml b/files/data/l10n/Interface/ru.yaml index 03d7ba53b12..eb98026298b 100644 --- a/files/data/l10n/Interface/ru.yaml +++ b/files/data/l10n/Interface/ru.yaml @@ -1,12 +1,17 @@ Ask: "Спросить" Back: "Назад" +Barter: "Торговать" Buy: "Купить" Cancel: "Отмена" +Center: "Центр" Close: "Закрыть" +Container: "Контейнер" Copy: "Скопировать" Create: "Создать" +Delete: "Удалить" DisposeOfCorpse: "Убрать тело" Done: "Готово" +Drop: "Бросить" DurationDay: "{days} д " DurationHour: "{hours} ч " DurationMinute: "{minutes} мин " @@ -18,24 +23,41 @@ DurationYear: |- few{{years} г } other{{years} л } } +Equip: "Надеть" +Face: "Лицо" Goodbye: "Прощание" +Hair: "Прическа" Info: "Инфо" Inventory: "Инвентарь" Item: "Предмет" +Local: "Местность" MagicEffects: "Маг. эффекты" Mouse: "Мышь" +Move: "Переместить" Next: "След" No: "Нет" None: "Нет" NotAvailableShort: "Н/Д" Off: "Выкл" +Offer: "Предложить" OK: "OK" On: "Вкл" Prev: "Пред" +Repair: "Ремонт" Reset: "Сбросить" +Rest: "Отдых" +ScrollDown: "Прокрутить вниз" ScrollUp: "Прокрутить вверх" Select: "Выбрать" +Sell: "Продать" +Sex: "Пол" +Share: "Доля" Soul: "Душа" Take: "Взять" TakeAll: "Взять все" +Topics: "Темы" +Travel: "Путешествие" +UntilHealed: "Выздороветь" +Wait: "Ждать" +World: "Мир" Yes: "Да" diff --git a/files/data/l10n/Interface/sv.yaml b/files/data/l10n/Interface/sv.yaml index 8e183edb55f..6871a27cf25 100644 --- a/files/data/l10n/Interface/sv.yaml +++ b/files/data/l10n/Interface/sv.yaml @@ -1,12 +1,17 @@ Ask: "Fråga" Back: "Bakåt" +Barter: "Handla" Buy: "Köp" Cancel: "Avbryt" +Center: "Centrera" Close: "Stäng" +Container: "Behållare" Copy: "Kopiera" Create: "Skapa" +Delete: "Radera" DisposeOfCorpse: "Undanröj liket" Done: "Klar" +Drop: "Släpp" DurationDay: "{days} d " DurationHour: "{hours} tim " DurationMinute: "{minutes} min " @@ -21,24 +26,41 @@ DurationYear: |- one{{years} år } other{{years} år } } +Equip: "Utrusta" +Face: "Ansikte" Goodbye: "Adjö" +Hair: "Hår" Info: "Info" Item: "Föremål" Inventory: "Inventariet" +Local: "Lokal" MagicEffects: "Magiska effekter" Mouse: "Mus" +Move: "Flytta" Next: "Nästa" No: "Nej" None: "Inget" NotAvailableShort: "N/A" Off: "Av" +Offer: "Föreslå" OK: "Ok" On: "På" Prev: "Föreg." +Repair: "Laga" Reset: "Återställ" +Rest: "Vila" +ScrollDown: "Scrolla ner" ScrollUp: "Scrolla upp" Select: "Välj" +Sell: "Sälj" +Sex: "Kön" +Share: "Dela" Soul: "Själ" Take: "Ta" TakeAll: "Ta allt" +Topics: "Ämnen" +Travel: "Res" +UntilHealed: "Tills återställd" +Wait: "Vänta" +World: "Värld" Yes: "Ja" diff --git a/files/data/l10n/OMWCombat/de.yaml b/files/data/l10n/OMWCombat/de.yaml new file mode 100644 index 00000000000..7a51d5928da --- /dev/null +++ b/files/data/l10n/OMWCombat/de.yaml @@ -0,0 +1,16 @@ +Combat: "OpenMW: Kampf" +combatSettingsPageDescription: "OpenMW-Kampfeinstellungen" + +combatSettings: "Kampf" + +unarmedCreatureAttacksDamageArmor: "Angriffe unbewaffneter Kreaturen beschädigen Rüstung" +unarmedCreatureAttacksDamageArmorDescription: | + Auch Angriffe unbewaffneter Kreaturen beschädigen Rüstung. + +redistributeShieldHitsWhenNotWearingShield: "Schildtreffer bei fehlendem Schild umverteilen" +redistributeShieldHitsWhenNotWearingShieldDescription: | + Entspricht "Shield hit location fix" aus dem Morrowind Code Patch. Wenn kein Schild getragen wird, werden Treffer auf den Schild‑Slot auf den linken Schulterpanzer oder den Kürass umverteilt. + +spawnBloodEffectsOnPlayer: "Bluteffekte für Spieler anzeigen" +spawnBloodEffectsOnPlayerDescription: | + Wenn aktiviert, werden beim Spieler bei Treffern im Kampf Bluteffekte angezeigt, genau wie bei anderen Charakteren. diff --git a/files/data/l10n/OMWCombat/fr.yaml b/files/data/l10n/OMWCombat/fr.yaml new file mode 100644 index 00000000000..424f9e19904 --- /dev/null +++ b/files/data/l10n/OMWCombat/fr.yaml @@ -0,0 +1,16 @@ +Combat: "OpenMW : Combat" +combatSettingsPageDescription: "Paramètres de combat d'OpenMW" + +combatSettings: "Combat" + +unarmedCreatureAttacksDamageArmor: "Les attaques de créatures sans armes endomagent l'armure" +unarmedCreatureAttacksDamageArmorDescription: | + Les attaques des créatures sans armes endomagent également l'armure. + +redistributeShieldHitsWhenNotWearingShield: "Redistribe les impacts visant le bouclier lors de son absence" +redistributeShieldHitsWhenNotWearingShieldDescription: | + Équivalent au "Shield hit location fix" du Morrowind Code Patch. Redistribe les impacts visant le bouclier lors de son absence sur l'épaulette gauche ou la cuirasse. + +spawnBloodEffectsOnPlayer: "Effets de sang sur le joueur" +spawnBloodEffectsOnPlayerDescription: | + L'activation de cette option fait apparaitre du sang sur le joueur s'il est blessé lors d'un combat, comme c'est le cas sur les PNJ. diff --git a/files/data/mygui/openmw_postprocessor_hud.layout b/files/data/mygui/openmw_postprocessor_hud.layout index 4ed8ecdb36a..758b1b2e990 100644 --- a/files/data/mygui/openmw_postprocessor_hud.layout +++ b/files/data/mygui/openmw_postprocessor_hud.layout @@ -3,7 +3,7 @@ - + @@ -20,7 +20,7 @@ - + diff --git a/files/data/openmw_aux/util.lua b/files/data/openmw_aux/util.lua index ca4fe7ed313..3c4462deec9 100644 --- a/files/data/openmw_aux/util.lua +++ b/files/data/openmw_aux/util.lua @@ -110,5 +110,38 @@ function aux_util.mapFilterSort(array, scoreFn) return sortedValues, sortedScores end +--- +-- Iterates over an array of event handlers, calling each in turn until one returns false. +-- @function [parent=#util] callEventHandlers +-- @param #table handlers An optional array of handlers to invoke +-- @param #any ... Arguments to pass to each event handler +-- @return boolean True if no further handlers should be called +function aux_util.callEventHandlers(handlers, ...) + if handlers then + for i = #handlers, 1, -1 do + if handlers[i](...) == false then + return true + end + end + end + return false +end + +--- +-- Iterates over an array of event handler arrays, passing each to `aux_util.callEventHandlers` until the event is handled. +-- @function [parent=#util] callMultipleEventHandlers +-- @param #table handlers An array of event handler arrays +-- @param #any ... Arguments to pass to each event handler +-- @return boolean True if no further handlers should be called +function aux_util.callMultipleEventHandlers(handlers, ...) + for i = 1, #handlers do + local stop = aux_util.callEventHandlers(handlers[i], ...) + if stop then + return true + end + end + return false +end + return aux_util diff --git a/files/data/scripts/omw/activationhandlers.lua b/files/data/scripts/omw/activationhandlers.lua index 3850b207ebb..b879d567067 100644 --- a/files/data/scripts/omw/activationhandlers.lua +++ b/files/data/scripts/omw/activationhandlers.lua @@ -2,6 +2,7 @@ local async = require('openmw.async') local core = require('openmw.core') local types = require('openmw.types') local world = require('openmw.world') +local auxUtil = require('openmw_aux.util') local EnableObject = async:registerTimerCallback('EnableObject', function(obj) obj.enabled = true end) @@ -38,21 +39,9 @@ local function onActivate(obj, actor) if obj.parentContainer then return end - local handlers = handlersPerObject[obj.id] - if handlers then - for i = #handlers, 1, -1 do - if handlers[i](obj, actor) == false then - return -- skip other handlers - end - end - end - handlers = handlersPerType[obj.type] - if handlers then - for i = #handlers, 1, -1 do - if handlers[i](obj, actor) == false then - return -- skip other handlers - end - end + local handled = auxUtil.callMultipleEventHandlers({ handlersPerObject[obj.id], handlersPerType[obj.type] }, obj, actor) + if handled then + return end types.Actor.activeEffects(actor):remove('invisibility') world._runStandardActivationAction(obj, actor) diff --git a/files/data/scripts/omw/combat/local.lua b/files/data/scripts/omw/combat/local.lua index 7c688d65698..2cc9e7728f4 100644 --- a/files/data/scripts/omw/combat/local.lua +++ b/files/data/scripts/omw/combat/local.lua @@ -6,6 +6,7 @@ local self = require('openmw.self') local storage = require('openmw.storage') local types = require('openmw.types') local util = require('openmw.util') +local auxUtil = require('openmw_aux.util') local Actor = types.Actor local Weapon = types.Weapon local Player = types.Player @@ -270,10 +271,8 @@ local function spawnBloodEffect(position) end local function onHit(data) - for i = #onHitHandlers, 1, -1 do - if onHitHandlers[i](data) == false then - return -- skip other handlers - end + if auxUtil.callEventHandlers(onHitHandlers, data) then + return end if data.successful and not godMode() then I.Combat.applyArmor(data) diff --git a/files/data/scripts/omw/mechanics/animationcontroller.lua b/files/data/scripts/omw/mechanics/animationcontroller.lua index 9edc7565cad..b7a8e74ca3e 100644 --- a/files/data/scripts/omw/mechanics/animationcontroller.lua +++ b/files/data/scripts/omw/mechanics/animationcontroller.lua @@ -1,13 +1,10 @@ local anim = require('openmw.animation') local self = require('openmw.self') +local auxUtil = require('openmw_aux.util') local playBlendedHandlers = {} -local function onPlayBlendedAnimation(groupname, options) - for i = #playBlendedHandlers, 1, -1 do - if playBlendedHandlers[i](groupname, options) == false then - return - end - end +local function onPlayBlendedAnimation(groupname, options) + auxUtil.callEventHandlers(playBlendedHandlers, groupname, options) end local function playBlendedAnimation(groupname, options) @@ -20,22 +17,7 @@ end local textKeyHandlers = {} local function onAnimationTextKey(groupname, key) - local handlers = textKeyHandlers[groupname] - if handlers then - for i = #handlers, 1, -1 do - if handlers[i](groupname, key) == false then - return - end - end - end - handlers = textKeyHandlers[''] - if handlers then - for i = #handlers, 1, -1 do - if handlers[i](groupname, key) == false then - return - end - end - end + auxUtil.callMultipleEventHandlers({ textKeyHandlers[groupname], textKeyHandlers[''] }, groupname, key) end local initialized = false diff --git a/files/data/scripts/omw/mechanics/playercontroller.lua b/files/data/scripts/omw/mechanics/playercontroller.lua index a0d1b113626..8345ed21661 100644 --- a/files/data/scripts/omw/mechanics/playercontroller.lua +++ b/files/data/scripts/omw/mechanics/playercontroller.lua @@ -132,6 +132,12 @@ local function skillUsedHandler(skillid, params) end local skillStat = NPC.stats.skills[skillid](self) + + if (skillStat.base >= 100 and params.skillGain > 0) or + (skillStat.base <= 0 and params.skillGain < 0) then + return false + end + skillStat.progress = skillStat.progress + params.skillGain / I.SkillProgression.getSkillProgressRequirement(skillid) if skillStat.progress >= 1 then diff --git a/files/data/scripts/omw/mwui/constants.lua b/files/data/scripts/omw/mwui/constants.lua index 8a02268f776..918a09376ba 100644 --- a/files/data/scripts/omw/mwui/constants.lua +++ b/files/data/scripts/omw/mwui/constants.lua @@ -1,11 +1,12 @@ +local core = require('openmw.core') local ui = require('openmw.ui') local util = require('openmw.util') return { - textNormalSize = 16, - textHeaderSize = 16, - headerColor = util.color.rgb(223 / 255, 201 / 255, 159 / 255), - normalColor = util.color.rgb(202 / 255, 165 / 255, 96 / 255), + textNormalSize = ui._getDefaultFontSize(), + textHeaderSize = ui._getDefaultFontSize(), + headerColor = util.color.commaString(core.getGMST("FontColor_color_header")), + normalColor = util.color.commaString(core.getGMST("FontColor_color_normal")), border = 2, thickBorder = 4, padding = 2, diff --git a/files/data/scripts/omw/skillhandlers.lua b/files/data/scripts/omw/skillhandlers.lua index 9b58d811748..c5e3293fa64 100644 --- a/files/data/scripts/omw/skillhandlers.lua +++ b/files/data/scripts/omw/skillhandlers.lua @@ -2,6 +2,7 @@ local self = require('openmw.self') local I = require('openmw.interfaces') local types = require('openmw.types') local core = require('openmw.core') +local auxUtil = require('openmw_aux.util') local NPC = require('openmw.types').NPC local Skill = core.stats.Skill @@ -104,11 +105,7 @@ local function skillUsed(skillid, options) end end - for i = #skillUsedHandlers, 1, -1 do - if skillUsedHandlers[i](skillid, options) == false then - return - end - end + auxUtil.callEventHandlers(skillUsedHandlers, skillid, options) end local function skillLevelUp(skillid, source) @@ -144,11 +141,7 @@ local function skillLevelUp(skillid, source) options.levelUpSpecializationIncreaseValue = core.getGMST('iLevelupSpecialization') end - for i = #skillLevelUpHandlers, 1, -1 do - if skillLevelUpHandlers[i](skillid, source, options) == false then - return - end - end + auxUtil.callEventHandlers(skillLevelUpHandlers, skillid, source, options) end return { diff --git a/files/data/scripts/omw/usehandlers.lua b/files/data/scripts/omw/usehandlers.lua index cf976994be8..c94ab12a407 100644 --- a/files/data/scripts/omw/usehandlers.lua +++ b/files/data/scripts/omw/usehandlers.lua @@ -1,26 +1,15 @@ local types = require('openmw.types') local world = require('openmw.world') +local auxUtil = require('openmw_aux.util') local handlersPerObject = {} local handlersPerType = {} local function useItem(obj, actor, force) local options = { force = force or false } - local handlers = handlersPerObject[obj.id] - if handlers then - for i = #handlers, 1, -1 do - if handlers[i](obj, actor, options) == false then - return -- skip other handlers - end - end - end - handlers = handlersPerType[obj.type] - if handlers then - for i = #handlers, 1, -1 do - if handlers[i](obj, actor, options) == false then - return -- skip other handlers - end - end + local handled = auxUtil.callMultipleEventHandlers({ handlersPerObject[obj.id], handlersPerType[obj.type] }, obj, actor, options) + if handled then + return end world._runStandardUseAction(obj, actor, options.force) end diff --git a/files/gamecontrollerdb.txt b/files/gamecontrollerdb.txt index ccdea73f6d2..979e950680d 100644 --- a/files/gamecontrollerdb.txt +++ b/files/gamecontrollerdb.txt @@ -10,6 +10,7 @@ 03000000d0160000060d000000000000,4Play Adapter,a:b1,b:b3,back:b4,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,leftstick:b14,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b15,righttrigger:b9,rightx:a3,righty:a4,start:b5,x:b0,y:b2,platform:Windows, 03000000d0160000070d000000000000,4Play Adapter,a:b1,b:b3,back:b4,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,leftstick:b14,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b15,righttrigger:b9,rightx:a3,righty:a4,start:b5,x:b0,y:b2,platform:Windows, 03000000d0160000600a000000000000,4Play Adapter,a:b1,b:b3,back:b4,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,leftstick:b14,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b15,righttrigger:b9,rightx:a3,righty:a4,start:b5,x:b0,y:b2,platform:Windows, +03000000c82d00001930000000000000,8BitDo 64,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b11,platform:Windows, 03000000c82d00000031000000000000,8BitDo Adapter,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, 03000000c82d00000531000000000000,8BitDo Adapter 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, 03000000c82d00000951000000000000,8BitDo Dogbone,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a2,rightx:a3,righty:a5,start:b11,platform:Windows, @@ -20,7 +21,7 @@ 03000000801000000900000000000000,8BitDo F30 Arcade Stick,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows, 03000000c82d00001038000000000000,8BitDo F30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows, 03000000c82d00000090000000000000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, -05000000c82d00006a28000000000000,8BitDo GameCube,a:b0,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b9,paddle2:b8,rightshoulder:b10,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b1,y:b4,platform:Windows, +03000000c82d00006a28000000000000,8BitDo GameCube,a:b0,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b9,paddle2:b8,rightshoulder:b10,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b1,y:b4,platform:Windows, 03000000c82d00001251000000000000,8BitDo Lite 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, 03000000c82d00001151000000000000,8BitDo Lite SE,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, 03000000c82d00000150000000000000,8BitDo M30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a3,righty:a5,start:b11,x:b4,y:b3,platform:Windows, @@ -50,6 +51,7 @@ 03000000c82d00000360000000000000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, 03000000c82d00000361000000000000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, 03000000c82d00000660000000000000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000960000000000000,8BitDo Pro 3,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b17,paddle2:b16,paddle3:b2,paddle4:b5,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, 03000000c82d00000131000000000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, 03000000c82d00000231000000000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, 03000000c82d00000331000000000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, @@ -74,6 +76,7 @@ 03000000c82d00000260000000000000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows, 03000000c82d00000261000000000000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows, 03000000c82d00001230000000000000,8BitDo Ultimate,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b2,paddle2:b5,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000c82d00001260000000000000,8BitDo Ultimate 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b17,paddle2:b16,paddle3:b2,paddle4:b5,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, 03000000c82d00001b30000000000000,8BitDo Ultimate 2C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b5,paddle2:b2,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, 03000000c82d00001d30000000000000,8BitDo Ultimate 2C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b5,paddle2:b2,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, 03000000c82d00001530000000000000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, @@ -109,6 +112,10 @@ 03000000491900001904000000000000,Amazon Luna Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Windows, 03000000710100001904000000000000,Amazon Luna Controller,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b8,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b4,rightstick:b7,rightx:a3,righty:a4,start:b6,x:b3,y:b2,platform:Windows, 0300000008100000e501000000000000,Anbernic Game Pad,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000020500000913000000000000,Anbernic RG P01,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a5,start:b11,x:b3,y:b4,platform:Windows, +03000000373500000710000000000000,Anbernic RG P01,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000373500004610000000000000,Anbernic RG P01,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000190e00000110000000000000,Aquaplus Piece,a:b1,b:b0,back:b3,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b2,platform:Windows, 03000000830500000160000000000000,Arcade,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b3,x:b4,y:b4,platform:Windows, 03000000120c0000100e000000000000,Armor 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, 03000000490b00004406000000000000,ASCII Seamic Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows, @@ -134,13 +141,13 @@ 030000000d0500000208000000000000,Belkin Nostromo N40,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Windows, 03000000bc2000006012000000000000,Betop 2126F,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, 03000000bc2000000055000000000000,Betop BFM,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000790000000700000000000000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b3,y:b0,platform:Windows, +03000000808300000300000000000000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b3,y:b0,platform:Windows, 03000000bc2000006312000000000000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, 03000000bc2000006321000000000000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, 03000000bc2000006412000000000000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, 03000000c01100000555000000000000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, 03000000c01100000655000000000000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, -03000000790000000700000000000000,Betop Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b3,y:b0,platform:Windows, -03000000808300000300000000000000,Betop Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b3,y:b0,platform:Windows, 030000006f0e00006401000000000000,BF One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Windows, 03000000300f00000202000000000000,Bigben,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a5,righty:a2,start:b7,x:b2,y:b3,platform:Windows, 030000006b1400000209000000000000,Bigben,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, @@ -151,6 +158,7 @@ 03000000120c0000f10e000000000000,Brook PS2 Adapter,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, 03000000120c0000310c000000000000,Brook Super Converter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows, 03000000d81d00000b00000000000000,Buffalo BSGP1601 Series,a:b5,b:b3,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b13,x:b4,y:b2,platform:Windows, +030000005a1c00002400000000000000,Capcom Home Arcade Controller,a:b3,b:b4,back:b7,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b6,x:b0,y:b1,platform:Windows, 030000005b1c00002400000000000000,Capcom Home Arcade Controller,a:b3,b:b4,back:b7,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b6,x:b0,y:b1,platform:Windows, 030000005b1c00002500000000000000,Capcom Home Arcade Controller,a:b3,b:b4,back:b7,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b6,x:b0,y:b1,platform:Windows, 030000006d04000042c2000000000000,ChillStream,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, @@ -173,15 +181,17 @@ 030000004f04000020b3000000000000,Dual Trigger,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows, 03000000bd12000002e0000000000000,Dual Vibration Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a2,start:b11,x:b3,y:b0,platform:Windows, 03000000ff1100003133000000000000,DualForce,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b1,platform:Windows, -030000008f0e00000910000000000000,DualShock 2,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a2,start:b11,x:b3,y:b0,platform:Windows, -03000000317300000100000000000000,DualShock 3,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows, 030000006f0e00003001000000000000,EA Sports PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 03000000fc0400000250000000000000,Easy Grip,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows, 03000000bc2000000091000000000000,EasySMX Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, 030000006e0500000a20000000000000,Elecom DUX60 MMO,a:b2,b:b3,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b14,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b15,righttrigger:b13,rightx:a3,righty:a4,start:b20,x:b0,y:b1,platform:Windows, 03000000b80500000410000000000000,Elecom Gamepad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Windows, 03000000b80500000610000000000000,Elecom Gamepad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Windows, +03000095090000010000000000000000,Elecom JC-U609,a:b0,b:b1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,start:b8,x:b3,y:b4,platform:Windows, +0300004112000000e500000000000000,Elecom JC-U909Z,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,start:b8,x:b3,y:b4,platform:Windows, +03000041120000001050000000000000,Elecom JC-U911,a:b1,b:b2,back:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,start:b0,x:b4,y:b5,platform:Windows, 030000006e0500000520000000000000,Elecom P301U PlayStation Controller Adapter,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Windows, +03000000250900000218000000000000,Elecom PlayStation Adapter,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows, 03000000411200004450000000000000,Elecom U1012,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Windows, 030000006e0500000320000000000000,Elecom U3613M,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Windows, 030000006e0500000e20000000000000,Elecom U3912T,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Windows, @@ -192,6 +202,7 @@ 030000007d0400000640000000000000,Eliminator AfterShock,a:b1,b:b2,back:b9,dpdown:+a3,dpleft:-a5,dpright:+a5,dpup:-a3,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a4,righty:a2,start:b8,x:b0,y:b3,platform:Windows, 03000000120c0000f61c000000000000,Elite,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, 03000000430b00000300000000000000,EMS Production PS2 Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows, +03000000062000001801000000000000,EMS TrioLinker Plus II,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b2,y:b3,platform:Windows, 03000000242f000000b7000000000000,ESM 9110,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Windows, 03000000101c0000181c000000000000,Essential,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b4,leftx:a1,lefty:a0,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows, 030000008f0e00000f31000000000000,EXEQ,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows, @@ -210,7 +221,7 @@ 03000000b50700000399000000000000,Firestorm 2,a:b2,b:b4,back:b10,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b8,righttrigger:b9,start:b11,x:b3,y:b5,platform:Windows, 03000000b50700001302000000000000,Firestorm D3,a:b0,b:b2,leftshoulder:b4,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,x:b1,y:b3,platform:Windows, 03000000b40400001024000000000000,Flydigi Apex,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows, -03000000151900004000000000000000,Flydigi Vader 2,a:b27,b:b26,back:b19,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b23,leftstick:b17,lefttrigger:b21,leftx:a0,lefty:a1,misc1:b15,paddle1:b11,paddle2:b10,paddle3:b13,paddle4:b12,rightshoulder:b22,rightstick:b16,righttrigger:b20,rightx:a3,righty:a4,start:b18,x:b25,y:b24,platform:Windows, +03000000151900004000000000000000,Flydigi Vader 2,a:b27,b:b26,back:b19,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b23,leftstick:b17,lefttrigger:b21,leftx:a0,lefty:a1,rightshoulder:b22,rightstick:b16,righttrigger:b20,rightx:a3,righty:a4,start:b18,x:b25,y:b24,platform:Windows, 03000000b40400001124000000000000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b14,paddle1:b4,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b2,y:b3,platform:Windows, 03000000b40400001224000000000000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b2,paddle1:b16,paddle2:b17,paddle3:b14,paddle4:b15,rightshoulder:b7,rightstick:b13,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, 030000008305000000a0000000000000,G08XU,a:b0,b:b1,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b5,x:b2,y:b3,platform:Windows, @@ -225,7 +236,8 @@ 03000000ac0500005b05000000000000,GameSir G3w,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, 03000000ac0500002d02000000000000,GameSir G4,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows, 03000000ac0500004d04000000000000,GameSir G4,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, -03000000ac0500001a06000000000000,GameSir-T3 2.02,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000ac0500001a06000000000000,GameSir T3 2.02,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000373500009410000000000000,GameSir Tegenaria Lite,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, 030000004c0e00001035000000000000,Gamester,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows, 030000000d0f00001110000000000000,GameStick Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows, 0300000047530000616d000000000000,GameStop,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, @@ -241,9 +253,11 @@ 03000000300f00000b01000000000000,GGE909 Recoil,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows, 03000000f0250000c283000000000000,Gioteck PlayStation Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, 03000000f025000021c1000000000000,Gioteck PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000f025000021c1000010010000,Gioteck PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, 03000000f025000031c1000000000000,Gioteck PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, 03000000f0250000c383000000000000,Gioteck VX2 PlayStation Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, 03000000f0250000c483000000000000,Gioteck VX2 PlayStation Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000d11800000094000000000000,Google Stadia Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:b11,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:Windows, 030000004f04000026b3000000000000,GP XID,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, 0300000079000000d418000000000000,GPD Win,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, 03000000c6240000025b000000000000,GPX,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, @@ -253,6 +267,8 @@ 030000008f0e00000610000000000000,GreenAsia,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a5,righty:a2,start:b11,x:b3,y:b0,platform:Windows, 03000000ac0500006b05000000000000,GT2a,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows, 03000000341a00000302000000000000,Hama Scorpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000008a2e0000dd10000000000000,Hand Held Legend GC Ultimate,a:b0,b:b2,back:b17,dpdown:b5,dpleft:b6,dpright:b7,dpup:b4,guide:b18,leftshoulder:b10,leftstick:b8,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b19,misc2:b24,paddle1:b13,paddle2:b12,rightshoulder:b11,rightstick:b9,righttrigger:a4,rightx:a2,righty:a5,start:b16,x:b1,y:b3,platform:Windows, +030000008a2e0000df10000000000000,Hand Held Legend ProGCC,a:b1,b:b0,back:b17,dpdown:b5,dpleft:b6,dpright:b7,dpup:b4,guide:b18,leftshoulder:b10,leftstick:b8,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b19,paddle1:b13,paddle2:b12,rightshoulder:b11,rightstick:b9,righttrigger:a4,rightx:a2,righty:a5,start:b16,x:b3,y:b2,platform:Windows, 030000000d0f00004900000000000000,Hatsune Miku Sho PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 030000001008000001e1000000000000,Havit HV G60,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b0,platform:Windows, 030000000d0f00000c00000000000000,HEXT,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, @@ -270,8 +286,8 @@ 030000000d0f00005100000000000000,Hori Fighting Commander PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, 030000000d0f00008600000000000000,Hori Fighting Commander Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, 030000000d0f0000ba00000000000000,Hori Fighting Commander Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, -030000000d0f00008800000000000000,Hori Fighting Stick mini 4 (PS3),a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b8,x:b0,y:b3,platform:Windows, -030000000d0f00008700000000000000,Hori Fighting Stick mini 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, +030000000d0f00008800000000000000,Hori Fighting Stick mini 4 PS3,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b8,x:b0,y:b3,platform:Windows, +030000000d0f00008700000000000000,Hori Fighting Stick mini 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, 030000000d0f00001000000000000000,Hori Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, 030000000d0f00003200000000000000,Hori Fightstick 3W,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, 030000000d0f0000c000000000000000,Hori Fightstick 4,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, @@ -322,14 +338,18 @@ 030000000d0f0000ee00000000000000,Horipad Mini 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, 030000000d0f0000c100000000000000,Horipad Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 030000000d0f0000f600000000000000,Horipad Nintendo Switch Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +030000000d0f00000202000000000000,Horipad O Nintendo Switch 2 Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,misc2:b14,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows, 030000000d0f00006700000000000000,Horipad One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000000d0f00009601000000000000,Horipad Steam,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,misc2:b2,paddle1:b5,paddle2:b15,paddle3:b18,paddle4:b19,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, 030000000d0f0000dc00000000000000,Horipad Switch,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, 03000000242e00000b20000000000000,Hyperkin Admiral N64 Controller,+rightx:b11,+righty:b13,-rightx:b8,-righty:b12,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,platform:Windows, 03000000242e0000ff0b000000000000,Hyperkin N64 Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a3,start:b9,platform:Windows, 03000000790000004e95000000000000,Hyperkin N64 Controller Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a5,righty:a2,start:b9,platform:Windows, 03000000242e00006a48000000000000,Hyperkin RetroN Sq,a:b3,b:b7,back:b5,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,leftshoulder:b0,rightshoulder:b1,start:b4,x:b2,y:b6,platform:Windows, 03000000242f00000a20000000000000,Hyperkin Scout,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Windows, +03000000242e00000a20000000000000,Hyperkin Scout Premium SNES Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Windows, 03000000242e00006a38000000000000,Hyperkin Trooper 2,a:b0,b:b1,back:b4,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b3,start:b5,platform:Windows, +03000000f00300008d04000000000000,HyperX Clutch,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:-a2,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:+a5,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, 03000000d81d00000e00000000000000,iBuffalo AC02 Arcade Joystick,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b11,righttrigger:b3,rightx:a2,righty:a5,start:b8,x:b4,y:b5,platform:Windows, 03000000d81d00000f00000000000000,iBuffalo BSGP1204 Series,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, 03000000d81d00001000000000000000,iBuffalo BSGP1204P Series,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, @@ -384,7 +404,7 @@ 03000000380700006652000000000000,Mad Catz CTRLR,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows, 03000000380700005032000000000000,Mad Catz Fightpad Pro PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 03000000380700005082000000000000,Mad Catz Fightpad Pro PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, -03000000380700008031000000000000,Mad Catz FightStick Alpha PS3 ,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000380700008031000000000000,Mad Catz FightStick Alpha PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, 030000003807000038b7000000000000,Mad Catz Fightstick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,rightshoulder:b5,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows, 03000000380700008433000000000000,Mad Catz Fightstick TE S PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 03000000380700008483000000000000,Mad Catz Fightstick TE S PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, @@ -411,7 +431,7 @@ 03000000242f00007300000000000000,Mayflash Magic NS,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows, 0300000079000000d218000000000000,Mayflash Magic NS,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, 03000000d620000010a7000000000000,Mayflash Magic NS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, -03000000242e0000f500000000000000,Mayflash N64 Adapter,a:b2,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a5,start:b9,platform:Windows, +03000000242f0000f500000000000000,Mayflash N64 Adapter,a:b2,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a5,start:b9,platform:Windows, 03000000242f0000f400000000000000,Mayflash N64 Controller Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a5,start:b9,platform:Windows, 03000000790000007918000000000000,Mayflash N64 Controller Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,righttrigger:b7,rightx:a3,righty:a2,start:b8,platform:Windows, 030000008f0e00001030000000000000,Mayflash Saturn Adapter,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:b7,rightshoulder:b6,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows, @@ -443,7 +463,6 @@ 03000000250900006688000000000000,MP-8866 Super Dual Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows, 03000000091200004488000000000000,MUSIA PlayStation 2 Input Display,a:b0,b:b2,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b6,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b7,righttrigger:b11,rightx:a2,righty:a3,start:b5,x:b1,y:b3,platform:Windows, 03000000f70600000100000000000000,N64 Adaptoid,+rightx:b2,+righty:b1,-rightx:b4,-righty:b5,a:b0,b:b3,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,start:b8,platform:Windows, -030000006f0e00001311000000000000,N64 Controller,+rightx:b10,+righty:b3,-rightx:b0,-righty:b11,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,platform:Windows, 030000006b140000010c000000000000,Nacon GC 400ES,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, 030000006b1400001106000000000000,Nacon Revolution 3 PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, 0300000085320000170d000000000000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, @@ -461,8 +480,11 @@ 030000001008000001e5000000000000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,platform:Windows, 03000000050b00000045000000000000,Nexus,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b10,x:b2,y:b3,platform:Windows, 03000000152000000182000000000000,NGDS,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Windows, +03000000ec110000e1a7000000000000,Nintendo Switch,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +030000007e0500006920000000000000,Nintendo Switch 2 Pro Controller,a:b0,b:b1,back:b14,dpdown:b8,dpleft:b10,dpright:b9,dpup:b11,guide:b16,leftshoulder:b12,leftstick:b15,lefttrigger:b13,leftx:a0,lefty:a1~,misc1:b17,misc2:b20,paddle1:b18,paddle2:b19,rightshoulder:b4,rightstick:b7,righttrigger:b5,rightx:a2,righty:a3~,start:b6,x:b2,y:b3,platform:Windows, 030000007e0500000920000000000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, 030000000d0500000308000000000000,Nostromo N45,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b12,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b2,y:b3,platform:Windows, +030000007e0500007320000000000000,NSO GameCube Controller,a:b1,b:b3,dpdown:b8,dpleft:b10,dpright:b9,dpup:b11,guide:b16,leftshoulder:b13,lefttrigger:b12,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b4,rightx:a2,righty:a3~,start:b6,x:b0,y:b2,platform:Windows, 030000007e0500001920000000000000,NSO N64 Controller,+rightx:b8,+righty:b2,-rightx:b3,-righty:b7,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,righttrigger:b10,start:b9,platform:Windows, 030000007e0500001720000000000000,NSO SNES Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b15,start:b9,x:b2,y:b3,platform:Windows, 03000000550900001472000000000000,NVIDIA Controller,a:b11,b:b10,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b7,leftstick:b5,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b4,righttrigger:a5,rightx:a3,righty:a6,start:b3,x:b9,y:b8,platform:Windows, @@ -478,6 +500,7 @@ 030000008916000000fd000000000000,Onza TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, 03000000d62000006d57000000000000,OPP PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 030000006b14000001a1000000000000,Orange Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Windows, +0300000009120000072f000000000000,OrangeFox86 DreamPicoPort,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:-a2,leftx:a0,lefty:a1,righttrigger:-a5,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, 03000000362800000100000000000000,OUYA Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,platform:Windows, 03000000120c0000f60e000000000000,P4 Gamepad,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b7,rightshoulder:b4,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows, 03000000790000002201000000000000,PC Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, @@ -485,18 +508,13 @@ 030000006f0e00000901000000000000,PDP PS3 Versus Fighting,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, 030000006f0e00008901000000000000,PDP Realmz Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 030000008f0e00004100000000000000,PlaySega,a:b1,b:b0,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,start:b8,x:b4,y:b3,platform:Windows, -03000000666600006706000000000000,PlayStation Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,platform:Windows, -03000000e30500009605000000000000,PlayStation Adapter,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows, -030000004c050000da0c000000000000,PlayStation Classic Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows, -03000000632500002306000000000000,PlayStation Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Windows, -03000000f0250000c183000000000000,PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, -03000000d9040000160f000000000000,PlayStation Controller Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows, -030000004c0500003713000000000000,PlayStation Vita,a:b1,b:b2,back:b8,dpdown:b13,dpleft:b15,dpright:b14,dpup:b12,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows, 03000000d620000011a7000000000000,PowerA Core Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 03000000dd62000015a7000000000000,PowerA Fusion Nintendo Switch Arcade Stick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 03000000d620000012a7000000000000,PowerA Fusion Nintendo Switch Fight Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 03000000dd62000016a7000000000000,PowerA Fusion Pro Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 03000000d620000013a7000000000000,PowerA Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000d62000003340000000000000,PowerA OPS Pro Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000d62000002640000000000000,PowerA OPS Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, 03000000d62000006dca000000000000,PowerA Pro Ex,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 0300000062060000d570000000000000,PowerA PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 03000000d620000014a7000000000000,PowerA Spectra Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, @@ -520,7 +538,6 @@ 03000000120c00001cf1000000000000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, 03000000120c0000f90e000000000000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, 03000000250900000118000000000000,PS3 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows, -03000000250900000218000000000000,PS3 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows, 03000000250900000500000000000000,PS3 Controller,a:b2,b:b1,back:b9,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b0,y:b3,platform:Windows, 030000004c0500006802000000000000,PS3 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b10,lefttrigger:a3~,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:a4~,rightx:a2,righty:a5,start:b8,x:b3,y:b0,platform:Windows, 030000004f1f00000800000000000000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, @@ -578,8 +595,10 @@ 030000009b2800003200000000000000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:+a2,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Windows, 030000009b2800006000000000000000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:+a2,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Windows, 030000009b2800001800000000000000,Raphnet Jaguar Adapter,a:b2,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b10,start:b3,x:b11,y:b12,platform:Windows, +030000009b2800003c00000000000000,Raphnet N64 Adapter,+rightx:b9,+righty:b7,-rightx:b8,-righty:b6,a:b0,b:b1,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,lefttrigger:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Windows, 030000009b2800006100000000000000,Raphnet N64 Adapter,+rightx:b9,+righty:b7,-rightx:b8,-righty:b6,a:b0,b:b1,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,lefttrigger:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Windows, 030000009b2800006300000000000000,Raphnet N64 Adapter,+rightx:b9,+righty:b7,-rightx:b8,-righty:b6,a:b0,b:b1,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,lefttrigger:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Windows, +030000009b2800006400000000000000,Raphnet N64 Adapter,+rightx:b9,+righty:b7,-rightx:b8,-righty:b6,a:b0,b:b1,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,lefttrigger:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Windows, 030000009b2800000200000000000000,Raphnet NES Adapter,a:b7,b:b6,back:b5,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,start:b4,platform:Windows, 030000009b2800004400000000000000,Raphnet PS1 and PS2 Adapter,a:b1,b:b2,back:b5,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b9,rightx:a3,righty:a4,start:b4,x:b0,y:b3,platform:Windows, 030000009b2800004300000000000000,Raphnet Saturn,a:b0,b:b1,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows, @@ -595,6 +614,7 @@ 030000009b2800002c00000000000000,Raphnet Wii Classic Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b10,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b3,x:b0,y:b5,platform:Windows, 030000009b2800008000000000000000,Raphnet Wii Classic Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b10,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b3,x:b0,y:b5,platform:Windows, 03000000790000008f18000000000000,Rapoo Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b3,y:b0,platform:Windows, +0300000032150000a602000000000000,Razer Huntsman V3 Pro,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b12,dpright:b13,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, 03000000321500000003000000000000,Razer Hydra,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, 03000000f8270000bf0b000000000000,Razer Kishi,a:b6,b:b7,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b18,leftshoulder:b12,leftstick:b19,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b13,rightstick:b20,righttrigger:b15,rightx:a3,righty:a4,start:b17,x:b9,y:b10,platform:Windows, 03000000321500000204000000000000,Razer Panthera PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, @@ -611,6 +631,7 @@ 03000000921200004547000000000000,Retro Bit Sega Genesis Controller Adapter,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,start:b6,x:b3,y:b4,platform:Windows, 03000000790000001100000000000000,Retro Controller,a:b1,b:b2,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows, 03000000830500006020000000000000,Retro Controller,a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b8,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows, +03000000632500007805000000000000,Retro Fighters Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, 0300000003040000c197000000000000,Retrode Adapter,a:b0,b:b4,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Windows, 03000000bd12000013d0000000000000,Retrolink Sega Saturn Classic Controller,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b5,lefttrigger:b6,rightshoulder:b2,righttrigger:b7,start:b8,x:b3,y:b4,platform:Windows, 03000000bd12000015d0000000000000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Windows, @@ -628,6 +649,7 @@ 030000006f0e00001e01000000000000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 030000006f0e00002801000000000000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 030000006f0e00002f01000000000000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000830500007030000000000000,Rockfire Space Ranger,a:b0,b:b1,back:b5,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b9,righttrigger:b8,start:b2,x:b3,y:b4,platform:Windows, 03000000050b0000e318000000000000,ROG Chakram,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,platform:Windows, 03000000050b0000e518000000000000,ROG Chakram,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,platform:Windows, 03000000050b00005819000000000000,ROG Chakram Core,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,platform:Windows, @@ -638,8 +660,9 @@ 030000000d0f0000ad00000000000000,RX Gamepad,a:b0,b:b4,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,rightshoulder:b6,start:b9,x:b2,y:b1,platform:Windows, 030000008916000000fe000000000000,Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, 03000000c6240000045d000000000000,Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000006f0e00001311000000000000,Saffun Controller,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b0,platform:Windows, 03000000a30600001af5000000000000,Saitek Cyborg,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows, -03000000a306000023f6000000000000,Saitek Cyborg V.1 Game,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows, +03000000a306000023f6000000000000,Saitek Cyborg,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows, 03000000300f00001201000000000000,Saitek Dual Analog,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows, 03000000a30600000701000000000000,Saitek P220,a:b2,b:b3,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,x:b0,y:b1,platform:Windows, 03000000a30600000cff000000000000,Saitek P2500 Force Rumble,a:b2,b:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b0,y:b1,platform:Windows, @@ -660,13 +683,14 @@ 03000000c01100004150000000000000,Sanwa Micro Grip Pro,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows, 03000000c01100004450000000000000,Sanwa Online Grip,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b8,rightstick:b11,righttrigger:b9,rightx:a3,righty:a2,start:b14,x:b3,y:b4,platform:Windows, 03000000730700000401000000000000,Sanwa PlayOnline Mobile,a:b0,b:b1,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b3,platform:Windows, +030000009d0d00001130000000000000,Sanwa PlayStation Adapter,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, 03000000830500006120000000000000,Sanwa Smart Grip II,a:b0,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,x:b1,y:b3,platform:Windows, 03000000c01100000051000000000000,Satechi Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows, 030000004f04000028b3000000000000,Score A,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, 03000000952e00002577000000000000,Scuf PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, 03000000a30c00002500000000000000,Sega Genesis Mini 3B Controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,righttrigger:b5,start:b9,platform:Windows, 03000000a30c00002400000000000000,Sega Mega Drive Mini 6B Controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows, -03000000d804000086e6000000000000,Sega Multi Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows, +03000000d804000086e6000000000000,Sega Multi Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:a2,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows, 0300000000050000289b000000000000,Sega Saturn Adapter,a:b1,b:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows, 0300000000f000000800000000000000,Sega Saturn Controller,a:b1,b:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b7,righttrigger:b3,start:b0,x:b5,y:b6,platform:Windows, 03000000730700000601000000000000,Sega Saturn Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows, @@ -679,13 +703,22 @@ 03000000811700009d0a000000000000,SNES Controller,a:b0,b:b4,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Windows, 030000008b2800000300000000000000,SNES Controller,a:b0,b:b4,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Windows, 03000000921200004653000000000000,SNES Controller,a:b0,b:b4,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Windows, +030000008f0e00000910000000000000,Sony DualShock 2,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a2,start:b11,x:b3,y:b0,platform:Windows, +03000000317300000100000000000000,Sony DualShock 3,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows, +03000000666600006706000000000000,Sony PlayStation Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,platform:Windows, +03000000e30500009605000000000000,Sony PlayStation Adapter,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows, +03000000fe1400002a23000000000000,Sony PlayStation Adapter,a:b0,b:b1,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,x:b2,y:b3,platform:Windows, +030000004c050000da0c000000000000,Sony PlayStation Classic Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows, +03000000632500002306000000000000,Sony PlayStation Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Windows, +03000000f0250000c183000000000000,Sony PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000d9040000160f000000000000,Sony PlayStation Controller Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows, 03000000ff000000cb01000000000000,Sony PlayStation Portable,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows, +030000004c0500003713000000000000,Sony PlayStation Vita,a:b1,b:b2,back:b8,dpdown:b13,dpleft:b15,dpright:b14,dpup:b12,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows, 03000000341a00000208000000000000,Speedlink 6555,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:-a4,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a3,righty:a2,start:b7,x:b2,y:b3,platform:Windows, 03000000341a00000908000000000000,Speedlink 6566,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, 03000000380700001722000000000000,Speedlink Competition Pro,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,x:b2,y:b3,platform:Windows, 030000008f0e00000800000000000000,Speedlink Strike FX,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, 03000000c01100000591000000000000,Speedlink Torid,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, -03000000d11800000094000000000000,Stadia Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:b11,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:Windows, 03000000de280000fc11000000000000,Steam Virtual Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, 03000000de280000ff11000000000000,Steam Virtual Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, 03000000120c0000160e000000000000,Steel Play Metaltech PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, @@ -695,7 +728,6 @@ 03000000381000003014000000000000,SteelSeries Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, 03000000381000003114000000000000,SteelSeries Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, 03000000381000001814000000000000,SteelSeries Stratus XL,a:b0,b:b1,back:b18,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b19,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b2,y:b3,platform:Windows, -03000000790000001c18000000000000,STK 7024X,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, 03000000380700003847000000000000,Street Fighter Fightstick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b11,start:b7,x:b2,y:b3,platform:Windows, 030000001f08000001e4000000000000,Super Famicom Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Windows, 03000000790000000418000000000000,Super Famicom Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b33,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows, @@ -710,17 +742,18 @@ 03000000b50700001203000000000000,Techmobility X6-38V,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows, 03000000ba2200000701000000000000,Technology Innovation PS2 Adapter,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b2,platform:Windows, 03000000c61100001000000000000000,Tencent Xianyou Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,x:b3,y:b4,platform:Windows, -03000000790000002601000000000000,TGZ,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b3,y:b0,platform:Windows, +03000000790000001c18000000000000,TGZ Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000790000002601000000000000,TGZ Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b3,y:b0,platform:Windows, 03000000591c00002400000000000000,THEC64 Joystick,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows, 03000000591c00002600000000000000,THEGamepad,a:b2,b:b1,back:b6,leftx:a0,lefty:a1,start:b7,x:b3,y:b0,platform:Windows, 030000004f04000015b3000000000000,Thrustmaster Dual Analog 4,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows, 030000004f04000023b3000000000000,Thrustmaster Dual Trigger PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, -030000004f0400000ed0000000000000,ThrustMaster eSwap Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, -030000004f04000008d0000000000000,ThrustMaster Ferrari 150 PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000004f0400000ed0000000000000,Thrustmaster eSwap Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000004f04000008d0000000000000,Thrustmaster Ferrari 150 PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, 030000004f04000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Windows, 030000004f04000004b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows, -030000004f04000003d0000000000000,ThrustMaster Run N Drive PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b7,leftshoulder:a3,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:a4,rightstick:b11,righttrigger:b5,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, -030000004f04000009d0000000000000,ThrustMaster Run N Drive PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000004f04000003d0000000000000,Thrustmaster Run N Drive PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b7,leftshoulder:a3,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:a4,rightstick:b11,righttrigger:b5,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000004f04000009d0000000000000,Thrustmaster Run N Drive PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 030000006d04000088ca000000000000,Thunderpad,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows, 03000000666600000288000000000000,TigerGame PlayStation Adapter,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows, 03000000666600000488000000000000,TigerGame PlayStation Adapter,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows, @@ -748,8 +781,9 @@ 03000000bd12000012d0000000000000,USB Controller,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows, 03000000ff1100004133000000000000,USB Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a4,righty:a2,start:b9,x:b3,y:b0,platform:Windows, 03000000632500002305000000000000,USB Vibration Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, -03000000790000001a18000000000000,Venom,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, -03000000790000001b18000000000000,Venom Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +03000000882800000305000000000000,V5 Game Pad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,x:b2,y:b3,platform:Windows, +03000000790000001a18000000000000,Venom PS4 Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000790000001b18000000000000,Venom PS4 Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, 030000006f0e00000302000000000000,Victrix PS4 Pro Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, 030000006f0e00000702000000000000,Victrix PS4 Pro Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, 0300000034120000adbe000000000000,vJoy Device,a:b0,b:b1,back:b15,dpdown:b6,dpleft:b7,dpright:b8,dpup:b5,guide:b16,leftshoulder:b9,leftstick:b13,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b14,righttrigger:b12,rightx:a3,righty:a4,start:b4,x:b2,y:b3,platform:Windows, @@ -794,7 +828,7 @@ 030000005e040000e302000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, 030000005e040000ea02000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, 030000005e040000fd02000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, -030000005e040000ff02000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000005e040000ff02000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, 030000006f0e0000a802000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, 030000006f0e0000c802000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, 03000000c62400003a54000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, @@ -810,12 +844,14 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 030000007d0400000340000000000000,Xterminator Digital Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:-a4,lefttrigger:+a4,leftx:a0,lefty:a1,paddle1:b7,paddle2:b6,rightshoulder:b5,rightstick:b9,righttrigger:b2,rightx:a3,righty:a5,start:b8,x:b3,y:b4,platform:Windows, 030000002c3600000100000000000000,Yawman Arrow,+rightx:h0.2,+righty:h0.4,-rightx:h0.8,-righty:h0.1,a:b4,b:b5,back:b6,dpdown:b15,dpleft:b14,dpright:b16,dpup:b13,leftshoulder:b10,leftstick:b0,lefttrigger:-a4,leftx:a0,lefty:a1,paddle1:b11,paddle2:b12,rightshoulder:b8,rightstick:b9,righttrigger:+a4,start:b3,x:b1,y:b2,platform:Windows, 03000000790000004f18000000000000,ZDT Android Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000073500000400000000000000,Zenaim Arcade Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, 03000000120c00000500000000000000,Zeroplus Adapter,a:b2,b:b1,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b0,righttrigger:b5,rightx:a3,righty:a2,start:b8,x:b3,y:b0,platform:Windows, 03000000120c0000101e000000000000,Zeroplus P4 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, -03000000882800000305000000000000,V5 GAME PAD,a:b0,b:b1,x:b2,y:b3,guide:b8,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows # Mac OS X 030000008f0e00000300000009010000,2 In 1 Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X, +03000000c82d00001930000000020000,8BitDo 64,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,platform:Mac OS X, +03000000c82d00001930000001000000,8BitDo 64,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,platform:Mac OS X, 03000000c82d00000031000001000000,8BitDo Adapter,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, 03000000c82d00000531000000020000,8BitDo Adapter 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, 03000000c82d00000951000000010000,8BitDo Dogbone,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b11,platform:Mac OS X, @@ -869,15 +905,16 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 03000000c82d00001630000001000000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, 03000000c82d00001730000001000000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, 03000000c82d00001130000000020000,8BitDo Ultimate Wired,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b24,paddle2:b25,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000c82d00001330000000020000,8BitDo Ultimate Wireless,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b23,paddle2:b19,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, 03000000c82d00001330000001000000,8BitDo Ultimate Wireless,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b23,paddle2:b19,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, -03000000c82d00001330000000020000,8BitDo Ultimate Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b23,paddle2:b19,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, 03000000a00500003232000008010000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X, 03000000a00500003232000009010000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X, 03000000c82d00001890000001000000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X, 03000000c82d00003032000000010000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a31,start:b11,x:b4,y:b3,platform:Mac OS X, 03000000491900001904000001010000,Amazon Luna Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Mac OS X, 03000000710100001904000000010000,Amazon Luna Controller,a:b0,b:b1,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Mac OS X, -0300000008100000e501000019040000,Anbernic Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a4,start:b11,x:b4,y:b3,platform:Mac OS X, +0300000008100000e501000019040000,Anbernic Handheld,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a4,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000373500004610000001000000,Anbernic RG P01,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, 03000000a30c00002700000003030000,Astro City Mini,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Mac OS X, 03000000a30c00002800000003030000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a3,lefty:a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Mac OS X, 03000000050b00000045000031000000,ASUS Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X, @@ -890,7 +927,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 030000008a3500000201000000010000,Backbone One,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, 030000008a3500000202000000010000,Backbone One,a:b0,b:b1,back:b16,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b17,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b15,x:b2,y:b3,platform:Mac OS X, 030000008a3500000402000000010000,Backbone One,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, -030000008a3500000302000000010000,Backbone One PlayStationÆ Edition,a:b0,b:b1,back:b16,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b17,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b15,x:b2,y:b3,platform:Mac OS X, +030000008a3500000302000000010000,Backbone One PlayStation Edition,a:b0,b:b1,back:b16,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b17,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b15,x:b2,y:b3,platform:Mac OS X, 03000000c62400001a89000000010000,BDA MOGA XP5-X Plus,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b14,leftshoulder:b6,leftstick:b15,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b16,righttrigger:a4,rightx:a2,righty:a3,start:b13,x:b3,y:b4,platform:Mac OS X, 03000000c62400001b89000000010000,BDA MOGA XP5-X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, 03000000d62000002a79000000010000,BDA PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X, @@ -907,12 +944,14 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 03000000b40400001124000001040000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b14,paddle1:b2,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, 03000000b40400001224000003030000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b2,paddle1:b16,paddle2:b17,paddle3:b14,paddle4:b15,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, 03000000790000004618000000010000,GameCube Controller Adapter,a:b4,b:b0,dpdown:b56,dpleft:b60,dpright:b52,dpup:b48,lefttrigger:a12,leftx:a0,lefty:a4,rightshoulder:b28,righttrigger:a16,rightx:a20,righty:a8,start:b36,x:b8,y:b12,platform:Mac OS X, -03000000ac0500001a06000002020000,GameSir-T3 2.02,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000ac0500001a06000002020000,GameSir T3 2.02,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000373500000411000023000000,GameSir X4A Xbox Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, 03000000ad1b000001f9000000000000,Gamestop BB070 X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, 0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X, 03000000c01100000140000000010000,GameStop PS4 Fun Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X, 030000006f0e00000102000000000000,GameStop Xbox 360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, 03000000ff1100003133000007010000,GameWare PC Control Pad,a:b2,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b0,platform:Mac OS X, +03000000d11800000094000000010000,Google Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Mac OS X, 030000007d0400000540000001010000,Gravis Eliminator Pro,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X, 03000000280400000140000000020000,Gravis GamePad Pro,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X, 030000008f0e00000300000007010000,GreenAsia Joystick,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Mac OS X, @@ -924,8 +963,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 030000000d0f00008400000000010000,Hori Fighting Commander PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, 030000000d0f00008500000000010000,Hori Fighting Commander PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, 03000000341a00000302000014010000,Hori Fighting Stick Mini,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X, -030000000d0f00008800000000010000,Hori Fighting Stick mini 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X, -030000000d0f00008700000000010000,Hori Fighting Stick mini 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X, +030000000d0f00008800000000010000,Hori Fighting Stick mini 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X, +030000000d0f00008700000000010000,Hori Fighting Stick mini 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X, 030000000d0f00004d00000000000000,Hori Gem Pad 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, 030000000d0f00003801000008010000,Hori PC Engine Mini Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,platform:Mac OS X, 030000000d0f00009200000000010000,Hori Pokken Tournament DX Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X, @@ -958,6 +997,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 03000000380700008433000000010000,Mad Catz PS3 Fightstick TE S Plus,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, 03000000380700005082000000010000,Mad Catz PS4 Fightpad Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X, 03000000380700008483000000010000,Mad Catz PS4 Fightstick TE S Plus,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X, +0300000049190000020400001b010000,Manba One,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b22,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, 03000000790000000600000007010000,Marvo GT-004,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X, 030000008f0e00001330000011010000,Mayflash Controller Adapter,a:b2,b:b4,back:b16,dpdown:h0.8,dpleft:h0.2,dpright:h0.1,dpup:h0.4,leftshoulder:b12,lefttrigger:b16,leftx:a0,lefty:a2,rightshoulder:b14,rightx:a6~,righty:a4,start:b18,x:b0,y:b6,platform:Mac OS X, 03000000790000004318000000010000,Mayflash GameCube Adapter,a:b4,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a12,leftx:a0,lefty:a4,rightshoulder:b28,righttrigger:a16,rightx:a20,righty:a8,start:b36,x:b8,y:b12,platform:Mac OS X, @@ -978,22 +1018,24 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 03000000d62000007162000001000000,Moga Pro 2,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Mac OS X, 03000000c62400002a89000000010000,MOGA XP5A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, 03000000c62400002b89000000010000,MOGA XP5A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000853200008906000000010000,Nacon Revolution X Unlimited,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, 03000000632500007505000000020000,NeoGeo mini PAD Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,x:b2,y:b3,platform:Mac OS X, 03000000921200004b46000003020000,NES 2-port Adapter,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b11,platform:Mac OS X, 030000001008000001e5000006010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,platform:Mac OS X, +03000000ec110000e1a7000001010000,Nintendo Switch,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X, +030000007e0500006920000001010000,Nintendo Switch 2 Pro Controller,a:b0,b:b1,back:b14,dpdown:b8,dpleft:b10,dpright:b9,dpup:b11,guide:b16,leftshoulder:b12,leftstick:b15,lefttrigger:b13,leftx:a0,lefty:a1~,misc1:b17,misc2:b20,paddle1:b18,paddle2:b19,rightshoulder:b4,rightstick:b7,righttrigger:b5,rightx:a2,righty:a3~,start:b6,x:b2,y:b3,platform:Mac OS X, 030000007e0500000920000000000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X, 030000007e0500000920000001000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X, 030000007e0500000920000010020000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:Mac OS X, 050000007e05000009200000ff070000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:Mac OS X, +030000007e0500007320000001010000,NSO GameCube Controller,a:b1,b:b3,dpdown:b8,dpleft:b10,dpright:b9,dpup:b11,guide:b16,leftshoulder:b13,lefttrigger:b12,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b4,rightx:a2,righty:a3~,start:b6,x:b0,y:b2,platform:Mac OS X, 030000007e0500001920000001000000,NSO N64 Controller,+rightx:b8,+righty:b7,-rightx:b3,-righty:b2,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,righttrigger:b10,start:b9,platform:Mac OS X, 030000007e0500001720000001000000,NSO SNES Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b15,start:b9,x:b2,y:b3,platform:Mac OS X, 03000000550900001472000025050000,NVIDIA Controller,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Mac OS X, 030000004b120000014d000000010000,Nyko Airflo EX,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Mac OS X, +0300000009120000072f000000010000,OrangeFox86 DreamPicoPort,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a2,leftx:a0,lefty:a1,righttrigger:a5,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Mac OS X, 030000006f0e00000901000002010000,PDP PS3 Versus Fighting,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X, 030000008f0e00000300000000000000,Piranha Xtreme PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Mac OS X, -03000000666600006706000088020000,PlayStation Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,platform:Mac OS X, -030000004c050000da0c000000010000,PlayStation Classic Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Mac OS X, -030000004c0500003713000000010000,PlayStation Vita,a:b1,b:b2,back:b8,dpdown:b13,dpleft:b15,dpright:b14,dpup:b12,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Mac OS X, 03000000d620000011a7000000020000,PowerA Core Plus Gamecube Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X, 03000000d620000011a7000010050000,PowerA Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, 03000000d62000006dca000000010000,PowerA Pro Ex,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, @@ -1011,7 +1053,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 050000004c050000e60c000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X, 050000004c050000f20d000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X, 030000005e040000e002000001000000,PXN P30 Pro Mobile,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Mac OS X, -03000000222c00000225000000010000,Qanba Dragon Arcade Joystick (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000222c00000225000000010000,Qanba Dragon Arcade Joystick PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, 03000000222c00000020000000010000,Qanba Drone Arcade Stick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, 030000009b2800005600000020020000,Raphnet SNES Adapter,a:b1,b:b4,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Mac OS X, 030000009b2800008000000022020000,Raphnet Wii Classic Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b10,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b3,x:b0,y:b5,platform:Mac OS X, @@ -1025,6 +1067,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 030000003215000000090000163a0000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Mac OS X, 0300000032150000030a000000000000,Razer Wildcat,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, 03000000632500008005000000010000,Redgear,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X, +03000000632500002305000000010000,Redragon Saturn,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X, 03000000921200004547000000020000,Retro Bit Sega Genesis Controller Adapter,a:b0,b:b2,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,lefttrigger:b14,rightshoulder:b10,righttrigger:b4,start:b12,x:b6,y:b8,platform:Mac OS X, 03000000790000001100000000000000,Retro Controller,a:b1,b:b2,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,start:b9,x:b0,y:b3,platform:Mac OS X, 03000000790000001100000005010000,Retro Controller,a:b1,b:b2,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b4,start:b9,x:b0,y:b3,platform:Mac OS X, @@ -1046,7 +1089,9 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 0300000000f00000f100000000000000,SNES RetroPort,a:b2,b:b3,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b5,rightshoulder:b7,start:b6,x:b0,y:b1,platform:Mac OS X, 030000004c050000a00b000000000000,Sony DualShock 4 Adapter,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X, 030000004c050000cc09000000000000,Sony DualShock 4 V2,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X, -03000000d11800000094000000010000,Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Mac OS X, +03000000666600006706000088020000,Sony PlayStation Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,platform:Mac OS X, +030000004c050000da0c000000010000,Sony PlayStation Classic Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Mac OS X, +030000004c0500003713000000010000,Sony PlayStation Vita,a:b1,b:b2,back:b8,dpdown:b13,dpleft:b15,dpright:b14,dpup:b12,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Mac OS X, 030000005e0400008e02000001000000,Steam Virtual Gamepad,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, 03000000110100002014000000000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,platform:Mac OS X, 03000000110100002014000001000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,platform:Mac OS X, @@ -1061,11 +1106,12 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 03000000457500002211000000010000,SZMY Power PC Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, 03000000e40a00000307000001000000,Taito Egret II Mini Control Panel,a:b4,b:b2,back:b6,guide:b9,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b1,start:b7,x:b8,y:b3,platform:Mac OS X, 03000000e40a00000207000001000000,Taito Egret II Mini Controller,a:b4,b:b2,back:b6,guide:b9,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b1,start:b7,x:b8,y:b3,platform:Mac OS X, +03000000790000001c18000000010000,TGZ Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, 03000000790000001c18000003100000,TGZ Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, 03000000591c00002400000021000000,THEC64 Joystick,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Mac OS X, 03000000591c00002600000021000000,THEGamepad,a:b2,b:b1,back:b6,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b0,platform:Mac OS X, 030000004f04000015b3000000000000,Thrustmaster Dual Analog 3.2,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Mac OS X, -030000004f0400000ed0000000020000,ThrustMaster eSwap Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +030000004f0400000ed0000000020000,Thrustmaster eSwap Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, 030000004f04000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Mac OS X, 03000000571d00002100000021000000,Tomee NES Controller Adapter,a:b1,b:b0,back:b2,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,start:b3,platform:Mac OS X, 03000000bd12000015d0000000010000,Tomee Retro Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X, @@ -1080,6 +1126,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 050000005769696d6f74652028303000,Wii Remote,a:b4,b:b5,back:b7,dpdown:b3,dpleft:b0,dpright:b1,dpup:b2,guide:b8,leftshoulder:b11,lefttrigger:b12,leftx:a0,lefty:a1,start:b6,x:b10,y:b9,platform:Mac OS X, 050000005769696d6f74652028313800,Wii U Pro Controller,a:b16,b:b15,back:b7,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b8,leftshoulder:b19,leftstick:b23,lefttrigger:b21,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b24,righttrigger:b22,rightx:a2,righty:a3,start:b6,x:b18,y:b17,platform:Mac OS X, 030000005e0400008e02000000000000,Xbox 360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +030000005e0400008e02000010010000,Xbox 360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4~,start:b8,x:b2,y:b3,platform:Mac OS X, 030000006f0e00000104000000000000,Xbox 360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, 03000000c6240000045d000000000000,Xbox 360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, 030000005e0400000a0b000000000000,Xbox Adaptive Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, @@ -1095,6 +1142,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 030000005e040000e302000000000000,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, 030000005e040000ea02000000000000,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, 030000005e040000fd02000003090000,Xbox One Controller,a:b0,b:b1,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +030000005e040000220b000013050000,Xbox One Elite 2 Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,paddle1:b11,paddle2:b13,paddle3:b12,paddle4:b14,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Mac OS X, 03000000c62400003a54000000000000,Xbox One PowerA Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, 030000005e040000130b000001050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, 030000005e040000130b000005050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, @@ -1103,14 +1151,17 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 030000005e040000130b000015050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, 030000005e040000130b000007050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, 030000005e040000130b000017050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +030000005e040000130b000022050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, 030000005e040000220b000017050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, -030000005e040000130b000022050000,Xbox Wireless Controller,a:b0,b:b1,x:b3,y:b4,back:b10,guide:b12,start:b11,leftstick:b13,rightstick:b14,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a5,righttrigger:a4,platform:Mac OS X, 03000000172700004431000029010000,XiaoMi Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Mac OS X, 03000000120c0000100e000000010000,Zeroplus P4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, 03000000120c0000101e000000010000,Zeroplus P4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, # Linux +03000000c82d00001930000011010000,8BitDo 64,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,platform:Linux, +05000000c82d00001930000001000000,8BitDo 64,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,platform:Linux, 03000000c82d00000031000011010000,8BitDo Adapter,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000c82d00000631000000010000,8BitDo Adapter 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 03000000c82d00000951000000010000,8BitDo Dogbone,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b11,platform:Linux, 03000000021000000090000011010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, 03000000c82d00000090000011010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, @@ -1178,10 +1229,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 03000000c82d00001730000011010000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 03000000c82d00001130000011010000,8BitDo Ultimate Wired,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b24,paddle2:b25,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 03000000c82d00000631000010010000,8BitDo Ultimate Wireless,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000c82d00000631000014010000,8BitDo Ultimate Wireless,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 03000000c82d00000760000011010000,8BitDo Ultimate Wireless,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, 03000000c82d00001230000011010000,8BitDo Ultimate Wireless,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b2,paddle2:b5,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 03000000c82d00001330000011010000,8BitDo Ultimate Wireless,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b23,paddle2:b19,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, -03000000c82d00000631000014010000,8BitDo Ultimate Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 03000000c82d00000121000011010000,8BitDo Xbox One SN30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 05000000c82d00000121000000010000,8BitDo Xbox One SN30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 05000000a00500003232000001000000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux, @@ -1199,7 +1250,11 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 05000000491900000204000021000000,Amazon Fire Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b17,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b12,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 03000000491900001904000011010000,Amazon Luna Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Linux, 05000000710100001904000000010000,Amazon Luna Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux, -0300000008100000e501000001010000,Anbernic Gamepad,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a4,start:b11,x:b3,y:b4,platform:Linux, +0300000008100000e501000001010000,Anbernic Handheld,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a4,start:b11,x:b3,y:b4,platform:Linux, +03000000020500000913000010010000,Anbernic RG P01,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000373500000710000010010000,Anbernic RG P01,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +05000000373500004610000001000000,Anbernic RG P01,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000190e00000110000010010000,Aquaplus Piece,a:b1,b:b0,back:b3,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b2,platform:Linux, 03000000790000003018000011010000,Arcade Fightstick F300,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, 03000000a30c00002700000011010000,Astro City Mini,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux, 03000000a30c00002800000011010000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux, @@ -1231,14 +1286,19 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 05000000bc2000000055000001000000,Betop AX1 BFM,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 03000000bc2000006412000011010000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b30,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, 030000006b1400000209000011010000,Bigben,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000120c0000300e000011010000,Brook Audio Fighting Board PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000120c0000310e000011010000,Brook Audio Fighting Board PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, 03000000120c0000200e000011010000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, 03000000120c0000210e000011010000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, 03000000120c0000f70e000011010000,Brook Universal Fighting Board,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +03000000d81d00000b00000010010000,Buffalo BSGP1601,a:b5,b:b3,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b8,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b9,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b13,x:b4,y:b2,platform:Linux, 03000000e82000006058000001010000,Cideko AK08b,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, 03000000af1e00002400000010010000,Clockwork Pi DevTerm,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b9,x:b3,y:b0,platform:Linux, 030000000b0400003365000000010000,Competition Pro,a:b0,b:b1,back:b2,leftx:a0,lefty:a1,start:b3,platform:Linux, +03000000632500007a05000001020000,Cosmic Byte Ares Wired Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, 03000000260900008888000000010000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Linux, 03000000a306000022f6000011010000,Cyborg V3 Rumble,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux, +030000005e0400008e02000002010000,Data Frog S80,a:b1,b:b0,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b2,platform:Linux, 03000000791d00000103000010010000,Dual Box Wii Classic Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, 030000006f0e00003001000001010000,EA Sports PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 03000000c11100000191000011010000,EasySMX,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, @@ -1250,35 +1310,44 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 030000006f0e00008401000011010000,Faceoff Deluxe Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 030000006f0e00008101000011010000,Faceoff Deluxe Pro Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 030000006f0e00008001000011010000,Faceoff Pro Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, -03005036852100000201000010010000,Final Fantasy XIV Online Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000852100000201000010010000,FF GP1,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +05000000b40400001224000001010000,Flydigi APEX 4,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b14,leftshoulder:b4,leftstick:b10,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b20,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, 03000000b40400001124000011010000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b14,paddle1:b2,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 03000000b40400001224000011010000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b2,paddle1:b16,paddle2:b17,paddle3:b14,paddle4:b15,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 05000000151900004000000001000000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b14,paddle1:b2,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 030000007e0500003703000000000000,GameCube Adapter,a:b0,b:b1,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b2,platform:Linux, 19000000030000000300000002030000,GameForce Controller,a:b1,b:b0,back:b8,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,guide:b16,leftshoulder:b4,leftstick:b14,lefttrigger:b6,leftx:a1,lefty:a0,rightshoulder:b5,rightstick:b15,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux, +03000000373500000b10000019010000,GameSir Cyclone 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 03000000ac0500005b05000010010000,GameSir G3w,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, 03000000bc2000000055000011010000,GameSir G3w,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 03000000558500001b06000010010000,GameSir G4 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 05000000ac0500002d0200001b010000,GameSir G4s,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b33,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 03000000ac0500007a05000011010000,GameSir G5,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b16,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000373500009710000001020000,GameSir Kaleid Flux,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000ac0500001a06000011010000,GameSir T3 2.02,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 03000000bc2000005656000011010000,GameSir T4w,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, -03000000ac0500001a06000011010000,GameSir-T3 2.02,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000373500009410000010010000,GameSir Tegenaria Lite,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, 030000006f0e00000104000000010000,Gamestop Logic3 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000008f0e00000800000010010000,Gasia PlayStation Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, 03000000451300000010000010010000,Genius Maxfire Grandias 12,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +03000000f0250000c283000010010000,Gioteck VX2 PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 190000004b4800000010000000010000,GO-Advance Controller,a:b1,b:b0,back:b10,dpdown:b7,dpleft:b8,dpright:b9,dpup:b6,leftshoulder:b4,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b13,start:b15,x:b2,y:b3,platform:Linux, 190000004b4800000010000001010000,GO-Advance Controller,a:b1,b:b0,back:b12,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,leftshoulder:b4,leftstick:b13,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b16,righttrigger:b15,start:b17,x:b2,y:b3,platform:Linux, -190000004b4800000011000000010000,GO-Super Controller,a:b1,b:b0,back:b12,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b16,leftshoulder:b4,leftstick:b14,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b15,righttrigger:b7,rightx:a2,righty:a3,start:b13,x:b2,y:b3,platform:Linux, +190000004b4800000011000000010000,GO-Super Gamepad,a:b0,b:b1,back:b12,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b16,leftshoulder:b4,leftstick:b14,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b15,righttrigger:b7,rightx:a2,righty:a3,start:b13,x:b3,y:b2,platform:Linux, 03000000f0250000c183000010010000,Goodbetterbest Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000d11800000094000011010000,Google Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux, +05000000d11800000094000000010000,Google Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux, 0300000079000000d418000000010000,GPD Win 2 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -030000005e0400008e02000001010000,GPD Win Max 2 (6800U) Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400008e02000001010000,GPD Win Max 2 6800U Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000007d0400000540000000010000,Gravis Eliminator Pro,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, 03000000280400000140000000010000,Gravis GamePad Pro,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, 030000008f0e00000610000000010000,GreenAsia Electronics Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a2,start:b11,x:b3,y:b0,platform:Linux, 030000008f0e00001200000010010000,GreenAsia Joystick,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux, 0500000047532067616d657061640000,GS gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, 03000000f0250000c383000010010000,GT VX2,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +030000008a2e0000dd10000011010000,Hand Held Legend GC Ultimate,a:b0,b:b2,back:b17,dpdown:b5,dpleft:b6,dpright:b7,dpup:b4,guide:b18,leftshoulder:b10,leftstick:b8,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b19,misc2:b24,paddle1:b13,paddle2:b12,rightshoulder:b11,rightstick:b9,righttrigger:a4,rightx:a2,righty:a5,start:b16,x:b1,y:b3,platform:Linux, +030000008a2e0000df10000011010000,Hand Held Legend ProGCC,a:b1,b:b0,back:b17,dpdown:b5,dpleft:b6,dpright:b7,dpup:b4,guide:b18,leftshoulder:b10,leftstick:b8,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b19,paddle1:b13,paddle2:b12,rightshoulder:b11,rightstick:b9,righttrigger:a4,rightx:a2,righty:a5,start:b16,x:b3,y:b2,platform:Linux, 06000000adde0000efbe000002010000,Hidromancer Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 03000000d81400000862000011010000,HitBox PS3 PC Analog Mode,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b12,x:b0,y:b3,platform:Linux, 03000000c9110000f055000011010000,HJC Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, @@ -1286,12 +1355,12 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 030000000d0f00008400000011010000,Hori Fighting Commander,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, 030000000d0f00005f00000011010000,Hori Fighting Commander 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 030000000d0f00005e00000011010000,Hori Fighting Commander 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, -030000000d0f00005001000009040000,Hori Fighting Commander OCTA Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000000d0f00005001000009040000,Hori Fighting Commander Octa Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000000d0f00008500000010010000,Hori Fighting Commander PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 030000000d0f00008600000002010000,Hori Fighting Commander Xbox 360,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, 030000000d0f00003701000013010000,Hori Fighting Stick Mini,a:b1,b:b0,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b3,y:b2,platform:Linux, -030000000d0f00008800000011010000,Hori Fighting Stick mini 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, -030000000d0f00008700000011010000,Hori Fighting Stick mini 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,rightshoulder:b5,rightstick:b11,righttrigger:a4,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, +030000000d0f00008800000011010000,Hori Fighting Stick mini 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +030000000d0f00008700000011010000,Hori Fighting Stick mini 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,rightshoulder:b5,rightstick:b11,righttrigger:a4,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, 030000000d0f00001000000011010000,Hori Fightstick 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, 03000000ad1b000003f5000033050000,Hori Fightstick VX,+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b8,guide:b10,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b2,y:b3,platform:Linux, 030000000d0f00004d00000011010000,Hori Gem Pad 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, @@ -1308,9 +1377,11 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 030000000d0f00008501000015010000,Hori Switch Split Pad Pro,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000000d0f00006e00000011010000,Horipad 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 030000000d0f00006600000011010000,Horipad 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, -030000000d0f0000ee00000011010000,Horipad Mini 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +030000000d0f0000ee00000011010000,Horipad Mini 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, 030000000d0f0000c100000011010000,Horipad Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 030000000d0f00006700000001010000,Horipad One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000000d0f0000ab01000011010000,Horipad Steam,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc2:b2,paddle1:b19,paddle2:b18,paddle3:b15,paddle4:b5,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +050000000d0f00009601000091000000,Horipad Steam,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc2:b2,paddle1:b19,paddle2:b18,paddle3:b15,paddle4:b5,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 050000000d0f0000f600000001000000,Horipad Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, 03000000341a000005f7000010010000,HuiJia GameCube Controller Adapter,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Linux, 05000000242e00000b20000001000000,Hyperkin Admiral N64 Controller,+rightx:b11,+righty:b13,-rightx:b8,-righty:b12,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,platform:Linux, @@ -1331,6 +1402,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 03000000632500007505000011010000,Ipega PG 9099,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, 0500000049190000030400001b010000,Ipega PG9099,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 05000000491900000204000000000000,Ipega PG9118,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000300f00001101000010010000,Jess Tech Colour Rumble Pad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux, 03000000300f00001001000010010000,Jess Tech Dual Analog Rumble,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux, 03000000300f00000b01000010010000,Jess Tech GGE909 PC Recoil,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux, 03000000ba2200002010000001010000,Jess Technology Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux, @@ -1360,6 +1432,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 03000000380700005032000011010000,Mad Catz Fightpad Pro PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 03000000380700005082000011010000,Mad Catz Fightpad Pro PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, 03000000ad1b00002ef0000090040000,Mad Catz Fightpad SFxT,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b2,y:b3,platform:Linux, +03000000380700008031000011010000,Mad Catz FightStick Alpha PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000380700008081000011010000,Mad Catz FightStick Alpha PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 03000000380700008034000011010000,Mad Catz Fightstick PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 03000000380700008084000011010000,Mad Catz Fightstick PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, 03000000380700008433000011010000,Mad Catz Fightstick TE S PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, @@ -1369,7 +1443,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 03000000380700001647000010040000,Mad Catz Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 03000000380700003847000090040000,Mad Catz Xbox 360 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, 03000000ad1b000016f0000090040000,Mad Catz Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -03000000120c00000500000000010000,Manta Dualshock 2,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux, +03000000120c00000500000000010000,Manta DualShock 2,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux, 030000008f0e00001330000010010000,Mayflash Controller Adapter,a:b1,b:b2,back:b8,dpdown:h0.8,dpleft:h0.2,dpright:h0.1,dpup:h0.4,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a3~,righty:a2,start:b9,x:b0,y:b3,platform:Linux, 03000000790000004318000010010000,Mayflash GameCube Adapter,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Linux, 03000000790000004418000010010000,Mayflash GameCube Controller,a:b1,b:b0,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Linux, @@ -1399,6 +1473,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 030000005e040000d102000003020000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000005e040000dd02000003020000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000005e040000ea02000008040000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000ea0200000f050000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 060000005e040000120b000009050000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000005e040000e302000003020000,Microsoft Xbox One Elite,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000005e040000000b000007040000,Microsoft Xbox One Elite 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b12,paddle2:b14,paddle3:b13,paddle4:b15,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, @@ -1406,7 +1481,9 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 050000005e040000050b000003090000,Microsoft Xbox One Elite 2,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 050000005e0400008e02000030110000,Microsoft Xbox One Elite 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b13,paddle3:b12,paddle4:b14,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000005e040000120b00000b050000,Microsoft Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -060000005e040000120b000001050000,Microsoft Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000120b000016050000,Microsoft Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000120b000017050000,Microsoft Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +060000005e040000120b000001050000,Microsoft Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 03000000030000000300000002000000,Miroof,a:b1,b:b0,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Linux, 03000000790000001c18000010010000,Mobapad Chitu HD,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 050000004d4f435554452d3035335800,Mocute 053X,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, @@ -1420,18 +1497,22 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 05000000c62400001a89000000010000,MOGA XP5X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 03000000250900006688000000010000,MP8866 Super Dual Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux, 030000005e0400008e02000010020000,MSI GC20 V2,a:b0,b:b1,back:b6,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -030000006f0e00001311000011010000,N64 Controller,+rightx:b10,+righty:b3,-rightx:b0,-righty:b11,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,platform:Linux, +03000000f70600000100000000010000,N64 Adaptoid,+rightx:b2,+righty:b1,-rightx:b4,-righty:b5,a:b0,b:b3,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,start:b8,platform:Linux, 030000006b1400000906000014010000,Nacon Asymmetric Wireless PS4 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000006b140000010c000010010000,Nacon GC 400ES,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, 03000000853200000706000012010000,Nacon GC-100,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +05000000853200000503000000010000,Nacon MG-X Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +0300000085320000170d000011010000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, +0300000085320000190d000011010000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, 030000000d0f00000900000010010000,Natec Genesis P44,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 030000004f1f00000800000011010000,NeoGeo PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, 0300000092120000474e000000010000,NeoGeo X Arcade Stick,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,x:b3,y:b2,platform:Linux, 03000000790000004518000010010000,Nexilux GameCube Controller Adapter,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Linux, 030000001008000001e5000010010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,platform:Linux, 060000007e0500003713000000000000,Nintendo 3DS,a:b0,b:b1,back:b8,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux, -030000007e0500003703000000016800,Nintendo GameCube Controller,a:b0,b:b2,dpdown:b6,dpleft:b4,dpright:b5,dpup:b7,lefttrigger:a4,leftx:a0,lefty:a1~,rightshoulder:b9,righttrigger:a5,rightx:a2,righty:a3~,start:b8,x:b1,y:b3,platform:Linux, 03000000790000004618000010010000,Nintendo GameCube Controller Adapter,a:b1,b:b0,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a5~,righty:a2~,start:b9,x:b2,y:b3,platform:Linux, +03000000ec110000e1a7000010010000,Nintendo Switch,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +030000007e0500006920000011010000,Nintendo Switch 2 Pro Controller,a:b0,b:b1,back:b14,dpdown:b8,dpleft:b10,dpright:b9,dpup:b11,guide:b16,leftshoulder:b12,leftstick:b15,lefttrigger:b13,leftx:a0,lefty:a1~,misc1:b17,misc2:b20,paddle1:b18,paddle2:b19,rightshoulder:b4,rightstick:b7,righttrigger:b5,rightx:a2,righty:a3~,start:b6,x:b2,y:b3,platform:Linux, 060000004e696e74656e646f20537700,Nintendo Switch Combined Joy-Cons,a:b0,b:b1,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux, 060000007e0500000620000000000000,Nintendo Switch Combined Joy-Cons,a:b0,b:b1,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux, 060000007e0500000820000000000000,Nintendo Switch Combined Joy-Cons,a:b0,b:b1,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux, @@ -1444,16 +1525,19 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 050000007e0500000720000001800000,Nintendo Switch Right Joy-Con,a:b1,b:b2,back:b9,leftshoulder:b4,leftstick:b10,leftx:a1~,lefty:a0,rightshoulder:b6,start:b8,x:b0,y:b3,platform:Linux, 05000000010000000100000003000000,Nintendo Wii Remote,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, 050000007e0500003003000001000000,Nintendo Wii U Pro Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux, +050000005a1d00000218000003000000,Nokia GC 5000,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 030000000d0500000308000010010000,Nostromo n45 Dual Analog,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b12,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b2,y:b3,platform:Linux, -030000007e0500001920000011810000,NSO N64 Controller,+rightx:b10,+righty:b8,-rightx:b9,-righty:b7,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b3,lefttrigger:b2,leftx:a0,lefty:a1,misc1:b12,rightshoulder:b4,righttrigger:b5,start:b6,platform:Linux, +030000007e0500007320000011010000,NSO GameCube Controller,a:b1,b:b3,dpdown:b8,dpleft:b10,dpright:b9,dpup:b11,guide:b16,leftshoulder:b13,lefttrigger:b12,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b4,rightx:a2,righty:a3~,start:b6,x:b0,y:b2,platform:Linux, +030000007e0500001920000011810000,NSO N64 Controller,+rightx:b2,+righty:b3,-rightx:b4,-righty:b10,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b5,rightshoulder:b7,righttrigger:b9,start:b11,platform:Linux, 050000007e0500001920000001000000,NSO N64 Controller,+rightx:b8,+righty:b7,-rightx:b3,-righty:b2,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,righttrigger:b10,start:b9,platform:Linux, -050000007e0500001920000001800000,NSO N64 Controller,+rightx:b10,+righty:b8,-rightx:b9,-righty:b7,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b3,lefttrigger:b2,leftx:a0,lefty:a1,misc1:b12,rightshoulder:b4,righttrigger:b5,start:b6,platform:Linux, -030000007e0500001720000011810000,NSO SNES Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b2,platform:Linux, +050000007e0500001920000001800000,NSO N64 Controller,+rightx:b2,+righty:b3,-rightx:b4,-righty:b10,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b5,rightshoulder:b7,righttrigger:b9,start:b11,platform:Linux, +030000007e0500001e20000011810000,NSO Sega Genesis Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,misc1:b3,rightshoulder:b2,righttrigger:b4,start:b5,platform:Linux, +030000007e0500001720000011810000,NSO SNES Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b2,platform:Linux, 050000007e0500001720000001000000,NSO SNES Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:b7,rightshoulder:b6,righttrigger:b8,start:b10,x:b3,y:b2,platform:Linux, -050000007e0500001720000001800000,NSO SNES Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b2,platform:Linux, +050000007e0500001720000001800000,NSO SNES Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b2,platform:Linux, 03000000550900001072000011010000,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b8,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux, -03000000550900001472000011010000,NVIDIA Controller v01.04,a:b0,b:b1,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Linux, -05000000550900001472000001000000,NVIDIA Controller v01.04,a:b0,b:b1,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Linux, +03000000550900001472000011010000,NVIDIA Controller,a:b0,b:b1,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b8,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Linux, +05000000550900001472000001000000,NVIDIA Controller,a:b0,b:b1,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b8,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Linux, 030000004b120000014d000000010000,NYKO Airflo EX,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux, 03000000451300000830000010010000,NYKO CORE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, 19000000010000000100000001010000,ODROID Go 2,a:b1,b:b0,dpdown:b7,dpleft:b8,dpright:b9,dpup:b6,guide:b10,leftshoulder:b4,leftstick:b12,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b13,righttrigger:b14,start:b15,x:b2,y:b3,platform:Linux, @@ -1466,7 +1550,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 030000006f0e0000b802000001010000,PDP Afterglow Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000006f0e0000b802000013020000,PDP Afterglow Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000006f0e00006401000001010000,PDP Battlefield One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -030000006f0e0000d702000006640000,PDP Black Camo Wired Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:b13,dpleft:b14,dpright:b13,dpup:b14,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006f0e0000d702000006640000,PDP Black Camo Wired Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:b13,dpleft:b14,dpright:b13,dpup:b14,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000006f0e00003101000000010000,PDP EA Sports Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000006f0e00008501000011010000,PDP Fightpad Pro Gamecube Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, 030000006f0e0000c802000012010000,PDP Kingdom Hearts Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, @@ -1474,16 +1558,14 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 030000006f0e00000901000011010000,PDP PS3 Versus Fighting,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, 030000006f0e00002f01000011010000,PDP Wired PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 03000000ad1b000004f9000000010000,PDP Xbox 360 Versus Fighting,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b2,y:b3,platform:Linux, +030000006f0e0000f102000000000000,PDP Xbox Atomic,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000006f0e0000a802000023020000,PDP Xbox One Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, 030000006f0e0000a702000023020000,PDP Xbox One Raven Black,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000006f0e0000d802000006640000,PDP Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000006f0e0000ef02000007640000,PDP Xbox Series Kinetic Wired Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -03000000666600006706000000010000,PlayStation Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,platform:Linux, -030000004c050000da0c000011010000,PlayStation Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux, -03000000d9040000160f000000010000,PlayStation Controller Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux, -030000004c0500003713000011010000,PlayStation Vita,a:b1,b:b2,back:b8,dpdown:b13,dpleft:b15,dpright:b14,dpup:b12,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Linux, 03000000c62400000053000000010000,PowerA,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 03000000c62400003a54000001010000,PowerA 1428124-01,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000d62000000540000001010000,PowerA Advantage Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 03000000d620000011a7000011010000,PowerA Core Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 03000000dd62000015a7000011010000,PowerA Fusion Nintendo Switch Arcade Stick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 03000000d620000012a7000011010000,PowerA Fusion Nintendo Switch Fight Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, @@ -1498,8 +1580,9 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 03000000d62000000228000001010000,PowerA Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 03000000c62400001a54000001010000,PowerA Xbox One Mini Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 03000000d62000000240000001010000,PowerA Xbox One Spectra Infinity,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000d62000000520000050010000,PowerA Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000d62000000b20000001010000,PowerA Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 03000000d62000000f20000001010000,PowerA Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b7,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -03000000d62000000b20000001010000,PowerA Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000006d040000d2ca000011010000,Precision Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 03000000250900000017000010010000,PS/SS/N64 Adapter,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b5,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2~,righty:a3,start:b8,platform:Linux, 03000000ff1100004133000010010000,PS2 Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux, @@ -1519,6 +1602,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 060000004c0500006802000000010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux, 030000004c050000a00b000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, 030000004c050000a00b000011810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, +030000004c050000c405000000810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, 030000004c050000c405000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, 030000004c050000c405000011810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, 030000004c050000cc09000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, @@ -1535,25 +1619,32 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 030000004c050000e60c000011010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, 030000004c050000e60c000011810000,PS5 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, 030000004c050000f20d000011010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, +030000004c050000f20d000011810000,PS5 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, 050000004c050000e60c000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, 050000004c050000e60c000000810000,PS5 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, 050000004c050000f20d000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, +050000004c050000f20d000000810000,PS5 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, 03000000300f00001211000011010000,Qanba Arcade Joystick,a:b2,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b6,start:b9,x:b1,y:b3,platform:Linux, -03000000222c00000225000011010000,Qanba Dragon Arcade Joystick (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, -03000000222c00000025000011010000,Qanba Dragon Arcade Joystick (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, -03000000222c00001220000011010000,Qanba Drone 2 Arcade Joystick (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, -03000000222c00001020000011010000,Qanba Drone 2 Arcade Joystick (PS5),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +03000000222c00000225000011010000,Qanba Dragon Arcade Joystick PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000222c00000025000011010000,Qanba Dragon Arcade Joystick PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, +03000000222c00001220000011010000,Qanba Drone 2 Arcade Joystick PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +03000000222c00001020000011010000,Qanba Drone 2 Arcade Joystick PS5,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, 03000000222c00000020000011010000,Qanba Drone Arcade PS4 Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,rightshoulder:b5,righttrigger:a4,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, 03000000300f00001210000010010000,Qanba Joystick Plus,a:b0,b:b1,back:b8,leftshoulder:b5,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b6,start:b9,x:b2,y:b3,platform:Linux, -03000000222c00000223000011010000,Qanba Obsidian Arcade Joystick (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, -03000000222c00000023000011010000,Qanba Obsidian Arcade Joystick (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, +03000000222c00000223000011010000,Qanba Obsidian Arcade Joystick PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000222c00000023000011010000,Qanba Obsidian Arcade Joystick PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, 030000009b2800000300000001010000,Raphnet 4nes4snes,a:b0,b:b4,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Linux, 030000009b2800004200000001010000,Raphnet Dual NES Adapter,a:b0,b:b1,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b3,platform:Linux, 0300132d9b2800006500000000000000,Raphnet GameCube Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Linux, 0300132d9b2800006500000001010000,Raphnet GameCube Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Linux, 030000009b2800003200000001010000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Linux, 030000009b2800006000000001010000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Linux, +030000009b2800003c00000001010000,Raphnet N64 Adapter,+rightx:b9,+righty:b7,-rightx:b8,-righty:b6,a:b0,b:b1,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,lefttrigger:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Linux, +030000009b2800006100000001010000,Raphnet N64 Adapter,+rightx:b9,+righty:b7,-rightx:b8,-righty:b6,a:b0,b:b1,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,lefttrigger:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Linux, +030000009b2800006300000001010000,Raphnet N64 Adapter,+rightx:b9,+righty:b7,-rightx:b8,-righty:b6,a:b0,b:b1,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,lefttrigger:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Linux, +030000009b2800006400000001010000,Raphnet N64 Adapter,+rightx:b9,+righty:b7,-rightx:b8,-righty:b6,a:b0,b:b1,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,lefttrigger:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Linux, 030000009b2800008000000020020000,Raphnet Wii Classic Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Linux, +030000009b2800008000000001010000,Raphnet Wii Classic Adapter V3,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Linux, 03000000f8270000bf0b000011010000,Razer Kishi,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 030000008916000001fd000024010000,Razer Onza Classic Edition,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 03000000321500000204000011010000,Razer Panthera PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, @@ -1570,6 +1661,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 050000003215000000090000163a0000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux, 0300000032150000030a000001010000,Razer Wildcat,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 03000000321500000b10000011010000,Razer Wolverine PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, +0300000032150000140a000001010000,Razer Wolverine Ultimate Xbox,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000000d0f0000c100000010010000,Retro Bit Legacy16,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b12,leftshoulder:b4,lefttrigger:b6,misc1:b13,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, 03000000790000001100000010010000,Retro Controller,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,start:b9,x:b0,y:b3,platform:Linux, 0300000003040000c197000011010000,Retrode Adapter,a:b0,b:b4,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Linux, 190000004b4800000111000000010000,RetroGame Joypad,a:b1,b:b0,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, @@ -1584,10 +1677,12 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 030000006f0e00001e01000011010000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 03000000c6240000fefa000000010000,Rock Candy Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000006f0e00004601000001010000,Rock Candy Xbox One Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -03000000a306000023f6000011010000,Saitek Cyborg V1 PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux, +030000006f0e00001311000011010000,Saffun Controller,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b0,platform:Linux, +03000000a306000023f6000011010000,Saitek Cyborg PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux, 03000000a30600001005000000010000,Saitek P150,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b7,lefttrigger:b6,rightshoulder:b2,righttrigger:b5,x:b3,y:b4,platform:Linux, 03000000a30600000701000000010000,Saitek P220,a:b2,b:b3,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,x:b0,y:b1,platform:Linux, 03000000a30600000cff000010010000,Saitek P2500 Force Rumble,a:b2,b:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b0,y:b1,platform:Linux, +03000000a30600000d5f000010010000,Saitek P2600,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a3,righty:a2,start:b8,x:b0,y:b3,platform:Linux, 03000000a30600000c04000011010000,Saitek P2900,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b12,x:b0,y:b3,platform:Linux, 03000000a306000018f5000010010000,Saitek P3200 Rumble,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Linux, 03000000300f00001201000010010000,Saitek P380,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux, @@ -1603,21 +1698,21 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 03000000790000001100000011010000,Sega Saturn,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b4,start:b9,x:b0,y:b3,platform:Linux, 03000000790000002201000011010000,Sega Saturn,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,start:b9,x:b2,y:b3,platform:Linux, 03000000b40400000a01000000010000,Sega Saturn,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Linux, -030000001f08000001e4000010010000,SFC Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Linux, 03000000632500002305000010010000,ShanWan Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, -03000000632500002605000010010000,Shanwan Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, -03000000632500007505000010010000,Shanwan Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, -03000000bc2000000055000010010000,Shanwan Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, -03000000f025000021c1000010010000,Shanwan Gioteck PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +03000000632500002605000010010000,ShanWan Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000632500007505000010010000,ShanWan Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +03000000bc2000000055000010010000,ShanWan Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 03000000341a00000908000010010000,SL6566,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, 030000004b2900000430000011000000,Snakebyte Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 050000004c050000cc09000001000000,Sony DualShock 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, +03000000666600006706000000010000,Sony PlayStation Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,platform:Linux, +030000004c050000da0c000011010000,Sony PlayStation Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux, +03000000d9040000160f000000010000,Sony PlayStation Controller Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux, 03000000ff000000cb01000010010000,Sony PlayStation Portable,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Linux, +030000004c0500003713000011010000,Sony PlayStation Vita,a:b1,b:b2,back:b8,dpdown:b13,dpleft:b15,dpright:b14,dpup:b12,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Linux, 03000000250900000500000000010000,Sony PS2 pad with SmartJoy Adapter,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux, 030000005e0400008e02000073050000,Speedlink Torid,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000005e0400008e02000020200000,SpeedLink Xeox Pro Analog,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -03000000d11800000094000011010000,Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux, -05000000d11800000094000000010000,Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux, 03000000de2800000112000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux, 03000000de2800000112000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:+a5,dpleft:-a4,dpright:+a4,dpup:-a5,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,paddle1:b15,paddle2:b16,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a3,start:b11,x:b4,y:b5,platform:Linux, 03000000de2800000211000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux, @@ -1638,6 +1733,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 05000000110100001914000009010000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 03000000ad1b000038f0000090040000,Street Fighter IV Fightstick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000003b07000004a1000000010000,Suncom SFX Plus,a:b0,b:b2,back:b7,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b9,righttrigger:b5,start:b8,x:b1,y:b3,platform:Linux, +030000001f08000001e4000010010000,Super Famicom Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Linux, 03000000666600000488000000010000,Super Joy Box 5 Pro,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux, 0300000000f00000f100000000010000,Super RetroPort,a:b1,b:b5,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Linux, 030000008f0e00000d31000010010000,SZMY Power 3 Turbo,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, @@ -1647,7 +1743,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 03000000e40a00000307000011010000,Taito Egret II Mini Control Panel,a:b4,b:b2,back:b6,guide:b9,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b1,start:b7,x:b8,y:b3,platform:Linux, 03000000e40a00000207000011010000,Taito Egret II Mini Controller,a:b4,b:b2,back:b6,guide:b9,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b1,start:b7,x:b8,y:b3,platform:Linux, 03000000ba2200000701000001010000,Technology Innovation PS2 Adapter,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a5,righty:a2,start:b9,x:b3,y:b2,platform:Linux, -03000000790000001c18000011010000,TGZ Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000790000001c18000011010000,TGZ Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 03000000591c00002400000010010000,THEC64 Joystick,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Linux, 03000000591c00002600000010010000,THEGamepad,a:b2,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b3,y:b0,platform:Linux, 030000004f04000015b3000001010000,Thrustmaster Dual Analog 3.2,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux, @@ -1681,6 +1777,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 03000000100800000300000010010000,USB Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux, 03000000790000000600000007010000,USB gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Linux, 03000000790000001100000000010000,USB Gamepad,a:b2,b:b1,back:b8,dpdown:a0,dpleft:a1,dpright:a2,dpup:a4,start:b9,platform:Linux, +03000000790000001a18000011010000,Venom PS4 Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000790000001b18000011010000,Venom PS4 Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, 030000006f0e00000302000011010000,Victrix Pro Fightstick PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, 030000006f0e00000702000011010000,Victrix Pro Fightstick PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, 05000000ac0500003232000001000000,VR Box Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux, @@ -1696,10 +1794,11 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 030000006f0e00001503000000020000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000005e0400008e02000000010000,Xbox 360 EasySMX,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000005e040000a102000014010000,Xbox 360 Receiver,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +0000000058626f782047616d65706100,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux, 030000005e0400000202000000010000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux, +030000005e0400008e02000072050000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000006f0e00001304000000010000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 03000000ffff0000ffff000000010000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux, -0000000058626f782047616d65706100,Xbox Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux, 030000005e0400000a0b000005040000,Xbox One Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux, 030000005e040000d102000002010000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000005e040000ea02000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, @@ -1707,18 +1806,24 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 050000005e040000e002000003090000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 050000005e040000fd02000003090000,Xbox One Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 050000005e040000fd02000030110000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +060000005e040000dd02000003020000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 050000005e040000e302000002090000,Xbox One Elite,a:b0,b:b1,back:b136,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 050000005e040000220b000013050000,Xbox One Elite 2 Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 050000005e040000050b000002090000,Xbox One Elite Series 2,a:b0,b:b1,back:b136,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 030000005e040000ea02000011050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000ea02000015050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000ea02000017050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 060000005e040000ea0200000b050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 060000005e040000ea0200000d050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +060000005e040000ea02000016050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000005e040000120b000001050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000005e040000120b000005050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000005e040000120b000007050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000005e040000120b000009050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000005e040000120b00000d050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000005e040000120b00000f050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000120b000011050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000120b000014050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000005e040000120b000015050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000005e040000130b000005050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 050000005e040000130b000001050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, @@ -1728,15 +1833,16 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 050000005e040000130b000011050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 050000005e040000130b000013050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 050000005e040000130b000015050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +050000005e040000130b000017050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 060000005e040000120b000007050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 060000005e040000120b00000b050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +060000005e040000120b00000d050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 060000005e040000120b00000f050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -030000005e040000120b000011050000,Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -030000005e040000120b000014050000,Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -050000005e040000130b000017050000,Xbox Series X Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, -060000005e040000120b00000d050000,Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +050000005e040000130b000022050000,Xbox Series X Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +060000005e040000120b000011050000,Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 050000005e040000200b000013050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 050000005e040000200b000017050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +050000005e040000200b000023050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 050000005e040000220b000017050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 03000000450c00002043000010010000,XEOX SL6556 BK,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, 05000000172700004431000029010000,XiaoMi Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Linux, @@ -1745,6 +1851,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 03000000120c0000100e000011010000,Zeroplus P4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, 03000000120c0000101e000011010000,Zeroplus P4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +03000000120c0000182e000011010000,Zeroplus PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, # Android 38653964633230666463343334313533,8BitDo Adapter,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, @@ -1756,7 +1863,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 33313433353539306634656436353432,8BitDo Dogbone,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 38426974446f20446f67626f6e65204d,8BitDo Dogbone,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b6,platform:Android, 34343439373236623466343934376233,8BitDo FC30 Pro,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b28,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b29,righttrigger:b7,start:b5,x:b30,y:b2,platform:Android, -38426974446f204e4743204d6f646b69,8BitDo GameCube,a:b0,b:b2,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,paddle1:b18,paddle2:b17,rightshoulder:b15,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b1,y:b3,platform:Android, +38426974446f204e4743204d6f646b69,8BitDo GameCube,a:b0,b:b2,back:b4,dpdown:b12,dpleft:b13,dpright:b14,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,paddle1:b18,paddle2:b17,rightshoulder:b15,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b1,y:b3,platform:Android, 38426974446f2038426974446f204c69,8BitDo Lite,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, 30643332373663313263316637356631,8BitDo Lite 2,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, 38426974446f204c6974652032000000,8BitDo Lite 2,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, @@ -1830,7 +1937,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 63396666386564393334393236386630,8BitDo Zero 2,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android, 63633435623263373466343461646430,8BitDo Zero 2,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b2,y:b3,platform:Android, 32333634613735616163326165323731,Amazon Luna Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,x:b2,y:b3,platform:Android, -4c696e757820342e31392e3137322077,Anbernic Gamepad,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a4,start:b6,x:b2,y:b3,platform:Android, +4c696e757820342e31392e3137322077,Anbernic Handheld,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a4,start:b6,x:b2,y:b3,platform:Android, 417374726f2063697479206d696e6920,Astro City Mini,a:b23,b:b22,back:b29,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b25,righttrigger:b26,start:b30,x:b24,y:b21,platform:Android, 35643263313264386134376362363435,Atari VCS Classic Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,start:b6,platform:Android, 32353831643566306563643065356239,Atari VCS Modern Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, @@ -1844,6 +1951,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 05000000bc20000000550000ffff3f00,GameSir G3w,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 34323662653333636330306631326233,Google Nexus,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 35383633353935396534393230616564,Google Stadia Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +476f6f676c65204c4c43205374616469,Google Stadia Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +5374616469614e3848532d6532633400,Google Stadia Controller,a:b0,b:b1,back:b15,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 05000000d6020000e5890000dfff3f00,GPD XD Plus,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Android, 05000000d6020000e5890000dfff3f80,GPD XD Plus,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a3,rightx:a4,righty:a5,start:b6,x:b2,y:b3,platform:Android, 66633030656131663837396562323935,Hori Battle,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Android, @@ -1868,6 +1977,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 4a6f792d436f6e20284c290000000000,Joy-Con (L),a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,rightshoulder:b20,start:b17,x:b19,y:b2,platform:Android, 38383665633039363066383334653465,Joy-Con (R),a:b0,b:b1,back:b5,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,rightshoulder:b20,start:b18,x:b19,y:b2,platform:Android, 39363561613936303237333537383931,Joy-Con (R),a:b0,b:b1,back:b5,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,rightshoulder:b20,start:b18,x:b19,y:b2,platform:Android, +39373064396565646338333134303131,Joy-Con (R),a:b1,b:b2,back:b5,leftstick:b8,leftx:a1~,lefty:a0,start:b6,x:b0,y:b3,platform:Android, 4a6f792d436f6e202852290000000000,Joy-Con (R),a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,rightshoulder:b20,start:b18,x:b19,y:b2,platform:Android, 39656136363638323036303865326464,JYS Aapter,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android, 63316564383539663166353034616434,JYS Adapter,a:b1,b:b3,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b0,y:b2,platform:Android, @@ -1901,6 +2011,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 39306635663061636563316166303966,Mocute M053,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 7573622067616d657061642020202020,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,platform:Android, 050000007e05000009200000ffff0f00,Nintendo Switch Pro Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b16,x:b17,y:b2,platform:Android, +31316661666466633938376335383661,Nintendo Switch Pro Controller,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,misc1:b5,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,start:b6,x:b3,y:b2,platform:Android, 34323437396534643531326161633738,Nintendo Switch Pro Controller,a:b0,b:b1,back:b15,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,misc1:b5,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 50726f20436f6e74726f6c6c65720000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b2,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b10,rightx:a2,righty:a3,start:b18,y:b3,platform:Android, 36326533353166323965623661303933,NSO N64 Controller,+rightx:b17,+righty:b10,-rightx:b2,-righty:b19,a:b1,b:b0,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,misc1:b7,rightshoulder:b20,righttrigger:b15,start:b18,platform:Android, @@ -1917,9 +2028,6 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 39383335313438623439373538343266,OUYA Controller,a:b0,b:b2,dpdown:b18,dpleft:b15,dpright:b16,dpup:b17,leftshoulder:b3,leftstick:b9,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b10,righttrigger:b7,rightx:a3,righty:a4,x:b1,y:b19,platform:Android, 4f5559412047616d6520436f6e74726f,OUYA Controller,a:b0,b:b2,dpdown:b18,dpleft:b15,dpright:b6,dpup:b17,leftshoulder:b3,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b19,platform:Android, 506572666f726d616e63652044657369,PDP PS3 Rock Candy Controller,a:b1,b:b17,back:h0.2,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b4,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b16,x:b0,y:b2,platform:Android, -62653335326261303663356263626339,PlayStation Classic Controller,a:b19,b:b1,back:b17,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,lefttrigger:b3,rightshoulder:b10,righttrigger:b20,start:b18,x:b2,y:b0,platform:Android, -536f6e7920496e746572616374697665,PlayStation Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,misc1:b8,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, -576972656c65737320436f6e74726f6c,PlayStation Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 61653962353232366130326530363061,Pokken,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,lefttrigger:b9,rightshoulder:b20,righttrigger:b10,start:b18,x:b0,y:b2,platform:Android, 32666633663735353234363064386132,PS2,a:b23,b:b22,back:b29,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b27,lefttrigger:b25,leftx:a0,lefty:a1,rightshoulder:b28,righttrigger:b26,rightx:a3,righty:a2,start:b30,x:b24,y:b21,platform:Android, 050000004c05000068020000dfff3f00,PS3 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, @@ -1947,7 +2055,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 65366465656364636137653363376531,PS4 Controller,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android, 66613532303965383534396638613230,PS4 Controller,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a5,start:b18,x:b0,y:b2,platform:Android, 050000004c050000e60c0000fffe3f00,PS5 Controller,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,platform:Android, -050000004c050000e60c0000fffe3f80,PS5 Controller,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:a3,rightx:a4,righty:a5,start:b16,x:b0,y:b2,platform:Android, +050000004c050000e60c0000fffe3f80,PS5 Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:a3,rightx:a4,righty:a5,start:b16,x:b2,y:b17,platform:Android, 050000004c050000e60c0000ffff3f00,PS5 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 32346465346533616263386539323932,PS5 Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 32633532643734376632656664383733,PS5 Controller,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a5,start:b18,x:b0,y:b2,platform:Android, @@ -1967,6 +2075,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 61343739353764363165343237303336,Retro Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b17,lefttrigger:b18,leftx:a0,lefty:a1,start:b10,x:b2,y:b3,platform:Android, 526574726f696420506f636b65742043,Retroid Pocket,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b17,paddle2:b18,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, 582d426f7820436f6e74726f6c6c6572,Retroid Pocket,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b17,paddle2:b18,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +64633735616665613536653363336132,Retroid Pocket,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,paddle1:b19,paddle2:b20,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, 38653130373365613538333235303036,Retroid Pocket 2,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 64363363336633363736393038313463,Retrolink,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,start:b6,platform:Android, 37393234373533633333323633646531,RetroUSB N64 RetroPort,+rightx:b17,+righty:b15,-rightx:b18,-righty:b6,a:b10,b:b9,dpdown:b19,dpleft:b1,dpright:b0,dpup:b2,leftshoulder:b7,lefttrigger:b20,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Android, @@ -1988,10 +2097,11 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 38376662666661636265313264613039,SNES,a:b0,b:b1,back:b9,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b3,rightshoulder:b20,start:b10,x:b19,y:b2,platform:Android, 5346432f555342205061640000000000,SNES Adapter,a:b0,b:b1,back:b9,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b3,rightshoulder:b20,start:b10,x:b19,y:b2,platform:Android, 5553422047616d657061642000000000,SNES Controller,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android, +62653335326261303663356263626339,Sony PlayStation Classic Controller,a:b19,b:b1,back:b17,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,lefttrigger:b3,rightshoulder:b10,righttrigger:b20,start:b18,x:b2,y:b0,platform:Android, +536f6e7920496e746572616374697665,Sony PlayStation Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,misc1:b8,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +576972656c65737320436f6e74726f6c,Sony PlayStation Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 63303964303462366136616266653561,Sony PSP,a:b21,b:b22,back:b27,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b25,leftx:a0,lefty:a1,rightshoulder:b26,start:b28,x:b23,y:b24,platform:Android, 63376637643462343766333462383235,Sony Vita,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftx:a0,lefty:a1,rightshoulder:b20,rightx:a3,righty:a4,start:b18,x:b0,y:b2,platform:Android, -476f6f676c65204c4c43205374616469,Stadia Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, -5374616469614e3848532d6532633400,Stadia Controller,a:b0,b:b1,back:b15,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Android, 05000000de2800000611000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Android, 0500000011010000201400000f7e0f00,SteelSeries Nimbus,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:b10,rightx:a2,righty:a3,x:b19,y:b2,platform:Android, @@ -2001,7 +2111,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 62363434353532386238336663643836,TGZ Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 37323236633763666465316365313236,THEC64 Joystick,a:b21,b:b22,back:b27,leftshoulder:b25,leftx:a0,lefty:a1,rightshoulder:b26,start:b27,x:b23,y:b24,platform:Android, 38346162326232346533316164363336,THEGamepad,a:b23,b:b22,back:b27,leftshoulder:b25,leftx:a0,lefty:a1,rightshoulder:b26,start:b28,x:b24,y:b21,platform:Android, -050000004f0400000ed00000fffe3f00,ThrustMaster eSwap Pro Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +050000004f0400000ed00000fffe3f00,Thrustmaster eSwap Pro Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 5477696e20555342204a6f7973746963,Twin Joystick,a:b22,b:b21,back:b28,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b26,leftstick:b30,lefttrigger:b24,leftx:a0,lefty:a1,rightshoulder:b27,rightstick:b31,righttrigger:b25,rightx:a3,righty:a2,start:b29,x:b23,y:b20,platform:Android, 30623739343039643830333266346439,Valve Steam Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,leftx:a0,lefty:a1,paddle1:b24,paddle2:b23,rightshoulder:b10,rightstick:b8,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 31643365666432386133346639383937,Valve Steam Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,leftx:a0,lefty:a1,paddle1:b24,paddle2:b23,rightshoulder:b10,rightstick:b8,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, @@ -2026,8 +2136,9 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 33356661323266333733373865656366,Xbox One Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 34356136633366613530316338376136,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b3,leftstick:b15,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b16,righttrigger:a5,rightx:a3,righty:a4,x:b17,y:b2,platform:Android, 35623965373264386238353433656138,Xbox One Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, -36616131643361333337396261666433,Xbox One Controller,a:b0,b:b1,back:b15,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +36616131643361333337396261666433,Xbox One Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 58626f7820576972656c65737320436f,Xbox One Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +65316262316265373335666131623538,Xbox One Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 050000005e040000000b000000783f00,Xbox One Elite 2 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Android, 050000005e040000000b000000783f80,Xbox One Elite 2 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 050000005e040000050b0000ffff3f00,Xbox One Elite 2 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a6,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, @@ -2048,17 +2159,22 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 05000000ac05000001000000ff076d01,*,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS, 05000000ac0500000200000000006d02,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,rightshoulder:b5,x:b2,y:b3,platform:iOS, 05000000ac050000020000004f066d02,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,rightshoulder:b5,x:b2,y:b3,platform:iOS, +05000000ac05000004000000a8986d04,8BitDo Micro,a:b1,b:b0,back:b4,dpdown:b7,dpleft:b8,dpright:b9,dpup:b10,guide:b2,leftshoulder:b11,lefttrigger:b12,rightshoulder:b13,righttrigger:b14,start:b3,x:b6,y:b5,platform:iOS, +05000000ac05000004000000fd216d04,8BitDo Pro 2,a:b3,b:b2,back:b6,dpdown:b9,dpleft:b10,dpright:b11,dpup:b12,guide:b4,leftshoulder:b13,leftstick:b14,lefttrigger:+a2,leftx:a0,lefty:a1~,paddle1:b1,paddle2:b0,rightshoulder:b16,rightstick:b17,righttrigger:+a5,rightx:a3,righty:a4~,start:b5,x:b8,y:b7,platform:iOS, +05000000ac05000004000000209f6d04,8Bitdo SN30 Pro,a:b1,b:b0,back:b4,dpdown:b7,dpleft:b8,dpright:b9,dpup:b10,guide:b2,leftshoulder:b11,leftstick:b12,lefttrigger:b13,leftx:a0,lefty:a1~,rightshoulder:b14,rightstick:b15,righttrigger:b16,rightx:a2,righty:a3~,start:b3,x:b6,y:b5,platform:iOS, +05000000ac050000040000003b8a6d04,8BitDo SN30 Pro+,a:b1,b:b0,back:b4,dpdown:b7,dpleft:b8,dpright:b9,dpup:b10,guide:b2,leftshoulder:b11,leftstick:b12,lefttrigger:b13,leftx:a0,lefty:a1~,rightshoulder:b14,rightstick:b15,righttrigger:b16,rightx:a2,righty:a3~,start:b3,x:b6,y:b5,platform:iOS, 050000008a35000003010000ff070000,Backbone One,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS, 050000008a35000004010000ff070000,Backbone One,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS, 4d466947616d65706164010000000000,MFi Extended Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:iOS, 4d466947616d65706164020000000000,MFi Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,start:b6,x:b2,y:b3,platform:iOS, 050000007e050000062000000f060000,Nintendo Switch Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b2,leftshoulder:b4,rightshoulder:b5,x:b1,y:b3,platform:iOS, 050000007e050000062000004f060000,Nintendo Switch Joy-Con (L),+leftx:h0.1,+lefty:h0.2,-leftx:h0.4,-lefty:h0.8,dpdown:b2,dpleft:b0,dpright:b3,dpup:b1,leftshoulder:b4,misc1:b6,rightshoulder:b5,platform:iOS, -050000007e05000008200000df070000,Nintendo Switch Joy-Con (L/R),a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS, +050000007e05000008200000df070000,Nintendo Switch Joy-Con (L/R),a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:iOS, 050000007e0500000e200000df070000,Nintendo Switch Joy-Con (L/R),a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:iOS, -050000007e050000072000004f060000,Nintendo Switch Joy-Con (R),+rightx:h0.4,+righty:h0.8,-rightx:h0.1,-righty:h0.2,a:b1,b:b0,guide:b6,leftshoulder:b4,rightshoulder:b5,x:b3,y:b2,platform:iOS, +050000007e050000072000000f060000,Nintendo Switch Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b2,leftshoulder:b4,rightshoulder:b5,x:b1,y:b3,platform:iOS, +050000007e050000072000004f060000,Nintendo Switch Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b2,guide:b6,leftshoulder:b4,rightshoulder:b5,x:b1,y:b3,platform:iOS, 050000007e05000009200000df870000,Nintendo Switch Pro Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b10,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:iOS, -050000007e05000009200000ff870000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS, +050000007e05000009200000ff870000,Nintendo Switch Pro Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b3,y:b2,platform:iOS, 050000004c050000cc090000df070000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS, 050000004c050000cc090000df870001,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS, 050000004c050000cc090000ff070000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS, @@ -2070,9 +2186,9 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 05000000ac0500000300000043006d03,Remote,a:b0,b:b2,leftx:a0,lefty:a1,platform:iOS, 05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:iOS, 05000000de2800000611000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:iOS, -050000005e040000050b0000df070001,Xbox Elite Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b10,paddle2:b12,paddle3:b11,paddle4:b13,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS, -050000005e040000050b0000ff070001,Xbox Elite Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b13,paddle3:b12,paddle4:b14,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS, -050000005e040000e0020000df070000,Xbox One Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS, -050000005e040000e0020000ff070000,Xbox One Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS, +050000005e040000050b0000df070001,Xbox Elite Wireless Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b10,paddle2:b12,paddle3:b11,paddle4:b13,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS, +050000005e040000050b0000ff070001,Xbox Elite Wireless Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b13,paddle3:b12,paddle4:b14,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS, 050000005e040000130b0000df870001,Xbox Series X Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b10,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS, 050000005e040000130b0000ff870001,Xbox Series X Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS, +050000005e040000e0020000df070000,Xbox Wireless Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS, +050000005e040000e0020000ff070000,Xbox Wireless Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS, diff --git a/files/lang/launcher_fr.ts b/files/lang/launcher_fr.ts index 28892978361..dd83c376419 100644 --- a/files/lang/launcher_fr.ts +++ b/files/lang/launcher_fr.ts @@ -1472,11 +1472,11 @@ to default Morrowind fonts. Check this box if you still prefer original fonts ov Doppler Factor - + Facteur Doppler <html><head/><body><p>Controls the strength of the Doppler effect. Zero means it is completely disabled.</p><p>The Doppler effect increases or decreases the pitch of sounds relative to the velocity of the sound source and the listener.</p></body></html> - + <html><head/><body><p>Controle la puissance de l'effet Doppler. La valeur zéro le désactivant complétement.</p><p>L'effet Doppler augmente ou diminue la hauteur des sons relativement à la vélocité de leur source par rapport au joueur.</p></body></html> diff --git a/files/lua_api/openmw/core.lua b/files/lua_api/openmw/core.lua index 5dc4bfb4e24..e5d5a3ae7fe 100644 --- a/files/lua_api/openmw/core.lua +++ b/files/lua_api/openmw/core.lua @@ -57,10 +57,13 @@ -- @return #number --- --- Get a GMST setting from content files. +-- Get a game setting with given name (from GMST ESM records or from openmw.cfg). -- @function [parent=#core] getGMST -- @param #string setting Setting name -- @return #any +-- @usage local skillBonus = core.getGMST('fMinorSkillBonus') -- get a numeric GMST from ESM data +-- @usage local jailFormatString = core.getGMST('sNotifyMessage42') -- get a string GMST from ESM data +-- @usage local bloodTextureName = core.getGMST('Blood_Texture_1') -- get a "fallback" parameter value from openmw.cfg (always a string) --- -- The game's difficulty setting. @@ -297,13 +300,14 @@ -- A cell of the game world. -- @type Cell -- @field #string name Name of the cell (can be empty string). +-- @field #string displayName Human-readable cell name (takes into account *.cel file localizations). Can be empty string. -- @field #string id Unique record ID of the cell, based on cell name for interiors and the worldspace for exteriors, or the formID of the cell for ESM4 cells. --- @field #string region Region of the cell. +-- @field #string region Region of the cell (can be nil). -- @field #boolean isExterior Whether the cell is an exterior cell. "Exterior" means grid of cells where the player can seamless walk from one cell to another without teleports. QuasiExterior (interior with sky) is not an exterior. -- @field #boolean isQuasiExterior (DEPRECATED, use `hasTag("QuasiExterior")`) Whether the cell is a quasi exterior (like interior but with the sky and the weather). -- @field #number gridX Index of the cell by X (only for exteriors). -- @field #number gridY Index of the cell by Y (only for exteriors). --- @field #string worldSpaceId Id of the world space. +-- @field #string worldSpaceId Id of the world space (can be nil). -- @field #boolean hasWater True if the cell contains water. -- @field #number waterLevel The water level of the cell. (nil if cell has no water). -- @field #boolean hasSky True if in this cell sky should be rendered. @@ -1305,24 +1309,24 @@ -- Weather data -- @type WeatherRecord -- @field #string recordId --- @field #number scriptId --- @field #string name --- @field #number windSpeed +-- @field #number scriptId Read-only ID used in mwscript and dialogue +-- @field #string name Read-only weather name +-- @field #number windSpeed Affects the angle of falling rain -- @field #number cloudSpeed -- @field #string cloudTexture --- @field #number cloudsMaximumPercent --- @field #boolean isStorm +-- @field #number cloudsMaximumPercent Affects the speed of weather transitions (0, 1] +-- @field #boolean isStorm Controls whether the weather is considered a storm for animation and movement purposes -- @field openmw.util#Vector3 stormDirection --- @field #number glareView --- @field #number rainSpeed --- @field #number rainEntranceSpeed +-- @field #number glareView Strength of the sun glare [0, 1] +-- @field #number rainSpeed The speed at which rain falls +-- @field #number rainEntranceSpeed The number of seconds between rain particle batches being created -- @field #string rainEffect Will return nil if weather has no rainEffect --- @field #number rainMaxRaindrops --- @field #number rainDiameter --- @field #number rainMaxHeight --- @field #number rainMinHeight +-- @field #number rainMaxRaindrops The maximum number of rain particle batches to create every rainEntranceSpeed +-- @field #number rainDiameter The area around the player to spawn rain in +-- @field #number rainMaxHeight The maximum height relative to the player to spawn rain at +-- @field #number rainMinHeight The minimum height relative to the player to spawn rain at -- @field #string rainLoopSoundID --- @field #table thunderSoundID An array containing the recordIds of the thunder sounds +-- @field #table thunderSoundID A read-only array containing the recordIds of the thunder sounds -- @field #string ambientLoopSoundID -- @field #string particleEffect Will return nil if weather has no particleEffect -- @field #number distantLandFogFactor diff --git a/files/lua_api/openmw/types.lua b/files/lua_api/openmw/types.lua index add678a37f7..c2b3d78ea9e 100644 --- a/files/lua_api/openmw/types.lua +++ b/files/lua_api/openmw/types.lua @@ -1224,6 +1224,16 @@ -- @usage -- Start a new quest, add it to the player's quest list but don't add any journal entries -- types.Player.quests(player)["ms_fargothring"].stage = 0 +--- +-- Adds a topic to the list of ones known by the player, so that it can be used in dialogue with actors who can talk about that topic. +-- @function [parent=#PLAYER] addTopic +-- @param openmw.core#GameObject player +-- @param string topicId +-- @usage -- Add topic to the list of known ones, in a player script +-- self.type.addTopic(self, "Some Work") +-- @usage -- Give all players in the current world a specific topic, in a global script +-- for _, player in ipairs(world.players) do player.type.addTopic(player, "Some Unrelated Work") end + --- -- Returns @{#PlayerJournal}, which contains the read-only access to journal text data accumulated by the player. -- Not the same as @{openmw_core#Dialogue.journal} which holds raw game records: with placeholders for dynamic variables and no player-specific info. diff --git a/files/lua_api/openmw/util.lua b/files/lua_api/openmw/util.lua index 0ba1fe2a8ed..f04b24843d0 100644 --- a/files/lua_api/openmw/util.lua +++ b/files/lua_api/openmw/util.lua @@ -477,6 +477,16 @@ -- @param #number a -- @return #Color +--- +-- Creates a Color from comma-separated string (in RGB or RGBA order, spaces are ignored) +-- @function [parent=#COLOR] commaString +-- @param #string str +-- @return #Color +-- @usage local color = util.color.commaString('255,0,0') -- red color +-- @usage local color = util.color.commaString('10000,0,0') -- red color (values are still capped at 255) +-- @usage local color = util.color.commaString('0, 0, 255, 255') -- blue color, with explicit alpha +-- @usage local color = util.color.commaString('0,255,0,128') -- green color, semi-transparent + --- -- Creates a Color from RGB format. Equivalent to calling util.rgba with a = 1. -- @function [parent=#COLOR] rgb diff --git a/files/lua_api/openmw/world.lua b/files/lua_api/openmw/world.lua index 0b3e3f2e40e..f578ec375e5 100644 --- a/files/lua_api/openmw/world.lua +++ b/files/lua_api/openmw/world.lua @@ -166,18 +166,19 @@ -- potion = world.createObject('Generated:0x0', 1) --- --- Creates a custom record in the world database; String ids that came from ESM3 content files are lower-cased. +-- Creates a custom record in the world database; string IDs that came from ESM3 content files are lower-cased. -- Eventually meant to support all records, but the current -- set of supported types is limited to: -- --- * @{openmw.types#PotionRecord}, +-- * @{openmw.types#ActivatorRecord}, -- * @{openmw.types#ArmorRecord}, -- * @{openmw.types#BookRecord}, --- * @{openmw.types#MiscellaneousRecord}, -- * @{openmw.types#ClothingRecord}, --- * @{openmw.types#WeaponRecord}, --- * @{openmw.types#ActivatorRecord}, --- * @{openmw.types#LightRecord} +-- * @{openmw.types#LightRecord}, +-- * @{openmw.types#MiscellaneousRecord}, +-- * @{openmw.types#NpcRecord}, +-- * @{openmw.types#PotionRecord}, +-- * @{openmw.types#WeaponRecord} -- @function [parent=#world] createRecord -- @param #any record A record to be registered in the database. Must be one of the supported types. The id field is not used, one will be generated for you. -- @return #any A new record added to the database. The type is the same as the input's. diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 2c4bbab9538..2280e49f477 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -522,7 +522,7 @@ antialias alpha test = false # This will somewhat mitigate these objects appearing to shrink as they get further from the camera, but isn't perfect. # Better results can be achieved by generating more appropriate mipmaps in the first place, but if this workaround is used with such textures, affected objects will appear to grow as they get further from the camera. # It is recommended that mod authors specify how this setting should be set, and mod users follow their advice. -adjust coverage for alpha test = true +adjust coverage for alpha test = false # Soften intersection of blended particle systems with opaque geometry soft particles = false @@ -1078,6 +1078,10 @@ object shadows = false # Allow shadows indoors. Due to limitations with Morrowind's data, only actors can cast shadows indoors, which some might feel is distracting. enable indoor shadows = true + +# Smooth out shadows edges, 0 = 1 sample, 1 = 2*2 samples, 2 = 3*3 samples and so on. +percentage closer filtering = 0 + [Physics] # Set the number of background threads used for physics. # If no background threads are used, physics calculations are processed in the main thread diff --git a/files/shaders/compatibility/bs/default.frag b/files/shaders/compatibility/bs/default.frag index 6f38c4df5ea..d02ac878681 100644 --- a/files/shaders/compatibility/bs/default.frag +++ b/files/shaders/compatibility/bs/default.frag @@ -1,13 +1,5 @@ #version 120 -#pragma import_defines(FORCE_OPAQUE, DISTORTION) - -#if @useUBO - #extension GL_ARB_uniform_buffer_object : require -#endif - -#if @useGPUShader4 - #extension GL_EXT_gpu_shader4: require -#endif +#pragma import_defines(FORCE_OPAQUE, DISTORTION, WRITE_NORMALS, FORCE_PPL, CLASSIC_FALLOFF, MAX_LIGHTS) #define PER_PIXEL_LIGHTING 1 @@ -109,7 +101,7 @@ void main() gl_FragData[0].a = 1.0; #endif -#if !defined(FORCE_OPAQUE) && !@disableNormals +#if !defined(FORCE_OPAQUE) && defined(WRITE_NORMALS) && WRITE_NORMALS gl_FragData[1].xyz = viewNormal * 0.5 + 0.5; #endif diff --git a/files/shaders/compatibility/bs/default.vert b/files/shaders/compatibility/bs/default.vert index 21942ec91e8..479ef3bcea4 100644 --- a/files/shaders/compatibility/bs/default.vert +++ b/files/shaders/compatibility/bs/default.vert @@ -1,13 +1,5 @@ #version 120 -#if @useUBO - #extension GL_ARB_uniform_buffer_object : require -#endif - -#if @useGPUShader4 - #extension GL_EXT_gpu_shader4: require -#endif - #define PER_PIXEL_LIGHTING 1 #include "lib/core/vertex.h.glsl" diff --git a/files/shaders/compatibility/bs/nolighting.frag b/files/shaders/compatibility/bs/nolighting.frag index a46e99aa823..6d254a63aed 100644 --- a/files/shaders/compatibility/bs/nolighting.frag +++ b/files/shaders/compatibility/bs/nolighting.frag @@ -1,13 +1,5 @@ #version 120 -#pragma import_defines(FORCE_OPAQUE) - -#if @useUBO - #extension GL_ARB_uniform_buffer_object : require -#endif - -#if @useGPUShader4 - #extension GL_EXT_gpu_shader4: require -#endif +#pragma import_defines(FORCE_OPAQUE, WRITE_NORMALS) #if @diffuseMap uniform sampler2D diffuseMap; @@ -81,7 +73,7 @@ void main() gl_FragData[0].a = 1.0; #endif -#if !defined(FORCE_OPAQUE) && !@disableNormals +#if !defined(FORCE_OPAQUE) && defined(WRITE_NORMALS) && WRITE_NORMALS vec3 viewNormal = normalize(gl_NormalMatrix * passNormal); gl_FragData[1].xyz = viewNormal * 0.5 + 0.5; #endif diff --git a/files/shaders/compatibility/debug.frag b/files/shaders/compatibility/debug.frag index a92b406d46b..041562fc0e2 100644 --- a/files/shaders/compatibility/debug.frag +++ b/files/shaders/compatibility/debug.frag @@ -4,7 +4,7 @@ varying vec3 vertexNormal; -uniform bool useAdvancedShader = false; +uniform bool useAdvancedShader; void main() { diff --git a/files/shaders/compatibility/debug.vert b/files/shaders/compatibility/debug.vert index 47d5337a66f..a1fa462f397 100644 --- a/files/shaders/compatibility/debug.vert +++ b/files/shaders/compatibility/debug.vert @@ -6,7 +6,7 @@ uniform vec3 color; uniform vec3 trans; uniform vec3 scale; uniform bool useNormalAsColor; -uniform bool useAdvancedShader = false; +uniform bool useAdvancedShader; centroid varying vec4 passColor; varying vec3 vertexNormal; diff --git a/files/shaders/compatibility/fog.glsl b/files/shaders/compatibility/fog.glsl index a7cccbf7876..77270e3668f 100644 --- a/files/shaders/compatibility/fog.glsl +++ b/files/shaders/compatibility/fog.glsl @@ -16,7 +16,7 @@ vec4 applyFogAtDist(vec4 color, float euclideanDist, float linearDist, float far #else float fogValue = clamp((dist - gl_Fog.start) * gl_Fog.scale, 0.0, 1.0); #endif -#ifdef ADDITIVE_BLENDING +#if defined(ADDITIVE_BLENDING) color.xyz *= 1.0 - fogValue; #else color.xyz = mix(color.xyz, gl_Fog.color.xyz, fogValue); @@ -25,7 +25,7 @@ vec4 applyFogAtDist(vec4 color, float euclideanDist, float linearDist, float far #if @skyBlending float fadeValue = clamp((far - dist) / (far - skyBlendingStart), 0.0, 1.0); fadeValue *= fadeValue; -#ifdef ADDITIVE_BLENDING +#if defined(ADDITIVE_BLENDING) color.xyz *= fadeValue; #else color.xyz = mix(sampleSkyColor(gl_FragCoord.xy / screenRes), color.xyz, fadeValue); diff --git a/files/shaders/compatibility/fullscreen_tri.vert b/files/shaders/compatibility/fullscreen_tri.vert index 3174384212e..a85f189e212 100644 --- a/files/shaders/compatibility/fullscreen_tri.vert +++ b/files/shaders/compatibility/fullscreen_tri.vert @@ -1,6 +1,6 @@ #version 120 -uniform vec2 scaling = vec2(1.0, 1.0); +uniform vec2 scaling; varying vec2 uv; diff --git a/files/shaders/compatibility/groundcover.frag b/files/shaders/compatibility/groundcover.frag index 96a79c8793e..7551bd67b15 100644 --- a/files/shaders/compatibility/groundcover.frag +++ b/files/shaders/compatibility/groundcover.frag @@ -1,12 +1,5 @@ #version 120 - -#if @useUBO - #extension GL_ARB_uniform_buffer_object : require -#endif - -#if @useGPUShader4 - #extension GL_EXT_gpu_shader4: require -#endif +#pragma import_defines(WRITE_NORMALS, CLASSIC_FALLOFF, MAX_LIGHTS) #define GROUNDCOVER @@ -85,7 +78,7 @@ void main() gl_FragData[0].xyz *= lighting; gl_FragData[0] = applyFogAtDist(gl_FragData[0], euclideanDepth, linearDepth, far); -#if !@disableNormals +#if defined(WRITE_NORMALS) && WRITE_NORMALS gl_FragData[1].xyz = viewNormal * 0.5 + 0.5; #endif diff --git a/files/shaders/compatibility/groundcover.vert b/files/shaders/compatibility/groundcover.vert index 8cf53a19e05..76bcba6b9a7 100644 --- a/files/shaders/compatibility/groundcover.vert +++ b/files/shaders/compatibility/groundcover.vert @@ -1,12 +1,5 @@ #version 120 - -#if @useUBO - #extension GL_ARB_uniform_buffer_object : require -#endif - -#if @useGPUShader4 - #extension GL_EXT_gpu_shader4: require -#endif +#pragma import_defines(CLASSIC_FALLOFF, MAX_LIGHTS) #include "lib/core/vertex.h.glsl" diff --git a/files/shaders/compatibility/objects.frag b/files/shaders/compatibility/objects.frag index 2e3ea795fbe..895f4f7a0c5 100644 --- a/files/shaders/compatibility/objects.frag +++ b/files/shaders/compatibility/objects.frag @@ -1,13 +1,5 @@ #version 120 -#pragma import_defines(FORCE_OPAQUE, DISTORTION) - -#if @useUBO - #extension GL_ARB_uniform_buffer_object : require -#endif - -#if @useGPUShader4 - #extension GL_EXT_gpu_shader4: require -#endif +#pragma import_defines(FORCE_OPAQUE, DISTORTION, WRITE_NORMALS, FORCE_PPL, CLASSIC_FALLOFF, MAX_LIGHTS) #if @diffuseMap uniform sampler2D diffuseMap; @@ -68,7 +60,11 @@ uniform float far; uniform float alphaRef; uniform float distortionStrength; +#if defined(FORCE_PPL) +#define PER_PIXEL_LIGHTING (@normalMap || @specularMap || FORCE_PPL) +#else #define PER_PIXEL_LIGHTING (@normalMap || @specularMap || @forcePPL) +#endif #if !PER_PIXEL_LIGHTING centroid varying vec3 passLighting; @@ -266,7 +262,7 @@ vec2 screenCoords = gl_FragCoord.xy / screenRes; gl_FragData[0].a = 1.0; #endif -#if !defined(FORCE_OPAQUE) && !@disableNormals +#if !defined(FORCE_OPAQUE) && defined(WRITE_NORMALS) && WRITE_NORMALS gl_FragData[1].xyz = viewNormal * 0.5 + 0.5; #endif diff --git a/files/shaders/compatibility/objects.vert b/files/shaders/compatibility/objects.vert index 081ff909cf0..a0307310ba0 100644 --- a/files/shaders/compatibility/objects.vert +++ b/files/shaders/compatibility/objects.vert @@ -1,12 +1,6 @@ #version 120 -#if @useUBO - #extension GL_ARB_uniform_buffer_object : require -#endif - -#if @useGPUShader4 - #extension GL_EXT_gpu_shader4: require -#endif +#pragma import_defines(FORCE_PPL, CLASSIC_FALLOFF, MAX_LIGHTS) #include "lib/core/vertex.h.glsl" #if @diffuseMap @@ -49,7 +43,11 @@ varying vec2 specularMapUV; varying vec2 glossMapUV; #endif +#if defined(FORCE_PPL) +#define PER_PIXEL_LIGHTING (@normalMap || @specularMap || FORCE_PPL) +#else #define PER_PIXEL_LIGHTING (@normalMap || @specularMap || @forcePPL) +#endif #if !PER_PIXEL_LIGHTING centroid varying vec3 passLighting; diff --git a/files/shaders/compatibility/shadowcasting.frag b/files/shaders/compatibility/shadowcasting.frag index 5e550e99fb1..595c8312815 100644 --- a/files/shaders/compatibility/shadowcasting.frag +++ b/files/shaders/compatibility/shadowcasting.frag @@ -1,9 +1,5 @@ #version 120 -#if @useGPUShader4 - #extension GL_EXT_gpu_shader4: require -#endif - uniform sampler2D diffuseMap; varying vec2 diffuseMapUV; diff --git a/files/shaders/compatibility/shadowcasting.vert b/files/shaders/compatibility/shadowcasting.vert index c68bdd5c177..41136c2d42d 100644 --- a/files/shaders/compatibility/shadowcasting.vert +++ b/files/shaders/compatibility/shadowcasting.vert @@ -6,8 +6,8 @@ varying float alphaPassthrough; uniform int colorMode; uniform bool useTreeAnim; -uniform bool useDiffuseMapForShadowAlpha = true; -uniform bool alphaTestShadows = true; +uniform bool useDiffuseMapForShadowAlpha; +uniform bool alphaTestShadows; void main(void) { diff --git a/files/shaders/compatibility/shadows_fragment.glsl b/files/shaders/compatibility/shadows_fragment.glsl index 3c7a37a1628..487b21914c2 100644 --- a/files/shaders/compatibility/shadows_fragment.glsl +++ b/files/shaders/compatibility/shadows_fragment.glsl @@ -13,6 +13,25 @@ @endforeach #endif // SHADOWS +float calcShadowing(sampler2DShadow shadowTexture, vec4 LightSpacePos) +{ + float Offset = 1.0/@shadowMapSize.0; + float shadowing = 1.0; + + float numPixels = @PCFSamples.0 + 1.0; + float mult = (numPixels -1.0) / 2.0; + shadowing = 0.0; + for (float y = -1.0 * mult; y <= mult; y+=1.0) { + for (float x = -1.0 * mult; x <= mult; x+=1.0) { + vec4 Offsets = vec4(float(x) * Offset, float(y) * Offset, -0.001, 0.0); + shadowing += min(shadow2DProj(shadowTexture, LightSpacePos + (Offsets * vec4(LightSpacePos.w, LightSpacePos.w, 1.0, 1.0))), 1.0); + } + } + shadowing = shadowing / (numPixels * numPixels); + + return shadowing; +} + float unshadowedLightRatio(float distance) { float shadowing = 1.0; @@ -32,7 +51,7 @@ float unshadowedLightRatio(float distance) #endif if (all(lessThan(shadowXYZ.xy, vec2(1.0, 1.0))) && all(greaterThan(shadowXYZ.xy, vec2(0.0, 0.0)))) { - shadowing = min(shadow2DProj(shadowTexture@shadow_texture_unit_index, shadowSpaceCoords@shadow_texture_unit_index).r, shadowing); + shadowing = calcShadowing(shadowTexture@shadow_texture_unit_index, shadowSpaceCoords@shadow_texture_unit_index); doneShadows = all(lessThan(shadowXYZ, vec3(0.95, 0.95, 1.0))) && all(greaterThan(shadowXYZ, vec3(0.05, 0.05, 0.0))); #if @perspectiveShadowMaps diff --git a/files/shaders/compatibility/terrain.frag b/files/shaders/compatibility/terrain.frag index d206b9028fb..3a7b40cf7b6 100644 --- a/files/shaders/compatibility/terrain.frag +++ b/files/shaders/compatibility/terrain.frag @@ -1,12 +1,5 @@ #version 120 - -#if @useUBO - #extension GL_ARB_uniform_buffer_object : require -#endif - -#if @useGPUShader4 - #extension GL_EXT_gpu_shader4: require -#endif +#pragma import_defines(WRITE_NORMALS, FORCE_PPL, CLASSIC_FALLOFF, MAX_LIGHTS) varying vec2 uv; @@ -23,7 +16,11 @@ uniform sampler2D blendMap; varying float euclideanDepth; varying float linearDepth; +#if defined(FORCE_PPL) +#define PER_PIXEL_LIGHTING (@normalMap || @specularMap || FORCE_PPL) +#else #define PER_PIXEL_LIGHTING (@normalMap || @specularMap || @forcePPL) +#endif #if !PER_PIXEL_LIGHTING centroid varying vec3 passLighting; @@ -98,7 +95,7 @@ void main() gl_FragData[0] = applyFogAtDist(gl_FragData[0], euclideanDepth, linearDepth, far); -#if !@disableNormals && @writeNormals +#if defined(WRITE_NORMALS) && WRITE_NORMALS && @writeNormals gl_FragData[1].xyz = viewNormal * 0.5 + 0.5; #endif diff --git a/files/shaders/compatibility/terrain.vert b/files/shaders/compatibility/terrain.vert index 40d69ff35dd..5f18600ce61 100644 --- a/files/shaders/compatibility/terrain.vert +++ b/files/shaders/compatibility/terrain.vert @@ -1,19 +1,16 @@ #version 120 - -#if @useUBO - #extension GL_ARB_uniform_buffer_object : require -#endif - -#if @useGPUShader4 - #extension GL_EXT_gpu_shader4: require -#endif +#pragma import_defines(FORCE_PPL, CLASSIC_FALLOFF, MAX_LIGHTS) #include "lib/core/vertex.h.glsl" varying vec2 uv; varying float euclideanDepth; varying float linearDepth; +#if defined(FORCE_PPL) +#define PER_PIXEL_LIGHTING (@normalMap || @specularMap || FORCE_PPL) +#else #define PER_PIXEL_LIGHTING (@normalMap || @specularMap || @forcePPL) +#endif #if !PER_PIXEL_LIGHTING centroid varying vec3 passLighting; diff --git a/files/shaders/compatibility/water.frag b/files/shaders/compatibility/water.frag index dbf36560b3f..c405fcb92d6 100644 --- a/files/shaders/compatibility/water.frag +++ b/files/shaders/compatibility/water.frag @@ -1,12 +1,5 @@ #version 120 - -#if @useUBO - #extension GL_ARB_uniform_buffer_object : require -#endif - -#if @useGPUShader4 - #extension GL_EXT_gpu_shader4: require -#endif +#pragma import_defines(WRITE_NORMALS, CLASSIC_FALLOFF, MAX_LIGHTS) #include "lib/core/fragment.h.glsl" @@ -245,7 +238,7 @@ void main(void) gl_FragData[0] = applyFogAtDist(gl_FragData[0], radialDepth, linearDepth, far); -#if !@disableNormals +#if defined(WRITE_NORMALS) && WRITE_NORMALS gl_FragData[1].rgb = normalize(gl_NormalMatrix * normal) * 0.5 + 0.5; #endif diff --git a/files/shaders/lib/core/fragment.h.glsl b/files/shaders/lib/core/fragment.h.glsl old mode 100644 new mode 100755 index 9b7ef768e6c..fc9cf8f7a78 --- a/files/shaders/lib/core/fragment.h.glsl +++ b/files/shaders/lib/core/fragment.h.glsl @@ -1,22 +1,50 @@ #ifndef OPENMW_FRAGMENT_H_GLSL #define OPENMW_FRAGMENT_H_GLSL -@link "lib/core/fragment.glsl" if !@useOVR_multiview -@link "lib/core/fragment_multiview.glsl" if @useOVR_multiview +uniform sampler2D reflectionMap; -vec4 sampleReflectionMap(vec2 uv); +vec4 sampleReflectionMap(vec2 uv) +{ + return texture2D(reflectionMap, uv); +} #if @waterRefraction -vec4 sampleRefractionMap(vec2 uv); -float sampleRefractionDepthMap(vec2 uv); +uniform sampler2D refractionMap; +uniform highp sampler2D refractionDepthMap; + +vec4 sampleRefractionMap(vec2 uv) +{ + return texture2D(refractionMap, uv); +} + +float sampleRefractionDepthMap(vec2 uv) +{ + return texture2D(refractionDepthMap, uv).x; +} + #endif -vec4 samplerLastShader(vec2 uv); +uniform sampler2D lastShader; + +vec4 samplerLastShader(vec2 uv) +{ + return texture2D(lastShader, uv); +} #if @skyBlending -vec3 sampleSkyColor(vec2 uv); +uniform sampler2D sky; + +vec3 sampleSkyColor(vec2 uv) +{ + return texture2D(sky, uv).xyz; +} #endif -vec4 sampleOpaqueDepthTex(vec2 uv); +uniform sampler2D opaqueDepthTex; + +vec4 sampleOpaqueDepthTex(vec2 uv) +{ + return texture2D(opaqueDepthTex, uv); +} #endif // OPENMW_FRAGMENT_H_GLSL diff --git a/files/shaders/lib/core/fragment.h_orig.glsl b/files/shaders/lib/core/fragment.h_orig.glsl new file mode 100644 index 00000000000..9b7ef768e6c --- /dev/null +++ b/files/shaders/lib/core/fragment.h_orig.glsl @@ -0,0 +1,22 @@ +#ifndef OPENMW_FRAGMENT_H_GLSL +#define OPENMW_FRAGMENT_H_GLSL + +@link "lib/core/fragment.glsl" if !@useOVR_multiview +@link "lib/core/fragment_multiview.glsl" if @useOVR_multiview + +vec4 sampleReflectionMap(vec2 uv); + +#if @waterRefraction +vec4 sampleRefractionMap(vec2 uv); +float sampleRefractionDepthMap(vec2 uv); +#endif + +vec4 samplerLastShader(vec2 uv); + +#if @skyBlending +vec3 sampleSkyColor(vec2 uv); +#endif + +vec4 sampleOpaqueDepthTex(vec2 uv); + +#endif // OPENMW_FRAGMENT_H_GLSL diff --git a/files/shaders/lib/core/vertex.h.glsl b/files/shaders/lib/core/vertex.h.glsl old mode 100644 new mode 100755 index 6e22f6deb15..c8a1080574d --- a/files/shaders/lib/core/vertex.h.glsl +++ b/files/shaders/lib/core/vertex.h.glsl @@ -1,6 +1,16 @@ -@link "lib/core/vertex.glsl" if !@useOVR_multiview -@link "lib/core/vertex_multiview.glsl" if @useOVR_multiview +uniform mat4 projectionMatrix; -vec4 modelToClip(vec4 pos); -vec4 modelToView(vec4 pos); -vec4 viewToClip(vec4 pos); +vec4 modelToView(vec4 pos) +{ + return gl_ModelViewMatrix * pos; +} + +vec4 modelToClip(vec4 pos) +{ + return projectionMatrix * modelToView(pos); +} + +vec4 viewToClip(vec4 pos) +{ + return projectionMatrix * pos; +} diff --git a/files/shaders/lib/core/vertex.h_orig.glsl b/files/shaders/lib/core/vertex.h_orig.glsl new file mode 100644 index 00000000000..6e22f6deb15 --- /dev/null +++ b/files/shaders/lib/core/vertex.h_orig.glsl @@ -0,0 +1,6 @@ +@link "lib/core/vertex.glsl" if !@useOVR_multiview +@link "lib/core/vertex_multiview.glsl" if @useOVR_multiview + +vec4 modelToClip(vec4 pos); +vec4 modelToView(vec4 pos); +vec4 viewToClip(vec4 pos); diff --git a/files/shaders/lib/light/lighting.glsl b/files/shaders/lib/light/lighting.glsl index 4a86233294f..fd2696652ed 100644 --- a/files/shaders/lib/light/lighting.glsl +++ b/files/shaders/lib/light/lighting.glsl @@ -66,7 +66,7 @@ void doLighting(vec3 viewPos, vec3 viewNormal, float shininess, out vec3 diffuse float lightDistance = length(lightPos); // cull non-FFP point lighting by radius, light is guaranteed to not fall outside this bound with our cutoff -#if !@classicFalloff && !@lightingMethodFFP +#if defined(CLASSIC_FALLOFF) && !CLASSIC_FALLOFF && !@lightingMethodFFP if (lightDistance > lcalcRadius(lightIndex) * 2.0) continue; #endif diff --git a/files/shaders/lib/light/lighting_util.glsl b/files/shaders/lib/light/lighting_util.glsl index b56afe285b7..0812ea77ab6 100644 --- a/files/shaders/lib/light/lighting_util.glsl +++ b/files/shaders/lib/light/lighting_util.glsl @@ -35,11 +35,16 @@ struct LightData vec4 attenuation; }; +#if defined(MAX_LIGHTS) +uniform int PointLightIndex[MAX_LIGHTS]; +#else uniform int PointLightIndex[@maxLights]; +#endif + uniform int PointLightCount; // Defaults to shared layout. If we ever move to GLSL 140, std140 layout should be considered -uniform LightBufferBinding +layout(std140) uniform LightBufferBinding { LightData LightBuffer[@maxLightsInScene]; }; @@ -54,7 +59,12 @@ uniform LightBufferBinding | att_c | att_l | att_q | radius/spec_a | -------------------------------------------------- */ +#if defined(MAX_LIGHTS) +uniform mat4 LightBuffer[MAX_LIGHTS]; +#else uniform mat4 LightBuffer[@maxLights]; +#endif + uniform int PointLightCount; #endif @@ -106,7 +116,7 @@ float lcalcRadius(int lightIndex) float lcalcIllumination(int lightIndex, float dist) { float illumination = 1.0 / (lcalcConstantAttenuation(lightIndex) + lcalcLinearAttenuation(lightIndex) * dist + lcalcQuadraticAttenuation(lightIndex) * dist * dist); -#if !@classicFalloff && !@lightingMethodFFP +#if defined(CLASSIC_FALLOFF) && !CLASSIC_FALLOFF && !@lightingMethodFFP // Fade illumination between the radius and the radius doubled to diminish pop-in illumination *= 1.0 - quickstep((dist / lcalcRadius(lightIndex)) - 1.0); #endif diff --git a/files/shaders/lib/material/alpha.glsl b/files/shaders/lib/material/alpha.glsl index 62722e52a18..d9d83ff37b6 100644 --- a/files/shaders/lib/material/alpha.glsl +++ b/files/shaders/lib/material/alpha.glsl @@ -23,7 +23,7 @@ float coveragePreservingAlphaScale(sampler2D diffuseMap, vec2 uv) #if @adjustCoverage vec2 textureSize; #if @useGPUShader4 - textureSize = textureSize2D(diffuseMap, 0); + textureSize = vec2(textureSize2D(diffuseMap, 0)); #else textureSize = vec2(256.0); #endif diff --git a/scripts/data/integration_tests/test_lua_api/global.lua b/scripts/data/integration_tests/test_lua_api/global.lua index fec0b4ead68..dbc1864195d 100644 --- a/scripts/data/integration_tests/test_lua_api/global.lua +++ b/scripts/data/integration_tests/test_lua_api/global.lua @@ -7,6 +7,13 @@ local vfs = require('openmw.vfs') local world = require('openmw.world') local I = require('openmw.interfaces') +testing.registerGlobalTest('crash in lua coroutine when accessing type (#8757)', function() + local co = coroutine.wrap(function() + testing.expectEqual(tostring(world.players[1].type), 'Player') + end) + co() +end) + testing.registerGlobalTest('timers', function() testing.expectAlmostEqual(core.getGameTimeScale(), 30, 'incorrect getGameTimeScale() result') testing.expectAlmostEqual(core.getSimulationTimeScale(), 1, 'incorrect getSimulationTimeScale result') diff --git a/scripts/data/integration_tests/test_lua_api/menu.lua b/scripts/data/integration_tests/test_lua_api/menu.lua index ca5f40c526e..52c2c15d00f 100644 --- a/scripts/data/integration_tests/test_lua_api/menu.lua +++ b/scripts/data/integration_tests/test_lua_api/menu.lua @@ -61,6 +61,7 @@ local function registerGlobalTest(name, description) end) end +registerGlobalTest('crash in lua coroutine when accessing type (#8757)') registerGlobalTest('timers') registerGlobalTest('teleport') registerGlobalTest('getGMST')