From f9771c38a61cf038e3e6dcc632f745afce4cf56a Mon Sep 17 00:00:00 2001 From: tellowkrinkle Date: Sun, 24 May 2020 01:19:47 -0500 Subject: [PATCH] macOS fixes (#3357) * macOS compile * Fix memprotect error on macOS * Fix semaphore wait + thread cancel on macOS * Fix timedlock timeout calculation * spu2-x macOS * onepad macOS support * Add MacOS game controller db * Disable onepad_legacy on macOS * Fix spu2-x configuration crashes * Make recompiler work on 32-bit macOS * Use dylib extension for plugins on macOS * Make app bundle on macOS * Use git info for Info.plist version --- CMakeLists.txt | 1 + cmake/BuildParameters.cmake | 35 +++++ cmake/Pcsx2PostprocessBundle.cmake | 10 ++ cmake/Pcsx2Utils.cmake | 25 ++- cmake/SelectPcsx2Plugins.cmake | 5 +- common/include/Utilities/Console.h | 2 +- .../src/Utilities/Darwin/DarwinSemaphore.cpp | 20 ++- common/src/Utilities/Linux/LnxHostSys.cpp | 5 + common/src/Utilities/Mutex.cpp | 23 ++- pcsx2/CMakeLists.txt | 32 +++- pcsx2/DebugTools/Debug.h | 1 - pcsx2/gui/Resources/Info.plist.in | 42 +++++ pcsx2/gui/Resources/PCSX2.icns | Bin 0 -> 23876 bytes plugins/onepad/Linux/linux.cpp | 8 +- plugins/onepad/keyboard.cpp | 95 +++++++++--- plugins/onepad/keyboard.h | 8 +- plugins/onepad/onepad.cpp | 2 +- plugins/onepad/onepad.h | 2 +- plugins/onepad/res/game_controller_db.txt | 125 ++++++++++++++- plugins/onepad/wx_dialog/dialog.cpp | 146 +++++++++++++++++- plugins/spu2-x/src/CMakeLists.txt | 2 +- plugins/spu2-x/src/Linux/Config.cpp | 30 +++- plugins/spu2-x/src/Linux/ConfigDebug.cpp | 2 +- plugins/spu2-x/src/Linux/ConfigSoundTouch.cpp | 2 +- 24 files changed, 561 insertions(+), 62 deletions(-) create mode 100644 cmake/Pcsx2PostprocessBundle.cmake create mode 100644 pcsx2/gui/Resources/Info.plist.in create mode 100644 pcsx2/gui/Resources/PCSX2.icns diff --git a/CMakeLists.txt b/CMakeLists.txt index 2983b2a397..bd74628c85 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,6 +31,7 @@ include(SearchForStuff) include(SelectPcsx2Plugins) # Must be done after SearchForStuff +get_git_version_info() write_svnrev_h() if(NOT NO_TRANSLATION) diff --git a/cmake/BuildParameters.cmake b/cmake/BuildParameters.cmake index 707eb91f56..8c41725623 100644 --- a/cmake/BuildParameters.cmake +++ b/cmake/BuildParameters.cmake @@ -77,6 +77,11 @@ if(PACKAGE_MODE) add_definitions(-DPLUGIN_DIR_COMPILATION=${PLUGIN_DIR} -DGAMEINDEX_DIR_COMPILATION=${GAMEINDEX_DIR} -DDOC_DIR_COMPILATION=${DOC_DIR}) endif() +if(APPLE) + option(OSX_USE_DEFAULT_SEARCH_PATH "Don't prioritize system library paths" OFF) + option(SKIP_POSTPROCESS_BUNDLE "Skip postprocessing bundle for redistributability" OFF) +endif() + #------------------------------------------------------------------------------- # Compiler extra #------------------------------------------------------------------------------- @@ -468,3 +473,33 @@ if(CMAKE_BUILD_TYPE MATCHES "Release" OR PACKAGE_MODE) message(WARNING "GTK3 is highly experimental besides it requires a wxWidget built with __WXGTK3__ support !!!") endif() endif() + + +#------------------------------------------------------------------------------- +# MacOS-specific things +#------------------------------------------------------------------------------- + +set(CMAKE_OSX_DEPLOYMENT_TARGET 10.9) + +# CMake defaults the suffix for modules to .so on macOS but wx tells us that the +# extension is .dylib (so that's what we search for) +if(APPLE) + set(CMAKE_SHARED_MODULE_SUFFIX ".dylib") +endif() + +if(CMAKE_SYSTEM_NAME MATCHES "Darwin") + if(NOT OSX_USE_DEFAULT_SEARCH_PATH) + # Hack up the path to prioritize the path to built-in OS libraries to + # increase the chance of not depending on a bunch of copies of them + # installed by MacPorts, Fink, Homebrew, etc, and ending up copying + # them into the bundle. Since we depend on libraries which are not + # part of OS X (wx, etc.), however, don't remove the default path + # entirely. This is still kinda evil, since it defeats the user's + # path settings... + # See http://www.cmake.org/cmake/help/v3.0/command/find_program.html + list(APPEND CMAKE_PREFIX_PATH "/usr") + endif() + + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-dead_strip,-dead_strip_dylibs") + set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,-dead_strip,-dead_strip_dylibs") +endif() \ No newline at end of file diff --git a/cmake/Pcsx2PostprocessBundle.cmake b/cmake/Pcsx2PostprocessBundle.cmake new file mode 100644 index 0000000000..b74431b37f --- /dev/null +++ b/cmake/Pcsx2PostprocessBundle.cmake @@ -0,0 +1,10 @@ +# This file should be run with cmake -DPCSX2_BUNDLE_PATH=path -P Pcsx2PostprocessBundle.cmake + +get_filename_component(PCSX2_BUNDLE_PATH "${PCSX2_BUNDLE_PATH}" ABSOLUTE) + +# Fixup plugins too +file(GLOB_RECURSE plugins "${PCSX2_BUNDLE_PATH}/Contents/MacOS/*.dylib") + +include(BundleUtilities) +set(BU_CHMOD_BUNDLE_ITEMS ON) +fixup_bundle("${PCSX2_BUNDLE_PATH}" "${plugins}" "") diff --git a/cmake/Pcsx2Utils.cmake b/cmake/Pcsx2Utils.cmake index 06ebe8dd54..84304b6902 100644 --- a/cmake/Pcsx2Utils.cmake +++ b/cmake/Pcsx2Utils.cmake @@ -35,7 +35,7 @@ function(detectOperatingSystem) endif() endfunction() -function(write_svnrev_h) +function(get_git_version_info) set(PCSX2_WC_TIME 0) set(PCSX2_GIT_REV "") if (GIT_FOUND AND EXISTS ${PROJECT_SOURCE_DIR}/.git) @@ -50,9 +50,24 @@ function(write_svnrev_h) OUTPUT_VARIABLE PCSX2_GIT_REV OUTPUT_STRIP_TRAILING_WHITESPACE) endif() + if(PCSX2_GIT_REV) + set(PCSX2_VERSION_LONG "${PCSX2_GIT_REV}") + string(REGEX MATCH "[0-9]+\\.[0-9]+(\\.[0-9]+)?(-[a-z][a-z0-9]+)?" PCSX2_VERSION_SHORT "${PCSX2_VERSION_LONG}") + else() + set(PCSX2_VERSION_LONG "Unknown (git unavailable)") + set(PCSX2_VERSION_SHORT "Unknown") + endif() if ("${PCSX2_WC_TIME}" STREQUAL "") set(PCSX2_WC_TIME 0) endif() + + set(PCSX2_WC_TIME "${PCSX2_WC_TIME}" PARENT_SCOPE) + set(PCSX2_GIT_REV "${PCSX2_GIT_REV}" PARENT_SCOPE) + set(PCSX2_VERSION_LONG "${PCSX2_VERSION_LONG}" PARENT_SCOPE) + set(PCSX2_VERSION_SHORT "${PCSX2_VERSION_SHORT}" PARENT_SCOPE) +endfunction() + +function(write_svnrev_h) file(WRITE ${CMAKE_BINARY_DIR}/common/include/svnrev.h "#define SVN_REV ${PCSX2_WC_TIME}ll \n#define SVN_MODS 0\n#define GIT_REV \"${PCSX2_GIT_REV}\"") endfunction() @@ -114,6 +129,14 @@ macro(add_pcsx2_plugin lib srcs libs flags) else(PACKAGE_MODE) install(TARGETS ${lib} DESTINATION ${CMAKE_SOURCE_DIR}/bin/plugins) endif(PACKAGE_MODE) + if (APPLE) + # Copy to app bundle + add_custom_command(TARGET ${lib} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E make_directory "$/plugins" + COMMAND ${CMAKE_COMMAND} -E copy_if_different "$" "$/plugins/" + ) + add_dependencies(pcsx2-postprocess-bundle ${lib}) + endif() endmacro(add_pcsx2_plugin) macro(add_pcsx2_lib lib srcs libs flags) diff --git a/cmake/SelectPcsx2Plugins.cmake b/cmake/SelectPcsx2Plugins.cmake index 00bf22e6ca..2f1e445b62 100644 --- a/cmake/SelectPcsx2Plugins.cmake +++ b/cmake/SelectPcsx2Plugins.cmake @@ -245,9 +245,10 @@ else() endif() # old version of the plugin that still supports SDL1 -if(wxWidgets_FOUND AND GTKn_FOUND AND SDLn_FOUND AND X11_FOUND) +# Was never ported to macOS +if(wxWidgets_FOUND AND GTKn_FOUND AND SDLn_FOUND AND X11_FOUND AND NOT APPLE) set(onepad_legacy TRUE) -elseif(NOT EXISTS "${CMAKE_SOURCE_DIR}/plugins/onepad_legacy") +elseif(NOT EXISTS "${CMAKE_SOURCE_DIR}/plugins/onepad_legacy" OR APPLE) set(onepad_legacy FALSE) else() set(onepad_legacy FALSE) diff --git a/common/include/Utilities/Console.h b/common/include/Utilities/Console.h index e83b0fab36..0a6eb2ef0a 100644 --- a/common/include/Utilities/Console.h +++ b/common/include/Utilities/Console.h @@ -233,7 +233,7 @@ public: extern IConsoleWriter Console; -#if defined(__unix__) +#if defined(__unix__) || defined(__APPLE__) extern void Console_SetStdout(FILE *fp); #endif extern void Console_SetActiveHandler(const IConsoleWriter &writer, FILE *flushfp = NULL); diff --git a/common/src/Utilities/Darwin/DarwinSemaphore.cpp b/common/src/Utilities/Darwin/DarwinSemaphore.cpp index 7584c944bb..dea234ca7d 100644 --- a/common/src/Utilities/Darwin/DarwinSemaphore.cpp +++ b/common/src/Utilities/Darwin/DarwinSemaphore.cpp @@ -47,14 +47,18 @@ // // -------------------------------------------------------------------------------------- -#define MACH_CHECK(mach_retval) \ - do { \ - kern_return_t _kr = (mach_retval); \ - if (_kr != KERN_SUCCESS) { \ - fprintf(stderr, "mach error: %s", mach_error_string(_kr)); \ - assert(_kr == KERN_SUCCESS); \ - } \ - } while (0) +static void MACH_CHECK(kern_return_t mach_retval) +{ + switch (mach_retval) { + case KERN_SUCCESS: break; + case KERN_ABORTED: // Awoken due reason unrelated to semaphore (e.g. pthread_cancel) + pthread_testcancel(); // Unlike sem_wait, mach semaphore ops aren't cancellation points + // fallthrough + default: + fprintf(stderr, "mach error: %s", mach_error_string(mach_retval)); + assert(mach_retval == KERN_SUCCESS); + } +} Threading::Semaphore::Semaphore() { diff --git a/common/src/Utilities/Linux/LnxHostSys.cpp b/common/src/Utilities/Linux/LnxHostSys.cpp index 9c5250d053..f25d9d7c40 100644 --- a/common/src/Utilities/Linux/LnxHostSys.cpp +++ b/common/src/Utilities/Linux/LnxHostSys.cpp @@ -86,7 +86,12 @@ void _platform_InstallSignalHandler() sigemptyset(&sa.sa_mask); sa.sa_flags = SA_SIGINFO; sa.sa_sigaction = SysPageFaultSignalFilter; +#ifdef __APPLE__ + // MacOS uses SIGBUS for memory permission violations + sigaction(SIGBUS, &sa, NULL); +#else sigaction(SIGSEGV, &sa, NULL); +#endif } static __ri void PageSizeAssertionTest(size_t size) diff --git a/common/src/Utilities/Mutex.cpp b/common/src/Utilities/Mutex.cpp index 9f48bc4def..2b968dd066 100644 --- a/common/src/Utilities/Mutex.cpp +++ b/common/src/Utilities/Mutex.cpp @@ -61,22 +61,21 @@ static int xpthread_mutex_timedlock( int err = 0; while ((err = pthread_mutex_trylock(mutex)) == EBUSY) { + // check if the timeout has expired, gettimeofday() is implemented + // efficiently (in userspace) on OSX + struct timeval now; + gettimeofday(&now, NULL); + if (now.tv_sec > abs_timeout->tv_sec + || (now.tv_sec == abs_timeout->tv_sec + && (u64)now.tv_usec * 1000ULL > (u64)abs_timeout->tv_nsec)) { + return ETIMEDOUT; + } + // acquiring lock failed, sleep some struct timespec ts; ts.tv_sec = 0; ts.tv_nsec = TIMEDLOCK_EMU_SLEEP_NS; - int status; - while ((status = nanosleep(&ts, &ts)) == -1) - ; - - // check if the timeout has expired, gettimeofday() is implemented - // efficiently (in userspace) on OSX - struct timeval now; - int res = gettimeofday(&now, NULL); - if (abs_timeout->tv_sec == 0 || now.tv_sec > abs_timeout->tv_sec || - (u64)now.tv_usec * 1000ULL > (u64)abs_timeout->tv_nsec) { - return ETIMEDOUT; - } + while (nanosleep(&ts, &ts) == -1); } return err; diff --git a/pcsx2/CMakeLists.txt b/pcsx2/CMakeLists.txt index 07d6bc8cdb..2c7cda13a2 100644 --- a/pcsx2/CMakeLists.txt +++ b/pcsx2/CMakeLists.txt @@ -410,7 +410,7 @@ set(pcsx2LinuxSources set(pcsx2OSXSources gui/CpuUsageProviderLnx.cpp -# Linux/LnxConsolePipe.cpp + Linux/LnxConsolePipe.cpp # Linux/LnxKeyCodes.cpp Darwin/DarwinFlatFileReader.cpp ) @@ -745,6 +745,36 @@ if(NOT USE_CLANG) endif() endif() +if (APPLE) + # MacOS defaults to having a maximum protection of the __DATA segment of rw (non-executable) + # We have a bunch of page-sized arrays in bss that we use for jit + # Obviously not being able to make those arrays executable would be a problem + target_link_options(${Output} PRIVATE -Wl,-segprot,__DATA,rwx,rw) + + set_target_properties(${Output} PROPERTIES + MACOSX_BUNDLE true + MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/gui/Resources/Info.plist.in" + OUTPUT_NAME PCSX2 + ) + + target_sources(${Output} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/gui/Resources/PCSX2.icns") + set_source_files_properties("${CMAKE_CURRENT_SOURCE_DIR}/gui/Resources/PCSX2.icns" PROPERTIES MACOSX_PACKAGE_LOCATION Resources) + + # If they say to skip postprocess bundle, leave the target in but make it so they have + # to manually run it + if (SKIP_POSTPROCESS_BUNDLE) + set(postprocessBundleType "") + else() + set(postprocessBundleType ALL) + endif() + # Use custom_target and not custom_command so plugins can add themselves as dependencies + add_custom_target(pcsx2-postprocess-bundle ${postprocessBundleType} + COMMAND ${CMAKE_COMMAND} "-DPCSX2_BUNDLE_PATH=$/../.." + -P ${CMAKE_SOURCE_DIR}/cmake/Pcsx2PostprocessBundle.cmake + ) + add_dependencies(pcsx2-postprocess-bundle ${Output}) +endif() + if(dev9ghzdrk) if(PACKAGE_MODE) install(CODE "execute_process(COMMAND /bin/bash -c \"echo 'Enabling networking capability on Linux...';set -x; [ -f ${BIN_DIR}/${Output} ] && sudo setcap 'CAP_NET_RAW+eip CAP_NET_ADMIN+eip' ${BIN_DIR}/${Output}; set +x\")") diff --git a/pcsx2/DebugTools/Debug.h b/pcsx2/DebugTools/Debug.h index 6dfece3e73..8adfc0c505 100644 --- a/pcsx2/DebugTools/Debug.h +++ b/pcsx2/DebugTools/Debug.h @@ -347,7 +347,6 @@ extern void __Log( const char* fmt, ... ); # define SetDoubleBuffered(x) // TODO OSX OsxKeyCodes.cpp pending -# define NewPipeRedir(x) NULL #endif #define macTrace(trace) SysTraceActive(trace) && SysTrace.trace.Write diff --git a/pcsx2/gui/Resources/Info.plist.in b/pcsx2/gui/Resources/Info.plist.in new file mode 100644 index 0000000000..e519ca6f8e --- /dev/null +++ b/pcsx2/gui/Resources/Info.plist.in @@ -0,0 +1,42 @@ + + + + + CFBundleDocumentTypes + + + CFBundleTypeExtensions + + iso + cso + + CFBundleTypeIconFile + PCSX2.icns + CFBundleTypeName + PS2 Game + CFBundleTypeRole + Viewer + + + CFBundleExecutable + PCSX2 + CFBundleIconFile + PCSX2.icns + CFBundleIdentifier + net.pcsx2.pcsx2 + CFBundleDevelopmentRegion + English + CFBundlePackageType + APPL + CFBundleShortVersionString + ${PCSX2_VERSION_SHORT} + CFBundleVersion + ${PCSX2_VERSION_LONG} + NSHumanReadableCopyright + Licensed under GPL version 3 + LSMinimumSystemVersion + ${CMAKE_OSX_DEPLOYMENT_TARGET} + NSHighResolutionCapable + + + diff --git a/pcsx2/gui/Resources/PCSX2.icns b/pcsx2/gui/Resources/PCSX2.icns new file mode 100644 index 0000000000000000000000000000000000000000..46ed9be85f2aedf0e5d1390207ed0236cc89b455 GIT binary patch literal 23876 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

}G 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 Ji?Vgp{{ZK_{ILK4 literal 0 HcmV?d00001 diff --git a/plugins/onepad/Linux/linux.cpp b/plugins/onepad/Linux/linux.cpp index 685b7d212c..d5b62bf6a0 100644 --- a/plugins/onepad/Linux/linux.cpp +++ b/plugins/onepad/Linux/linux.cpp @@ -28,8 +28,10 @@ #include #include "wx_dialog/dialog.h" +#ifndef __APPLE__ Display *GSdsp; Window GSwin; +#endif void SysMessage(const char *fmt, ...) { @@ -67,8 +69,10 @@ PADtest() s32 _PADopen(void *pDsp) { +#ifndef __APPLE__ GSdsp = *(Display **)pDsp; GSwin = (Window) * (((u32 *)pDsp) + 1); +#endif return 0; } @@ -100,6 +104,7 @@ void PollForJoystickInput(int cpad) EXPORT_C_(void) PADupdate(int pad) { +#ifndef __APPLE__ // Gamepad inputs don't count as an activity. Therefore screensaver will // be fired after a couple of minute. // Emulate an user activity @@ -109,6 +114,7 @@ PADupdate(int pad) // 1 call every 4096 Vsync is enough XResetScreenSaver(GSdsp); } +#endif // Actually PADupdate is always call with pad == 0. So you need to update both // pads -- Gregory @@ -118,7 +124,7 @@ PADupdate(int pad) for (int cpad = 0; cpad < GAMEPAD_NUMBER; cpad++) { g_key_status.keyboard_state_acces(cpad); } - PollForX11KeyboardInput(); + UpdateKeyboardInput(); // Get joystick state + Commit for (int cpad = 0; cpad < GAMEPAD_NUMBER; cpad++) { diff --git a/plugins/onepad/keyboard.cpp b/plugins/onepad/keyboard.cpp index fd73d81f12..572f2c621e 100644 --- a/plugins/onepad/keyboard.cpp +++ b/plugins/onepad/keyboard.cpp @@ -27,6 +27,8 @@ #if defined(__unix__) #include #include +#elif defined(__APPLE__) +#include #endif #include "keyboard.h" @@ -41,7 +43,75 @@ char *KeysymToChar(int keysym) } #endif -#if defined(__unix__) +/// g_key_status.press but with proper handling for analog buttons +static void PressButton(u32 pad, u32 button) { + // Analog controls. + if (IsAnalogKey(button)) { + switch (button) { + case PAD_R_LEFT: + case PAD_R_UP: + case PAD_L_LEFT: + case PAD_L_UP: + g_key_status.press(pad, button, -MAX_ANALOG_VALUE); + break; + case PAD_R_RIGHT: + case PAD_R_DOWN: + case PAD_L_RIGHT: + case PAD_L_DOWN: + g_key_status.press(pad, button, MAX_ANALOG_VALUE); + break; + } + } else { + g_key_status.press(pad, button); + } +} + +#if defined(__APPLE__) +// Mac keyboard input code is based on Dolphin's Source/Core/InputCommon/ControllerInterface/Quartz/QuartzKeyboardAndMouse.mm +// Copyright 2016 Dolphin Emulator Project +// Licensed under GPLv2+ + +// All keycodes are 16 bits or less, so we use top 16 bits to differentiate source +// Keyboard keys use discriminator 0 +// Mouse buttons use discriminator 1 + +void UpdateKeyboardInput() { + for (int pad = 0; pad < GAMEPAD_NUMBER; pad++) { + const auto& map = g_conf.keysym_map[pad]; + // If we loop over all keys press/release based on current state, + // joystick axes (which have two bound keys) will always go to the later-polled key + // Instead, release all keys first and then set the ones that are pressed + for (const auto& key : map) g_key_status.release(pad, key.second); + for (const auto& key : map) { + bool state; + if (key.first >> 16 == 0) { + state = CGEventSourceKeyState(kCGEventSourceStateHIDSystemState, key.first); + } else { + state = CGEventSourceButtonState(kCGEventSourceStateHIDSystemState, (CGMouseButton)(key.first & 0xFFFF)); + } + if (state) PressButton(pad, key.second); + } + } +} + +bool PollForNewKeyboardKeys(u32 &pkey) { + // All keycodes in are 0x7e or lower. If you notice + // keys that aren't being recognized, bump this number up! + for (int key = 0; key < 0x80; key++) { + if (CGEventSourceKeyState(kCGEventSourceStateHIDSystemState, key)) { + pkey = key == kVK_Escape ? 0 : key; + return true; + } + } + for (auto btn : {kCGMouseButtonLeft, kCGMouseButtonCenter, kCGMouseButtonRight}) { + if (CGEventSourceButtonState(kCGEventSourceStateHIDSystemState, btn)) { + pkey = btn | (1 << 16); + return true; + } + } + return false; +} +#elif defined(__unix__) static bool s_grab_input = false; static bool s_Shift = false; static unsigned int s_previous_mouse_x = 0; @@ -82,24 +152,7 @@ static void AnalyzeKeyEvent(keyEvent &evt) } } - // Analog controls. - if (IsAnalogKey(index)) { - switch (index) { - case PAD_R_LEFT: - case PAD_R_UP: - case PAD_L_LEFT: - case PAD_L_UP: - g_key_status.press(pad, index, -MAX_ANALOG_VALUE); - break; - case PAD_R_RIGHT: - case PAD_R_DOWN: - case PAD_L_RIGHT: - case PAD_L_DOWN: - g_key_status.press(pad, index, MAX_ANALOG_VALUE); - break; - } - } else if (index != -1) - g_key_status.press(pad, index); + PressButton(pad, index); //PAD_LOG("Key pressed:%d\n", index); @@ -191,7 +244,7 @@ static void AnalyzeKeyEvent(keyEvent &evt) } } -void PollForX11KeyboardInput() +void UpdateKeyboardInput() { keyEvent evt = {0}; XEvent E = {0}; @@ -222,7 +275,7 @@ void PollForX11KeyboardInput() } } -bool PollX11KeyboardMouseEvent(u32 &pkey) +bool PollForNewKeyboardKeys(u32 &pkey) { GdkEvent *ev = gdk_event_get(); diff --git a/plugins/onepad/keyboard.h b/plugins/onepad/keyboard.h index beb20aa310..a6e0681e55 100644 --- a/plugins/onepad/keyboard.h +++ b/plugins/onepad/keyboard.h @@ -24,12 +24,14 @@ #include "onepad.h" -#if defined(__unix__) +#if defined(__unix__) || defined(__APPLE__) +extern void UpdateKeyboardInput(); +extern bool PollForNewKeyboardKeys(u32 &pkey); +#ifndef __APPLE__ extern Display *GSdsp; -extern void PollForX11KeyboardInput(); -extern bool PollX11KeyboardMouseEvent(u32 &pkey); extern Window GSwin; +#endif #else diff --git a/plugins/onepad/onepad.cpp b/plugins/onepad/onepad.cpp index c8653cf794..003157b38b 100644 --- a/plugins/onepad/onepad.cpp +++ b/plugins/onepad/onepad.cpp @@ -183,7 +183,7 @@ PADopen(void *pDsp) g_ev_fifo.reset(); -#if defined(__unix__) +#if defined(__unix__) || defined(__APPLE__) GamePad::EnumerateGamePads(s_vgamePad); #endif return _PADopen(pDsp); diff --git a/plugins/onepad/onepad.h b/plugins/onepad/onepad.h index 2dd787d592..b20abd5290 100644 --- a/plugins/onepad/onepad.h +++ b/plugins/onepad/onepad.h @@ -101,7 +101,7 @@ enum gamePadValues { PAD_R_LEFT // Right joystick (Left) ← }; -#if defined(__unix__) +#if defined(__unix__) || defined(__APPLE__) #include "GamePad.h" #endif #include "bitwise.h" diff --git a/plugins/onepad/res/game_controller_db.txt b/plugins/onepad/res/game_controller_db.txt index feda960850..7e561bb27a 100644 --- a/plugins/onepad/res/game_controller_db.txt +++ b/plugins/onepad/res/game_controller_db.txt @@ -1,4 +1,127 @@ -# Linux - from # https://github.com/gabomdq/ +# Mac OS, Linux - from # https://github.com/gabomdq/ +# Mac OS X +030000008f0e00000300000009010000,2In1 USB Joystick,+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X, +03000000c82d00000650000001000000,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000022000000090000001000000,8Bitdo NES30 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:Mac OS X, +03000000203800000900000000010000,8Bitdo NES30 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:Mac OS X, +03000000c82d00000190000001000000,8Bitdo NES30 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:Mac OS X, +03000000102800000900000000000000,8Bitdo SFC30 GamePad Joystick,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00000161000000010000,8BitDo SN30 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:Mac OS X, +03000000c82d00000260000001000000,8BitDo SN30 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:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00000261000000010000,8BitDo SN30 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:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00000031000001000000,8BitDo Wireless Adapter,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: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, +03000000a00500003232000008010000,8Bitdo Zero GamePad,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 GamePad,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, +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, +030000008305000031b0000000000000,Cideko AK08b,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:Mac OS X, +03000000260900008888000088020000,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:Mac OS X, +03000000a306000022f6000001030000,Cyborg V.3 Rumble 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:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000ad1b000001f9000000000000,Gamestop BB-070 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, +030000006f0e00000102000000000000,GameStop Xbox 360 Wired 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, +030000007d0400000540000001010000,Gravis Eliminator GamePad Pro,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X, +030000000d0f00002d00000000100000,Hori Fighting Commander 3 Pro,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:Mac OS X, +030000000d0f00005f00000000010000,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:Mac OS X, +030000000d0f00005e00000000010000,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,x:b0,y:b3,platform:Mac OS X, +030000000d0f00005f00000000000000,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,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, +030000000d0f00005e00000000000000,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,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, +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, +030000000d0f00009200000000010000,Hori Pokken Tournament DX Pro Pad,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, +030000000d0f00006e00000000010000,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:Mac OS X, +030000000d0f00006600000000010000,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,x:b0,y:b3,platform:Mac OS X, +030000000d0f00006600000000000000,HORIPAD FPS PLUS 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:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +030000000d0f0000ee00000000010000,HORIPAD mini4,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:Mac OS X, +030000008f0e00001330000011010000,HuiJia SNES Controller,a:b4,b:b2,back:b16,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b12,rightshoulder:b14,start:b18,x:b6,y:b0,platform:Mac OS X, +03000000830500006020000000010000,iBuffalo SNES Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Mac OS X, +03000000830500006020000000000000,iBuffalo USB 2-axis 8-button Gamepad,a:b1,b:b0,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Mac OS X, +030000007e0500000620000001000000,Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b13,leftshoulder:b4,leftstick:b10,rightshoulder:b5,start:b8,x:b2,y:b3,platform:Mac OS X, +030000007e0500000720000001000000,Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b12,leftshoulder:b4,leftstick:b11,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Mac OS X, +03000000242f00002d00000007010000,JYS Wireless Adapter,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, +030000006d04000016c2000000020000,Logitech Dual Action,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:Mac OS X, +030000006d04000016c2000000030000,Logitech Dual Action,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:Mac OS X, +030000006d04000016c2000014040000,Logitech Dual Action,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:Mac OS X, +030000006d04000016c2000000000000,Logitech F310 Gamepad (DInput),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:Mac OS X, +030000006d04000018c2000000000000,Logitech F510 Gamepad (DInput),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:Mac OS X, +030000006d04000019c2000005030000,Logitech F710,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:Mac OS X, +030000006d0400001fc2000000000000,Logitech F710 Gamepad (XInput),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, +030000006d04000018c2000000010000,Logitech RumblePad 2 USB,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:Mac OS X, +030000006d04000019c2000000000000,Logitech Wireless Gamepad (DInput),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:Mac OS X, +03000000380700005032000000010000,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:Mac OS X, +03000000380700005082000000010000,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,x:b0,y:b3,platform:Mac OS X, +03000000380700008433000000010000,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:Mac OS X, +03000000380700008483000000010000,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,x:b0,y:b3,platform:Mac OS X, +03000000790000004418000000010000,Mayflash GameCube Controller,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:Mac OS X, +03000000242f00007300000000020000,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:a2,righty:a3,start:b11,x:b0,y:b3,platform:Mac OS X, +0300000079000000d218000026010000,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:Mac OS X, +03000000d620000010a7000003010000,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:Mac OS X, +0300000025090000e803000000000000,Mayflash Wii Classic Controller,a:b1,b:b0,back:b8,dpdown:b13,dpleft:b12,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Mac OS X, +03000000790000000018000000000000,Mayflash WiiU Pro Game Controller Adapter (DInput),a:b4,b:b8,back:b32,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b16,leftstick:b40,lefttrigger:b24,leftx:a0,lefty:a4,rightshoulder:b20,rightstick:b44,righttrigger:b28,rightx:a8,righty:a12,start:b36,x:b0,y:b12,platform:Mac OS X, +03000000d8140000cecf000000000000,MC Cthulhu,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, +030000005e0400002700000001010000,Microsoft SideWinder Plug & Play Game Pad,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,lefttrigger:b4,leftx:a0,lefty:a1,righttrigger:b5,x:b2,y:b3,platform:Mac OS X, +03000000d62000007162000001000000,Moga Pro 2 HID,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, +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, +030000001008000001e5000006010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b6,start:b9,x:b3,y:b0,platform:Mac OS X, +03000000d620000011a7000000020000,Nintendo Switch Core (Plus) Wired 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, +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, +030000008f0e00000300000000000000,Piranha xtreme,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, +030000004c050000da0c000000010000,Playstation Classic 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: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, +030000004c0500006802000000000000,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:Mac OS X, +030000004c0500006802000000010000,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:Mac OS X, +030000004c050000a00b000000010000,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:Mac OS X, +030000004c050000c405000000000000,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:Mac OS X, +030000004c050000c405000000010000,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:Mac OS X, +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,x:b0,y:b3,platform:Mac OS X, +030000008916000000fd000000000000,Razer Onza TE,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, +03000000321500000204000000010000,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:Mac OS X, +03000000321500000104000000010000,Razer Panthera (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,x:b0,y:b3,platform:Mac OS X, +03000000321500000010000000010000,Razer RAIJU,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, +03000000321500000507000001010000,Razer Raiju Mobile,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, +03000000321500000009000000020000,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, +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, +03000000790000001100000000000000,Retrolink Classic Controller,a:b2,b:b1,back:b8,leftshoulder:b4,leftx:a3,lefty:a4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X, +03000000790000001100000006010000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X, +030000006b140000010d000000010000,Revolution 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, +03000000c6240000fefa000000000000,Rock Candy Gamepad for PS3,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, +03000000730700000401000000010000,Sanwa PlayOnline Mobile,a:b0,b:b1,back:b2,leftx:a0,lefty:a1,start:b3,platform:Mac OS X, +03000000811700007e05000000000000,Sega Saturn,a:b2,b:b4,dpdown:b16,dpleft:b15,dpright:b14,dpup:b17,leftshoulder:b8,lefttrigger:a5,leftx:a0,lefty:a2,rightshoulder:b9,righttrigger:a4,start:b13,x:b0,y:b6,platform:Mac OS X, +03000000b40400000a01000000000000,Sega Saturn USB Gamepad,a:b0,b:b1,back:b5,guide:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b8,x:b3,y:b4,platform:Mac OS X, +030000003512000021ab000000000000,SFC30 Joystick,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X, +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, +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,x:b0,y:b3,platform:Mac OS X, +030000004c050000a00b000000000000,Sony DualShock 4 Wireless Adaptor,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,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, +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,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b12,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, +03000000381000002014000001000000,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, +03000000110100001714000000000000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,start:b12,x:b2,y:b3,platform:Mac OS X, +03000000110100001714000020010000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,start:b12,x:b2,y:b3,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, +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, +03000000bd12000015d0000000000000,Tomee SNES USB Controller,a:b2,b:b1,back:b8,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X, +03000000bd12000015d0000000010000,Tomee SNES USB 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, +03000000100800000100000000000000,Twin USB Joystick,a:b4,b:b2,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b12,leftstick:b20,lefttrigger:b8,leftx:a0,lefty:a2,rightshoulder:b14,rightstick:b22,righttrigger:b10,rightx:a6,righty:a4,start:b18,x:b6,y:b0,platform:Mac OS X, +030000006f0e00000302000025040000,Victrix Pro Fight Stick for 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,x:b0,y:b3,platform:Mac OS X, +03000000791d00000103000009010000,Wii Classic Controller,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,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:Mac OS X, +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,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, +03000000c6240000045d000000000000,Xbox 360 Wired 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, +030000005e040000d102000000000000,Xbox One Wired 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, +030000005e040000dd02000000000000,Xbox One Wired 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, +030000005e040000e302000000000000,Xbox One Wired 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, +030000005e040000e002000000000000,Xbox Wireless 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:Mac OS X, +030000005e040000e002000003090000,Xbox Wireless 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:Mac OS X, +030000005e040000ea02000000000000,Xbox Wireless 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 Wireless 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, +03000000172700004431000029010000,XiaoMi Game 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 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:Mac OS X, + # Linux 05000000c82d00001038000000010000,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, 05000000c82d00005106000000010000,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Linux, diff --git a/plugins/onepad/wx_dialog/dialog.cpp b/plugins/onepad/wx_dialog/dialog.cpp index c87660dc40..fa8cd93366 100644 --- a/plugins/onepad/wx_dialog/dialog.cpp +++ b/plugins/onepad/wx_dialog/dialog.cpp @@ -19,6 +19,149 @@ #include "dialog.h" +#ifdef __APPLE__ +#include + +static std::string KeyName(int pad, int key, int keysym) +{ + // Mouse + if (keysym >> 16) { + switch (keysym & 0xFFFF) { + case kCGMouseButtonLeft: + return "Mouse Left"; + case kCGMouseButtonRight: + return "Mouse Right"; + case kCGMouseButtonCenter: + return "Mouse Middle"; + default: // Use only number for extra button + return "Mouse " + std::to_string(keysym & 0xFFFF); + } + } + + switch (keysym) { + case kVK_ANSI_A: return "A"; + case kVK_ANSI_B: return "B"; + case kVK_ANSI_C: return "C"; + case kVK_ANSI_D: return "D"; + case kVK_ANSI_E: return "E"; + case kVK_ANSI_F: return "F"; + case kVK_ANSI_G: return "G"; + case kVK_ANSI_H: return "H"; + case kVK_ANSI_I: return "I"; + case kVK_ANSI_J: return "J"; + case kVK_ANSI_K: return "K"; + case kVK_ANSI_L: return "L"; + case kVK_ANSI_M: return "M"; + case kVK_ANSI_N: return "N"; + case kVK_ANSI_O: return "O"; + case kVK_ANSI_P: return "P"; + case kVK_ANSI_Q: return "Q"; + case kVK_ANSI_R: return "R"; + case kVK_ANSI_S: return "S"; + case kVK_ANSI_T: return "T"; + case kVK_ANSI_U: return "U"; + case kVK_ANSI_V: return "V"; + case kVK_ANSI_W: return "W"; + case kVK_ANSI_X: return "X"; + case kVK_ANSI_Y: return "Y"; + case kVK_ANSI_Z: return "Z"; + case kVK_ANSI_0: return "0"; + case kVK_ANSI_1: return "1"; + case kVK_ANSI_2: return "2"; + case kVK_ANSI_3: return "3"; + case kVK_ANSI_4: return "4"; + case kVK_ANSI_5: return "5"; + case kVK_ANSI_6: return "6"; + case kVK_ANSI_7: return "7"; + case kVK_ANSI_8: return "8"; + case kVK_ANSI_9: return "9"; + case kVK_ANSI_Grave: return "`"; + case kVK_ANSI_Minus: return "-"; + case kVK_ANSI_Equal: return "="; + case kVK_ANSI_LeftBracket: return "["; + case kVK_ANSI_RightBracket: return "]"; + case kVK_ANSI_Backslash: return "\\"; + case kVK_ANSI_Semicolon: return ";"; + case kVK_ANSI_Quote: return "'"; + case kVK_ANSI_Comma: return ","; + case kVK_ANSI_Period: return "."; + case kVK_ANSI_Slash: return "/"; + case kVK_Escape: return "⎋"; + case kVK_Tab: return "⇥"; + case kVK_Delete: return "⌫"; + case kVK_ForwardDelete: return "⌦"; + case kVK_Return: return "↩"; + case kVK_Space: return "␣"; + case kVK_ANSI_KeypadDecimal: return "Keypad ."; + case kVK_ANSI_KeypadMultiply: return "Keypad *"; + case kVK_ANSI_KeypadPlus: return "Keypad +"; + case kVK_ANSI_KeypadClear: return "⌧"; + case kVK_ANSI_KeypadDivide: return "Keypad /"; + case kVK_ANSI_KeypadEnter: return "⌤"; + case kVK_ANSI_KeypadMinus: return "Keypad -"; + case kVK_ANSI_KeypadEquals: return "Keypad ="; + case kVK_ANSI_Keypad0: return "Keypad 0"; + case kVK_ANSI_Keypad1: return "Keypad 1"; + case kVK_ANSI_Keypad2: return "Keypad 2"; + case kVK_ANSI_Keypad3: return "Keypad 3"; + case kVK_ANSI_Keypad4: return "Keypad 4"; + case kVK_ANSI_Keypad5: return "Keypad 5"; + case kVK_ANSI_Keypad6: return "Keypad 6"; + case kVK_ANSI_Keypad7: return "Keypad 7"; + case kVK_ANSI_Keypad8: return "Keypad 8"; + case kVK_ANSI_Keypad9: return "Keypad 9"; + case kVK_Command: return "Left ⌘"; + case kVK_Shift: return "Left ⇧"; + case kVK_CapsLock: return "⇪"; + case kVK_Option: return "Left ⌥"; + case kVK_Control: return "Left ⌃"; + case kVK_RightCommand: return "Right ⌘"; + case kVK_RightShift: return "Right ⇧"; + case kVK_RightOption: return "Right ⌥"; + case kVK_RightControl: return "Right ⌃"; + case kVK_Function: return "fn"; + case kVK_VolumeUp: return "Volume Up"; + case kVK_VolumeDown: return "Volume Down"; + case kVK_Mute: return "Mute"; + case kVK_F1: return "F1"; + case kVK_F2: return "F2"; + case kVK_F3: return "F3"; + case kVK_F4: return "F4"; + case kVK_F5: return "F5"; + case kVK_F6: return "F6"; + case kVK_F7: return "F7"; + case kVK_F8: return "F8"; + case kVK_F9: return "F9"; + case kVK_F10: return "F10"; + case kVK_F11: return "F11"; + case kVK_F12: return "F12"; + case kVK_F13: return "F13"; + case kVK_F14: return "F14"; + case kVK_F15: return "F15"; + case kVK_F16: return "F16"; + case kVK_F17: return "F17"; + case kVK_F18: return "F18"; + case kVK_F19: return "F19"; + case kVK_F20: return "F20"; + case kVK_Help: return "Help"; + case kVK_Home: return "↖"; + case kVK_PageUp: return "⇞"; + case kVK_End: return "↘"; + case kVK_PageDown: return "⇟"; + case kVK_LeftArrow: return "←"; + case kVK_RightArrow: return "→"; + case kVK_DownArrow: return "↓"; + case kVK_UpArrow: return "↑"; + case kVK_ISO_Section: return "Section"; + case kVK_JIS_Yen: return "¥"; + case kVK_JIS_Underscore: return "_"; + case kVK_JIS_KeypadComma: return "Keypad ,"; + case kVK_JIS_Eisu: return "英数"; + case kVK_JIS_Kana: return "かな"; + default: return "Key " + std::to_string(keysym); + } +} +#else static std::string KeyName(int pad, int key, int keysym) { // Mouse @@ -39,6 +182,7 @@ static std::string KeyName(int pad, int key, int keysym) return std::string(XKeysymToString(keysym)); } +#endif // Construtor of Dialog Dialog::Dialog() @@ -431,7 +575,7 @@ void Dialog::config_key(int pad, int key) u32 key_pressed = 0; while (!captured) { - if (PollX11KeyboardMouseEvent(key_pressed)) { + if (PollForNewKeyboardKeys(key_pressed)) { // special case for keyboard/mouse to handle multiple keys // Note: key_pressed == 0 when ESC is hit to abort the capture if (key_pressed > 0) { diff --git a/plugins/spu2-x/src/CMakeLists.txt b/plugins/spu2-x/src/CMakeLists.txt index f14ad5038b..30a443decf 100644 --- a/plugins/spu2-x/src/CMakeLists.txt +++ b/plugins/spu2-x/src/CMakeLists.txt @@ -20,7 +20,7 @@ set(CommonFlags # plugin name set(Output spu2x-2.0.0) -if (UNIX AND NOT APPLE) +if (UNIX) if (SDL2_API) set(spu2xFinalFlags "-DSPU2X_SDL2" ${CommonFlags}) else() diff --git a/plugins/spu2-x/src/Linux/Config.cpp b/plugins/spu2-x/src/Linux/Config.cpp index 96a9e7bc8b..f4d3d1f2e6 100644 --- a/plugins/spu2-x/src/Linux/Config.cpp +++ b/plugins/spu2-x/src/Linux/Config.cpp @@ -23,6 +23,9 @@ #include #include #endif +#ifdef __APPLE__ +#include +#endif #ifdef PCSX2_DEVBUILD static const int LATENCY_MAX = 3000; @@ -147,7 +150,7 @@ void ReadSettings() #endif #endif -#ifdef __unix__ +#if defined(__unix__) || defined(__APPLE__) CfgReadStr(L"SDL", L"HostApi", temp, L"pulseaudio"); SdlOutputAPI = 0; #if SDL_MAJOR_VERSION >= 2 @@ -165,7 +168,7 @@ void ReadSettings() #ifdef SPU2X_PORTAUDIO PortaudioOut->ReadSettings(); #endif -#ifdef __unix__ +#if defined(__unix__) || defined(__APPLE__) SDLOut->ReadSettings(); #endif SoundtouchCfg::ReadSettings(); @@ -218,7 +221,7 @@ void WriteSettings() #ifdef SPU2X_PORTAUDIO PortaudioOut->WriteSettings(); #endif -#ifdef __unix__ +#if defined(__unix__) || defined(__APPLE__) SDLOut->WriteSettings(); #endif SoundtouchCfg::WriteSettings(); @@ -235,7 +238,7 @@ void debug_dialog() DebugConfig::DisplayDialog(); } -#if defined(__unix__) +#if defined(__unix__) || defined(__APPLE__) // Format the slider with ms. static gchar *cb_scale_format_ms(GtkScale *scale, gdouble value) @@ -334,6 +337,8 @@ void DisplayDialog() gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(api_box), "0 - ALSA (recommended)"); gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(api_box), "1 - OSS (legacy)"); gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(api_box), "2 - JACK"); +#elif defined(__APPLE__) + gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(api_box), "CoreAudio"); #else gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(api_box), "OSS"); #endif @@ -466,7 +471,11 @@ void DisplayDialog() #else switch (OutputAPI) { case 0: +#ifdef __APPLE__ + PortaudioOut->SetApiSettings(L"CoreAudio"); +#else PortaudioOut->SetApiSettings(L"OSS"); +#endif break; default: PortaudioOut->SetApiSettings(L"Unknown"); @@ -499,10 +508,23 @@ void DisplayDialog() void configure() { +#ifdef __APPLE__ + // Rest of macOS UI doesn't use GTK so we need to init it now + gtk_init(nullptr, nullptr); + // GTK expects us to be using its event loop, rather than Cocoa's + // If we call its stuff right now, it'll attempt to drain a static autorelease pool that was already drained by Cocoa (see https://github.com/GNOME/gtk/blob/8c1072fad1cb6a2e292fce2441b4a571f173ce0f/gdk/quartz/gdkeventloop-quartz.c#L640-L646) + // We can convince it that touching that pool would be unsafe by running all GTK calls within a CFRunLoop + // (Blocks submitted to the main queue by dispatch_async are run by its CFRunLoop) + dispatch_async(dispatch_get_main_queue(), ^{ +#endif initIni(); ReadSettings(); DisplayDialog(); WriteSettings(); delete spuConfig; spuConfig = NULL; +#ifdef __APPLE__ + // End of `dispatch_async(...` above + }); +#endif } diff --git a/plugins/spu2-x/src/Linux/ConfigDebug.cpp b/plugins/spu2-x/src/Linux/ConfigDebug.cpp index ea98e2068c..cd48527755 100644 --- a/plugins/spu2-x/src/Linux/ConfigDebug.cpp +++ b/plugins/spu2-x/src/Linux/ConfigDebug.cpp @@ -154,7 +154,7 @@ void WriteSettings() CfgWriteStr(Section, L"Reg_Dump_Filename", RegDumpFileName); } -#ifdef __unix__ +#if defined(__unix__) || defined(__APPLE__) void DisplayDialog() { GtkWidget *dialog; diff --git a/plugins/spu2-x/src/Linux/ConfigSoundTouch.cpp b/plugins/spu2-x/src/Linux/ConfigSoundTouch.cpp index 4d3d8cc4b1..f55a907c14 100644 --- a/plugins/spu2-x/src/Linux/ConfigSoundTouch.cpp +++ b/plugins/spu2-x/src/Linux/ConfigSoundTouch.cpp @@ -71,7 +71,7 @@ void WriteSettings() CfgWriteInt(L"SOUNDTOUCH", L"OverlapMS", OverlapMS); } -#ifdef __unix__ +#if defined(__unix__) || defined(__APPLE__) static GtkWidget *seq_label, *seek_label, *over_label; static GtkWidget *seq_slide, *seek_slide, *over_slide;