bindings-GLFW 3.3.9.0 → 3.3.9.1
raw patch · 44 files changed
+6475/−4285 lines, 44 files
Files
- Test.hs +2/−3
- bindings-GLFW.cabal +7/−2
- glfw/include/GLFW/glfw3.h +160/−102
- glfw/src/cocoa_init.m +21/−9
- glfw/src/cocoa_joystick.h +1/−0
- glfw/src/cocoa_joystick.m +16/−10
- glfw/src/cocoa_monitor.m +65/−50
- glfw/src/cocoa_platform.h +17/−8
- glfw/src/cocoa_window.m +169/−50
- glfw/src/context.c +25/−18
- glfw/src/egl_context.c +106/−45
- glfw/src/egl_context.h +4/−2
- glfw/src/glx_context.c +18/−10
- glfw/src/glx_context.h +0/−3
- glfw/src/init.c +107/−21
- glfw/src/input.c +60/−30
- glfw/src/internal.h +33/−22
- glfw/src/linux_joystick.c +10/−6
- glfw/src/mappings.h +624/−99
- glfw/src/monitor.c +3/−5
- glfw/src/nsgl_context.h +4/−4
- glfw/src/nsgl_context.m +6/−7
- glfw/src/null_window.c +3/−0
- glfw/src/osmesa_context.c +15/−1
- glfw/src/vulkan.c +2/−0
- glfw/src/wgl_context.c +13/−22
- glfw/src/wgl_context.h +0/−6
- glfw/src/win32_init.c +20/−13
- glfw/src/win32_joystick.c +19/−12
- glfw/src/win32_joystick.h +1/−0
- glfw/src/win32_monitor.c +15/−2
- glfw/src/win32_platform.h +23/−21
- glfw/src/win32_time.c +4/−20
- glfw/src/win32_window.c +322/−148
- glfw/src/window.c +24/−24
- glfw/src/wl_init.c +707/−1280
- glfw/src/wl_monitor.c +76/−28
- glfw/src/wl_platform.h +232/−61
- glfw/src/wl_window.c +2938/−1775
- glfw/src/x11_init.c +291/−123
- glfw/src/x11_monitor.c +1/−1
- glfw/src/x11_platform.h +6/−6
- glfw/src/x11_window.c +303/−234
- glfw/src/xkb_unicode.c +2/−2
Test.hs view
@@ -61,7 +61,7 @@ versionMajor, versionMinor, versionRevision :: Int versionMajor = 3 versionMinor = 3-versionRevision = 2+versionRevision = 9 giveItTime :: IO () giveItTime = threadDelay 500000@@ -280,10 +280,9 @@ test_glfwGetMonitorName p'mon = do p'name <- c'glfwGetMonitorName p'mon if p'name == nullPtr- then assertFailure ""+ then return () else do name <- peekCString p'name- assertBool "" $ length name `between` (0, 20) assertBool "" $ all isAscii name test_glfwGetMonitorWorkarea :: Ptr C'GLFWmonitor -> IO ()
bindings-GLFW.cabal view
@@ -1,5 +1,5 @@ name: bindings-GLFW-version: 3.3.9.0+version: 3.3.9.1 category: Graphics author: Brian Lewis <brian@lorf.org>@@ -137,9 +137,14 @@ c-sources: glfw/src/glx_context.c glfw/src/xkb_unicode.c- glfw/src/linux_joystick.c glfw/src/posix_time.c glfw/src/posix_thread.c+ if os(linux)+ c-sources:+ glfw/src/linux_joystick.c+ if os(freebsd)+ c-sources:+ glfw/src/null_joystick.c if flag(X) cc-options: -DBINDINGS_GLFW_USE_X11 -D_GLFW_X11 c-sources:
glfw/include/GLFW/glfw3.h view
@@ -52,7 +52,7 @@ * This is the reference documentation for OpenGL and OpenGL ES context related * functions. For more task-oriented information, see the @ref context_guide. */-/*! @defgroup vulkan Vulkan reference+/*! @defgroup vulkan Vulkan support reference * @brief Functions and types related to Vulkan. * * This is the reference documentation for Vulkan related functions and types.@@ -190,20 +190,51 @@ #else /*__APPLE__*/ #include <GL/glcorearb.h>+ #if defined(GLFW_INCLUDE_GLEXT)+ #include <GL/glext.h>+ #endif #endif /*__APPLE__*/ -#elif !defined(GLFW_INCLUDE_NONE)+#elif defined(GLFW_INCLUDE_GLU) #if defined(__APPLE__) + #if defined(GLFW_INCLUDE_GLU)+ #include <OpenGL/glu.h>+ #endif++ #else /*__APPLE__*/++ #if defined(GLFW_INCLUDE_GLU)+ #include <GL/glu.h>+ #endif++ #endif /*__APPLE__*/++#elif !defined(GLFW_INCLUDE_NONE) && \+ !defined(__gl_h_) && \+ !defined(__gles1_gl_h_) && \+ !defined(__gles2_gl2_h_) && \+ !defined(__gles2_gl3_h_) && \+ !defined(__gles2_gl31_h_) && \+ !defined(__gles2_gl32_h_) && \+ !defined(__gl_glcorearb_h_) && \+ !defined(__gl2_h_) /*legacy*/ && \+ !defined(__gl3_h_) /*legacy*/ && \+ !defined(__gl31_h_) /*legacy*/ && \+ !defined(__gl32_h_) /*legacy*/ && \+ !defined(__glcorearb_h_) /*legacy*/ && \+ !defined(__GL_H__) /*non-standard*/ && \+ !defined(__gltypes_h_) /*non-standard*/ && \+ !defined(__glee_h_) /*non-standard*/++ #if defined(__APPLE__)+ #if !defined(GLFW_INCLUDE_GLEXT) #define GL_GLEXT_LEGACY #endif #include <OpenGL/gl.h>- #if defined(GLFW_INCLUDE_GLU)- #include <OpenGL/glu.h>- #endif #else /*__APPLE__*/ @@ -211,9 +242,6 @@ #if defined(GLFW_INCLUDE_GLEXT) #include <GL/glext.h> #endif- #if defined(GLFW_INCLUDE_GLU)- #include <GL/glu.h>- #endif #endif /*__APPLE__*/ @@ -234,13 +262,12 @@ /* We are building GLFW as a Win32 DLL */ #define GLFWAPI __declspec(dllexport) #elif defined(_WIN32) && defined(GLFW_DLL)- /* We are calling GLFW as a Win32 DLL */+ /* We are calling a GLFW Win32 DLL */ #define GLFWAPI __declspec(dllimport) #elif defined(__GNUC__) && defined(_GLFW_BUILD_DLL)- /* We are building GLFW as a shared / dynamic library */+ /* We are building GLFW as a Unix shared library */ #define GLFWAPI __attribute__((visibility("default"))) #else- /* We are building or calling GLFW as a static library */ #define GLFWAPI #endif @@ -251,26 +278,27 @@ /*! @name GLFW version macros * @{ */-/*! @brief The major version number of the GLFW library.+/*! @brief The major version number of the GLFW header. *- * This is incremented when the API is changed in non-compatible ways.+ * The major version number of the GLFW header. This is incremented when the+ * API is changed in non-compatible ways. * @ingroup init */ #define GLFW_VERSION_MAJOR 3-/*! @brief The minor version number of the GLFW library.+/*! @brief The minor version number of the GLFW header. *- * This is incremented when features are added to the API but it remains- * backward-compatible.+ * The minor version number of the GLFW header. This is incremented when+ * features are added to the API but it remains backward-compatible. * @ingroup init */ #define GLFW_VERSION_MINOR 3-/*! @brief The revision number of the GLFW library.+/*! @brief The revision number of the GLFW header. *- * This is incremented when a bug fix release is made that does not contain any- * API changes.+ * The revision number of the GLFW header. This is incremented when a bug fix+ * release is made that does not contain any API changes. * @ingroup init */-#define GLFW_VERSION_REVISION 2+#define GLFW_VERSION_REVISION 9 /*! @} */ /*! @brief One.@@ -333,10 +361,15 @@ #define GLFW_HAT_RIGHT_DOWN (GLFW_HAT_RIGHT | GLFW_HAT_DOWN) #define GLFW_HAT_LEFT_UP (GLFW_HAT_LEFT | GLFW_HAT_UP) #define GLFW_HAT_LEFT_DOWN (GLFW_HAT_LEFT | GLFW_HAT_DOWN)++/*! @ingroup input+ */+#define GLFW_KEY_UNKNOWN -1+ /*! @} */ -/*! @defgroup keys Keyboard keys- * @brief Keyboard key IDs.+/*! @defgroup keys Keyboard key tokens+ * @brief Keyboard key tokens. * * See [key input](@ref input_key) for how these are used. *@@ -359,9 +392,6 @@ * @{ */ -/* The unknown key */-#define GLFW_KEY_UNKNOWN -1- /* Printable keys */ #define GLFW_KEY_SPACE 32 #define GLFW_KEY_APOSTROPHE 39 /* ' */@@ -931,7 +961,7 @@ * and [attribute](@ref GLFW_CONTEXT_VERSION_MINOR_attrib). */ #define GLFW_CONTEXT_VERSION_MINOR 0x00022003-/*! @brief Context client API revision number hint and attribute.+/*! @brief Context client API revision number attribute. * * Context client API revision number * [attribute](@ref GLFW_CONTEXT_REVISION_attrib).@@ -949,9 +979,9 @@ * and [attribute](@ref GLFW_OPENGL_FORWARD_COMPAT_attrib). */ #define GLFW_OPENGL_FORWARD_COMPAT 0x00022006-/*! @brief OpenGL debug context hint and attribute.+/*! @brief Debug mode context hint and attribute. *- * OpenGL debug context [hint](@ref GLFW_OPENGL_DEBUG_CONTEXT_hint) and+ * Debug mode context [hint](@ref GLFW_OPENGL_DEBUG_CONTEXT_hint) and * [attribute](@ref GLFW_OPENGL_DEBUG_CONTEXT_attrib). */ #define GLFW_OPENGL_DEBUG_CONTEXT 0x00022007@@ -1035,6 +1065,9 @@ #define GLFW_EGL_CONTEXT_API 0x00036002 #define GLFW_OSMESA_CONTEXT_API 0x00036003 +#define GLFW_WAYLAND_PREFER_LIBDECOR 0x00038001+#define GLFW_WAYLAND_DISABLE_LIBDECOR 0x00038002+ /*! @defgroup shapes Standard cursor shapes * @brief Standard system cursor shapes. *@@ -1095,6 +1128,11 @@ * macOS specific [init hint](@ref GLFW_COCOA_MENUBAR_hint). */ #define GLFW_COCOA_MENUBAR 0x00051002+/*! @brief Wayland specific init hint.+ *+ * Wayland specific [init hint](@ref GLFW_WAYLAND_LIBDECOR_hint).+ */+#define GLFW_WAYLAND_LIBDECOR 0x00053001 /*! @} */ #define GLFW_DONT_CARE -1@@ -1190,7 +1228,7 @@ * * @ingroup init */-typedef void (* GLFWerrorfun)(int,const char*);+typedef void (* GLFWerrorfun)(int error_code, const char* description); /*! @brief The function pointer type for window position callbacks. *@@ -1213,7 +1251,7 @@ * * @ingroup window */-typedef void (* GLFWwindowposfun)(GLFWwindow*,int,int);+typedef void (* GLFWwindowposfun)(GLFWwindow* window, int xpos, int ypos); /*! @brief The function pointer type for window size callbacks. *@@ -1235,7 +1273,7 @@ * * @ingroup window */-typedef void (* GLFWwindowsizefun)(GLFWwindow*,int,int);+typedef void (* GLFWwindowsizefun)(GLFWwindow* window, int width, int height); /*! @brief The function pointer type for window close callbacks. *@@ -1255,7 +1293,7 @@ * * @ingroup window */-typedef void (* GLFWwindowclosefun)(GLFWwindow*);+typedef void (* GLFWwindowclosefun)(GLFWwindow* window); /*! @brief The function pointer type for window content refresh callbacks. *@@ -1275,7 +1313,7 @@ * * @ingroup window */-typedef void (* GLFWwindowrefreshfun)(GLFWwindow*);+typedef void (* GLFWwindowrefreshfun)(GLFWwindow* window); /*! @brief The function pointer type for window focus callbacks. *@@ -1296,7 +1334,7 @@ * * @ingroup window */-typedef void (* GLFWwindowfocusfun)(GLFWwindow*,int);+typedef void (* GLFWwindowfocusfun)(GLFWwindow* window, int focused); /*! @brief The function pointer type for window iconify callbacks. *@@ -1317,7 +1355,7 @@ * * @ingroup window */-typedef void (* GLFWwindowiconifyfun)(GLFWwindow*,int);+typedef void (* GLFWwindowiconifyfun)(GLFWwindow* window, int iconified); /*! @brief The function pointer type for window maximize callbacks. *@@ -1328,7 +1366,7 @@ * @endcode * * @param[in] window The window that was maximized or restored.- * @param[in] iconified `GLFW_TRUE` if the window was maximized, or+ * @param[in] maximized `GLFW_TRUE` if the window was maximized, or * `GLFW_FALSE` if it was restored. * * @sa @ref window_maximize@@ -1338,7 +1376,7 @@ * * @ingroup window */-typedef void (* GLFWwindowmaximizefun)(GLFWwindow*,int);+typedef void (* GLFWwindowmaximizefun)(GLFWwindow* window, int maximized); /*! @brief The function pointer type for framebuffer size callbacks. *@@ -1359,7 +1397,7 @@ * * @ingroup window */-typedef void (* GLFWframebuffersizefun)(GLFWwindow*,int,int);+typedef void (* GLFWframebuffersizefun)(GLFWwindow* window, int width, int height); /*! @brief The function pointer type for window content scale callbacks. *@@ -1380,7 +1418,7 @@ * * @ingroup window */-typedef void (* GLFWwindowcontentscalefun)(GLFWwindow*,float,float);+typedef void (* GLFWwindowcontentscalefun)(GLFWwindow* window, float xscale, float yscale); /*! @brief The function pointer type for mouse button callbacks. *@@ -1406,7 +1444,7 @@ * * @ingroup input */-typedef void (* GLFWmousebuttonfun)(GLFWwindow*,int,int,int);+typedef void (* GLFWmousebuttonfun)(GLFWwindow* window, int button, int action, int mods); /*! @brief The function pointer type for cursor position callbacks. *@@ -1429,7 +1467,7 @@ * * @ingroup input */-typedef void (* GLFWcursorposfun)(GLFWwindow*,double,double);+typedef void (* GLFWcursorposfun)(GLFWwindow* window, double xpos, double ypos); /*! @brief The function pointer type for cursor enter/leave callbacks. *@@ -1450,7 +1488,7 @@ * * @ingroup input */-typedef void (* GLFWcursorenterfun)(GLFWwindow*,int);+typedef void (* GLFWcursorenterfun)(GLFWwindow* window, int entered); /*! @brief The function pointer type for scroll callbacks. *@@ -1471,7 +1509,7 @@ * * @ingroup input */-typedef void (* GLFWscrollfun)(GLFWwindow*,double,double);+typedef void (* GLFWscrollfun)(GLFWwindow* window, double xoffset, double yoffset); /*! @brief The function pointer type for keyboard key callbacks. *@@ -1497,7 +1535,7 @@ * * @ingroup input */-typedef void (* GLFWkeyfun)(GLFWwindow*,int,int,int,int);+typedef void (* GLFWkeyfun)(GLFWwindow* window, int key, int scancode, int action, int mods); /*! @brief The function pointer type for Unicode character callbacks. *@@ -1518,7 +1556,7 @@ * * @ingroup input */-typedef void (* GLFWcharfun)(GLFWwindow*,unsigned int);+typedef void (* GLFWcharfun)(GLFWwindow* window, unsigned int codepoint); /*! @brief The function pointer type for Unicode character with modifiers * callbacks.@@ -1545,7 +1583,7 @@ * * @ingroup input */-typedef void (* GLFWcharmodsfun)(GLFWwindow*,unsigned int,int);+typedef void (* GLFWcharmodsfun)(GLFWwindow* window, unsigned int codepoint, int mods); /*! @brief The function pointer type for path drop callbacks. *@@ -1569,7 +1607,7 @@ * * @ingroup input */-typedef void (* GLFWdropfun)(GLFWwindow*,int,const char*[]);+typedef void (* GLFWdropfun)(GLFWwindow* window, int path_count, const char* paths[]); /*! @brief The function pointer type for monitor configuration callbacks. *@@ -1590,7 +1628,7 @@ * * @ingroup monitor */-typedef void (* GLFWmonitorfun)(GLFWmonitor*,int);+typedef void (* GLFWmonitorfun)(GLFWmonitor* monitor, int event); /*! @brief The function pointer type for joystick configuration callbacks. *@@ -1611,7 +1649,7 @@ * * @ingroup input */-typedef void (* GLFWjoystickfun)(int,int);+typedef void (* GLFWjoystickfun)(int jid, int event); /*! @brief Video mode type. *@@ -1753,6 +1791,10 @@ * bundle, if present. This can be disabled with the @ref * GLFW_COCOA_CHDIR_RESOURCES init hint. *+ * @remark @x11 This function will set the `LC_CTYPE` category of the+ * application locale according to the current environment if that category is+ * still "C". This is because the "C" locale breaks Unicode text input.+ * * @thread_safety This function must only be called from the main thread. * * @sa @ref intro_init@@ -1776,6 +1818,8 @@ * call this function, as it is called by @ref glfwInit before it returns * failure. *+ * This function has no effect if GLFW is not initialized.+ * * @errors Possible errors include @ref GLFW_PLATFORM_ERROR. * * @remark This function may be called before @ref glfwInit.@@ -2093,8 +2137,8 @@ * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. *- * @remark @win32 calculates the returned physical size from the- * current resolution and system DPI instead of querying the monitor EDID data.+ * @remark @win32 On Windows 8 and earlier the physical size is calculated from+ * the current resolution and system DPI instead of querying the monitor EDID data. * * @thread_safety This function must only be called from the main thread. *@@ -2248,8 +2292,9 @@ * * This function returns an array of all video modes supported by the specified * monitor. The returned array is sorted in ascending order, first by color- * bit depth (the sum of all channel depths) and then by resolution area (the- * product of width and height).+ * bit depth (the sum of all channel depths), then by resolution area (the+ * product of width and height), then resolution width and finally by refresh+ * rate. * * @param[in] monitor The monitor to query. * @param[out] count Where to store the number of video modes in the returned@@ -2772,8 +2817,8 @@ * @param[in] images The images to create the icon from. This is ignored if * count is zero. *- * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref- * GLFW_PLATFORM_ERROR.+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref+ * GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR. * * @pointer_lifetime The specified image data is copied before this function * returns.@@ -3183,18 +3228,15 @@ * previously restored. If the window is already iconified, this function does * nothing. *- * If the specified window is a full screen window, the original monitor- * resolution is restored until the window is restored.+ * If the specified window is a full screen window, GLFW restores the original+ * video mode of the monitor. The window's desired video mode is set again+ * when the window is restored. * * @param[in] window The window to iconify. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_PLATFORM_ERROR. *- * @remark @wayland There is no concept of iconification in wl_shell, this- * function will emit @ref GLFW_PLATFORM_ERROR when using this deprecated- * protocol.- * * @thread_safety This function must only be called from the main thread. * * @sa @ref window_iconify@@ -3214,8 +3256,8 @@ * (minimized) or maximized. If the window is already restored, this function * does nothing. *- * If the specified window is a full screen window, the resolution chosen for- * the window is restored on the selected monitor.+ * If the specified window is an iconified full screen window, its desired+ * video mode is set again for its monitor when the window is restored. * * @param[in] window The window to restore. *@@ -3276,6 +3318,11 @@ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_PLATFORM_ERROR. *+ * @remark @wayland Because Wayland wants every frame of the desktop to be+ * complete, this function does not immediately make the window visible.+ * Instead it will become visible the next time the window framebuffer is+ * updated after this call.+ * * @thread_safety This function must only be called from the main thread. * * @sa @ref window_hide@@ -3478,6 +3525,9 @@ * errors. However, this function should not fail as long as it is passed * valid arguments and the library has been [initialized](@ref intro_init). *+ * @remark @wayland The Wayland protocol provides no way to check whether a+ * window is iconfied, so @ref GLFW_ICONIFIED always returns `GLFW_FALSE`.+ * * @thread_safety This function must only be called from the main thread. * * @sa @ref window_attribs@@ -3769,8 +3819,8 @@ * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. *- * @remark @wayland The wl_shell protocol has no concept of iconification,- * this callback will never be called when using this deprecated protocol.+ * @remark @wayland The XDG-shell protocol has no event for iconification, so+ * this callback will never be called. * * @thread_safety This function must only be called from the main thread. *@@ -4190,8 +4240,8 @@ * @param[in] scancode The scancode of the key to query. * @return The UTF-8 encoded, layout-specific name of the key, or `NULL`. *- * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref- * GLFW_PLATFORM_ERROR.+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref+ * GLFW_INVALID_VALUE, @ref GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. * * @remark The contents of the returned string may change when a keyboard * layout change event is received.@@ -4213,15 +4263,18 @@ * * This function returns the platform-specific scancode of the specified key. *- * If the key is `GLFW_KEY_UNKNOWN` or does not exist on the keyboard this- * method will return `-1`.+ * If the specified [key token](@ref keys) corresponds to a physical key not+ * supported on the current platform then this method will return `-1`.+ * Calling this function with anything other than a key token will return `-1`+ * and generate a @ref GLFW_INVALID_ENUM error. *- * @param[in] key Any [named key](@ref keys).- * @return The platform-specific scancode for the key, or `-1` if an- * [error](@ref error_handling) occurred.+ * @param[in] key Any [key token](@ref keys).+ * @return The platform-specific scancode for the key, or `-1` if the key is+ * not supported on the current platform or an [error](@ref error_handling)+ * occurred. *- * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref- * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR.+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref+ * GLFW_INVALID_ENUM. * * @thread_safety This function may be called from any thread. *@@ -4238,8 +4291,7 @@ * * This function returns the last state reported for the specified key to the * specified window. The returned state is one of `GLFW_PRESS` or- * `GLFW_RELEASE`. The higher-level action `GLFW_REPEAT` is only reported to- * the key callback.+ * `GLFW_RELEASE`. The action `GLFW_REPEAT` is only reported to the key callback. * * If the @ref GLFW_STICKY_KEYS input mode is enabled, this function returns * `GLFW_PRESS` the first time you call it for a key that was pressed, even if@@ -4400,8 +4452,8 @@ * @return The handle of the created cursor, or `NULL` if an * [error](@ref error_handling) occurred. *- * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref- * GLFW_PLATFORM_ERROR.+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref+ * GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR. * * @pointer_lifetime The specified image data is copied before this function * returns.@@ -4506,9 +4558,9 @@ * [character callback](@ref glfwSetCharCallback) instead. * * When a window loses input focus, it will generate synthetic key release- * events for all pressed keys. You can tell these events from user-generated- * events by the fact that the synthetic ones are generated after the focus- * loss event has been processed, i.e. after the+ * events for all pressed keys with associated key tokens. You can tell these+ * events from user-generated events by the fact that the synthetic ones are+ * generated after the focus loss event has been processed, i.e. after the * [window focus callback](@ref glfwSetWindowFocusCallback) has been called. * * The scancode of a key is specific to that platform or sometimes even to that@@ -5191,6 +5243,8 @@ * joystick is not present, does not have a mapping or an * [error](@ref error_handling) occurred. *+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref GLFW_INVALID_ENUM.+ * * @pointer_lifetime The returned string is allocated and freed by GLFW. You * should not free it yourself. It is valid until the specified joystick is * disconnected, the gamepad mappings are updated or the library is terminated.@@ -5280,8 +5334,8 @@ * @return The contents of the clipboard as a UTF-8 encoded string, or `NULL` * if an [error](@ref error_handling) occurred. *- * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref- * GLFW_PLATFORM_ERROR.+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref+ * GLFW_FORMAT_UNAVAILABLE and @ref GLFW_PLATFORM_ERROR. * * @pointer_lifetime The returned string is allocated and freed by GLFW. You * should not free it yourself. It is valid until the next call to @ref@@ -5405,13 +5459,16 @@ * thread. * * This function makes the OpenGL or OpenGL ES context of the specified window- * current on the calling thread. A context must only be made current on- * a single thread at a time and each thread can have only a single current- * context at a time.+ * current on the calling thread. It can also detach the current context from+ * the calling thread without making a new one current by passing in `NULL`. *- * When moving a context between threads, you must make it non-current on the- * old thread before making it current on the new one.+ * A context must only be made current on a single thread at a time and each+ * thread can have only a single current context at a time. Making a context+ * current detaches any previously current context on the calling thread. *+ * When moving a context between threads, you must detach it (make it+ * non-current) on the old thread before making it current on the new one.+ * * By default, making a context non-current implicitly forces a pipeline flush. * On machines that support `GL_KHR_context_flush_control`, you can control * whether a context performs this flush by setting the@@ -5425,6 +5482,10 @@ * @param[in] window The window whose context to make current, or `NULL` to * detach the current context. *+ * @remarks If the previously current context was created via a different+ * context creation API than the one passed to this function, GLFW will still+ * detach the previous one from its API before making the new one current.+ * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref * GLFW_NO_WINDOW_CONTEXT and @ref GLFW_PLATFORM_ERROR. *@@ -5625,13 +5686,11 @@ * This function returns whether the Vulkan loader and any minimally functional * ICD have been found. *- * The availability of a Vulkan loader and even an ICD does not by itself- * guarantee that surface creation or even instance creation is possible.- * For example, on Fermi systems Nvidia will install an ICD that provides no- * actual Vulkan support. Call @ref glfwGetRequiredInstanceExtensions to check- * whether the extensions necessary for Vulkan surface creation are available- * and @ref glfwGetPhysicalDevicePresentationSupport to check whether a queue- * family of a physical device supports image presentation.+ * The availability of a Vulkan loader and even an ICD does not by itself guarantee that+ * surface creation or even instance creation is possible. Call @ref+ * glfwGetRequiredInstanceExtensions to check whether the extensions necessary for Vulkan+ * surface creation are available and @ref glfwGetPhysicalDevicePresentationSupport to+ * check whether a queue family of a physical device supports image presentation. * * @return `GLFW_TRUE` if Vulkan is minimally available, or `GLFW_FALSE` * otherwise.@@ -5677,10 +5736,6 @@ * returned array, as it is an error to specify an extension more than once in * the `VkInstanceCreateInfo` struct. *- * @remark @macos This function currently supports either the- * `VK_MVK_macos_surface` extension from MoltenVK or `VK_EXT_metal_surface`- * extension.- * * @pointer_lifetime The returned array is allocated and freed by GLFW. You * should not free it yourself. It is guaranteed to be valid only until the * library is terminated.@@ -5762,7 +5817,7 @@ * GLFW_API_UNAVAILABLE and @ref GLFW_PLATFORM_ERROR. * * @remark @macos This function currently always returns `GLFW_TRUE`, as the- * `VK_MVK_macos_surface` extension does not provide+ * `VK_MVK_macos_surface` and `VK_EXT_metal_surface` extensions do not provide * a `vkGetPhysicalDevice*PresentationSupport` type function. * * @thread_safety This function may be called from any thread. For@@ -5819,8 +5874,10 @@ * @ref glfwVulkanSupported and @ref glfwGetRequiredInstanceExtensions should * eliminate almost all occurrences of these errors. *- * @remark @macos This function currently only supports the- * `VK_MVK_macos_surface` extension from MoltenVK.+ * @remark @macos GLFW prefers the `VK_EXT_metal_surface` extension, with the+ * `VK_MVK_macos_surface` extension as a fallback. The name of the selected+ * extension, if any, is included in the array returned by @ref+ * glfwGetRequiredInstanceExtensions. * * @remark @macos This function creates and sets a `CAMetalLayer` instance for * the window content view, which is required for MoltenVK to function.@@ -5861,6 +5918,7 @@ */ #ifndef GLAPIENTRY #define GLAPIENTRY APIENTRY+ #define GLFW_GLAPIENTRY_DEFINED #endif /* -------------------- END SYSTEM/COMPILER SPECIFIC --------------------- */
glfw/src/cocoa_init.m view
@@ -251,7 +251,7 @@ _glfw.ns.keycodes[0x6D] = GLFW_KEY_F10; _glfw.ns.keycodes[0x67] = GLFW_KEY_F11; _glfw.ns.keycodes[0x6F] = GLFW_KEY_F12;- _glfw.ns.keycodes[0x69] = GLFW_KEY_F13;+ _glfw.ns.keycodes[0x69] = GLFW_KEY_PRINT_SCREEN; _glfw.ns.keycodes[0x6B] = GLFW_KEY_F14; _glfw.ns.keycodes[0x71] = GLFW_KEY_F15; _glfw.ns.keycodes[0x6A] = GLFW_KEY_F16;@@ -428,9 +428,6 @@ { if (_glfw.hints.init.ns.menubar) {- // In case we are unbundled, make us a proper UI application- [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];- // Menu bar setup must go between sharedApplication and finishLaunching // in order to properly emulate the behavior of NSApplicationMain @@ -449,6 +446,11 @@ { _glfw.ns.finishedLaunching = GLFW_TRUE; _glfwPlatformPostEmptyEvent();++ // In case we are unbundled, make us a proper UI application+ if (_glfw.hints.init.ns.menubar)+ [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];+ [NSApp stop:nil]; } @@ -473,18 +475,26 @@ if (!bundle) return NULL; - CFURLRef url =- CFBundleCopyAuxiliaryExecutableURL(bundle, CFSTR("libvulkan.1.dylib"));- if (!url)+ CFURLRef frameworksUrl = CFBundleCopyPrivateFrameworksURL(bundle);+ if (!frameworksUrl) return NULL; + CFURLRef loaderUrl = CFURLCreateCopyAppendingPathComponent(+ kCFAllocatorDefault, frameworksUrl, CFSTR("libvulkan.1.dylib"), false);+ if (!loaderUrl)+ {+ CFRelease(frameworksUrl);+ return NULL;+ }+ char path[PATH_MAX]; void* handle = NULL; - if (CFURLGetFileSystemRepresentation(url, true, (UInt8*) path, sizeof(path) - 1))+ if (CFURLGetFileSystemRepresentation(loaderUrl, true, (UInt8*) path, sizeof(path) - 1)) handle = _glfw_dlopen(path); - CFRelease(url);+ CFRelease(loaderUrl);+ CFRelease(frameworksUrl); return handle; } @@ -605,6 +615,8 @@ free(_glfw.ns.clipboardString); _glfwTerminateNSGL();+ _glfwTerminateEGL();+ _glfwTerminateOSMesa(); _glfwTerminateJoysticksNS(); } // autoreleasepool
glfw/src/cocoa_joystick.h view
@@ -33,6 +33,7 @@ #define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE struct { int dummyJoystick; } #define _GLFW_PLATFORM_MAPPING_NAME "Mac OS X"+#define GLFW_BUILD_COCOA_MAPPINGS // Cocoa-specific per-joystick data //
glfw/src/cocoa_joystick.m view
@@ -98,8 +98,7 @@ { int i; - if (!js->present)- return;+ _glfwInputJoystick(js, GLFW_DISCONNECTED); for (i = 0; i < CFArrayGetCount(js->ns.axes); i++) free((void*) CFArrayGetValueAtIndex(js->ns.axes, i));@@ -114,7 +113,6 @@ CFRelease(js->ns.hats); _glfwFreeJoystick(js);- _glfwInputJoystick(js, GLFW_DISCONNECTED); } // Callback for user-initiated joystick addition@@ -139,6 +137,14 @@ return; } + CFArrayRef elements =+ IOHIDDeviceCopyMatchingElements(device, NULL, kIOHIDOptionsTypeNone);++ // It is reportedly possible for this to fail on macOS 13 Ventura+ // if the application does not have input monitoring permissions+ if (!elements)+ return;+ axes = CFArrayCreateMutable(NULL, 0, NULL); buttons = CFArrayCreateMutable(NULL, 0, NULL); hats = CFArrayCreateMutable(NULL, 0, NULL);@@ -182,9 +188,6 @@ name[8], name[9], name[10]); } - CFArrayRef elements =- IOHIDDeviceCopyMatchingElements(device, NULL, kIOHIDOptionsTypeNone);- for (i = 0; i < CFArrayGetCount(elements); i++) { IOHIDElementRef native = (IOHIDElementRef)@@ -294,9 +297,9 @@ for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) {- if (_glfw.joysticks[jid].ns.device == device)+ if (_glfw.joysticks[jid].connected && _glfw.joysticks[jid].ns.device == device) {- closeJoystick(_glfw.joysticks + jid);+ closeJoystick(&_glfw.joysticks[jid]); break; } }@@ -392,7 +395,10 @@ int jid; for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)- closeJoystick(_glfw.joysticks + jid);+ {+ if (_glfw.joysticks[jid].connected)+ closeJoystick(&_glfw.joysticks[jid]);+ } CFRelease(_glfw.ns.hidManager); _glfw.ns.hidManager = NULL;@@ -470,7 +476,7 @@ } } - return js->present;+ return js->connected; } void _glfwPlatformUpdateGamepadGUID(char* guid)
glfw/src/cocoa_monitor.m view
@@ -39,18 +39,31 @@ // Get the name of the specified display, or NULL //-static char* getDisplayName(CGDirectDisplayID displayID)+static char* getMonitorName(CGDirectDisplayID displayID, NSScreen* screen) {+ // IOKit doesn't work on Apple Silicon anymore+ // Luckily, 10.15 introduced -[NSScreen localizedName].+ // Use it if available, and fall back to IOKit otherwise.+ if (screen)+ {+ if ([screen respondsToSelector:@selector(localizedName)])+ {+ NSString* name = [screen valueForKey:@"localizedName"];+ if (name)+ return _glfw_strdup([name UTF8String]);+ }+ }+ io_iterator_t it; io_service_t service; CFDictionaryRef info; - if (IOServiceGetMatchingServices(kIOMasterPortDefault,+ if (IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceMatching("IODisplayConnect"), &it) != 0) { // This may happen if a desktop Mac is running headless- return NULL;+ return _glfw_strdup("Display"); } while ((service = IOIteratorNext(it)) != 0)@@ -85,11 +98,7 @@ IOObjectRelease(it); if (!service)- {- _glfwInputError(GLFW_PLATFORM_ERROR,- "Cocoa: Failed to find service port for display");- return NULL;- }+ return _glfw_strdup("Display"); CFDictionaryRef names = CFDictionaryGetValue(info, CFSTR(kDisplayProductName));@@ -101,7 +110,7 @@ { // This may happen if a desktop Mac is running headless CFRelease(info);- return NULL;+ return _glfw_strdup("Display"); } const CFIndex size =@@ -209,31 +218,6 @@ } } -// Finds and caches the NSScreen corresponding to the specified monitor-//-static GLFWbool refreshMonitorScreen(_GLFWmonitor* monitor)-{- if (monitor->ns.screen)- return GLFW_TRUE;-- for (NSScreen* screen in [NSScreen screens])- {- NSNumber* displayID = [screen deviceDescription][@"NSScreenNumber"];-- // HACK: Compare unit numbers instead of display IDs to work around- // display replacement on machines with automatic graphics- // switching- if (monitor->ns.unitNumber == CGDisplayUnitNumber([displayID unsignedIntValue]))- {- monitor->ns.screen = screen;- return GLFW_TRUE;- }- }-- _glfwInputError(GLFW_PLATFORM_ERROR, "Cocoa: Failed to find a screen for monitor");- return GLFW_FALSE;-}- // Returns the display refresh rate queried from the I/O registry // static double getFallbackRefreshRate(CGDirectDisplayID displayID)@@ -243,7 +227,7 @@ io_iterator_t it; io_service_t service; - if (IOServiceGetMatchingServices(kIOMasterPortDefault,+ if (IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceMatching("IOFramebuffer"), &it) != 0) {@@ -277,15 +261,21 @@ CFSTR("IOFBCurrentPixelCount"), kCFAllocatorDefault, kNilOptions);- if (!clockRef || !countRef)- break; uint32_t clock = 0, count = 0;- CFNumberGetValue(clockRef, kCFNumberIntType, &clock);- CFNumberGetValue(countRef, kCFNumberIntType, &count);- CFRelease(clockRef);- CFRelease(countRef); + if (clockRef)+ {+ CFNumberGetValue(clockRef, kCFNumberIntType, &clock);+ CFRelease(clockRef);+ }++ if (countRef)+ {+ CFNumberGetValue(countRef, kCFNumberIntType, &count);+ CFRelease(countRef);+ }+ if (clock > 0 && count > 0) refreshRate = clock / (double) count; @@ -328,27 +318,46 @@ if (CGDisplayIsAsleep(displays[i])) continue; + const uint32_t unitNumber = CGDisplayUnitNumber(displays[i]);+ NSScreen* screen = nil;++ for (screen in [NSScreen screens])+ {+ NSNumber* screenNumber = [screen deviceDescription][@"NSScreenNumber"];++ // HACK: Compare unit numbers instead of display IDs to work around+ // display replacement on machines with automatic graphics+ // switching+ if (CGDisplayUnitNumber([screenNumber unsignedIntValue]) == unitNumber)+ break;+ }+ // HACK: Compare unit numbers instead of display IDs to work around // display replacement on machines with automatic graphics // switching- const uint32_t unitNumber = CGDisplayUnitNumber(displays[i]);- for (uint32_t j = 0; j < disconnectedCount; j++)+ uint32_t j;+ for (j = 0; j < disconnectedCount; j++) { if (disconnected[j] && disconnected[j]->ns.unitNumber == unitNumber) {+ disconnected[j]->ns.screen = screen; disconnected[j] = NULL; break; } } + if (j < disconnectedCount)+ continue;+ const CGSize size = CGDisplayScreenSize(displays[i]);- char* name = getDisplayName(displays[i]);+ char* name = getMonitorName(displays[i], screen); if (!name)- name = _glfw_strdup("Unknown");+ continue; _GLFWmonitor* monitor = _glfwAllocMonitor(name, size.width, size.height); monitor->ns.displayID = displays[i]; monitor->ns.unitNumber = unitNumber;+ monitor->ns.screen = screen; free(name); @@ -457,8 +466,11 @@ { @autoreleasepool { - if (!refreshMonitorScreen(monitor))- return;+ if (!monitor->ns.screen)+ {+ _glfwInputError(GLFW_PLATFORM_ERROR,+ "Cocoa: Cannot query content scale without screen");+ } const NSRect points = [monitor->ns.screen frame]; const NSRect pixels = [monitor->ns.screen convertRectToBacking:points];@@ -477,8 +489,11 @@ { @autoreleasepool { - if (!refreshMonitorScreen(monitor))- return;+ if (!monitor->ns.screen)+ {+ _glfwInputError(GLFW_PLATFORM_ERROR,+ "Cocoa: Cannot query workarea without screen");+ } const NSRect frameRect = [monitor->ns.screen visibleFrame]; @@ -521,7 +536,7 @@ } // Skip duplicate modes- if (i < *count)+ if (j < *count) continue; (*count)++;
glfw/src/cocoa_platform.h view
@@ -31,7 +31,9 @@ // NOTE: All of NSGL was deprecated in the 10.14 SDK // This disables the pointless warnings for every symbol we use+#ifndef GL_SILENCE_DEPRECATION #define GL_SILENCE_DEPRECATION+#endif #if defined(__OBJC__) #import <Cocoa/Cocoa.h>@@ -40,8 +42,10 @@ #endif // NOTE: Many Cocoa enum values have been renamed and we need to build across-// SDK versions where one is unavailable or the other deprecated-// We use the newer names in code and these macros to handle compatibility+// SDK versions where one is unavailable or deprecated.+// We use the newer names in code and replace them with the older names if+// the base SDK does not provide the newer names.+ #if MAC_OS_X_VERSION_MAX_ALLOWED < 101200 #define NSBitmapFormatAlphaNonpremultiplied NSAlphaNonpremultipliedBitmapFormat #define NSEventMaskAny NSAnyEventMask@@ -60,6 +64,15 @@ #define NSWindowStyleMaskTitled NSTitledWindowMask #endif +// NOTE: Many Cocoa dynamically linked constants have been renamed and we need+// to build across SDK versions where one is unavailable or deprecated.+// We use the newer names in code and replace them with the older names if+// the deployment target is older than the newer names.++#if MAC_OS_X_VERSION_MIN_REQUIRED < 101300+ #define NSPasteboardTypeURL NSURLPboardType+#endif+ typedef VkFlags VkMacOSSurfaceCreateFlagsMVK; typedef VkFlags VkMetalSurfaceCreateFlagsEXT; @@ -92,7 +105,7 @@ #define _glfw_dlclose(handle) dlclose(handle) #define _glfw_dlsym(handle, name) dlsym(handle, name) -#define _GLFW_EGL_NATIVE_WINDOW ((EGLNativeWindowType) window->ns.view)+#define _GLFW_EGL_NATIVE_WINDOW ((EGLNativeWindowType) window->ns.layer) #define _GLFW_EGL_NATIVE_DISPLAY EGL_DEFAULT_DISPLAY #define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowNS ns@@ -121,6 +134,7 @@ id layer; GLFWbool maximized;+ GLFWbool occluded; GLFWbool retina; // Cached window properties to filter out duplicate events@@ -132,7 +146,6 @@ // since the last cursor motion event was processed // This is kept to counteract Cocoa doing the same internally double cursorWarpDeltaX, cursorWarpDeltaY;- } _GLFWwindowNS; // Cocoa-specific global data@@ -167,7 +180,6 @@ PFN_LMGetKbdType GetKbdType; CFStringRef kPropertyUnicodeKeyLayoutData; } tis;- } _GLFWlibraryNS; // Cocoa-specific per-monitor data@@ -179,7 +191,6 @@ uint32_t unitNumber; id screen; double fallbackRefreshRate;- } _GLFWmonitorNS; // Cocoa-specific per-cursor data@@ -187,7 +198,6 @@ typedef struct _GLFWcursorNS { id object;- } _GLFWcursorNS; // Cocoa-specific global timer data@@ -195,7 +205,6 @@ typedef struct _GLFWtimerNS { uint64_t frequency;- } _GLFWtimerNS;
glfw/src/cocoa_window.m view
@@ -31,25 +31,9 @@ #include <float.h> #include <string.h> -// Returns the style mask corresponding to the window settings-//-static NSUInteger getStyleMask(_GLFWwindow* window)-{- NSUInteger styleMask = NSWindowStyleMaskMiniaturizable;-- if (window->monitor || !window->decorated)- styleMask |= NSWindowStyleMaskBorderless;- else- {- styleMask |= NSWindowStyleMaskTitled |- NSWindowStyleMaskClosable;-- if (window->resizable)- styleMask |= NSWindowStyleMaskResizable;- }-- return styleMask;-}+// HACK: This enum value is missing from framework headers on OS X 10.11 despite+// having been (according to documentation) added in Mac OS X 10.7+#define NSWindowCollectionBehaviorFullScreenNone (1 << 9) // Returns whether the cursor is in the content area of the specified window //@@ -114,10 +98,11 @@ else if (_glfw.ns.disabledCursorWindow == window) { _glfw.ns.disabledCursorWindow = NULL;- CGAssociateMouseAndMouseCursorPosition(true); _glfwPlatformSetCursorPos(window, _glfw.ns.restoreCursorPosX, _glfw.ns.restoreCursorPosY);+ // NOTE: The matching CGAssociateMouseAndMouseCursorPosition call is+ // made in _glfwPlatformSetCursorPos as part of a workaround } if (cursorInContentArea(window))@@ -243,7 +228,7 @@ - (void)windowDidResize:(NSNotification *)notification {- if (window->context.client != GLFW_NO_API)+ if (window->context.source == GLFW_NATIVE_CONTEXT_API) [window->context.nsgl.object update]; if (_glfw.ns.disabledCursorWindow == window)@@ -278,7 +263,7 @@ - (void)windowDidMove:(NSNotification *)notification {- if (window->context.client != GLFW_NO_API)+ if (window->context.source == GLFW_NATIVE_CONTEXT_API) [window->context.nsgl.object update]; if (_glfw.ns.disabledCursorWindow == window)@@ -322,6 +307,19 @@ _glfwInputWindowFocus(window, GLFW_FALSE); } +- (void)windowDidChangeOcclusionState:(NSNotification* )notification+{+#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1090+ if ([window->ns.object respondsToSelector:@selector(occlusionState)])+ {+ if ([window->ns.object occlusionState] & NSWindowOcclusionStateVisible)+ window->ns.occluded = GLFW_FALSE;+ else+ window->ns.occluded = GLFW_TRUE;+ }+#endif+}+ @end @@ -352,9 +350,7 @@ markedText = [[NSMutableAttributedString alloc] init]; [self updateTrackingAreas];- // NOTE: kUTTypeURL corresponds to NSPasteboardTypeURL but is available- // on 10.7 without having been deprecated yet- [self registerForDraggedTypes:@[(__bridge NSString*) kUTTypeURL]];+ [self registerForDraggedTypes:@[NSPasteboardTypeURL]]; } return self;@@ -389,7 +385,7 @@ - (void)updateLayer {- if (window->context.client != GLFW_NO_API)+ if (window->context.source == GLFW_NATIVE_CONTEXT_API) [window->context.nsgl.object update]; _glfwInputWindowDamage(window);@@ -512,26 +508,25 @@ { const NSRect contentRect = [window->ns.view frame]; const NSRect fbRect = [window->ns.view convertRectToBacking:contentRect];-- if (fbRect.size.width != window->ns.fbWidth ||- fbRect.size.height != window->ns.fbHeight)- {- window->ns.fbWidth = fbRect.size.width;- window->ns.fbHeight = fbRect.size.height;- _glfwInputFramebufferSize(window, fbRect.size.width, fbRect.size.height);- }- const float xscale = fbRect.size.width / contentRect.size.width; const float yscale = fbRect.size.height / contentRect.size.height; if (xscale != window->ns.xscale || yscale != window->ns.yscale) {+ if (window->ns.retina && window->ns.layer)+ [window->ns.layer setContentsScale:[window->ns.object backingScaleFactor]];+ window->ns.xscale = xscale; window->ns.yscale = yscale; _glfwInputWindowContentScale(window, xscale, yscale);+ } - if (window->ns.retina && window->ns.layer)- [window->ns.layer setContentsScale:[window->ns.object backingScaleFactor]];+ if (fbRect.size.width != window->ns.fbWidth ||+ fbRect.size.height != window->ns.fbHeight)+ {+ window->ns.fbWidth = fbRect.size.width;+ window->ns.fbHeight = fbRect.size.height;+ _glfwInputFramebufferSize(window, fbRect.size.width, fbRect.size.height); } } @@ -723,14 +718,24 @@ else characters = (NSString*) string; - const NSUInteger length = [characters length];- for (NSUInteger i = 0; i < length; i++)+ NSRange range = NSMakeRange(0, [characters length]);+ while (range.length) {- const unichar codepoint = [characters characterAtIndex:i];- if ((codepoint & 0xff00) == 0xf700)- continue;+ uint32_t codepoint = 0; - _glfwInputChar(window, codepoint, mods, plain);+ if ([characters getBytes:&codepoint+ maxLength:sizeof(codepoint)+ usedLength:NULL+ encoding:NSUTF32StringEncoding+ options:0+ range:range+ remainingRange:&range])+ {+ if (codepoint >= 0xf700 && codepoint <= 0xf7ff)+ continue;++ _glfwInputChar(window, codepoint, mods, plain);+ } } } @@ -793,9 +798,21 @@ else contentRect = NSMakeRect(0, 0, wndconfig->width, wndconfig->height); + NSUInteger styleMask = NSWindowStyleMaskMiniaturizable;++ if (window->monitor || !window->decorated)+ styleMask |= NSWindowStyleMaskBorderless;+ else+ {+ styleMask |= (NSWindowStyleMaskTitled | NSWindowStyleMaskClosable);++ if (window->resizable)+ styleMask |= NSWindowStyleMaskResizable;+ }+ window->ns.object = [[GLFWWindow alloc] initWithContentRect:contentRect- styleMask:getStyleMask(window)+ styleMask:styleMask backing:NSBackingStoreBuffered defer:NO]; @@ -821,6 +838,12 @@ NSWindowCollectionBehaviorManaged; [window->ns.object setCollectionBehavior:behavior]; }+ else+ {+ const NSWindowCollectionBehavior behavior =+ NSWindowCollectionBehaviorFullScreenNone;+ [window->ns.object setCollectionBehavior:behavior];+ } if (wndconfig->floating) [window->ns.object setLevel:NSFloatingWindowLevel];@@ -901,6 +924,11 @@ } else if (ctxconfig->source == GLFW_EGL_CONTEXT_API) {+ // EGL implementation on macOS use CALayer* EGLNativeWindowType so we+ // need to get the layer for EGL window surface creation.+ [window->ns.view setWantsLayer:YES];+ window->ns.layer = [window->ns.view layer];+ if (!_glfwInitEGL()) return GLFW_FALSE; if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig))@@ -913,6 +941,9 @@ if (!_glfwCreateContextOSMesa(window, ctxconfig, fbconfig)) return GLFW_FALSE; }++ if (!_glfwRefreshContextAttribs(window, ctxconfig))+ return GLFW_FALSE; } if (window->monitor)@@ -920,7 +951,19 @@ _glfwPlatformShowWindow(window); _glfwPlatformFocusWindow(window); acquireMonitor(window);++ if (wndconfig->centerCursor)+ _glfwCenterCursorInContentArea(window); }+ else+ {+ if (wndconfig->visible)+ {+ _glfwPlatformShowWindow(window);+ if (wndconfig->focused)+ _glfwPlatformFocusWindow(window);+ }+ } return GLFW_TRUE; @@ -1198,9 +1241,10 @@ { const NSRect contentRect = NSMakeRect(xpos, _glfwTransformYNS(ypos + height - 1), width, height);+ const NSUInteger styleMask = [window->ns.object styleMask]; const NSRect frameRect = [window->ns.object frameRectForContentRect:contentRect- styleMask:getStyleMask(window)];+ styleMask:styleMask]; [window->ns.object setFrame:frameRect display:YES]; }@@ -1217,7 +1261,27 @@ // TODO: Solve this in a less terrible way _glfwPlatformPollEvents(); - const NSUInteger styleMask = getStyleMask(window);+ NSUInteger styleMask = [window->ns.object styleMask];++ if (window->monitor)+ {+ styleMask &= ~(NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskResizable);+ styleMask |= NSWindowStyleMaskBorderless;+ }+ else+ {+ if (window->decorated)+ {+ styleMask &= ~NSWindowStyleMaskBorderless;+ styleMask |= (NSWindowStyleMaskTitled | NSWindowStyleMaskClosable);+ }++ if (window->resizable)+ styleMask |= NSWindowStyleMaskResizable;+ else+ styleMask &= ~NSWindowStyleMaskResizable;+ }+ [window->ns.object setStyleMask:styleMask]; // HACK: Changing the style mask can cause the first responder to be cleared [window->ns.object makeFirstResponder:window->ns.view];@@ -1263,6 +1327,20 @@ else [window->ns.object setLevel:NSNormalWindowLevel]; + if (window->resizable)+ {+ const NSWindowCollectionBehavior behavior =+ NSWindowCollectionBehaviorFullScreenPrimary |+ NSWindowCollectionBehaviorManaged;+ [window->ns.object setCollectionBehavior:behavior];+ }+ else+ {+ const NSWindowCollectionBehavior behavior =+ NSWindowCollectionBehaviorFullScreenNone;+ [window->ns.object setCollectionBehavior:behavior];+ }+ [window->ns.object setHasShadow:YES]; // HACK: Clearing NSWindowStyleMaskTitled resets and disables the window // title property but the miniwindow title property is unaffected@@ -1296,7 +1374,12 @@ int _glfwPlatformWindowMaximized(_GLFWwindow* window) { @autoreleasepool {- return [window->ns.object isZoomed];++ if (window->resizable)+ return [window->ns.object isZoomed];+ else+ return GLFW_FALSE;+ } // autoreleasepool } @@ -1328,15 +1411,46 @@ void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled) { @autoreleasepool {- [window->ns.object setStyleMask:getStyleMask(window)];++ const NSUInteger styleMask = [window->ns.object styleMask];+ if (enabled)+ {+ [window->ns.object setStyleMask:(styleMask | NSWindowStyleMaskResizable)];+ const NSWindowCollectionBehavior behavior =+ NSWindowCollectionBehaviorFullScreenPrimary |+ NSWindowCollectionBehaviorManaged;+ [window->ns.object setCollectionBehavior:behavior];+ }+ else+ {+ [window->ns.object setStyleMask:(styleMask & ~NSWindowStyleMaskResizable)];+ const NSWindowCollectionBehavior behavior =+ NSWindowCollectionBehaviorFullScreenNone;+ [window->ns.object setCollectionBehavior:behavior];+ }+ } // autoreleasepool } void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled) { @autoreleasepool {- [window->ns.object setStyleMask:getStyleMask(window)];++ NSUInteger styleMask = [window->ns.object styleMask];+ if (enabled)+ {+ styleMask |= (NSWindowStyleMaskTitled | NSWindowStyleMaskClosable);+ styleMask &= ~NSWindowStyleMaskBorderless;+ }+ else+ {+ styleMask |= NSWindowStyleMaskBorderless;+ styleMask &= ~(NSWindowStyleMaskTitled | NSWindowStyleMaskClosable);+ }++ [window->ns.object setStyleMask:styleMask]; [window->ns.object makeFirstResponder:window->ns.view];+ } // autoreleasepool } @@ -1501,6 +1615,11 @@ _glfwTransformYNS(globalPoint.y))); } + // HACK: Calling this right after setting the cursor position prevents macOS+ // from freezing the cursor for a fraction of a second afterwards+ if (window->cursorMode != GLFW_CURSOR_DISABLED)+ CGAssociateMouseAndMouseCursorPosition(true);+ } // autoreleasepool } @@ -1519,7 +1638,7 @@ if (scancode < 0 || scancode > 0xff || _glfw.ns.keycodes[scancode] == GLFW_KEY_UNKNOWN) {- _glfwInputError(GLFW_INVALID_VALUE, "Invalid scancode");+ _glfwInputError(GLFW_INVALID_VALUE, "Invalid scancode %i", scancode); return NULL; }
glfw/src/context.c view
@@ -48,16 +48,6 @@ // GLFWbool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig) {- if (ctxconfig->share)- {- if (ctxconfig->client == GLFW_NO_API ||- ctxconfig->share->context.client == GLFW_NO_API)- {- _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);- return GLFW_FALSE;- }- }- if (ctxconfig->source != GLFW_NATIVE_CONTEXT_API && ctxconfig->source != GLFW_EGL_CONTEXT_API && ctxconfig->source != GLFW_OSMESA_CONTEXT_API)@@ -78,6 +68,23 @@ return GLFW_FALSE; } + if (ctxconfig->share)+ {+ if (ctxconfig->client == GLFW_NO_API ||+ ctxconfig->share->context.client == GLFW_NO_API)+ {+ _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);+ return GLFW_FALSE;+ }++ if (ctxconfig->source != ctxconfig->share->context.source)+ {+ _glfwInputError(GLFW_INVALID_ENUM,+ "Context creation APIs do not match between contexts");+ return GLFW_FALSE;+ }+ }+ if (ctxconfig->client == GLFW_OPENGL_API) { if ((ctxconfig->major < 1 || ctxconfig->minor < 0) ||@@ -196,12 +203,6 @@ continue; } - if (desired->doublebuffer != current->doublebuffer)- {- // Double buffering is a hard constraint- continue;- }- // Count number of missing buffers { missing = 0;@@ -362,6 +363,8 @@ previous = _glfwPlatformGetTls(&_glfw.contextSlot); glfwMakeContextCurrent((GLFWwindow*) window);+ if (_glfwPlatformGetTls(&_glfw.contextSlot) != window)+ return GLFW_FALSE; window->context.GetIntegerv = (PFNGLGETINTEGERVPROC) window->context.getProcAddress("glGetIntegerv");@@ -570,7 +573,9 @@ PFNGLCLEARPROC glClear = (PFNGLCLEARPROC) window->context.getProcAddress("glClear"); glClear(GL_COLOR_BUFFER_BIT);- window->context.swapBuffers(window);++ if (window->doublebuffer)+ window->context.swapBuffers(window); } glfwMakeContextCurrent((GLFWwindow*) previous);@@ -613,9 +618,11 @@ GLFWAPI void glfwMakeContextCurrent(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle;- _GLFWwindow* previous = _glfwPlatformGetTls(&_glfw.contextSlot);+ _GLFWwindow* previous; _GLFW_REQUIRE_INIT();++ previous = _glfwPlatformGetTls(&_glfw.contextSlot); if (window && window->context.client == GLFW_NO_API) {
glfw/src/egl_context.c view
@@ -88,14 +88,31 @@ // Return the EGLConfig most closely matching the specified hints // static GLFWbool chooseEGLConfig(const _GLFWctxconfig* ctxconfig,- const _GLFWfbconfig* desired,+ const _GLFWfbconfig* fbconfig, EGLConfig* result) { EGLConfig* nativeConfigs; _GLFWfbconfig* usableConfigs; const _GLFWfbconfig* closest;- int i, nativeCount, usableCount;+ int i, nativeCount, usableCount, apiBit;+ GLFWbool wrongApiAvailable = GLFW_FALSE; + if (ctxconfig->client == GLFW_OPENGL_ES_API)+ {+ if (ctxconfig->major == 1)+ apiBit = EGL_OPENGL_ES_BIT;+ else+ apiBit = EGL_OPENGL_ES2_BIT;+ }+ else+ apiBit = EGL_OPENGL_BIT;++ if (fbconfig->stereo)+ {+ _glfwInputError(GLFW_FORMAT_UNAVAILABLE, "EGL: Stereo rendering not supported");+ return GLFW_FALSE;+ }+ eglGetConfigs(_glfw.egl.display, NULL, 0, &nativeCount); if (!nativeCount) {@@ -131,7 +148,7 @@ if (!vi.visualid) continue; - if (desired->transparent)+ if (fbconfig->transparent) { int count; XVisualInfo* vis =@@ -145,23 +162,10 @@ } #endif // _GLFW_X11 - if (ctxconfig->client == GLFW_OPENGL_ES_API)- {- if (ctxconfig->major == 1)- {- if (!(getEGLConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES_BIT))- continue;- }- else- {- if (!(getEGLConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES2_BIT))- continue;- }- }- else if (ctxconfig->client == GLFW_OPENGL_API)+ if (!(getEGLConfigAttrib(n, EGL_RENDERABLE_TYPE) & apiBit)) {- if (!(getEGLConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_BIT))- continue;+ wrongApiAvailable = GLFW_TRUE;+ continue; } u->redBits = getEGLConfigAttrib(n, EGL_RED_SIZE);@@ -172,16 +176,57 @@ u->depthBits = getEGLConfigAttrib(n, EGL_DEPTH_SIZE); u->stencilBits = getEGLConfigAttrib(n, EGL_STENCIL_SIZE); +#if defined(_GLFW_WAYLAND)+ // NOTE: The wl_surface opaque region is no guarantee that its buffer+ // is presented as opaque, if it also has an alpha channel+ // HACK: If EGL_EXT_present_opaque is unavailable, ignore any config+ // with an alpha channel to ensure the buffer is opaque+ if (!_glfw.egl.EXT_present_opaque)+ {+ if (!fbconfig->transparent && u->alphaBits > 0)+ continue;+ }+#endif // _GLFW_WAYLAND+ u->samples = getEGLConfigAttrib(n, EGL_SAMPLES);- u->doublebuffer = GLFW_TRUE;+ u->doublebuffer = fbconfig->doublebuffer; u->handle = (uintptr_t) n; usableCount++; } - closest = _glfwChooseFBConfig(desired, usableConfigs, usableCount);+ closest = _glfwChooseFBConfig(fbconfig, usableConfigs, usableCount); if (closest) *result = (EGLConfig) closest->handle;+ else+ {+ if (wrongApiAvailable)+ {+ if (ctxconfig->client == GLFW_OPENGL_ES_API)+ {+ if (ctxconfig->major == 1)+ {+ _glfwInputError(GLFW_API_UNAVAILABLE,+ "EGL: Failed to find support for OpenGL ES 1.x");+ }+ else+ {+ _glfwInputError(GLFW_API_UNAVAILABLE,+ "EGL: Failed to find support for OpenGL ES 2 or later");+ }+ }+ else+ {+ _glfwInputError(GLFW_API_UNAVAILABLE,+ "EGL: Failed to find support for OpenGL");+ }+ }+ else+ {+ _glfwInputError(GLFW_FORMAT_UNAVAILABLE,+ "EGL: Failed to find a suitable EGLConfig");+ }+ } free(nativeConfigs); free(usableConfigs);@@ -230,6 +275,12 @@ return; } +#if defined(_GLFW_WAYLAND)+ // NOTE: Swapping buffers on a hidden window on Wayland makes it visible+ if (!window->wl.visible)+ return;+#endif+ eglSwapBuffers(_glfw.egl.display, window->context.egl.surface); } @@ -253,6 +304,7 @@ static GLFWglproc getProcAddressEGL(const char* procname) { _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot);+ assert(window != NULL); if (window->context.egl.client) {@@ -314,6 +366,8 @@ "libEGL.dylib", #elif defined(__CYGWIN__) "libEGL-1.so",+#elif defined(__OpenBSD__) || defined(__NetBSD__)+ "libEGL.so", #else "libEGL.so.1", #endif@@ -426,6 +480,8 @@ extensionSupportedEGL("EGL_KHR_get_all_proc_addresses"); _glfw.egl.KHR_context_flush_control = extensionSupportedEGL("EGL_KHR_context_flush_control");+ _glfw.egl.EXT_present_opaque =+ extensionSupportedEGL("EGL_EXT_present_opaque"); return GLFW_TRUE; }@@ -475,11 +531,7 @@ share = ctxconfig->share->context.egl.handle; if (!chooseEGLConfig(ctxconfig, fbconfig, &config))- {- _glfwInputError(GLFW_FORMAT_UNAVAILABLE,- "EGL: Failed to find a suitable EGLConfig"); return GLFW_FALSE;- } if (ctxconfig->client == GLFW_OPENGL_ES_API) {@@ -536,18 +588,18 @@ flags |= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR; } - if (ctxconfig->noerror)- {- if (_glfw.egl.KHR_create_context_no_error)- setAttrib(EGL_CONTEXT_OPENGL_NO_ERROR_KHR, GLFW_TRUE);- }- if (ctxconfig->major != 1 || ctxconfig->minor != 0) { setAttrib(EGL_CONTEXT_MAJOR_VERSION_KHR, ctxconfig->major); setAttrib(EGL_CONTEXT_MINOR_VERSION_KHR, ctxconfig->minor); } + if (ctxconfig->noerror)+ {+ if (_glfw.egl.KHR_create_context_no_error)+ setAttrib(EGL_CONTEXT_OPENGL_NO_ERROR_KHR, GLFW_TRUE);+ }+ if (mask) setAttrib(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, mask); @@ -588,18 +640,24 @@ } // Set up attributes for surface creation+ index = 0;++ if (fbconfig->sRGB) {- int index = 0;+ if (_glfw.egl.KHR_gl_colorspace)+ setAttrib(EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR);+ } - if (fbconfig->sRGB)- {- if (_glfw.egl.KHR_gl_colorspace)- setAttrib(EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR);- }+ if (!fbconfig->doublebuffer)+ setAttrib(EGL_RENDER_BUFFER, EGL_SINGLE_BUFFER); - setAttrib(EGL_NONE, EGL_NONE);- }+#if defined(_GLFW_WAYLAND)+ if (_glfw.egl.EXT_present_opaque)+ setAttrib(EGL_PRESENT_OPAQUE_EXT, !fbconfig->transparent);+#endif // _GLFW_WAYLAND + setAttrib(EGL_NONE, EGL_NONE);+ window->context.egl.surface = eglCreateWindowSurface(_glfw.egl.display, config,@@ -629,6 +687,8 @@ "libGLES_CM.dll", #elif defined(_GLFW_COCOA) "libGLESv1_CM.dylib",+#elif defined(__OpenBSD__) || defined(__NetBSD__)+ "libGLESv1_CM.so", #else "libGLESv1_CM.so.1", "libGLES_CM.so.1",@@ -646,6 +706,8 @@ "libGLESv2.dylib", #elif defined(__CYGWIN__) "libGLESv2-2.so",+#elif defined(__OpenBSD__) || defined(__NetBSD__)+ "libGLESv2.so", #else "libGLESv2.so.2", #endif@@ -657,7 +719,10 @@ _GLFW_OPENGL_LIBRARY, #elif defined(_GLFW_WIN32) #elif defined(_GLFW_COCOA)+#elif defined(__OpenBSD__) || defined(__NetBSD__)+ "libGL.so", #else+ "libOpenGL.so.0", "libGL.so.1", #endif NULL@@ -720,11 +785,7 @@ const long vimask = VisualScreenMask | VisualIDMask; if (!chooseEGLConfig(ctxconfig, fbconfig, &native))- {- _glfwInputError(GLFW_FORMAT_UNAVAILABLE,- "EGL: Failed to find a suitable EGLConfig"); return GLFW_FALSE;- } eglGetConfigAttrib(_glfw.egl.display, native, EGL_NATIVE_VISUAL_ID, &visualID);@@ -764,7 +825,7 @@ _GLFWwindow* window = (_GLFWwindow*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_CONTEXT); - if (window->context.client == GLFW_NO_API)+ if (window->context.source != GLFW_EGL_CONTEXT_API) { _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); return EGL_NO_CONTEXT;@@ -778,7 +839,7 @@ _GLFWwindow* window = (_GLFWwindow*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_SURFACE); - if (window->context.client == GLFW_NO_API)+ if (window->context.source != GLFW_EGL_CONTEXT_API) { _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); return EGL_NO_SURFACE;
glfw/src/egl_context.h view
@@ -80,6 +80,8 @@ #define EGL_OPENGL_ES_API 0x30a0 #define EGL_OPENGL_API 0x30a2 #define EGL_NONE 0x3038+#define EGL_RENDER_BUFFER 0x3086+#define EGL_SINGLE_BUFFER 0x3085 #define EGL_EXTENSIONS 0x3055 #define EGL_CONTEXT_CLIENT_VERSION 0x3098 #define EGL_NATIVE_VISUAL_ID 0x302e@@ -106,6 +108,7 @@ #define EGL_CONTEXT_RELEASE_BEHAVIOR_KHR 0x2097 #define EGL_CONTEXT_RELEASE_BEHAVIOR_NONE_KHR 0 #define EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR 0x2098+#define EGL_PRESENT_OPAQUE_EXT 0x31df typedef int EGLint; typedef unsigned int EGLBoolean;@@ -162,7 +165,6 @@ EGLSurface surface; void* client;- } _GLFWcontextEGL; // EGL-specific global data@@ -178,6 +180,7 @@ GLFWbool KHR_gl_colorspace; GLFWbool KHR_get_all_proc_addresses; GLFWbool KHR_context_flush_control;+ GLFWbool EXT_present_opaque; void* handle; @@ -197,7 +200,6 @@ PFN_eglSwapInterval SwapInterval; PFN_eglQueryString QueryString; PFN_eglGetProcAddress GetProcAddress;- } _GLFWlibraryEGL;
glfw/src/glx_context.c view
@@ -92,6 +92,9 @@ continue; } + if (getGLXFBConfigAttrib(n, GLX_DOUBLEBUFFER) != desired->doublebuffer)+ continue;+ if (desired->transparent) { XVisualInfo* vi = glXGetVisualFromFBConfig(_glfw.x11.display, n);@@ -119,8 +122,6 @@ if (getGLXFBConfigAttrib(n, GLX_STEREO)) u->stereo = GLFW_TRUE;- if (getGLXFBConfigAttrib(n, GLX_DOUBLEBUFFER))- u->doublebuffer = GLFW_TRUE; if (_glfw.glx.ARB_multisample) u->samples = getGLXFBConfigAttrib(n, GLX_SAMPLES);@@ -189,6 +190,7 @@ static void swapIntervalGLX(int interval) { _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot);+ assert(window != NULL); if (_glfw.glx.EXT_swap_control) {@@ -225,7 +227,10 @@ else if (_glfw.glx.GetProcAddressARB) return _glfw.glx.GetProcAddressARB((const GLubyte*) procname); else+ {+ // NOTE: glvnd provides GLX 1.4, so this can only happen with libGL return _glfw_dlsym(_glfw.glx.handle, procname);+ } } static void destroyContextGLX(_GLFWwindow* window)@@ -259,7 +264,10 @@ _GLFW_GLX_LIBRARY, #elif defined(__CYGWIN__) "libGL-1.so",+#elif defined(__OpenBSD__) || defined(__NetBSD__)+ "libGL.so", #else+ "libGLX.so.0", "libGL.so.1", "libGL.so", #endif@@ -306,10 +314,6 @@ _glfw_dlsym(_glfw.glx.handle, "glXCreateWindow"); _glfw.glx.DestroyWindow = _glfw_dlsym(_glfw.glx.handle, "glXDestroyWindow");- _glfw.glx.GetProcAddress =- _glfw_dlsym(_glfw.glx.handle, "glXGetProcAddress");- _glfw.glx.GetProcAddressARB =- _glfw_dlsym(_glfw.glx.handle, "glXGetProcAddressARB"); _glfw.glx.GetVisualFromFBConfig = _glfw_dlsym(_glfw.glx.handle, "glXGetVisualFromFBConfig"); @@ -325,8 +329,6 @@ !_glfw.glx.CreateNewContext || !_glfw.glx.CreateWindow || !_glfw.glx.DestroyWindow ||- !_glfw.glx.GetProcAddress ||- !_glfw.glx.GetProcAddressARB || !_glfw.glx.GetVisualFromFBConfig) { _glfwInputError(GLFW_PLATFORM_ERROR,@@ -334,6 +336,12 @@ return GLFW_FALSE; } + // NOTE: Unlike GLX 1.3 entry points these are not required to be present+ _glfw.glx.GetProcAddress = (PFNGLXGETPROCADDRESSPROC)+ _glfw_dlsym(_glfw.glx.handle, "glXGetProcAddress");+ _glfw.glx.GetProcAddressARB = (PFNGLXGETPROCADDRESSPROC)+ _glfw_dlsym(_glfw.glx.handle, "glXGetProcAddressARB");+ if (!glXQueryExtension(_glfw.x11.display, &_glfw.glx.errorBase, &_glfw.glx.eventBase))@@ -673,7 +681,7 @@ _GLFWwindow* window = (_GLFWwindow*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - if (window->context.client == GLFW_NO_API)+ if (window->context.source != GLFW_NATIVE_CONTEXT_API) { _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); return NULL;@@ -687,7 +695,7 @@ _GLFWwindow* window = (_GLFWwindow*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(None); - if (window->context.client == GLFW_NO_API)+ if (window->context.source != GLFW_NATIVE_CONTEXT_API) { _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); return None;
glfw/src/glx_context.h view
@@ -117,7 +117,6 @@ { GLXContext handle; GLXWindow window;- } _GLFWcontextGLX; // GLX-specific global data@@ -128,7 +127,6 @@ int eventBase; int errorBase; - // dlopen handle for libGL.so.1 void* handle; // GLX 1.3 functions@@ -165,7 +163,6 @@ GLFWbool EXT_create_context_es2_profile; GLFWbool ARB_create_context_no_error; GLFWbool ARB_context_flush_control;- } _GLFWlibraryGLX; GLFWbool _glfwInitGLX(void);
glfw/src/init.c view
@@ -28,7 +28,6 @@ //======================================================================== #include "internal.h"-#include "mappings.h" #include <string.h> #include <stdlib.h>@@ -37,16 +36,15 @@ #include <assert.h> -// The global variables below comprise all mutable global data in GLFW-//-// Any other global variable is a bug+// NOTE: The global variables below comprise all mutable global data in GLFW+// Any other mutable global variable is a bug -// Global state shared between compilation units of GLFW+// This contains all mutable state shared between compilation units of GLFW // _GLFWlibrary _glfw = { GLFW_FALSE }; // These are outside of _glfw so they can be used before initialization and-// after termination+// after termination without special handling when _glfw is cleared to zero // static _GLFWerror _glfwMainThreadError; static GLFWerrorfun _glfwErrorCallback;@@ -56,7 +54,10 @@ { GLFW_TRUE, // macOS menu bar GLFW_TRUE // macOS bundle chdir- }+ },+ {+ GLFW_WAYLAND_PREFER_LIBDECOR // Wayland libdecor mode+ }, }; // Terminate the library@@ -113,6 +114,90 @@ ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// +// Encode a Unicode code point to a UTF-8 stream+// Based on cutef8 by Jeff Bezanson (Public Domain)+//+size_t _glfwEncodeUTF8(char* s, uint32_t codepoint)+{+ size_t count = 0;++ if (codepoint < 0x80)+ s[count++] = (char) codepoint;+ else if (codepoint < 0x800)+ {+ s[count++] = (codepoint >> 6) | 0xc0;+ s[count++] = (codepoint & 0x3f) | 0x80;+ }+ else if (codepoint < 0x10000)+ {+ s[count++] = (codepoint >> 12) | 0xe0;+ s[count++] = ((codepoint >> 6) & 0x3f) | 0x80;+ s[count++] = (codepoint & 0x3f) | 0x80;+ }+ else if (codepoint < 0x110000)+ {+ s[count++] = (codepoint >> 18) | 0xf0;+ s[count++] = ((codepoint >> 12) & 0x3f) | 0x80;+ s[count++] = ((codepoint >> 6) & 0x3f) | 0x80;+ s[count++] = (codepoint & 0x3f) | 0x80;+ }++ return count;+}++// Splits and translates a text/uri-list into separate file paths+// NOTE: This function destroys the provided string+//+char** _glfwParseUriList(char* text, int* count)+{+ const char* prefix = "file://";+ char** paths = NULL;+ char* line;++ *count = 0;++ while ((line = strtok(text, "\r\n")))+ {+ char* path;++ text = NULL;++ if (line[0] == '#')+ continue;++ if (strncmp(line, prefix, strlen(prefix)) == 0)+ {+ line += strlen(prefix);+ // TODO: Validate hostname+ while (*line != '/')+ line++;+ }++ (*count)++;++ path = calloc(strlen(line) + 1, 1);+ paths = realloc(paths, *count * sizeof(char*));+ paths[*count - 1] = path;++ while (*line)+ {+ if (line[0] == '%' && line[1] && line[2])+ {+ const char digits[3] = { line[1], line[2], '\0' };+ *path = (char) strtol(digits, NULL, 16);+ line += 2;+ }+ else+ *path = *line;++ path++;+ line++;+ }+ }++ return paths;+}+ char* _glfw_strdup(const char* source) { const size_t length = strlen(source);@@ -121,6 +206,16 @@ return result; } +int _glfw_min(int a, int b)+{+ return a < b ? a : b;+}++int _glfw_max(int a, int b)+{+ return a > b ? a : b;+}+ float _glfw_fminf(float a, float b) { if (a != a)@@ -245,24 +340,12 @@ _glfwPlatformSetTls(&_glfw.errorSlot, &_glfwMainThreadError); + _glfwInitGamepadMappings();+ _glfw.initialized = GLFW_TRUE; _glfw.timer.offset = _glfwPlatformGetTimerValue(); glfwDefaultWindowHints();-- {- int i;-- for (i = 0; _glfwDefaultMappings[i]; i++)- {- if (!glfwUpdateGamepadMappings(_glfwDefaultMappings[i]))- {- terminate();- return GLFW_FALSE;- }- }- }- return GLFW_TRUE; } @@ -286,6 +369,9 @@ return; case GLFW_COCOA_MENUBAR: _glfwInitHints.ns.menubar = value;+ return;+ case GLFW_WAYLAND_LIBDECOR:+ _glfwInitHints.wl.libdecorMode = value; return; }
glfw/src/input.c view
@@ -28,6 +28,7 @@ //======================================================================== #include "internal.h"+#include "mappings.h" #include <assert.h> #include <float.h>@@ -85,25 +86,13 @@ for (i = 0; i <= GLFW_GAMEPAD_BUTTON_LAST; i++) { if (!isValidElementForJoystick(mapping->buttons + i, js))- {- _glfwInputError(GLFW_INVALID_VALUE,- "Invalid button in gamepad mapping %s (%s)",- mapping->guid,- mapping->name); return NULL;- } } for (i = 0; i <= GLFW_GAMEPAD_AXIS_LAST; i++) { if (!isValidElementForJoystick(mapping->axes + i, js))- {- _glfwInputError(GLFW_INVALID_VALUE,- "Invalid axis in gamepad mapping %s (%s)",- mapping->guid,- mapping->name); return NULL;- } } } @@ -289,7 +278,7 @@ // Notifies shared code of a Unicode codepoint input event // The 'plain' parameter determines whether to emit a regular character event //-void _glfwInputChar(_GLFWwindow* window, unsigned int codepoint, int mods, GLFWbool plain)+void _glfwInputChar(_GLFWwindow* window, uint32_t codepoint, int mods, GLFWbool plain) { if (codepoint < 32 || (codepoint > 126 && codepoint < 160)) return;@@ -371,6 +360,11 @@ { const int jid = (int) (js - _glfw.joysticks); + if (event == GLFW_CONNECTED)+ js->connected = GLFW_TRUE;+ else if (event == GLFW_DISCONNECTED)+ js->connected = GLFW_FALSE;+ if (_glfw.callbacks.joystick) _glfw.callbacks.joystick(jid, event); }@@ -408,6 +402,29 @@ ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// +// Adds the built-in set of gamepad mappings+//+void _glfwInitGamepadMappings(void)+{+ int jid;+ size_t i;+ const size_t count = sizeof(_glfwDefaultMappings) / sizeof(char*);+ _glfw.mappings = calloc(count, sizeof(_GLFWmapping));++ for (i = 0; i < count; i++)+ {+ if (parseMapping(&_glfw.mappings[_glfw.mappingCount], _glfwDefaultMappings[i]))+ _glfw.mappingCount++;+ }++ for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)+ {+ _GLFWjoystick* js = _glfw.joysticks + jid;+ if (js->connected)+ js->mapping = findValidMapping(js);+ }+}+ // Returns an available joystick object with arrays and name allocated // _GLFWjoystick* _glfwAllocJoystick(const char* name,@@ -421,7 +438,7 @@ for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) {- if (!_glfw.joysticks[jid].present)+ if (!_glfw.joysticks[jid].allocated) break; } @@ -429,8 +446,7 @@ return NULL; js = _glfw.joysticks + jid;- js->present = GLFW_TRUE;- js->name = _glfw_strdup(name);+ js->allocated = GLFW_TRUE; js->axes = calloc(axisCount, sizeof(float)); js->buttons = calloc(buttonCount + (size_t) hatCount * 4, 1); js->hats = calloc(hatCount, 1);@@ -438,6 +454,7 @@ js->buttonCount = buttonCount; js->hatCount = hatCount; + strncpy(js->name, name, sizeof(js->name) - 1); strncpy(js->guid, guid, sizeof(js->guid) - 1); js->mapping = findValidMapping(js); @@ -448,7 +465,6 @@ // void _glfwFreeJoystick(_GLFWjoystick* js) {- free(js->name); free(js->axes); free(js->buttons); free(js->hats);@@ -600,6 +616,12 @@ if (key != GLFW_KEY_UNKNOWN) {+ if (key < GLFW_KEY_SPACE || key > GLFW_KEY_LAST)+ {+ _glfwInputError(GLFW_INVALID_ENUM, "Invalid key %i", key);+ return NULL;+ }+ if (key != GLFW_KEY_KP_EQUAL && (key < GLFW_KEY_KP_0 || key > GLFW_KEY_KP_ADD) && (key < GLFW_KEY_APOSTROPHE || key > GLFW_KEY_WORLD_2))@@ -620,7 +642,7 @@ if (key < GLFW_KEY_SPACE || key > GLFW_KEY_LAST) { _glfwInputError(GLFW_INVALID_ENUM, "Invalid key %i", key);- return GLFW_RELEASE;+ return -1; } return _glfwPlatformGetKeyScancode(key);@@ -732,9 +754,16 @@ _GLFWcursor* cursor; assert(image != NULL);+ assert(image->pixels != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + if (image->width <= 0 || image->height <= 0)+ {+ _glfwInputError(GLFW_INVALID_VALUE, "Invalid image dimensions for cursor");+ return NULL;+ }+ cursor = calloc(1, sizeof(_GLFWcursor)); cursor->next = _glfw.cursorListHead; _glfw.cursorListHead = cursor;@@ -926,7 +955,7 @@ } js = _glfw.joysticks + jid;- if (!js->present)+ if (!js->connected) return GLFW_FALSE; return _glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE);@@ -951,7 +980,7 @@ } js = _glfw.joysticks + jid;- if (!js->present)+ if (!js->connected) return NULL; if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_AXES))@@ -980,7 +1009,7 @@ } js = _glfw.joysticks + jid;- if (!js->present)+ if (!js->connected) return NULL; if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_BUTTONS))@@ -1013,7 +1042,7 @@ } js = _glfw.joysticks + jid;- if (!js->present)+ if (!js->connected) return NULL; if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_BUTTONS))@@ -1039,7 +1068,7 @@ } js = _glfw.joysticks + jid;- if (!js->present)+ if (!js->connected) return NULL; if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE))@@ -1064,7 +1093,7 @@ } js = _glfw.joysticks + jid;- if (!js->present)+ if (!js->connected) return NULL; if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE))@@ -1083,7 +1112,7 @@ _GLFW_REQUIRE_INIT(); js = _glfw.joysticks + jid;- if (!js->present)+ if (!js->allocated) return; js->userPointer = pointer;@@ -1099,7 +1128,7 @@ _GLFW_REQUIRE_INIT_OR_RETURN(NULL); js = _glfw.joysticks + jid;- if (!js->present)+ if (!js->allocated) return NULL; return js->userPointer;@@ -1165,7 +1194,7 @@ for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) { _GLFWjoystick* js = _glfw.joysticks + jid;- if (js->present)+ if (js->connected) js->mapping = findValidMapping(js); } @@ -1188,7 +1217,7 @@ } js = _glfw.joysticks + jid;- if (!js->present)+ if (!js->connected) return GLFW_FALSE; if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE))@@ -1213,7 +1242,7 @@ } js = _glfw.joysticks + jid;- if (!js->present)+ if (!js->connected) return NULL; if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE))@@ -1245,7 +1274,7 @@ } js = _glfw.joysticks + jid;- if (!js->present)+ if (!js->connected) return GLFW_FALSE; if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_ALL))@@ -1354,3 +1383,4 @@ _GLFW_REQUIRE_INIT_OR_RETURN(0); return _glfwPlatformGetTimerFrequency(); }+
glfw/src/internal.h view
@@ -244,6 +244,9 @@ GLFWbool menubar; GLFWbool chdir; } ns;+ struct {+ int libdecorMode;+ } wl; }; // Window configuration@@ -342,9 +345,9 @@ int robustness; int release; - PFNGLGETSTRINGIPROC GetStringi;+ PFNGLGETSTRINGIPROC GetStringi; PFNGLGETINTEGERVPROC GetIntegerv;- PFNGLGETSTRINGPROC GetString;+ PFNGLGETSTRINGPROC GetString; _GLFWmakecontextcurrentfun makeCurrent; _GLFWswapbuffersfun swapBuffers;@@ -375,6 +378,7 @@ GLFWbool focusOnShow; GLFWbool shouldClose; void* userPointer;+ GLFWbool doublebuffer; GLFWvidmode videoMode; _GLFWmonitor* monitor; _GLFWcursor* cursor;@@ -396,23 +400,23 @@ _GLFWcontext context; struct {- GLFWwindowposfun pos;- GLFWwindowsizefun size;- GLFWwindowclosefun close;- GLFWwindowrefreshfun refresh;- GLFWwindowfocusfun focus;- GLFWwindowiconifyfun iconify;- GLFWwindowmaximizefun maximize;- GLFWframebuffersizefun fbsize;+ GLFWwindowposfun pos;+ GLFWwindowsizefun size;+ GLFWwindowclosefun close;+ GLFWwindowrefreshfun refresh;+ GLFWwindowfocusfun focus;+ GLFWwindowiconifyfun iconify;+ GLFWwindowmaximizefun maximize;+ GLFWframebuffersizefun fbsize; GLFWwindowcontentscalefun scale;- GLFWmousebuttonfun mouseButton;- GLFWcursorposfun cursorPos;- GLFWcursorenterfun cursorEnter;- GLFWscrollfun scroll;- GLFWkeyfun key;- GLFWcharfun character;- GLFWcharmodsfun charmods;- GLFWdropfun drop;+ GLFWmousebuttonfun mouseButton;+ GLFWcursorposfun cursorPos;+ GLFWcursorenterfun cursorEnter;+ GLFWscrollfun scroll;+ GLFWkeyfun key;+ GLFWcharfun character;+ GLFWcharmodsfun charmods;+ GLFWdropfun drop; } callbacks; // This is defined in the window API's platform.h@@ -423,7 +427,7 @@ // struct _GLFWmonitor {- char* name;+ char name[128]; void* userPointer; // Physical dimensions in millimeters.@@ -477,14 +481,15 @@ // struct _GLFWjoystick {- GLFWbool present;+ GLFWbool allocated;+ GLFWbool connected; float* axes; int axisCount; unsigned char* buttons; int buttonCount; unsigned char* hats; int hatCount;- char* name;+ char name[128]; void* userPointer; char guid[33]; _GLFWmapping* mapping;@@ -717,7 +722,7 @@ void _glfwInputKey(_GLFWwindow* window, int key, int scancode, int action, int mods); void _glfwInputChar(_GLFWwindow* window,- unsigned int codepoint, int mods, GLFWbool plain);+ uint32_t codepoint, int mods, GLFWbool plain); void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset); void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods); void _glfwInputCursorPos(_GLFWwindow* window, double xpos, double ypos);@@ -760,6 +765,7 @@ void _glfwFreeGammaArrays(GLFWgammaramp* ramp); void _glfwSplitBPP(int bpp, int* red, int* green, int* blue); +void _glfwInitGamepadMappings(void); _GLFWjoystick* _glfwAllocJoystick(const char* name, const char* guid, int axisCount,@@ -772,7 +778,12 @@ void _glfwTerminateVulkan(void); const char* _glfwGetVulkanResultString(VkResult result); +size_t _glfwEncodeUTF8(char* s, uint32_t codepoint);+char** _glfwParseUriList(char* text, int* count);+ char* _glfw_strdup(const char* source);+int _glfw_min(int a, int b);+int _glfw_max(int a, int b); float _glfw_fminf(float a, float b); float _glfw_fmaxf(float a, float b);
glfw/src/linux_joystick.c view
@@ -128,7 +128,7 @@ { for (int jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) {- if (!_glfw.joysticks[jid].present)+ if (!_glfw.joysticks[jid].connected) continue; if (strcmp(_glfw.joysticks[jid].linjs.path, path) == 0) return GLFW_FALSE;@@ -157,7 +157,7 @@ } // Ensure this device supports the events expected of a joystick- if (!isBitSet(EV_KEY, evBits) || !isBitSet(EV_ABS, evBits))+ if (!isBitSet(EV_ABS, evBits)) { close(linjs.fd); return GLFW_FALSE;@@ -245,9 +245,9 @@ // static void closeJoystick(_GLFWjoystick* js) {+ _glfwInputJoystick(js, GLFW_DISCONNECTED); close(js->linjs.fd); _glfwFreeJoystick(js);- _glfwInputJoystick(js, GLFW_DISCONNECTED); } // Lexically compare joysticks by name; used by qsort@@ -283,7 +283,8 @@ // Continue without device connection notifications if inotify fails - if (regcomp(&_glfw.linjs.regex, "^event[0-9]\\+$", 0) != 0)+ _glfw.linjs.regexCompiled = (regcomp(&_glfw.linjs.regex, "^event[0-9]\\+$", 0) == 0);+ if (!_glfw.linjs.regexCompiled) { _glfwInputError(GLFW_PLATFORM_ERROR, "Linux: Failed to compile regex"); return GLFW_FALSE;@@ -329,7 +330,7 @@ for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) { _GLFWjoystick* js = _glfw.joysticks + jid;- if (js->present)+ if (js->connected) closeJoystick(js); } @@ -342,6 +343,9 @@ close(_glfw.linjs.inotify); }++ if (_glfw.linjs.regexCompiled)+ regfree(&_glfw.linjs.regex); } void _glfwDetectJoystickConnectionLinux(void)@@ -424,7 +428,7 @@ handleAbsEvent(js, e.code, e.value); } - return js->present;+ return js->connected; } void _glfwPlatformUpdateGamepadGUID(char* guid)
glfw/src/mappings.h view
@@ -31,7 +31,7 @@ // all available in SDL_GameControllerDB. Do not edit this file. Any gamepad // mappings not specific to GLFW should be submitted to SDL_GameControllerDB. // This file can be re-generated from mappings.h.in and the upstream-// gamecontrollerdb.txt with the GenerateMappings.cmake script.+// gamecontrollerdb.txt with the 'update_mappings' CMake target. //======================================================================== // All gamepad mappings not labeled GLFW are copied from the@@ -60,95 +60,262 @@ const char* _glfwDefaultMappings[] = {+#if defined(GLFW_BUILD_WIN32_MAPPINGS) "03000000fa2d00000100000000000000,3DRUDDER,leftx:a0,lefty:a1,rightx:a5,righty:a2,platform:Windows,",+"03000000c82d00002038000000000000,8bitdo,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,",+"03000000c82d00000951000000000000,8BitDo Dogbone Modkit,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b11,platform:Windows,",+"03000000c82d000011ab000000000000,8BitDo F30,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,",+"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,",+"03000000c82d00000650000000000000,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:a4,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Windows,",+"03000000c82d00005106000000000000,8BitDo M30 Gamepad,a:b1,b:b0,back:b10,guide:b2,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,start:b11,x:b4,y:b3,platform:Windows,",+"03000000c82d00000151000000000000,8BitDo M30 ModKit,a:b0,b:b1,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Windows,",+"03000000c82d00000310000000000000,8BitDo N30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows,",+"03000000c82d00002028000000000000,8BitDo N30,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,",+"03000000c82d00008010000000000000,8BitDo N30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows,",+"03000000c82d00000451000000000000,8BitDo N30 Modkit,a:b1,b:b0,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,start:b11,platform:Windows,",+"03000000c82d00000190000000000000,8BitDo N30 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,",+"03000000c82d00001590000000000000,8BitDo N30 Pro 2,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,",+"03000000c82d00006528000000000000,8BitDo N30 Pro 2,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,", "03000000022000000090000000000000,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:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,", "03000000203800000900000000000000,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:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,",+"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,",+"03000000c82d00002867000000000000,8BitDo S30 Modkit,a:b0,b:b1,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b8,lefttrigger:b9,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Windows,",+"03000000c82d00000130000000000000,8BitDo SF30,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,",+"03000000c82d00000060000000000000,8Bitdo SF30 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:Windows,",+"03000000c82d00000061000000000000,8Bitdo SF30 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:Windows,",+"03000000c82d000021ab000000000000,8BitDo SFC30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,", "03000000102800000900000000000000,8Bitdo SFC30 GamePad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,",+"03000000c82d00003028000000000000,8Bitdo SFC30 GamePad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,",+"03000000c82d00000030000000000000,8BitDo SN30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,",+"03000000c82d00001290000000000000,8BitDo SN30,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:Windows,",+"03000000c82d000020ab000000000000,8BitDo SN30,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,",+"03000000c82d00004028000000000000,8BitDo SN30,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,",+"03000000c82d00006228000000000000,8BitDo SN30,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:Windows,",+"03000000c82d00000351000000000000,8BitDo SN30 Modkit,a:b1,b:b0,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,",+"03000000c82d00000160000000000000,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:Windows,",+"03000000c82d00000161000000000000,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:Windows,",+"03000000c82d00000121000000000000,8BitDo SN30 Pro for Android,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,",+"03000000c82d00000260000000000000,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:Windows,",+"03000000c82d00000261000000000000,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:Windows,",+"03000000c82d00000031000000000000,8BitDo Wireless 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:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",+"03000000c82d00001890000000000000,8BitDo Zero 2,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,",+"03000000c82d00003032000000000000,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:a3,start:b11,x:b4,y:b3,platform:Windows,", "03000000a00500003232000000000000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows,",-"030000008f0e00001200000000000000,Acme,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:Windows,",+"03000000a30c00002700000000000000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a3,lefty:a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows,",+"03000000a30c00002800000000000000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a3,lefty:a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows,",+"030000008f0e00001200000000000000,Acme GA-02,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:Windows,",+"03000000c01100000355000011010000,ACRUX USB GAME 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,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",+"03000000fa190000f0ff000000000000,Acteck AGJ-3200,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,",+"030000006f0e00001413000000000000,Afterglow,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,", "03000000341a00003608000000000000,Afterglow 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,",+"030000006f0e00000263000000000000,Afterglow 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,",+"030000006f0e00001101000000000000,Afterglow 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,",+"030000006f0e00001401000000000000,Afterglow 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,",+"030000006f0e00001402000000000000,Afterglow 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,",+"030000006f0e00001901000000000000,Afterglow 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,",+"030000006f0e00001a01000000000000,Afterglow 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,",+"03000000d62000001d57000000000000,Airflo 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,",+"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,",+"03000000ef0500000300000000000000,AxisPad,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:a3,righty:a2,start:b11,x:b0,y:b1,platform:Windows,",+"03000000d6200000e557000000000000,Batarang,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,", "03000000c01100001352000000000000,Battalife Joystick,a:b6,b:b7,back:b2,leftshoulder:b0,leftx:a0,lefty:a1,rightshoulder:b1,start:b3,x:b4,y:b5,platform:Windows,",-"030000006b1400000055000000000000,bigben ps3padstreetnew,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,",+"030000006f0e00003201000000000000,Battlefield 4 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,",+"03000000d62000002a79000000000000,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,x:b0,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 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:a3,righty:a4,start:b11,x:b3,y:b4,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,",+"030000006b1400000055000000000000,Bigben PS3 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:Windows,",+"030000006b1400000103000000000000,Bigben PS3 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:b3,y:b2,platform:Windows,",+"03000000120c0000210e000000000000,Brook Mars,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,", "0300000066f700000500000000000000,BrutalLegendTest,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:a2,start:b9,x:b0,y:b3,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,", "03000000e82000006058000000000000,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:Windows,",-"030000005e0400008e02000000000000,Controller (XBOX 360 For Windows),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,",+"03000000457500000401000000000000,Cobra,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,",+"030000005e0400008e02000000000000,Controller (XBOX 360 For Windows),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,",+"030000005e040000a102000000000000,Controller (Xbox 360 Wireless Receiver for Windows),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,Controller (Xbox One For Windows) - Wired,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,",+"030000005e040000ea02000000000000,Controller (Xbox One For Windows) - Wireless,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,", "03000000260900008888000000000000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a4,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Windows,", "03000000a306000022f6000000000000,Cyborg V.3 Rumble Pad,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:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows,",+"03000000451300000830000000000000,Defender Game Racer X7,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,",+"030000007d0400000840000000000000,Destroyer Tiltpad,+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b1,b:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,x:b0,y:b3,platform:Windows,", "03000000791d00000103000000000000,Dual Box WII,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:Windows,",-"030000004f04000023b3000000000000,Dual Trigger 3-in-1,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,",+"03000000bd12000002e0000000000000,Dual USB 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,",+"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,",+"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,",+"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,",+"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,",+"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,", "03000000341a00000108000000000000,EXEQ RF USB Gamepad 8206,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",+"030000006f0e00008401000000000000,Faceoff Deluxe+ Audio Wired Controller for Nintendo Switch,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,",+"030000006f0e00008001000000000000,Faceoff Wired Pro Controller for Nintendo Switch,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,",+"03000000852100000201000000000000,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:Windows,", "030000000d0f00008500000000000000,Fighting Commander 2016 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,", "030000000d0f00008400000000000000,Fighting Commander 5,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,",-"030000000d0f00008800000000000000,Fighting Stick mini 4,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,Fighting Stick mini 4,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,",+"030000000d0f00008800000000000000,Fighting Stick mini 4,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,", "030000000d0f00002700000000000000,FIGHTING STICK V3,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,", "78696e70757403000000000000000000,Fightstick TES,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b2,y:b3,platform:Windows,",+"03000000790000002201000000000000,Game Controller for PC,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,",+"0300000066f700000100000000000000,Game VIB Joystick,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:a3,righty:a2,start:b11,x:b0,y:b1,platform:Windows,", "03000000260900002625000000000000,Gamecube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,lefttrigger:a4,leftx:a0,lefty:a1,righttrigger:a5,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Windows,",+"03000000790000004618000000000000,GameCube Controller Adapter,a:b1,b:b2,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:b0,y:b3,platform:Windows,", "030000008f0e00000d31000000000000,GAMEPAD 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:Windows,", "03000000280400000140000000000000,GamePad Pro USB,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:Windows,",+"03000000ac0500003d03000000000000,GameSir,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,",+"03000000ac0500004d04000000000000,GameSir,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,", "03000000ffff00000000000000000000,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:Windows,",-"03000000451300000010000000000000,Generic USB Joystick,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,",+"03000000c01100000140000000000000,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,x:b0,y:b3,platform:Windows,",+"030000009b2800003200000000000000,GC/N64 to USB v3.4,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,GC/N64 to USB v3.6,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,",+"030000008305000009a0000000000000,Genius,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,",+"030000008305000031b0000000000000,Genius Maxfire Blaze 3,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,",+"03000000451300000010000000000000,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:Windows,",+"030000005c1a00003330000000000000,Genius MaxFire Grandias 12V,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Windows,",+"03000000300f00000b01000000000000,GGE909 Recoil Pad,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,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,",+"03000000f0250000c383000000000000,Gioteck VX2 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 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,",+"030000007d0400000540000000000000,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: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,", "030000000d0f00004900000000000000,Hatsune Miku Sho 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,", "03000000d81400000862000000000000,HitBox Edition Cthulhu+,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b4,rightshoulder:b7,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows,",+"03000000632500002605000000000000,HJD-X,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,",+"030000000d0f00002d00000000000000,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:Windows,", "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,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,", "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,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,", "030000000d0f00004000000000000000,Hori Fighting Stick Mini 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b4,rightshoulder:b7,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows,",+"030000000d0f00005400000000000000,Hori 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:Windows,",+"030000000d0f00000900000000000000,Hori Pad 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:Windows,",+"030000000d0f00004d00000000000000,Hori Pad A,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,",+"030000000d0f00009200000000000000,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:Windows,",+"030000000d0f00001600000000007803,HORI Real Arcade Pro EX-SE (Xbox 360),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b2,y:b3,platform:Windows,",+"030000000d0f00009c00000000000000,Hori TAC 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,x:b0,y:b3,platform:Windows,",+"030000000d0f0000c100000000000000,Horipad,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,", "030000000d0f00006e00000000000000,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:Windows,", "030000000d0f00006600000000000000,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:Windows,",+"030000000d0f00005500000000000000,Horipad 4 FPS,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,", "030000000d0f0000ee00000000000000,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:Windows,",-"030000000d0f00004d00000000000000,HORIPAD3 A,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,", "03000000250900000017000000000000,HRAP2 on PS/SS/N64 Joypad to USB BOX,a:b2,b:b1,back:b9,leftshoulder:b5,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b6,start:b8,x:b3,y:b0,platform:Windows,", "030000008f0e00001330000000000000,HuiJia SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b9,x:b3,y:b0,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,", "03000000830500006020000000000000,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:Windows,",-"03000000b50700001403000000000000,IMPACT BLACK,a:b2,b:b3,back:b8,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,",-"030000006f0e00002401000000000000,INJUSTICE FightStick for 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,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",+"03000000b50700001403000000000000,Impact Black,a:b2,b:b3,back:b8,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,",+"030000006f0e00002401000000000000,INJUSTICE FightStick PS3 Controller,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,",+"03000000ac0500002c02000000000000,IPEGA,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b13,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b14,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,", "03000000491900000204000000000000,Ipega PG-9023,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,",+"03000000491900000304000000000000,Ipega PG-9087 - Bluetooth Gamepad,+righty:+a5,-righty:-a4,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,start:b11,x:b3,y:b4,platform:Windows,",+"030000006e0500000a20000000000000,JC-DUX60 ELECOM MMO Gamepad,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,",+"030000006e0500000520000000000000,JC-P301U,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,JC-U3613M (DInput),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,",+"030000006e0500000720000000000000,JC-W01U,a:b2,b:b3,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:a2,righty:a3,start:b9,x:b0,y:b1,platform:Windows,",+"030000007e0500000620000000000000,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:Windows,",+"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:Windows,",+"030000007e0500000720000000000000,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:Windows,",+"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:Windows,",+"03000000bd12000003c0000010010000,Joypad Alpha Shock,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,",+"03000000bd12000003c0000000000000,JY-P70UR,a:b1,b:b0,back:b5,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:b4,x:b3,y:b2,platform:Windows,",+"03000000242f00002d00000000000000,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:Windows,",+"03000000242f00008a00000000000000,JYS Wireless Adapter,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,",+"03000000790000000200000000000000,King 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:a4,start:b9,x:b3,y:b0,platform:Windows,",+"030000006d040000d1ca000000000000,Logitech ChillStream,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,",+"030000006d040000d2ca000000000000,Logitech Cordless Precision,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,", "030000006d04000011c2000000000000,Logitech Cordless Wingman,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b5,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b2,righttrigger:b7,rightx:a3,righty:a4,x:b4,platform:Windows,", "030000006d04000016c2000000000000,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:Windows,", "030000006d04000018c2000000000000,Logitech F510 Gamepad,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,", "030000006d04000019c2000000000000,Logitech F710 Gamepad,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,",+"030000006d0400001ac2000000000000,Logitech Precision Gamepad,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:Windows,",+"030000006d0400000ac2000000000000,Logitech WingMan RumblePad,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,rightx:a3,righty:a4,x:b3,y:b4,platform:Windows,",+"03000000380700006652000000000000,Mad Catz C.T.R.L.R,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,x:b0,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,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,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:b6,rightx:a2,righty:a5,start:b9,x:b0,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,x:b0,y:b3,platform:Windows,", "03000000380700008134000000000000,Mad Catz FightStick TE2+ PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b7,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b4,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,", "03000000380700008184000000000000,Mad Catz FightStick TE2+ PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,leftstick:b10,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",+"03000000380700006252000000000000,Mad Catz Micro C.T.R.L.R,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,", "03000000380700008034000000000000,Mad Catz TE2 PS3 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,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,", "03000000380700008084000000000000,Mad Catz TE2 PS4 Fightstick,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:Windows,", "03000000380700008532000000000000,Madcatz Arcade 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,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,", "03000000380700003888000000000000,Madcatz Arcade 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,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,", "03000000380700001888000000000000,MadCatz SFIV FightStick PS3,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b6,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,", "03000000380700008081000000000000,MADCATZ SFV Arcade 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,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",-"030000008305000031b0000000000000,MaxfireBlaze3,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:Windows,",+"030000002a0600001024000000000000,Matricom,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:a3,righty:a4,start:b9,x:b2,y:b3,platform:Windows,",+"030000009f000000adbb000000000000,MaxJoypad Virtual Controller,a:b1,b:b2,back:b9,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:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,", "03000000250900000128000000000000,Mayflash Arcade Stick,a:b1,b:b2,back:b8,leftshoulder:b0,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b7,start:b9,x:b5,y:b6,platform:Windows,", "03000000790000004418000000000000,Mayflash GameCube Controller,a:b1,b:b2,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:b0,y:b3,platform:Windows,", "03000000790000004318000000000000,Mayflash GameCube Controller Adapter,a:b1,b:b2,back:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b0,leftshoulder:b4,leftstick:b0,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b0,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Windows,",+"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,", "030000008f0e00001030000000000000,Mayflash USB Adapter for original Sega Saturn controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b5,rightshoulder:b2,righttrigger:b7,start:b9,x:b3,y:b4,platform:Windows,", "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:Windows,", "03000000790000000018000000000000,Mayflash WiiU Pro Game Controller Adapter (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:Windows,",-"030000001008000001e5000000000000,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:Windows,",+"03000000790000002418000000000000,Mega Drive,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,rightshoulder:b2,start:b9,x:b3,y:b4,platform:Windows,",+"03000000380700006382000000000000,MLG GamePad 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,",+"03000000c62400002a89000000000000,MOGA XP5-A Plus,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,",+"03000000c62400002b89000000000000,MOGA XP5-A 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:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",+"03000000c62400001a89000000000000,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:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",+"03000000c62400001b89000000000000,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:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",+"03000000efbe0000edfe000000000000,Monect Virtual 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:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Windows,",+"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,",+"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,",+"03000000921200004b46000000000000,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:Windows,",+"03000000790000004518000000000000,NEXILUX GAMECUBE Controller Adapter,platform:Windows,a:b1,b:b0,x:b2,y:b3,start:b9,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a5,righty:a2,lefttrigger:a3,righttrigger:a4,",+"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,",+"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,", "03000000bd12000015d0000000000000,Nintendo Retrolink USB Super SNES Classic Controller,a:b2,b:b1,back:b8,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,x:b3,y:b0,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,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",-"030000004b120000014d000000000000,NYKO AIRFLO,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:a3,leftstick:a0,lefttrigger:b6,leftx:h0.6,lefty:h0.12,rightshoulder:b5,rightstick:a2,righttrigger:b7,rightx:h0.9,righty:h0.4,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,",+"03000000550900001472000000000000,NVIDIA Controller v01.04,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,",+"030000004b120000014d000000000000,NYKO AIRFLO,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:a3,leftstick:a0,lefttrigger:b6,rightshoulder:b5,rightstick:a2,righttrigger:b7,start:b9,x:b2,y:b3,platform:Windows,",+"03000000d620000013a7000000000000,NSW wired controller,platform:Windows,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,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,",+"03000000782300000a10000000000000,Onlive Wireless Controller,a:b15,b:b14,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b11,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b13,y:b12,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,", "03000000362800000100000000000000,OUYA Game 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:b13,rightx:a3,righty:a4,x:b1,y:b2,platform:Windows,", "03000000120c0000f60e000000000000,P4 Wired 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,",+"030000006f0e00000901000000000000,PDP Versus Fighting Pad,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,", "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: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,",+"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,", "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,",-"030000008f0e00007530000000000000,PS (R) Gamepad,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:b1,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",+"03000000d62000009557000000000000,Pro Elite 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,",+"03000000d62000009f31000000000000,Pro Ex mini 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,",+"03000000d6200000c757000000000000,Pro Ex mini 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,",+"03000000632500002306000000000000,PS 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,", "03000000e30500009605000000000000,PS to USB convert cable,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,",-"03000000100800000100000000000000,PS1 USB,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,",-"03000000100800000300000000000000,PS2 USB,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,",+"03000000100800000100000000000000,PS1 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:Windows,",+"030000008f0e00007530000000000000,PS1 Controller,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:b1,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",+"03000000100800000300000000000000,PS2 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,",+"03000000250900008888000000000000,PS2 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,",+"03000000666600006706000000000000,PS2 Controller,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,",+"030000006b1400000303000000000000,PS2 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:Windows,",+"030000009d0d00001330000000000000,PS2 Controller,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,",+"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,",+"03000000632500007505000000000000,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:b3,y:b0,platform:Windows,", "03000000888800000803000000000000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b9,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows,",-"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:Windows,",-"03000000250900000500000000000000,PS3 DualShock,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,",+"030000008f0e00001431000000000000,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,",+"030000003807000056a8000000000000,PS3 RF 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,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,", "03000000100000008200000000000000,PS360+ v1.66,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:h0.4,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,", "030000004c050000a00b000000000000,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:Windows,", "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:Windows,", "030000004c050000cc09000000000000,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:Windows,",+"030000004c050000e60c000000000000,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:b13,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",+"03000000ff000000cb01000000000000,PSP,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,", "03000000300f00000011000000000000,QanBa Arcade JoyStick 1008,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:b10,x:b0,y:b3,platform:Windows,", "03000000300f00001611000000000000,QanBa Arcade JoyStick 4018,a:b1,b:b2,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b8,x:b0,y:b3,platform:Windows,", "03000000222c00000020000000000000,QANBA DRONE 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:a3,rightshoulder:b5,righttrigger:a4,start:b9,x:b0,y:b3,platform:Windows,",@@ -157,320 +324,678 @@ "03000000222c00000223000000000000,Qanba Obsidian Arcade Joystick PS3 Mode,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,", "03000000222c00000023000000000000,Qanba Obsidian Arcade Joystick PS4 Mode,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: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,",+"03000000321500000204000000000000,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:Windows,",+"03000000321500000104000000000000,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:Windows,",+"03000000321500000507000000000000,Razer Raiju Mobile,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,",+"03000000321500000707000000000000,Razer Raiju Mobile,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,",+"03000000321500000011000000000000,Razer Raion Fightpad for 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:Windows,",+"03000000321500000009000000000000,Razer Serval,+lefty:+a2,-lefty:-a1,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,leftx:a0,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,", "030000000d0f00001100000000000000,REAL ARCADE PRO.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,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",-"030000000d0f00008b00000000000000,Real Arcade Pro.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:a3,start:b9,x:b0,y:b3,platform:Windows,",-"030000000d0f00008a00000000000000,Real Arcade Pro.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,x:b0,y:b3,platform:Windows,",-"030000000d0f00006b00000000000000,Real Arcade Pro.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:a3,start:b9,x:b0,y:b3,platform:Windows,", "030000000d0f00006a00000000000000,Real Arcade Pro.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,x:b0,y:b3,platform:Windows,",+"030000000d0f00006b00000000000000,Real Arcade Pro.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:a3,start:b9,x:b0,y:b3,platform:Windows,",+"030000000d0f00008a00000000000000,Real Arcade Pro.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,x:b0,y:b3,platform:Windows,",+"030000000d0f00008b00000000000000,Real Arcade Pro.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:a3,start:b9,x:b0,y:b3,platform:Windows,", "030000000d0f00007000000000000000,REAL ARCADE PRO.4 VLX,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,", "030000000d0f00002200000000000000,REAL ARCADE Pro.V3,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:Windows,",-"030000000d0f00005c00000000000000,Real Arcade Pro.V4,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,", "030000000d0f00005b00000000000000,Real Arcade Pro.V4,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,",+"030000000d0f00005c00000000000000,Real Arcade Pro.V4,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,", "03000000790000001100000000000000,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:Windows,",+"03000000bd12000013d0000000000000,Retrolink USB SEGA Saturn Classic,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,", "0300000000f000000300000000000000,RetroUSB.com RetroPad,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Windows,", "0300000000f00000f100000000000000,RetroUSB.com Super RetroPort,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Windows,", "030000006b140000010d000000000000,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:Windows,",-"030000006f0e00001e01000000000000,Rock Candy Gamepad for 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,",+"030000006b140000020d000000000000,Revolution Pro Controller 2(1/2),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,",+"030000006b140000130d000000000000,Revolution Pro Controller 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:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",+"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,", "030000004f04000003d0000000000000,run'n'drive,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,", "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 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,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows,", "03000000300f00001201000000000000,Saitek Dual Analog 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:Windows,",-"03000000a30600000cff000000000000,Saitek P2500 Force Rumble Pad,a:b2,b:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,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 Pad,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,", "03000000a30600000c04000000000000,Saitek P2900,a:b1,b:b2,back:b12,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:a3,righty:a2,start:b9,x:b0,y:b3,platform:Windows,", "03000000300f00001001000000000000,Saitek P480 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:Windows,", "03000000a30600000b04000000000000,Saitek P990,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:a2,start:b9,x:b0,y:b3,platform:Windows,", "03000000a30600000b04000000010000,Saitek P990 Dual Analog Pad,a:b1,b:b2,back:b9,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:b8,x:b0,y:b3,platform:Windows,",-"03000000300f00001101000000000000,saitek rumble pad,a:b2,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,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,",+"03000000a30600002106000000000000,Saitek PS1000,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,",+"03000000a306000020f6000000000000,Saitek PS2700,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,",+"03000000300f00001101000000000000,Saitek Rumble Pad,a:b2,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,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,",+"03000000730700000401000000000000,Sanwa PlayOnline Mobile,a:b0,b:b1,back:b2,leftx:a0,lefty:a1,start:b3,platform:Windows,", "0300000000050000289b000000000000,Saturn_Adapter_2.0,a:b1,b:b2,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows,", "030000009b2800000500000000000000,Saturn_Adapter_2.0,a:b1,b:b2,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,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,", "03000000341a00000208000000000000,SL-6555-SBK,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,",-"030000008f0e00000800000000000000,SpeedLink Strike FX Wireless,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,",+"03000000341a00000908000000000000,SL-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,",+"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,",+"03000000110100001914000000000000,SteelSeries,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftstick:b13,lefttrigger:b6,leftx:a0,lefty:a1,rightstick:b14,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",+"03000000381000001214000000000000,SteelSeries Free,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Windows,",+"03000000110100003114000000000000,SteelSeries Stratus Duo,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,",+"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,", "03000000ff1100003133000000000000,SVEN X-PAD,a:b2,b:b3,back:b4,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:a4,start:b5,x:b0,y:b1,platform:Windows,",+"03000000d620000011a7000000000000,Switch,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,",+"03000000457500002211000000000000,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:Windows,",+"030000004f04000007d0000000000000,T Mini Wireless,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,",+"030000004f0400000ab1000000000000,T.16000M,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b4,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b10,x:b2,y:b3,platform:Windows,", "03000000fa1900000706000000000000,Team 5,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,", "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,",-"030000004f04000015b3000000000000,Thrustmaster Dual Analog 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: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 3-in-1,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,", "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 3,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,", "03000000666600000488000000000000,TigerGame PS/PS2 Game Controller 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,",+"03000000d62000006000000000000000,Tournament 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,",+"030000005f140000c501000000000000,Trust 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:Windows,",+"03000000b80500000210000000000000,Trust 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:Windows,",+"030000004f04000087b6000000000000,TWCS Throttle,dpdown:b8,dpleft:b9,dpright:b7,dpup:b6,leftstick:b5,lefttrigger:-a5,leftx:a0,lefty:a1,righttrigger:+a5,platform:Windows,", "03000000d90400000200000000000000,TwinShock PS2,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,",-"03000000380700006652000000000000,UnKnown,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,",+"030000006e0500001320000000000000,U4113,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,",+"03000000101c0000171c000000000000,uRage 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:Windows,",+"03000000300f00000701000000000000,USB 4-Axis 12-Button 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:a2,start:b9,x:b3,y:b0,platform:Windows,",+"03000000341a00002308000000000000,USB gamepad,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,",+"030000005509000000b4000000000000,USB gamepad,a:b10,b:b11,back:b5,dpdown:b1,dpleft:b2,dpright:b3,dpup:b0,guide:b14,leftshoulder:b8,leftstick:b6,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b7,righttrigger:a5,rightx:a2,righty:a3,start:b4,x:b12,y:b13,platform:Windows,",+"030000006b1400000203000000000000,USB gamepad,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,",+"03000000790000000a00000000000000,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:a2,righty:a4,start:b9,x:b3,y:b0,platform:Windows,",+"03000000f0250000c183000000000000,USB 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:Windows,",+"03000000ff1100004133000000000000,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:a4,righty:a2,start:b9,x:b3,y:b0,platform:Windows,", "03000000632500002305000000000000,USB Vibration Joystick (BM),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,",+"030000006f0e00000302000000000000,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:Windows,",+"030000006f0e00000702000000000000,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,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,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,",+"030000005e0400000a0b000000000000,Xbox Adaptive 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,",+"030000005e040000130b000000000000,Xbox Series 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,",+"03000000341a00000608000000000000,Xeox,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,", "03000000450c00002043000000000000,XEOX Gamepad SL-6556-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:Windows,",+"03000000ac0500005b05000000000000,Xiaoji 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,", "03000000172700004431000000000000,XiaoMi Game 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:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a7,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,", "03000000786901006e70000000000000,XInput 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,",-"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,",+"03000000790000004f18000000000000,ZD-T Android,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,",+"03000000120c0000101e000000000000,ZEROPLUS P4 Wired 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,",+"78696e70757401000000000000000000,XInput Gamepad (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,",+"78696e70757402000000000000000000,XInput Wheel (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,",+"78696e70757403000000000000000000,XInput Arcade Stick (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,",+"78696e70757404000000000000000000,XInput Flight Stick (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,",+"78696e70757405000000000000000000,XInput Dance Pad (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,",+"78696e70757406000000000000000000,XInput Guitar (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,",+"78696e70757408000000000000000000,XInput Drum Kit (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,",+#endif // GLFW_BUILD_WIN32_MAPPINGS++#if defined(GLFW_BUILD_COCOA_MAPPINGS)+"030000008f0e00000300000009010000,2In1 USB 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,",+"03000000c82d00000090000001000000,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:Mac OS X,",+"03000000c82d00001038000000010000,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:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,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,",+"03000000c82d00005106000000010000,8BitDo M30 Gamepad,a:b1,b:b0,back:b10,guide:b2,leftshoulder:b6,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,start:b11,x:b4,y:b3,platform:Mac OS X,",+"03000000c82d00001590000001000000,8BitDo N30 Pro 2,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:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,",+"03000000c82d00006528000000010000,8BitDo N30 Pro 2,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:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,",+"030000003512000012ab000001000000,8BitDo NES30 Gamepad,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,", "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,",+"03000000c82d00001290000001000000,8BitDo SN30 Gamepad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,",+"03000000c82d00004028000000010000,8Bitdo SN30 GamePad,a:b1,b:b0,x:b4,y:b3,back:b10,start:b11,leftshoulder:b6,rightshoulder:b7,dpup:-a1,dpdown:+a1,dpleft:-a0,dpright:+a0,platform:Mac OS X,",+"03000000c82d00000160000001000000,8BitDo SN30 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: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: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,",+"03000000c82d00001890000001000000,8BitDo Zero 2,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,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,", "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,",+"03000000a30c00002700000003030000,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,",+"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,",+"03000000ef0500000300000000020000,AxisPad,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:a3,righty:a2,start:b11,x:b0,y:b1,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,",+"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,x:b0,y:b3,platform:Mac OS X,",+"03000000120c0000200e000000010000,Brook Mars,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,",+"03000000120c0000210e000000010000,Brook Mars,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,", "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,",+"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,", "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,",+"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,x:b0,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,",+"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 Inc. USB 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,",+"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,",+"03000000790000000600000007010000,Marvo GT-004,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftstick:b10,rightstick:b11,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: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,",+"03000000790000000018000000010000,Mayflash Wii U Pro Controller Adapter,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,", "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,",-"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,",+"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,",+"03000000c62400002a89000000010000,MOGA XP5-A 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 XP5-A 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,",+"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,",+"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,",+"03000000d620000011a7000010050000,Nintendo Switch PowerA 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,",+"03000000550900001472000025050000,NVIDIA Controller v01.04,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,",+"030000006f0e00000901000002010000,PDP Versus Fighting Pad,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,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,",-"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,",+"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,",+"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,",+"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,",+"03000000100800000300000006010000,PS2 Adapter,a:b2,b:b1,back:b8,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a4,righty:a3,start:b9,x:b3,y:b0,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,",-"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,", "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,",+"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,misc1:b13,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,",+"03000000321500000011000000010000,Razer Raion Fightpad for 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,",+"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,",+"030000006b140000130d000000010000,Revolution Pro Controller 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: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,",+"030000004c050000e60c000000010000,Sony DualSense,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,", "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,",-"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,",+"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,",+"050000004e696d6275732b0000000000,SteelSeries Nimbus Plus,a:b0,b:b1,back:b15,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b16,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b14,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,",+"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,", "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,", "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,",-"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,", "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,",+"030000006f0e00000702000003060000,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,leftstick:b10,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,",+"030000006f0e00000104000000000000,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,", "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,",-"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,",+"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,",+"030000005e040000050b000003090000,Xbox Elite Wireless Controller Series 2,a:b0,b:b1,back:b31,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b53,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:Mac OS X,",+"03000000c62400003a54000000000000,Xbox One PowerA 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,", "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,",+"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,", "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,",-"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,",-"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,", "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,",-"05000000203800000900000000010000,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:Linux,",+"03000000120c0000101e000000010000,ZEROPLUS P4 Wired 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,",+#endif // GLFW_BUILD_COCOA_MAPPINGS++#if defined(GLFW_BUILD_LINUX_MAPPINGS)+"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,",+"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,",+"03000000c82d00001590000011010000,8BitDo N30 Pro 2,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,",+"05000000c82d00006528000000010000,8BitDo N30 Pro 2,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,",+"03000000c82d00000310000011010000,8BitDo NES30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b6,rightshoulder:b9,righttrigger:b8,start:b11,x:b3,y:b4,platform:Linux,",+"05000000c82d00008010000000010000,8BitDo NES30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b6,rightshoulder:b9,righttrigger:b8,start:b11,x:b3,y:b4,platform:Linux,", "03000000022000000090000011010000,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:Linux,",+"05000000203800000900000000010000,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:Linux,", "05000000c82d00002038000000010000,8Bitdo NES30 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:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,", "03000000c82d00000190000011010000,8Bitdo NES30 Pro 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:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",-"05000000c82d00003028000000010000,8Bitdo SFC30 GamePad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,",+"05000000c82d00000060000000010000,8BitDo SF30 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,",+"05000000c82d00000061000000010000,8Bitdo SF30 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:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",+"03000000c82d000021ab000010010000,8BitDo SFC30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,",+"030000003512000012ab000010010000,8Bitdo SFC30 GamePad,a:b2,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b0,platform:Linux,", "05000000102800000900000000010000,8Bitdo SFC30 GamePad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,",-"05000000a00500003232000008010000,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:Linux,",+"05000000c82d00003028000000010000,8Bitdo SFC30 GamePad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,",+"03000000c82d00000160000000000000,8BitDo SN30 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:a3,righty:a4,start:b11,x:b4,y:b3,platform:Linux,",+"03000000c82d00000160000011010000,8BitDo SN30 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,",+"03000000c82d00000161000000000000,8BitDo SN30 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:a3,righty:a4,start:b11,x:b4,y:b3,platform:Linux,",+"03000000c82d00001290000011010000,8BitDo SN30 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:a3,righty:a4,start:b11,x:b4,y:b3,platform:Linux,",+"05000000c82d00000161000000010000,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:Linux,",+"05000000c82d00006228000000010000,8BitDo SN30 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,",+"03000000c82d00000260000011010000,8BitDo SN30 Pro+,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:a3,start:b11,x:b4,y:b3,platform:Linux,",+"05000000c82d00000261000000010000,8BitDo SN30 Pro+,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:a3,start:b11,x:b4,y:b3,platform:Linux,",+"05000000202800000900000000010000,8BitDo SNES30 Gamepad,a:b1,b:b0,back:b10,dpdown:b122,dpleft:b119,dpright:b120,dpup:b117,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,",+"03000000c82d00000031000011010000,8BitDo Wireless Adapter (DInput),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,",+"030000005e0400008e02000020010000,8BitDo Wireless Adapter (XInput),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,",+"03000000c82d00001890000011010000,8BitDo Zero 2,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,",+"05000000c82d00003032000000010000,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:a3,start:b11,x:b4,y:b3,platform:Linux,",+"050000005e040000e002000030110000,8BitDo Zero 2 (XInput),a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Linux,", "05000000a00500003232000001000000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux,",-"030000006f0e00003901000020060000,Afterglow Wired Controller for 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,",+"05000000a00500003232000008010000,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:Linux,",+"03000000c01100000355000011010000,ACRUX USB GAME 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,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",+"030000006f0e00001302000000010000,Afterglow,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,",+"030000006f0e00003901000020060000,Afterglow Controller for 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,",+"030000006f0e00003901000000430000,Afterglow Prismatic 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,",+"030000006f0e00003901000013020000,Afterglow Prismatic Wired Controller 048-007-NA,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,", "03000000100000008200000011010000,Akishop Customs PS360+ v1.66,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,",+"030000007c1800000006000010010000,Alienware Dual Compatible Game Pad,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:a2,start:b9,x:b0,y:b3,platform:Linux,",+"05000000491900000204000021000000,Amazon Fire Game 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,",+"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,leftx:a0,lefty: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,", "05000000050b00000045000031000000,ASUS Gamepad,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,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:Linux,",+"05000000050b00000045000040000000,ASUS Gamepad,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,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:Linux,",+"03000000503200000110000000000000,Atari Classic Controller,a:b0,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,start:b3,x:b1,platform:Linux,",+"05000000503200000110000000000000,Atari Classic Controller,a:b0,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,start:b3,x:b1,platform:Linux,",+"03000000503200000210000000000000,Atari Game 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:b3,y:b2,platform:Linux,",+"05000000503200000210000000000000,Atari Game 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:b3,y:b2,platform:Linux,",+"03000000120c00000500000010010000,AxisPad,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:a3,righty:a2,start:b11,x:b0,y:b1,platform:Linux,",+"03000000ef0500000300000000010000,AxisPad,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:a3,righty:a2,start:b11,x:b0,y:b1,platform:Linux,",+"03000000c62400001b89000011010000,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:Linux,",+"03000000d62000002a79000011010000,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,x:b0,y:b3,platform:Linux,",+"03000000c21100000791000011010000,Be1 GC101 Controller 1.03 mode,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,",+"03000000c31100000791000011010000,Be1 GC101 GAMEPAD 1.03 mode,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,",+"030000005e0400008e02000003030000,Be1 GC101 Xbox 360 Controller mode,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,",+"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,", "03000000666600006706000000010000,boom PSX to PC Converter,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,",+"03000000120c0000200e000011010000,Brook Mars,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,",+"03000000120c0000210e000011010000,Brook Mars,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,",+"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,",+"03000000ffff0000ffff000000010000,Chinese-made 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,", "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,",+"030000000b0400003365000000010000,Competition Pro,a:b0,b:b1,back:b2,leftx:a0,lefty:a1,start:b3,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 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:Linux,", "03000000b40400000a01000000010000,CYPRESS 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:Linux,", "03000000790000000600000010010000,DragonRise Inc. Generic USB 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:a3,righty:a4,start:b9,x:b3,y:b0,platform:Linux,",+"030000004f04000004b3000010010000,Dual Power 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,", "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,", "03000000341a000005f7000010010000,GameCube {HuiJia USB box},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,",+"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,", "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,",-"030000006f0e00001304000000010000,Generic X-Box pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:a0,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:a3,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",-"030000006f0e00001f01000000010000,Generic X-Box pad,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 Co. Ltd PS(R) 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,",+"030000006f0e00001304000000010000,Generic X-Box pad,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,",+"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,", "03000000f0250000c183000010010000,Goodbetterbest Ltd USB 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,",+"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,",+"030000007d0400000540000000010000,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:Linux,", "03000000280400000140000000010000,Gravis GamePad Pro USB ,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:Linux,", "030000008f0e00000610000000010000,GreenAsia Electronics 4Axes 12Keys GamePad ,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 Inc. USB 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,",-"030000008f0e00000300000010010000,GreenAsia Inc. USB Joystick,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,", "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,", "06000000adde0000efbe000002010000,Hidromancer Game 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,guide:b9,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b12,x:b0,y:b3,platform:Linux,", "03000000c9110000f055000011010000,HJC Game 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,",+"03000000632500002605000010010000,HJD-X,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:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,", "030000000d0f00000d00000000010000,hori,a:b0,b:b6,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b3,leftx:b4,lefty:b5,rightshoulder:b7,start:b9,x:b1,y:b2,platform:Linux,", "030000000d0f00001000000011010000,HORI CO. LTD. FIGHTING STICK 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,",+"030000000d0f0000c100000011010000,HORI CO. LTD. HORIPAD S,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:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,", "030000000d0f00006a00000011010000,HORI CO. LTD. Real Arcade Pro.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,x:b0,y:b3,platform:Linux,", "030000000d0f00006b00000011010000,HORI CO. LTD. Real Arcade Pro.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:a3,start:b9,x:b0,y:b3,platform:Linux,", "030000000d0f00002200000011010000,HORI CO. LTD. REAL ARCADE Pro.V3,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,",+"030000000d0f00008500000010010000,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: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,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,", "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,x:b0,y:b3,platform:Linux,", "03000000ad1b000001f5000033050000,Hori Pad EX Turbo 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,",+"030000000d0f00009200000011010000,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:Linux,",+"030000000d0f0000aa00000011010000,HORI Real Arcade Pro,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,",+"030000000d0f0000d800000072056800,HORI Real Arcade Pro S,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:Linux,",+"030000000d0f00001600000000010000,Hori Real Arcade Pro.EX-SE (Xbox 360),a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,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,x:b0,y:b3,platform:Linux,",+"030000000d0f0000ee00000011010000,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: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,", "030000008f0e00001330000010010000,HuiJia SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b9,x:b3,y:b0,platform:Linux,",+"03000000242e00008816000001010000,Hyperkin X91,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,", "03000000830500006020000010010000,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:Linux,", "050000006964726f69643a636f6e0000,idroid:con,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,", "03000000b50700001503000010010000,impact,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,",+"03000000d80400008200000003000000,IMS PCU#0 Gamepad Interface,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b5,x:b3,y:b2,platform:Linux,", "03000000fd0500000030000000010000,InterAct GoPad I-73000 (Fighting Game Layout),a:b3,b:b4,back:b6,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,start:b7,x:b0,y:b1,platform:Linux,",+"0500000049190000020400001b010000,Ipega PG-9069 - Bluetooth Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b161,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,",+"03000000632500007505000011010000,Ipega PG-9099 - Bluetooth 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,", "030000006e0500000320000010010000,JC-U3613M - DirectInput Mode,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:Linux,", "03000000300f00001001000010010000,Jess Tech Dual Analog 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,",+"03000000300f00000b01000010010000,Jess Tech GGE909 PC Recoil Pad,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 USB Game 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,",+"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:Linux,",+"050000007e0500000620000001000000,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:Linux,",+"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:Linux,",+"050000007e0500000720000001000000,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:Linux,",+"03000000bd12000003c0000010010000,Joypad Alpha Shock,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,",+"03000000242f00002d00000011010000,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:Linux,",+"03000000242f00008a00000011010000,JYS Wireless Adapter,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:Linux,", "030000006f0e00000103000000020000,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,",+"030000006d040000d1ca000000000000,Logitech ChillStream,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,", "030000006d04000019c2000010010000,Logitech Cordless RumblePad 2,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,",-"030000006d04000016c2000011010000,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:Linux,", "030000006d04000016c2000010010000,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:Linux,",+"030000006d04000016c2000011010000,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:Linux,", "030000006d0400001dc2000014400000,Logitech F310 Gamepad (XInput),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,",+"030000006d0400001ec2000019200000,Logitech F510 Gamepad (XInput),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,", "030000006d0400001ec2000020200000,Logitech F510 Gamepad (XInput),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,", "030000006d04000019c2000011010000,Logitech F710 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:Linux,", "030000006d0400001fc2000005030000,Logitech F710 Gamepad (XInput),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,",-"030000006d04000015c2000010010000,Logitech Logitech Extreme 3D,a:b0,b:b4,back:b6,guide:b8,leftshoulder:b9,leftstick:h0.8,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:h0.2,start:b7,x:b2,y:b5,platform:Linux,",+"030000006d0400000ac2000010010000,Logitech Inc. WingMan RumblePad,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,rightx:a3,righty:a4,x:b3,y:b4,platform:Linux,", "030000006d04000018c2000010010000,Logitech RumblePad 2,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,", "030000006d04000011c2000010010000,Logitech WingMan Cordless RumblePad,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b10,rightx:a3,righty:a4,start:b8,x:b3,y:b4,platform:Linux,",+"050000004d4f435554452d3035305800,M54-PC,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,", "05000000380700006652000025010000,Mad Catz C.T.R.L.R ,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,", "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,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,", "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,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,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",-"03000000380700008483000011010000,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,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,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,",+"03000000380700008483000011010000,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:Linux,", "03000000380700001647000010040000,Mad Catz Wired 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 Wired Xbox 360 Controller (SFIV),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,", "03000000380700001888000010010000,MadCatz PC USB Wired Stick 8818,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,", "03000000380700003888000010010000,MadCatz PC USB Wired Stick 8838,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:a0,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",-"03000000790000004418000010010000,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:Linux,",+"03000000242f0000f700000001010000,Magic-S 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,",+"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,",+"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,",+"03000000790000004318000010010000,Mayflash GameCube Controller Adapter,a:b1,b:b2,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:b0,y:b3,platform:Linux,",+"03000000242f00007300000011010000,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:Linux,",+"0300000079000000d218000011010000,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:Linux,",+"03000000d620000010a7000011010000,Mayflash Magic NS,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,",+"0300000025090000e803000001010000,Mayflash Wii Classic Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:a4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:a5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux,", "03000000780000000600000010010000,Microntek USB Joystick,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,",+"030000005e0400000e00000000010000,Microsoft SideWinder,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,rightshoulder:b7,start:b8,x:b3,y:b4,platform:Linux,", "030000005e0400008e02000004010000,Microsoft X-Box 360 pad,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,", "030000005e0400008e02000062230000,Microsoft X-Box 360 pad,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,",+"050000005e040000050b000003090000,Microsoft X-Box One Elite 2 pad,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,",+"030000005e040000e302000003020000,Microsoft X-Box One Elite pad,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,", "030000005e040000d102000001010000,Microsoft X-Box One pad,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 X-Box One pad (Firmware 2015),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,", "030000005e040000d102000003020000,Microsoft X-Box One pad v2,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,", "030000005e0400008502000000010000,Microsoft X-Box pad (Japan),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,", "030000005e0400008902000021010000,Microsoft X-Box pad v2 (US),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,",+"030000005e040000000b000008040000,Microsoft Xbox One Elite 2 pad - Wired,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 S pad - Wired,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,",+"03000000c62400001a53000000010000,Mini PE,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,",+"05000000d6200000e589000001000000,Moga 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:Linux,", "05000000d6200000ad0d000001000000,Moga Pro,a:b0,b:b1,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:Linux,",-"030000001008000001e5000010010000,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:Linux,",+"05000000d62000007162000001000000,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:Linux,",+"03000000c62400002b89000011010000,MOGA XP5-A 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,",+"05000000c62400002a89000000010000,MOGA XP5-A Plus,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:Linux,",+"05000000c62400001a89000000010000,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:Linux,",+"03000000250900006688000000010000,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: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,",+"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,",+"03000000790000004518000010010000,NEXILUX GAMECUBE Controller Adapter,a:b1,b:b0,x:b2,y:b3,start:b9,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a5,righty:a2,lefttrigger:a3,righttrigger:a4,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,",+"060000007e0500000820000000000000,Nintendo Combined Joy-Cons (joycond),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,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,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,",+"050000007e0500000620000001800000,Nintendo Switch Left Joy-Con,a:b9,b:b8,back:b5,leftshoulder:b2,leftstick:b6,leftx:a1,lefty:a0~,rightshoulder:b4,start:b0,x:b7,y:b10,platform:Linux,",+"030000007e0500000920000011810000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,", "050000007e0500000920000001000000,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:Linux,",+"050000007e0500000920000001800000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,",+"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,",+"050000007e0500001720000001000000,Nintendo Switch 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:Linux,", "050000007e0500003003000001000000,Nintendo Wii Remote 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,", "05000000010000000100000003000000,Nintendo Wiimote,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,", "030000000d0500000308000010010000,Nostromo n45 Dual Analog Gamepad,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,", "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,", "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,odroidgo2_joypad,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,",+"19000000010000000200000011000000,odroidgo2_joypad_v11,a:b1,b:b0,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b12,leftshoulder:b4,leftstick:b14,lefttrigger:b13,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b15,righttrigger:b16,start:b17,x:b2,y:b3,platform:Linux,", "030000005e0400000202000000010000,Old Xbox pad,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,",+"03000000c0160000dc27000001010000,OnyxSoft Dual JoyDivision,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b6,x:b2,y:b3,platform:Linux,", "05000000362800000100000002010000,OUYA Game 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:Linux,", "05000000362800000100000003010000,OUYA Game 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:Linux,",+"03000000830500005020000010010000,Padix Co. Ltd. Rockfire PSX/USB Bridge,a:b0,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:a2,righty:a3,start:b11,x:b2,y:b3,platform:Linux,",+"03000000790000001c18000011010000,PC Game 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,", "03000000ff1100003133000010010000,PC Game 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,",+"030000006f0e0000b802000001010000,PDP AFTERGLOW Wired 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 Wired 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,",+"030000006f0e00008001000011010000,PDP CO. LTD. Faceoff Wired Pro Controller for Nintendo Switch,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,",+"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,",+"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,",+"030000006f0e00008701000011010000,PDP Rock Candy Wired Controller for Nintendo Switch,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,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,",+"030000006f0e00000901000011010000,PDP Versus Fighting Pad,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,",+"030000006f0e0000a802000023020000,PDP Wired Controller for Xbox One,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,",+"030000006f0e00008501000011010000,PDP Wired Fight Pad Pro for Nintendo Switch,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,PG-9099,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,PG-9118,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,",+"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,",+"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,",+"03000000d62000006dca000011010000,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:Linux,",+"03000000d62000000228000001010000,PowerA Wired Controller for 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,",+"03000000c62400001a58000001010000,PowerA Xbox One Cabled,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 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,",+"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,", "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,",-"030000004c0500006802000010010000,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,",-"050000004c0500006802000000810000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,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,", "03000000341a00003608000011010000,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,",-"030000004c0500006802000011810000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,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,",-"050000004c0500006802000000010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:a12,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:a13,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux,",+"030000004c0500006802000010010000,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,", "030000004c0500006802000010810000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,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,", "030000004c0500006802000011010000,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,",-"060000004c0500006802000000010000,PS3 Controller (Bluetooth),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,",-"05000000504c415953544154494f4e00,PS3 Controller (Bluetooth),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,",-"050000004c050000c405000000010000,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,",+"030000004c0500006802000011810000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,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,",+"030000006f0e00001402000011010000,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,",+"030000008f0e00000300000010010000,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,",+"050000004c0500006802000000000000,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,",+"050000004c0500006802000000010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:a12,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:a13,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux,",+"050000004c0500006802000000800000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,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,",+"050000004c0500006802000000810000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,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,",+"05000000504c415953544154494f4e00,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,",+"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,x:b0,y:b3,platform:Linux,",-"050000004c050000cc09000000810000,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,",-"050000004c050000c405000000810000,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,",+"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,",+"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,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,",-"050000004c050000cc09000000010000,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,",+"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:Linux,", "030000004c050000cc09000011010000,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,",-"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,", "030000004c050000cc09000011810000,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,x:b0,y:b3,platform:Linux,",+"03000000c01100000140000011010000,PS4 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:Linux,",+"050000004c050000c405000000010000,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,",+"050000004c050000c405000000810000,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,",+"050000004c050000c405000001800000,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,",+"050000004c050000cc09000000010000,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,",+"050000004c050000cc09000000810000,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,",+"050000004c050000cc09000001800000,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,",+"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:b13,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,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,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",+"03000000ff000000cb01000010010000,PSP,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,", "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,",+"030000009b2800004200000001010000,Raphnet Technologies Dual NES to USB v2.0,a:b0,b:b1,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b3,platform:Linux,",+"030000009b2800003200000001010000,Raphnet Technologies GC/N64 to USB v3.4,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 Technologies GC/N64 to USB v3.6,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,", "030000009b2800000300000001010000,raphnet.net 4nes4snes v1.5,a:b0,b:b4,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,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,",-"030000008916000000fd000024010000,Razer Onza Tournament,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,",+"030000008916000000fd000024010000,Razer Onza Tournament Edition,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,",+"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,",+"03000000321500000104000011010000,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:Linux,",+"03000000321500000810000011010000,Razer Panthera Evo Arcade Stick for PS4,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,", "03000000321500000010000011010000,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:Linux,",+"03000000321500000507000000010000,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:Linux,",+"03000000321500000011000011010000,Razer Raion Fightpad for 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:Linux,",+"030000008916000000fe000024010000,Razer Sabertooth,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,",+"03000000c6240000045d000024010000,Razer Sabertooth,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,", "03000000c6240000045d000025010000,Razer Sabertooth,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,", "03000000321500000009000011010000,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,", "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,", "03000000790000001100000010010000,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:Linux,",-"0300000000f000000300000000010000,RetroUSB.com RetroPad,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Linux,",-"0300000000f00000f100000000010000,RetroUSB.com Super RetroPort,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Linux,",+"0300000081170000990a000001010000,Retronic Adapter,a:b0,leftx:a0,lefty:a1,platform:Linux,",+"0300000000f000000300000000010000,RetroPad,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Linux,", "030000006b140000010d000011010000,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:Linux,",-"030000006f0e00001e01000011010000,Rock Candy Gamepad for 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,",-"030000006f0e00004601000001010000,Rock Candy Wired Controller for Xbox One,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,",+"030000006b140000130d000011010000,Revolution Pro Controller 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:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",+"030000006f0e00001f01000000010000,Rock Candy,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,",+"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,",+"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 V.1 Game 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,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux,",-"03000000a30600000cff000010010000,Saitek P2500 Force Rumble Pad,a:b2,b:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,x:b0,y:b1,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 Pad,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,", "03000000a30600000c04000011010000,Saitek P2900 Wireless Pad,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,",+"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,", "03000000a30600000901000000010000,Saitek P880,a:b2,b:b3,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,x:b0,y:b1,platform:Linux,", "03000000a30600000b04000000010000,Saitek P990 Dual Analog Pad,a:b1,b:b2,back:b9,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:b8,x:b0,y:b3,platform:Linux,", "03000000a306000018f5000010010000,Saitek PLC Saitek P3200 Rumble Pad,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,",-"03000000c01600008704000011010000,Serial/Keyboard/Mouse/Joystick,a:b12,b:b10,back:b4,dpdown:b2,dpleft:b3,dpright:b1,dpup:b0,leftshoulder:b9,leftstick:b14,lefttrigger:b6,leftx:a1,lefty:a0,rightshoulder:b8,rightstick:b15,righttrigger:b7,rightx:a2,righty:a3,start:b5,x:b13,y:b11,platform:Linux,",+"03000000a306000020f6000011010000,Saitek PS2700 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:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux,",+"03000000d81d00000e00000010010000,Savior,a:b0,b:b1,back:b8,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b11,righttrigger:b3,start:b9,x:b4,y:b5,platform:Linux,", "03000000f025000021c1000010010000,ShanWan Gioteck PS3 Wired 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,",+"03000000632500007505000010010000,SHANWAN PS3/PC 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 PS3/PC Wired 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,",+"030000005f140000c501000010010000,SHANWAN Trust 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,",+"03000000632500002305000010010000,ShanWan 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:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,",+"03000000341a00000908000010010000,SL-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:Linux,",+"030000004c050000e60c000011810000,Sony DualSense,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,",+"050000004c050000e60c000000810000,Sony DualSense ,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,", "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 Wireless 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: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 Gamepad pad,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,",-"03000000de2800000211000001000000,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:Linux,",-"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:Linux,",-"03000000de2800000112000001000000,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:Linux,",-"05000000de2800000212000001000000,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:Linux,",-"03000000de280000fc11000001000000,Steam 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,",-"03000000de2800004211000001000000,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: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,",+"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,",+"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,",+"03000000de2800000211000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:b18,dpleft:b19,dpright:b20,dpup:b17,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b15,paddle2:b16,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b5,platform:Linux,",+"03000000de2800004211000001000000,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,",+"03000000de2800004211000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:b18,dpleft:b19,dpright:b20,dpup:b17,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b15,paddle2:b16,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b5,platform:Linux,",+"03000000de280000fc11000001000000,Steam 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,",+"05000000de2800000212000001000000,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,",+"05000000de2800000511000001000000,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,",+"05000000de2800000611000001000000,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,", "03000000de280000ff11000001000000,Steam Virtual 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:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",+"03000000381000003014000075010000,SteelSeries Stratus Duo,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,",+"03000000381000003114000075010000,SteelSeries Stratus Duo,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,",+"0500000011010000311400001b010000,SteelSeries Stratus Duo,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b32,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,",+"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 for USB,a:b0,b:b2,back:b7,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b5,start:b8,x:b1,y:b3,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,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Linux,",+"03000000457500002211000010010000,SZMY-POWER CO. LTD. 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,",+"030000008f0e00000d31000010010000,SZMY-POWER CO. LTD. GAMEPAD 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,",+"030000008f0e00001431000010010000,SZMY-POWER CO. LTD. PS3 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:Linux,", "030000004f04000020b3000010010000,Thrustmaster 2 in 1 DT,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,", "030000004f04000015b3000010010000,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:Linux,", "030000004f04000023b3000000010000,Thrustmaster Dual Trigger 3-in-1,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:Linux,",+"030000004f0400000ed0000011010000,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:Linux,",+"03000000b50700000399000000010000,Thrustmaster Firestorm Digital 2,a:b2,b:b4,back:b11,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b8,rightstick:b0,righttrigger:b9,start:b1,x:b3,y:b5,platform:Linux,",+"030000004f04000003b3000010010000,Thrustmaster Firestorm Dual Analog 2,a:b0,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b9,rightx:a2,righty:a3,x:b1,y:b3,platform:Linux,", "030000004f04000000b3000010010000,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:Linux,",+"030000004f04000026b3000002040000,Thrustmaster Gamepad GP XID,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,",+"03000000c6240000025b000002020000,Thrustmaster GPX 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:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", "030000004f04000008d0000000010000,Thrustmaster Run N Drive Wireless,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:Linux,", "030000004f04000009d0000000010000,Thrustmaster Run N Drive Wireless 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,",+"030000004f04000007d0000000010000,Thrustmaster T Mini Wireless,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,",+"030000004f04000012b3000010010000,Thrustmaster vibrating gamepad,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,", "03000000bd12000015d0000010010000,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:Linux,", "03000000d814000007cd000011010000,Toodles 2008 Chimp PC/PS3,a:b0,b:b1,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b2,platform:Linux,",+"030000005e0400008e02000070050000,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,",+"03000000c01100000591000011010000,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:Linux,", "03000000100800000100000010010000,Twin USB PS2 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,", "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 Gamepad1,a:b2,b:b1,back:b8,dpdown:a0,dpleft:a1,dpright:a2,dpup:a4,start:b9,platform:Linux,",+"030000006f0e00000302000011010000,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:Linux,",+"030000006f0e00000702000011010000,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,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,", "05000000ac0500003232000001000000,VR-BOX,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,",-"030000005e0400008e02000014010000,X360 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,",+"03000000791d00000103000010010000,Wii Classic Controller,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,",+"050000000d0f0000f600000001000000,Wireless 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,", "030000005e0400008e02000010010000,X360 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,",+"030000005e0400008e02000014010000,X360 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,", "030000005e0400001907000000010000,X360 Wireless Controller,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,", "030000005e0400009102000007010000,X360 Wireless Controller,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,",-"030000005e040000a102000007010000,X360 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,", "030000005e040000a102000000010000,X360 Wireless Controller,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,",+"030000005e040000a102000007010000,X360 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,", "0000000058626f782033363020576900,Xbox 360 Wireless Controller,a:b0,b:b1,back:b14,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,guide:b7,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Linux,",+"030000005e040000a102000014010000,Xbox 360 Wireless Receiver (XBOX),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 Gamepad (userspace driver),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,",+"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,",+"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,",+"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,",+"030000005e040000ea02000000000000,Xbox One 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,", "050000005e040000e002000003090000,Xbox One 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:Linux,", "050000005e040000fd02000003090000,Xbox One Wireless 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,",+"030000005e040000ea02000001030000,Xbox One Wireless Controller (Model 1708),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,",+"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,",+"050000005e040000130b000005050000,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,",+"030000005e040000120b000005050000,XBox Series pad,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,xbox360 Wireless 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,", "03000000450c00002043000010010000,XEOX Gamepad SL-6556-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,",+"03000000ac0500005b05000010010000,Xiaoji 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,", "05000000172700004431000029010000,XiaoMi Game 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,", "03000000c0160000e105000001010000,Xin-Mo Xin-Mo Dual Arcade,a:b4,b:b3,back:b6,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b9,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b1,y:b0,platform:Linux,", "03000000120c0000100e000011010000,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:Linux,",-"64633436313965656664373634323364,Microsoft X-Box 360 pad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,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,",-"61363931656135336130663561616264,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,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,",-"4e564944494120436f72706f72617469,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,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,",-"37336435666338653565313731303834,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,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,",-"35643031303033326130316330353564,PS4 Controller,a:b1,b:b17,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,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,",-"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,",-"5477696e20555342204a6f7973746963,Twin USB Joystick,a:b22,b:b21,back:b28,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,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,",-"34356136633366613530316338376136,Xbox Wireless Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,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,",-"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,",-"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,",--"78696e70757401000000000000000000,XInput Gamepad (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,",-"78696e70757402000000000000000000,XInput Wheel (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,",-"78696e70757403000000000000000000,XInput Arcade Stick (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,",-"78696e70757404000000000000000000,XInput Flight Stick (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,",-"78696e70757405000000000000000000,XInput Dance Pad (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,",-"78696e70757406000000000000000000,XInput Guitar (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,",-"78696e70757408000000000000000000,XInput Drum Kit (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,",-NULL+"03000000120c0000101e000011010000,ZEROPLUS P4 Wired 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:Linux,",+#endif // GLFW_BUILD_LINUX_MAPPINGS };
glfw/src/monitor.c view
@@ -170,8 +170,7 @@ monitor->widthMM = widthMM; monitor->heightMM = heightMM; - if (name)- monitor->name = _glfw_strdup(name);+ strncpy(monitor->name, name, sizeof(monitor->name) - 1); return monitor; }@@ -189,7 +188,6 @@ _glfwFreeGammaArrays(&monitor->currentRamp); free(monitor->modes);- free(monitor->name); free(monitor); } @@ -523,6 +521,8 @@ assert(ramp->green != NULL); assert(ramp->blue != NULL); + _GLFW_REQUIRE_INIT();+ if (ramp->size <= 0) { _glfwInputError(GLFW_INVALID_VALUE,@@ -530,8 +530,6 @@ ramp->size); return; }-- _GLFW_REQUIRE_INIT(); if (!monitor->originalRamp.size) {
glfw/src/nsgl_context.h view
@@ -25,8 +25,10 @@ //======================================================================== // NOTE: Many Cocoa enum values have been renamed and we need to build across-// SDK versions where one is unavailable or the other deprecated-// We use the newer names in code and these macros to handle compatibility+// SDK versions where one is unavailable or deprecated.+// We use the newer names in code and replace them with the older names if+// the base SDK does not provide the newer names.+ #if MAC_OS_X_VERSION_MAX_ALLOWED < 101400 #define NSOpenGLContextParameterSwapInterval NSOpenGLCPSwapInterval #define NSOpenGLContextParameterSurfaceOpacity NSOpenGLCPSurfaceOpacity@@ -44,7 +46,6 @@ { id pixelFormat; id object;- } _GLFWcontextNSGL; // NSGL-specific global data@@ -53,7 +54,6 @@ { // dlopen handle for OpenGL.framework (for glfwGetProcAddress) CFBundleRef framework;- } _GLFWlibraryNSGL;
glfw/src/nsgl_context.m view
@@ -51,7 +51,7 @@ // HACK: Simulate vsync with usleep as NSGL swap interval does not apply to // windows with a non-visible occlusion state- if (!([window->ns.object occlusionState] & NSWindowOcclusionStateVisible))+ if (window->ns.occluded) { int interval = 0; [window->context.nsgl.object getValues:&interval@@ -81,12 +81,11 @@ @autoreleasepool { _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot);- if (window)- {- [window->context.nsgl.object setValues:&interval- forParameter:NSOpenGLContextParameterSwapInterval];- }+ assert(window != NULL); + [window->context.nsgl.object setValues:&interval+ forParameter:NSOpenGLContextParameterSwapInterval];+ } // autoreleasepool } @@ -365,7 +364,7 @@ _GLFWwindow* window = (_GLFWwindow*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(nil); - if (window->context.client == GLFW_NO_API)+ if (window->context.source != GLFW_NATIVE_CONTEXT_API) { _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); return nil;
glfw/src/null_window.c view
@@ -67,6 +67,9 @@ _glfwInputError(GLFW_API_UNAVAILABLE, "Null: EGL not available"); return GLFW_FALSE; }++ if (!_glfwRefreshContextAttribs(window, ctxconfig))+ return GLFW_FALSE; } return GLFW_TRUE;
glfw/src/osmesa_context.c view
@@ -124,6 +124,8 @@ "libOSMesa.8.dylib", #elif defined(__CYGWIN__) "libOSMesa-8.so",+#elif defined(__OpenBSD__) || defined(__NetBSD__)+ "libOSMesa.so", #else "libOSMesa.so.8", "libOSMesa.so.6",@@ -302,6 +304,12 @@ _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE); + if (window->context.source != GLFW_OSMESA_CONTEXT_API)+ {+ _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);+ return GLFW_FALSE;+ }+ if (!OSMesaGetColorBuffer(window->context.osmesa.handle, &mesaWidth, &mesaHeight, &mesaFormat, &mesaBuffer))@@ -335,6 +343,12 @@ _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE); + if (window->context.source != GLFW_OSMESA_CONTEXT_API)+ {+ _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);+ return GLFW_FALSE;+ }+ if (!OSMesaGetDepthBuffer(window->context.osmesa.handle, &mesaWidth, &mesaHeight, &mesaBytes, &mesaBuffer))@@ -361,7 +375,7 @@ _GLFWwindow* window = (_GLFWwindow*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - if (window->context.client == GLFW_NO_API)+ if (window->context.source != GLFW_OSMESA_CONTEXT_API) { _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); return NULL;
glfw/src/vulkan.c view
@@ -59,6 +59,8 @@ _glfw.vk.handle = _glfw_dlopen("libvulkan.1.dylib"); if (!_glfw.vk.handle) _glfw.vk.handle = _glfwLoadLocalVulkanLoaderNS();+#elif defined(__OpenBSD__) || defined(__NetBSD__)+ _glfw.vk.handle = _glfw_dlopen("libvulkan.so"); #else _glfw.vk.handle = _glfw_dlopen("libvulkan.so.1"); #endif
glfw/src/wgl_context.c view
@@ -73,18 +73,13 @@ int attribs[40]; int values[sizeof(attribs) / sizeof(attribs[0])]; + nativeCount = DescribePixelFormat(window->context.wgl.dc,+ 1,+ sizeof(PIXELFORMATDESCRIPTOR),+ NULL);+ if (_glfw.wgl.ARB_pixel_format) {- const int attrib = WGL_NUMBER_PIXEL_FORMATS_ARB;-- if (!wglGetPixelFormatAttribivARB(window->context.wgl.dc,- 1, 0, 1, &attrib, &nativeCount))- {- _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,- "WGL: Failed to retrieve pixel format attribute");- return 0;- }- addAttrib(WGL_SUPPORT_OPENGL_ARB); addAttrib(WGL_DRAW_TO_WINDOW_ARB); addAttrib(WGL_PIXEL_TYPE_ARB);@@ -122,13 +117,6 @@ addAttrib(WGL_COLORSPACE_EXT); } }- else- {- nativeCount = DescribePixelFormat(window->context.wgl.dc,- 1,- sizeof(PIXELFORMATDESCRIPTOR),- NULL);- } usableConfigs = calloc(nativeCount, sizeof(_GLFWfbconfig)); @@ -165,6 +153,9 @@ if (findAttribValue(WGL_ACCELERATION_ARB) == WGL_NO_ACCELERATION_ARB) continue; + if (findAttribValue(WGL_DOUBLE_BUFFER_ARB) != fbconfig->doublebuffer)+ continue;+ u->redBits = findAttribValue(WGL_RED_BITS_ARB); u->greenBits = findAttribValue(WGL_GREEN_BITS_ARB); u->blueBits = findAttribValue(WGL_BLUE_BITS_ARB);@@ -182,8 +173,6 @@ if (findAttribValue(WGL_STEREO_ARB)) u->stereo = GLFW_TRUE;- if (findAttribValue(WGL_DOUBLE_BUFFER_ARB))- u->doublebuffer = GLFW_TRUE; if (_glfw.wgl.ARB_multisample) u->samples = findAttribValue(WGL_SAMPLES_ARB);@@ -239,6 +228,9 @@ if (pfd.iPixelType != PFD_TYPE_RGBA) continue; + if (!!(pfd.dwFlags & PFD_DOUBLEBUFFER) != fbconfig->doublebuffer)+ continue;+ u->redBits = pfd.cRedBits; u->greenBits = pfd.cGreenBits; u->blueBits = pfd.cBlueBits;@@ -256,8 +248,6 @@ if (pfd.dwFlags & PFD_STEREO) u->stereo = GLFW_TRUE;- if (pfd.dwFlags & PFD_DOUBLEBUFFER)- u->doublebuffer = GLFW_TRUE; } u->handle = pixelFormat;@@ -343,6 +333,7 @@ static void swapIntervalWGL(int interval) { _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot);+ assert(window != NULL); window->context.wgl.interval = interval; @@ -785,7 +776,7 @@ _GLFWwindow* window = (_GLFWwindow*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - if (window->context.client == GLFW_NO_API)+ if (window->context.source != GLFW_NATIVE_CONTEXT_API) { _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); return NULL;
glfw/src/wgl_context.h view
@@ -104,10 +104,6 @@ #define wglMakeCurrent _glfw.wgl.MakeCurrent #define wglShareLists _glfw.wgl.ShareLists -#define _GLFW_RECREATION_NOT_NEEDED 0-#define _GLFW_RECREATION_REQUIRED 1-#define _GLFW_RECREATION_IMPOSSIBLE 2- #define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextWGL wgl #define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE _GLFWlibraryWGL wgl @@ -119,7 +115,6 @@ HDC dc; HGLRC handle; int interval;- } _GLFWcontextWGL; // WGL-specific global data@@ -152,7 +147,6 @@ GLFWbool ARB_create_context_robustness; GLFWbool ARB_create_context_no_error; GLFWbool ARB_context_flush_control;- } _GLFWlibraryWGL;
glfw/src/win32_init.c view
@@ -39,6 +39,10 @@ #if defined(_GLFW_USE_HYBRID_HPG) || defined(_GLFW_USE_OPTIMUS_HPG) +#if defined(_GLFW_BUILD_DLL)+ #pragma message("These symbols must be exported by the executable and have no effect in a DLL")+#endif+ // Executables (but not DLLs) exporting this symbol with this value will be // automatically directed to the high-performance GPU on Nvidia Optimus systems // with up-to-date drivers@@ -68,17 +72,16 @@ // static GLFWbool loadLibraries(void) {- _glfw.win32.winmm.instance = LoadLibraryA("winmm.dll");- if (!_glfw.win32.winmm.instance)+ if (!GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |+ GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,+ (const WCHAR*) &_glfw,+ (HMODULE*) &_glfw.win32.instance)) { _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,- "Win32: Failed to load winmm.dll");+ "Win32: Failed to retrieve own module handle"); return GLFW_FALSE; } - _glfw.win32.winmm.GetTime = (PFN_timeGetTime)- GetProcAddress(_glfw.win32.winmm.instance, "timeGetTime");- _glfw.win32.user32.instance = LoadLibraryA("user32.dll"); if (!_glfw.win32.user32.instance) {@@ -99,6 +102,8 @@ GetProcAddress(_glfw.win32.user32.instance, "GetDpiForWindow"); _glfw.win32.user32.AdjustWindowRectExForDpi_ = (PFN_AdjustWindowRectExForDpi) GetProcAddress(_glfw.win32.user32.instance, "AdjustWindowRectExForDpi");+ _glfw.win32.user32.GetSystemMetricsForDpi_ = (PFN_GetSystemMetricsForDpi)+ GetProcAddress(_glfw.win32.user32.instance, "GetSystemMetricsForDpi"); _glfw.win32.dinput8.instance = LoadLibraryA("dinput8.dll"); if (_glfw.win32.dinput8.instance)@@ -143,6 +148,8 @@ GetProcAddress(_glfw.win32.dwmapi.instance, "DwmFlush"); _glfw.win32.dwmapi.EnableBlurBehindWindow = (PFN_DwmEnableBlurBehindWindow) GetProcAddress(_glfw.win32.dwmapi.instance, "DwmEnableBlurBehindWindow");+ _glfw.win32.dwmapi.GetColorizationColor = (PFN_DwmGetColorizationColor)+ GetProcAddress(_glfw.win32.dwmapi.instance, "DwmGetColorizationColor"); } _glfw.win32.shcore.instance = LoadLibraryA("shcore.dll");@@ -174,9 +181,6 @@ if (_glfw.win32.dinput8.instance) FreeLibrary(_glfw.win32.dinput8.instance); - if (_glfw.win32.winmm.instance)- FreeLibrary(_glfw.win32.winmm.instance);- if (_glfw.win32.user32.instance) FreeLibrary(_glfw.win32.user32.instance); @@ -260,7 +264,6 @@ _glfw.win32.keycodes[0x151] = GLFW_KEY_PAGE_DOWN; _glfw.win32.keycodes[0x149] = GLFW_KEY_PAGE_UP; _glfw.win32.keycodes[0x045] = GLFW_KEY_PAUSE;- _glfw.win32.keycodes[0x146] = GLFW_KEY_PAUSE; _glfw.win32.keycodes[0x039] = GLFW_KEY_SPACE; _glfw.win32.keycodes[0x00F] = GLFW_KEY_TAB; _glfw.win32.keycodes[0x03A] = GLFW_KEY_CAPS_LOCK;@@ -342,7 +345,7 @@ WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0, 0, 1, 1, NULL, NULL,- GetModuleHandleW(NULL),+ _glfw.win32.instance, NULL); if (!_glfw.win32.helperWindowHandle)@@ -492,7 +495,7 @@ vk = vks[key - GLFW_KEY_KP_0]; } else- vk = MapVirtualKey(scancode, MAPVK_VSC_TO_VK);+ vk = MapVirtualKeyW(scancode, MAPVK_VSC_TO_VK); length = ToUnicode(vk, scancode, state, chars, sizeof(chars) / sizeof(WCHAR),@@ -500,6 +503,8 @@ if (length == -1) {+ // This is a dead key, so we need a second simulated key press+ // to make it output its own character (usually a diacritic) length = ToUnicode(vk, scancode, state, chars, sizeof(chars) / sizeof(WCHAR), 0);@@ -515,7 +520,8 @@ } } -// Replacement for IsWindowsVersionOrGreater as MinGW lacks versionhelpers.h+// Replacement for IsWindowsVersionOrGreater, as we cannot rely on the+// application having a correct embedded manifest // BOOL _glfwIsWindowsVersionOrGreaterWin32(WORD major, WORD minor, WORD sp) {@@ -606,6 +612,7 @@ _glfwTerminateWGL(); _glfwTerminateEGL();+ _glfwTerminateOSMesa(); _glfwTerminateJoysticksWin32();
glfw/src/win32_joystick.c view
@@ -256,6 +256,8 @@ // static void closeJoystick(_GLFWjoystick* js) {+ _glfwInputJoystick(js, GLFW_DISCONNECTED);+ if (js->win32.device) { IDirectInputDevice8_Unacquire(js->win32.device);@@ -263,9 +265,7 @@ } free(js->win32.objects);- _glfwFreeJoystick(js);- _glfwInputJoystick(js, GLFW_DISCONNECTED); } // DirectInput device object enumeration callback@@ -356,8 +356,8 @@ for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) {- _GLFWjoystick* js = _glfw.joysticks + jid;- if (js->present)+ js = _glfw.joysticks + jid;+ if (js->connected) { if (memcmp(&js->win32.guid, &di->guidInstance, sizeof(GUID)) == 0) return DIENUM_CONTINUE;@@ -497,7 +497,7 @@ { if (_glfw.win32.dinput8.instance) {- if (FAILED(DirectInput8Create(GetModuleHandle(NULL),+ if (FAILED(DirectInput8Create(_glfw.win32.instance, DIRECTINPUT_VERSION, &IID_IDirectInput8W, (void**) &_glfw.win32.dinput8.api,@@ -541,7 +541,7 @@ for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) {- if (_glfw.joysticks[jid].present &&+ if (_glfw.joysticks[jid].connected && _glfw.joysticks[jid].win32.device == NULL && _glfw.joysticks[jid].win32.index == index) {@@ -593,7 +593,7 @@ for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) { _GLFWjoystick* js = _glfw.joysticks + jid;- if (js->present)+ if (js->connected) _glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE); } }@@ -609,7 +609,7 @@ { int i, ai = 0, bi = 0, pi = 0; HRESULT result;- DIJOYSTATE state;+ DIJOYSTATE state = {0}; IDirectInputDevice8_Poll(js->win32.device); result = IDirectInputDevice8_GetDeviceState(js->win32.device,@@ -672,11 +672,11 @@ }; // Screams of horror are appropriate at this point- int state = LOWORD(*(DWORD*) data) / (45 * DI_DEGREES);- if (state < 0 || state > 8)- state = 8;+ int stateIndex = LOWORD(*(DWORD*) data) / (45 * DI_DEGREES);+ if (stateIndex < 0 || stateIndex > 8)+ stateIndex = 8; - _glfwInputJoystickHat(js, pi, states[state]);+ _glfwInputJoystickHat(js, pi, states[stateIndex]); pi++; break; }@@ -735,6 +735,13 @@ dpad |= GLFW_HAT_DOWN; if (xis.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT) dpad |= GLFW_HAT_LEFT;++ // Treat invalid combinations as neither being pressed+ // while preserving what data can be preserved+ if ((dpad & GLFW_HAT_RIGHT) && (dpad & GLFW_HAT_LEFT))+ dpad &= ~(GLFW_HAT_RIGHT | GLFW_HAT_LEFT);+ if ((dpad & GLFW_HAT_UP) && (dpad & GLFW_HAT_DOWN))+ dpad &= ~(GLFW_HAT_UP | GLFW_HAT_DOWN); _glfwInputJoystickHat(js, 0, dpad); }
glfw/src/win32_joystick.h view
@@ -28,6 +28,7 @@ #define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE struct { int dummyLibraryJoystick; } #define _GLFW_PLATFORM_MAPPING_NAME "Windows"+#define GLFW_BUILD_WIN32_MAPPINGS // Joystick element (axis, button or slider) //
glfw/src/win32_monitor.c view
@@ -185,6 +185,8 @@ display.DeviceName) == 0) { disconnected[i] = NULL;+ // handle may have changed, update+ EnumDisplayMonitors(NULL, NULL, monitorCallback, (LPARAM) _glfw.monitors[i]); break; } }@@ -316,8 +318,19 @@ { UINT xdpi, ydpi; + if (xscale)+ *xscale = 0.f;+ if (yscale)+ *yscale = 0.f;+ if (IsWindows8Point1OrGreater())- GetDpiForMonitor(handle, MDT_EFFECTIVE_DPI, &xdpi, &ydpi);+ {+ if (GetDpiForMonitor(handle, MDT_EFFECTIVE_DPI, &xdpi, &ydpi) != S_OK)+ {+ _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to query monitor DPI");+ return;+ }+ } else { const HDC dc = GetDC(NULL);@@ -369,7 +382,7 @@ int* width, int* height) { MONITORINFO mi = { sizeof(mi) };- GetMonitorInfo(monitor->win32.handle, &mi);+ GetMonitorInfoW(monitor->win32.handle, &mi); if (xpos) *xpos = mi.rcWork.left;
glfw/src/win32_platform.h view
@@ -39,8 +39,8 @@ #endif // This is a workaround for the fact that glfw3.h needs to export APIENTRY (for-// example to allow applications to correctly declare a GL_ARB_debug_output-// callback) but windows.h assumes no one will define APIENTRY before it does+// example to allow applications to correctly declare a GL_KHR_debug callback)+// but windows.h assumes no one will define APIENTRY before it does #undef APIENTRY // GLFW on Windows is Unicode only and does not work in MBCS mode@@ -77,6 +77,9 @@ #ifndef WM_DWMCOMPOSITIONCHANGED #define WM_DWMCOMPOSITIONCHANGED 0x031E #endif+#ifndef WM_DWMCOLORIZATIONCOLORCHANGED+ #define WM_DWMCOLORIZATIONCOLORCHANGED 0x0320+#endif #ifndef WM_COPYGLOBALDATA #define WM_COPYGLOBALDATA 0x0049 #endif@@ -99,7 +102,7 @@ #define DISPLAY_DEVICE_ACTIVE 0x00000001 #endif #ifndef _WIN32_WINNT_WINBLUE- #define _WIN32_WINNT_WINBLUE 0x0602+ #define _WIN32_WINNT_WINBLUE 0x0603 #endif #ifndef _WIN32_WINNT_WIN8 #define _WIN32_WINNT_WIN8 0x0602@@ -159,7 +162,9 @@ #define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((HANDLE) -4) #endif /*DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2*/ -// HACK: Define versionhelpers.h functions manually as MinGW lacks the header+// Replacement for versionhelpers.h macros, as we cannot rely on the+// application having a correct embedded manifest+// #define IsWindowsXPOrGreater() \ _glfwIsWindowsVersionOrGreaterWin32(HIBYTE(_WIN32_WINNT_WINXP), \ LOBYTE(_WIN32_WINNT_WINXP), 0)@@ -215,10 +220,6 @@ #define DIDFT_OPTIONAL 0x80000000 #endif -// winmm.dll function pointer typedefs-typedef DWORD (WINAPI * PFN_timeGetTime)(void);-#define timeGetTime _glfw.win32.winmm.GetTime- // xinput.dll function pointer typedefs typedef DWORD (WINAPI * PFN_XInputGetCapabilities)(DWORD,DWORD,XINPUT_CAPABILITIES*); typedef DWORD (WINAPI * PFN_XInputGetState)(DWORD,XINPUT_STATE*);@@ -236,20 +237,24 @@ typedef BOOL (WINAPI * PFN_SetProcessDpiAwarenessContext)(HANDLE); typedef UINT (WINAPI * PFN_GetDpiForWindow)(HWND); typedef BOOL (WINAPI * PFN_AdjustWindowRectExForDpi)(LPRECT,DWORD,BOOL,DWORD,UINT);+typedef int (WINAPI * PFN_GetSystemMetricsForDpi)(int,UINT); #define SetProcessDPIAware _glfw.win32.user32.SetProcessDPIAware_ #define ChangeWindowMessageFilterEx _glfw.win32.user32.ChangeWindowMessageFilterEx_ #define EnableNonClientDpiScaling _glfw.win32.user32.EnableNonClientDpiScaling_ #define SetProcessDpiAwarenessContext _glfw.win32.user32.SetProcessDpiAwarenessContext_ #define GetDpiForWindow _glfw.win32.user32.GetDpiForWindow_ #define AdjustWindowRectExForDpi _glfw.win32.user32.AdjustWindowRectExForDpi_+#define GetSystemMetricsForDpi _glfw.win32.user32.GetSystemMetricsForDpi_ // dwmapi.dll function pointer typedefs typedef HRESULT (WINAPI * PFN_DwmIsCompositionEnabled)(BOOL*); typedef HRESULT (WINAPI * PFN_DwmFlush)(VOID); typedef HRESULT(WINAPI * PFN_DwmEnableBlurBehindWindow)(HWND,const DWM_BLURBEHIND*);+typedef HRESULT (WINAPI * PFN_DwmGetColorizationColor)(DWORD*,BOOL*); #define DwmIsCompositionEnabled _glfw.win32.dwmapi.IsCompositionEnabled #define DwmFlush _glfw.win32.dwmapi.Flush #define DwmEnableBlurBehindWindow _glfw.win32.dwmapi.EnableBlurBehindWindow+#define DwmGetColorizationColor _glfw.win32.dwmapi.GetColorizationColor // shcore.dll function pointer typedefs typedef HRESULT (WINAPI * PFN_SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS);@@ -316,15 +321,20 @@ GLFWbool transparent; GLFWbool scaleToMonitor; + // Cached size used to filter out duplicate events+ int width, height;+ // The last received cursor position, regardless of source int lastCursorPosX, lastCursorPosY;-+ // The last recevied high surrogate when decoding pairs of UTF-16 messages+ WCHAR highSurrogate; } _GLFWwindowWin32; // Win32-specific global data // typedef struct _GLFWlibraryWin32 {+ HINSTANCE instance; HWND helperWindowHandle; HDEVNOTIFY deviceNotificationHandle; DWORD foregroundLockTimeout;@@ -337,17 +347,14 @@ double restoreCursorPosX, restoreCursorPosY; // The window whose disabled cursor mode is active _GLFWwindow* disabledCursorWindow;+ // The window the cursor is captured in+ _GLFWwindow* capturedCursorWindow; RAWINPUT* rawInput; int rawInputSize; UINT mouseTrailSize; struct { HINSTANCE instance;- PFN_timeGetTime GetTime;- } winmm;-- struct {- HINSTANCE instance; PFN_DirectInput8Create Create; IDirectInput8W* api; } dinput8;@@ -366,6 +373,7 @@ PFN_SetProcessDpiAwarenessContext SetProcessDpiAwarenessContext_; PFN_GetDpiForWindow GetDpiForWindow_; PFN_AdjustWindowRectExForDpi AdjustWindowRectExForDpi_;+ PFN_GetSystemMetricsForDpi GetSystemMetricsForDpi_; } user32; struct {@@ -373,6 +381,7 @@ PFN_DwmIsCompositionEnabled IsCompositionEnabled; PFN_DwmFlush Flush; PFN_DwmEnableBlurBehindWindow EnableBlurBehindWindow;+ PFN_DwmGetColorizationColor GetColorizationColor; } dwmapi; struct {@@ -385,7 +394,6 @@ HINSTANCE instance; PFN_RtlVerifyVersionInfo RtlVerifyVersionInfo_; } ntdll;- } _GLFWlibraryWin32; // Win32-specific per-monitor data@@ -400,7 +408,6 @@ char publicDisplayName[32]; GLFWbool modesPruned; GLFWbool modeChanged;- } _GLFWmonitorWin32; // Win32-specific per-cursor data@@ -408,16 +415,13 @@ typedef struct _GLFWcursorWin32 { HCURSOR handle;- } _GLFWcursorWin32; // Win32-specific global timer data // typedef struct _GLFWtimerWin32 {- GLFWbool hasPC; uint64_t frequency;- } _GLFWtimerWin32; // Win32-specific thread local storage data@@ -426,7 +430,6 @@ { GLFWbool allocated; DWORD index;- } _GLFWtlsWin32; // Win32-specific mutex data@@ -435,7 +438,6 @@ { GLFWbool allocated; CRITICAL_SECTION section;- } _GLFWmutexWin32;
glfw/src/win32_time.c view
@@ -38,18 +38,7 @@ // void _glfwInitTimerWin32(void) {- uint64_t frequency;-- if (QueryPerformanceFrequency((LARGE_INTEGER*) &frequency))- {- _glfw.timer.win32.hasPC = GLFW_TRUE;- _glfw.timer.win32.frequency = frequency;- }- else- {- _glfw.timer.win32.hasPC = GLFW_FALSE;- _glfw.timer.win32.frequency = 1000;- }+ QueryPerformanceFrequency((LARGE_INTEGER*) &_glfw.timer.win32.frequency); } @@ -59,14 +48,9 @@ uint64_t _glfwPlatformGetTimerValue(void) {- if (_glfw.timer.win32.hasPC)- {- uint64_t value;- QueryPerformanceCounter((LARGE_INTEGER*) &value);- return value;- }- else- return (uint64_t) timeGetTime();+ uint64_t value;+ QueryPerformanceCounter((LARGE_INTEGER*) &value);+ return value; } uint64_t _glfwPlatformGetTimerFrequency(void)
glfw/src/win32_window.c view
@@ -186,53 +186,38 @@ return handle; } -// Translate content area size to full window size according to styles and DPI-//-static void getFullWindowSize(DWORD style, DWORD exStyle,- int contentWidth, int contentHeight,- int* fullWidth, int* fullHeight,- UINT dpi)-{- RECT rect = { 0, 0, contentWidth, contentHeight };-- if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())- AdjustWindowRectExForDpi(&rect, style, FALSE, exStyle, dpi);- else- AdjustWindowRectEx(&rect, style, FALSE, exStyle);-- *fullWidth = rect.right - rect.left;- *fullHeight = rect.bottom - rect.top;-}- // Enforce the content area aspect ratio based on which edge is being dragged // static void applyAspectRatio(_GLFWwindow* window, int edge, RECT* area) {- int xoff, yoff;- UINT dpi = USER_DEFAULT_SCREEN_DPI;+ RECT frame = {0}; const float ratio = (float) window->numer / (float) window->denom;+ const DWORD style = getWindowStyle(window);+ const DWORD exStyle = getWindowExStyle(window); if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())- dpi = GetDpiForWindow(window->win32.handle);-- getFullWindowSize(getWindowStyle(window), getWindowExStyle(window),- 0, 0, &xoff, &yoff, dpi);+ {+ AdjustWindowRectExForDpi(&frame, style, FALSE, exStyle,+ GetDpiForWindow(window->win32.handle));+ }+ else+ AdjustWindowRectEx(&frame, style, FALSE, exStyle); if (edge == WMSZ_LEFT || edge == WMSZ_BOTTOMLEFT || edge == WMSZ_RIGHT || edge == WMSZ_BOTTOMRIGHT) {- area->bottom = area->top + yoff +- (int) ((area->right - area->left - xoff) / ratio);+ area->bottom = area->top + (frame.bottom - frame.top) ++ (int) (((area->right - area->left) - (frame.right - frame.left)) / ratio); } else if (edge == WMSZ_TOPLEFT || edge == WMSZ_TOPRIGHT) {- area->top = area->bottom - yoff -- (int) ((area->right - area->left - xoff) / ratio);+ area->top = area->bottom - (frame.bottom - frame.top) -+ (int) (((area->right - area->left) - (frame.right - frame.left)) / ratio); } else if (edge == WMSZ_TOP || edge == WMSZ_BOTTOM) {- area->right = area->left + xoff +- (int) ((area->bottom - area->top - yoff) * ratio);+ area->right = area->left + (frame.right - frame.left) ++ (int) (((area->bottom - area->top) - (frame.bottom - frame.top)) * ratio); } } @@ -251,22 +236,26 @@ SetCursor(NULL); } -// Updates the cursor clip rect+// Sets the cursor clip rect to the window content area //-static void updateClipRect(_GLFWwindow* window)+static void captureCursor(_GLFWwindow* window) {- if (window)- {- RECT clipRect;- GetClientRect(window->win32.handle, &clipRect);- ClientToScreen(window->win32.handle, (POINT*) &clipRect.left);- ClientToScreen(window->win32.handle, (POINT*) &clipRect.right);- ClipCursor(&clipRect);- }- else- ClipCursor(NULL);+ RECT clipRect;+ GetClientRect(window->win32.handle, &clipRect);+ ClientToScreen(window->win32.handle, (POINT*) &clipRect.left);+ ClientToScreen(window->win32.handle, (POINT*) &clipRect.right);+ ClipCursor(&clipRect);+ _glfw.win32.capturedCursorWindow = window; } +// Disabled clip cursor+//+static void releaseCursor(void)+{+ ClipCursor(NULL);+ _glfw.win32.capturedCursorWindow = NULL;+}+ // Enables WM_INPUT messages for the mouse for the specified window // static void enableRawMouseMotion(_GLFWwindow* window)@@ -303,7 +292,7 @@ &_glfw.win32.restoreCursorPosY); updateCursorImage(window); _glfwCenterCursorInContentArea(window);- updateClipRect(window);+ captureCursor(window); if (window->rawMouseMotion) enableRawMouseMotion(window);@@ -317,7 +306,7 @@ disableRawMouseMotion(window); _glfw.win32.disabledCursorWindow = NULL;- updateClipRect(NULL);+ releaseCursor(); _glfwPlatformSetCursorPos(window, _glfw.win32.restoreCursorPosX, _glfw.win32.restoreCursorPosY);@@ -377,12 +366,17 @@ // static void updateFramebufferTransparency(const _GLFWwindow* window) {- BOOL enabled;+ BOOL composition, opaque;+ DWORD color; if (!IsWindowsVistaOrGreater()) return; - if (SUCCEEDED(DwmIsCompositionEnabled(&enabled)) && enabled)+ if (FAILED(DwmIsCompositionEnabled(&composition)) || !composition)+ return;++ if (IsWindows8OrGreater() ||+ (SUCCEEDED(DwmGetColorizationColor(&color, &opaque)) && !opaque)) { HRGN region = CreateRectRgn(0, 0, -1, -1); DWM_BLURBEHIND bb = {0};@@ -390,37 +384,18 @@ bb.hRgnBlur = region; bb.fEnable = TRUE; - if (SUCCEEDED(DwmEnableBlurBehindWindow(window->win32.handle, &bb)))- {- // Decorated windows don't repaint the transparent background- // leaving a trail behind animations- // HACK: Making the window layered with a transparency color key- // seems to fix this. Normally, when specifying- // a transparency color key to be used when composing the- // layered window, all pixels painted by the window in this- // color will be transparent. That doesn't seem to be the- // case anymore, at least when used with blur behind window- // plus negative region.- LONG exStyle = GetWindowLongW(window->win32.handle, GWL_EXSTYLE);- exStyle |= WS_EX_LAYERED;- SetWindowLongW(window->win32.handle, GWL_EXSTYLE, exStyle);-- // Using a color key not equal to black to fix the trailing- // issue. When set to black, something is making the hit test- // not resize with the window frame.- SetLayeredWindowAttributes(window->win32.handle,- RGB(255, 0, 255), 255, LWA_COLORKEY);- }-+ DwmEnableBlurBehindWindow(window->win32.handle, &bb); DeleteObject(region); } else {- LONG exStyle = GetWindowLongW(window->win32.handle, GWL_EXSTYLE);- exStyle &= ~WS_EX_LAYERED;- SetWindowLongW(window->win32.handle, GWL_EXSTYLE, exStyle);- RedrawWindow(window->win32.handle, NULL, NULL,- RDW_ERASE | RDW_INVALIDATE | RDW_FRAME);+ // HACK: Disable framebuffer transparency on Windows 7 when the+ // colorization color is opaque, because otherwise the window+ // contents is blended additively with the previous frame instead+ // of replacing it+ DWM_BLURBEHIND bb = {0};+ bb.dwFlags = DWM_BB_ENABLE;+ DwmEnableBlurBehindWindow(window->win32.handle, &bb); } } @@ -449,7 +424,7 @@ static void fitToMonitor(_GLFWwindow* window) { MONITORINFO mi = { sizeof(mi) };- GetMonitorInfo(window->monitor->win32.handle, &mi);+ GetMonitorInfoW(window->monitor->win32.handle, &mi); SetWindowPos(window->win32.handle, HWND_TOPMOST, mi.rcMonitor.left, mi.rcMonitor.top,@@ -470,8 +445,8 @@ // the OpenGL ICD switches to page flipping if (IsWindowsXPOrGreater()) {- SystemParametersInfo(SPI_GETMOUSETRAILS, 0, &_glfw.win32.mouseTrailSize, 0);- SystemParametersInfo(SPI_SETMOUSETRAILS, 0, 0, 0);+ SystemParametersInfoW(SPI_GETMOUSETRAILS, 0, &_glfw.win32.mouseTrailSize, 0);+ SystemParametersInfoW(SPI_SETMOUSETRAILS, 0, 0, 0); } } @@ -496,13 +471,63 @@ // HACK: Restore mouse trail length saved in acquireMonitor if (IsWindowsXPOrGreater())- SystemParametersInfo(SPI_SETMOUSETRAILS, _glfw.win32.mouseTrailSize, 0, 0);+ SystemParametersInfoW(SPI_SETMOUSETRAILS, _glfw.win32.mouseTrailSize, 0, 0); } _glfwInputMonitorWindow(window->monitor, NULL); _glfwRestoreVideoModeWin32(window->monitor); } +// Manually maximize the window, for when SW_MAXIMIZE cannot be used+//+static void maximizeWindowManually(_GLFWwindow* window)+{+ RECT rect;+ DWORD style;+ MONITORINFO mi = { sizeof(mi) };++ GetMonitorInfoW(MonitorFromWindow(window->win32.handle,+ MONITOR_DEFAULTTONEAREST), &mi);++ rect = mi.rcWork;++ if (window->maxwidth != GLFW_DONT_CARE && window->maxheight != GLFW_DONT_CARE)+ {+ rect.right = _glfw_min(rect.right, rect.left + window->maxwidth);+ rect.bottom = _glfw_min(rect.bottom, rect.top + window->maxheight);+ }++ style = GetWindowLongW(window->win32.handle, GWL_STYLE);+ style |= WS_MAXIMIZE;+ SetWindowLongW(window->win32.handle, GWL_STYLE, style);++ if (window->decorated)+ {+ const DWORD exStyle = GetWindowLongW(window->win32.handle, GWL_EXSTYLE);++ if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())+ {+ const UINT dpi = GetDpiForWindow(window->win32.handle);+ AdjustWindowRectExForDpi(&rect, style, FALSE, exStyle, dpi);+ OffsetRect(&rect, 0, GetSystemMetricsForDpi(SM_CYCAPTION, dpi));+ }+ else+ {+ AdjustWindowRectEx(&rect, style, FALSE, exStyle);+ OffsetRect(&rect, 0, GetSystemMetrics(SM_CYCAPTION));+ }++ rect.bottom = _glfw_min(rect.bottom, mi.rcWork.bottom);+ }++ SetWindowPos(window->win32.handle, HWND_TOP,+ rect.left,+ rect.top,+ rect.right - rect.left,+ rect.bottom - rect.top,+ SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED);+}+ // Window callback function (handles window messages) // static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,@@ -519,8 +544,18 @@ case WM_NCCREATE: { if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())- EnableNonClientDpiScaling(hWnd);+ {+ const CREATESTRUCTW* cs = (const CREATESTRUCTW*) lParam;+ const _GLFWwndconfig* wndconfig = cs->lpCreateParams; + // On per-monitor DPI aware V1 systems, only enable+ // non-client scaling for windows that scale the client area+ // We need WM_GETDPISCALEDSIZE from V2 to keep the client+ // area static when the non-client area is scaled+ if (wndconfig && wndconfig->scaleToMonitor)+ EnableNonClientDpiScaling(hWnd);+ }+ break; } @@ -645,11 +680,35 @@ case WM_CHAR: case WM_SYSCHAR:- case WM_UNICHAR: {- const GLFWbool plain = (uMsg != WM_SYSCHAR);+ if (wParam >= 0xd800 && wParam <= 0xdbff)+ window->win32.highSurrogate = (WCHAR) wParam;+ else+ {+ uint32_t codepoint = 0; - if (uMsg == WM_UNICHAR && wParam == UNICODE_NOCHAR)+ if (wParam >= 0xdc00 && wParam <= 0xdfff)+ {+ if (window->win32.highSurrogate)+ {+ codepoint += (window->win32.highSurrogate - 0xd800) << 10;+ codepoint += (WCHAR) wParam - 0xdc00;+ codepoint += 0x10000;+ }+ }+ else+ codepoint = (WCHAR) wParam;++ window->win32.highSurrogate = 0;+ _glfwInputChar(window, codepoint, getKeyMods(), uMsg != WM_SYSCHAR);+ }++ return 0;+ }++ case WM_UNICHAR:+ {+ if (wParam == UNICODE_NOCHAR) { // WM_UNICHAR is not sent by Windows, but is sent by some // third-party input method engine@@ -657,7 +716,7 @@ return TRUE; } - _glfwInputChar(window, (unsigned int) wParam, getKeyMods(), plain);+ _glfwInputChar(window, (uint32_t) wParam, getKeyMods(), GLFW_TRUE); return 0; } @@ -678,6 +737,18 @@ scancode = MapVirtualKeyW((UINT) wParam, MAPVK_VK_TO_VSC); } + // HACK: Alt+PrtSc has a different scancode than just PrtSc+ if (scancode == 0x54)+ scancode = 0x137;++ // HACK: Ctrl+Pause has a different scancode than just Pause+ if (scancode == 0x146)+ scancode = 0x45;++ // HACK: CJK IME sets the extended bit for right Shift+ if (scancode == 0x136)+ scancode = 0x36;+ key = _glfw.win32.keycodes[scancode]; // The Ctrl keys require special handling@@ -944,13 +1015,15 @@ case WM_SIZE: {+ const int width = LOWORD(lParam);+ const int height = HIWORD(lParam); const GLFWbool iconified = wParam == SIZE_MINIMIZED; const GLFWbool maximized = wParam == SIZE_MAXIMIZED || (window->win32.maximized && wParam != SIZE_RESTORED); - if (_glfw.win32.disabledCursorWindow == window)- updateClipRect(window);+ if (_glfw.win32.capturedCursorWindow == window)+ captureCursor(window); if (window->win32.iconified != iconified) _glfwInputWindowIconify(window, iconified);@@ -958,9 +1031,15 @@ if (window->win32.maximized != maximized) _glfwInputWindowMaximize(window, maximized); - _glfwInputFramebufferSize(window, LOWORD(lParam), HIWORD(lParam));- _glfwInputWindowSize(window, LOWORD(lParam), HIWORD(lParam));+ if (width != window->win32.width || height != window->win32.height)+ {+ window->win32.width = width;+ window->win32.height = height; + _glfwInputFramebufferSize(window, width, height);+ _glfwInputWindowSize(window, width, height);+ }+ if (window->monitor && window->win32.iconified != iconified) { if (iconified)@@ -979,8 +1058,8 @@ case WM_MOVE: {- if (_glfw.win32.disabledCursorWindow == window)- updateClipRect(window);+ if (_glfw.win32.capturedCursorWindow == window)+ captureCursor(window); // NOTE: This cannot use LOWORD/HIWORD recommended by MSDN, as // those macros do not handle negative window positions correctly@@ -1004,31 +1083,34 @@ case WM_GETMINMAXINFO: {- int xoff, yoff;- UINT dpi = USER_DEFAULT_SCREEN_DPI;+ RECT frame = {0}; MINMAXINFO* mmi = (MINMAXINFO*) lParam;+ const DWORD style = getWindowStyle(window);+ const DWORD exStyle = getWindowExStyle(window); if (window->monitor) break; if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())- dpi = GetDpiForWindow(window->win32.handle);-- getFullWindowSize(getWindowStyle(window), getWindowExStyle(window),- 0, 0, &xoff, &yoff, dpi);+ {+ AdjustWindowRectExForDpi(&frame, style, FALSE, exStyle,+ GetDpiForWindow(window->win32.handle));+ }+ else+ AdjustWindowRectEx(&frame, style, FALSE, exStyle); if (window->minwidth != GLFW_DONT_CARE && window->minheight != GLFW_DONT_CARE) {- mmi->ptMinTrackSize.x = window->minwidth + xoff;- mmi->ptMinTrackSize.y = window->minheight + yoff;+ mmi->ptMinTrackSize.x = window->minwidth + frame.right - frame.left;+ mmi->ptMinTrackSize.y = window->minheight + frame.bottom - frame.top; } if (window->maxwidth != GLFW_DONT_CARE && window->maxheight != GLFW_DONT_CARE) {- mmi->ptMaxTrackSize.x = window->maxwidth + xoff;- mmi->ptMaxTrackSize.y = window->maxheight + yoff;+ mmi->ptMaxTrackSize.x = window->maxwidth + frame.right - frame.left;+ mmi->ptMaxTrackSize.y = window->maxheight + frame.bottom - frame.top; } if (!window->decorated)@@ -1039,7 +1121,7 @@ ZeroMemory(&mi, sizeof(mi)); mi.cbSize = sizeof(mi);- GetMonitorInfo(mh, &mi);+ GetMonitorInfoW(mh, &mi); mmi->ptMaxPosition.x = mi.rcWork.left - mi.rcMonitor.left; mmi->ptMaxPosition.y = mi.rcWork.top - mi.rcMonitor.top;@@ -1073,6 +1155,7 @@ } case WM_DWMCOMPOSITIONCHANGED:+ case WM_DWMCOLORIZATIONCOLORCHANGED: { if (window->win32.transparent) updateFramebufferTransparency(window);@@ -1112,9 +1195,11 @@ const float xscale = HIWORD(wParam) / (float) USER_DEFAULT_SCREEN_DPI; const float yscale = LOWORD(wParam) / (float) USER_DEFAULT_SCREEN_DPI; - // Only apply the suggested size if the OS is new enough to have- // sent a WM_GETDPISCALEDSIZE before this- if (_glfwIsWindows10CreatorsUpdateOrGreaterWin32())+ // Resize windowed mode windows that either permit rescaling or that+ // need it to compensate for non-client area scaling+ if (!window->monitor &&+ (window->win32.scaleToMonitor ||+ _glfwIsWindows10CreatorsUpdateOrGreaterWin32())) { RECT* suggested = (RECT*) lParam; SetWindowPos(window->win32.handle, HWND_TOP,@@ -1184,36 +1269,38 @@ const _GLFWwndconfig* wndconfig, const _GLFWfbconfig* fbconfig) {- int xpos, ypos, fullWidth, fullHeight;+ int frameX, frameY, frameWidth, frameHeight; WCHAR* wideTitle; DWORD style = getWindowStyle(window); DWORD exStyle = getWindowExStyle(window); if (window->monitor) {- GLFWvidmode mode;+ MONITORINFO mi = { sizeof(mi) };+ GetMonitorInfoW(window->monitor->win32.handle, &mi); // NOTE: This window placement is temporary and approximate, as the // correct position and size cannot be known until the monitor // video mode has been picked in _glfwSetVideoModeWin32- _glfwPlatformGetMonitorPos(window->monitor, &xpos, &ypos);- _glfwPlatformGetVideoMode(window->monitor, &mode);- fullWidth = mode.width;- fullHeight = mode.height;+ frameX = mi.rcMonitor.left;+ frameY = mi.rcMonitor.top;+ frameWidth = mi.rcMonitor.right - mi.rcMonitor.left;+ frameHeight = mi.rcMonitor.bottom - mi.rcMonitor.top; } else {- xpos = CW_USEDEFAULT;- ypos = CW_USEDEFAULT;+ RECT rect = { 0, 0, wndconfig->width, wndconfig->height }; window->win32.maximized = wndconfig->maximized; if (wndconfig->maximized) style |= WS_MAXIMIZE; - getFullWindowSize(style, exStyle,- wndconfig->width, wndconfig->height,- &fullWidth, &fullHeight,- USER_DEFAULT_SCREEN_DPI);+ AdjustWindowRectEx(&rect, style, FALSE, exStyle);++ frameX = CW_USEDEFAULT;+ frameY = CW_USEDEFAULT;+ frameWidth = rect.right - rect.left;+ frameHeight = rect.bottom - rect.top; } wideTitle = _glfwCreateWideStringFromUTF8Win32(wndconfig->title);@@ -1224,12 +1311,12 @@ _GLFW_WNDCLASSNAME, wideTitle, style,- xpos, ypos,- fullWidth, fullHeight,+ frameX, frameY,+ frameWidth, frameHeight, NULL, // No parent window NULL, // No window menu- GetModuleHandleW(NULL),- NULL);+ _glfw.win32.instance,+ (LPVOID) wndconfig); free(wideTitle); @@ -1254,24 +1341,29 @@ window->win32.scaleToMonitor = wndconfig->scaleToMonitor; - // Adjust window rect to account for DPI scaling of the window frame and- // (if enabled) DPI scaling of the content area- // This cannot be done until we know what monitor the window was placed on if (!window->monitor) { RECT rect = { 0, 0, wndconfig->width, wndconfig->height }; WINDOWPLACEMENT wp = { sizeof(wp) };+ const HMONITOR mh = MonitorFromWindow(window->win32.handle,+ MONITOR_DEFAULTTONEAREST); + // Adjust window rect to account for DPI scaling of the window frame and+ // (if enabled) DPI scaling of the content area+ // This cannot be done until we know what monitor the window was placed on+ // Only update the restored window rect as the window may be maximized+ if (wndconfig->scaleToMonitor) { float xscale, yscale;- _glfwPlatformGetWindowContentScale(window, &xscale, &yscale);- rect.right = (int) (rect.right * xscale);- rect.bottom = (int) (rect.bottom * yscale);- }+ _glfwGetMonitorContentScaleWin32(mh, &xscale, &yscale); - ClientToScreen(window->win32.handle, (POINT*) &rect.left);- ClientToScreen(window->win32.handle, (POINT*) &rect.right);+ if (xscale > 0.f && yscale > 0.f)+ {+ rect.right = (int) (rect.right * xscale);+ rect.bottom = (int) (rect.bottom * yscale);+ }+ } if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) {@@ -1281,11 +1373,30 @@ else AdjustWindowRectEx(&rect, style, FALSE, exStyle); - // Only update the restored window rect as the window may be maximized GetWindowPlacement(window->win32.handle, &wp);+ OffsetRect(&rect,+ wp.rcNormalPosition.left - rect.left,+ wp.rcNormalPosition.top - rect.top);+ wp.rcNormalPosition = rect; wp.showCmd = SW_HIDE; SetWindowPlacement(window->win32.handle, &wp);++ // Adjust rect of maximized undecorated window, because by default Windows will+ // make such a window cover the whole monitor instead of its workarea++ if (wndconfig->maximized && !wndconfig->decorated)+ {+ MONITORINFO mi = { sizeof(mi) };+ GetMonitorInfoW(mh, &mi);++ SetWindowPos(window->win32.handle, HWND_TOP,+ mi.rcWork.left,+ mi.rcWork.top,+ mi.rcWork.right - mi.rcWork.left,+ mi.rcWork.bottom - mi.rcWork.top,+ SWP_NOACTIVATE | SWP_NOZORDER);+ } } DragAcceptFiles(window->win32.handle, TRUE);@@ -1296,6 +1407,8 @@ window->win32.transparent = GLFW_TRUE; } + _glfwPlatformGetWindowSize(window, &window->win32.width, &window->win32.height);+ return GLFW_TRUE; } @@ -1313,8 +1426,8 @@ ZeroMemory(&wc, sizeof(wc)); wc.cbSize = sizeof(wc); wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;- wc.lpfnWndProc = (WNDPROC) windowProc;- wc.hInstance = GetModuleHandleW(NULL);+ wc.lpfnWndProc = windowProc;+ wc.hInstance = _glfw.win32.instance; wc.hCursor = LoadCursorW(NULL, IDC_ARROW); wc.lpszClassName = _GLFW_WNDCLASSNAME; @@ -1344,7 +1457,7 @@ // void _glfwUnregisterWindowClassWin32(void) {- UnregisterClassW(_GLFW_WNDCLASSNAME, GetModuleHandleW(NULL));+ UnregisterClassW(_GLFW_WNDCLASSNAME, _glfw.win32.instance); } @@ -1383,6 +1496,9 @@ if (!_glfwCreateContextOSMesa(window, ctxconfig, fbconfig)) return GLFW_FALSE; }++ if (!_glfwRefreshContextAttribs(window, ctxconfig))+ return GLFW_FALSE; } if (window->monitor)@@ -1391,7 +1507,19 @@ _glfwPlatformFocusWindow(window); acquireMonitor(window); fitToMonitor(window);++ if (wndconfig->centerCursor)+ _glfwCenterCursorInContentArea(window); }+ else+ {+ if (wndconfig->visible)+ {+ _glfwPlatformShowWindow(window);+ if (wndconfig->focused)+ _glfwPlatformFocusWindow(window);+ }+ } return GLFW_TRUE; }@@ -1405,8 +1533,11 @@ window->context.destroy(window); if (_glfw.win32.disabledCursorWindow == window)- _glfw.win32.disabledCursorWindow = NULL;+ enableCursor(window); + if (_glfw.win32.capturedCursorWindow == window)+ releaseCursor();+ if (window->win32.handle) { RemovePropW(window->win32.handle, L"GLFW");@@ -1454,8 +1585,8 @@ smallIcon = (HICON) GetClassLongPtrW(window->win32.handle, GCLP_HICONSM); } - SendMessage(window->win32.handle, WM_SETICON, ICON_BIG, (LPARAM) bigIcon);- SendMessage(window->win32.handle, WM_SETICON, ICON_SMALL, (LPARAM) smallIcon);+ SendMessageW(window->win32.handle, WM_SETICON, ICON_BIG, (LPARAM) bigIcon);+ SendMessageW(window->win32.handle, WM_SETICON, ICON_SMALL, (LPARAM) smallIcon); if (window->win32.bigIcon) DestroyIcon(window->win32.bigIcon);@@ -1635,7 +1766,10 @@ void _glfwPlatformMaximizeWindow(_GLFWwindow* window) {- ShowWindow(window->win32.handle, SW_MAXIMIZE);+ if (IsWindowVisible(window->win32.handle))+ ShowWindow(window->win32.handle, SW_MAXIMIZE);+ else+ maximizeWindowManually(window); } void _glfwPlatformShowWindow(_GLFWwindow* window)@@ -1722,7 +1856,7 @@ acquireMonitor(window); - GetMonitorInfo(window->monitor->win32.handle, &mi);+ GetMonitorInfoW(window->monitor->win32.handle, &mi); SetWindowPos(window->win32.handle, HWND_TOPMOST, mi.rcMonitor.left, mi.rcMonitor.top,@@ -1797,7 +1931,8 @@ int _glfwPlatformFramebufferTransparent(_GLFWwindow* window) {- BOOL enabled;+ BOOL composition, opaque;+ DWORD color; if (!window->win32.transparent) return GLFW_FALSE;@@ -1805,7 +1940,20 @@ if (!IsWindowsVistaOrGreater()) return GLFW_FALSE; - return SUCCEEDED(DwmIsCompositionEnabled(&enabled)) && enabled;+ if (FAILED(DwmIsCompositionEnabled(&composition)) || !composition)+ return GLFW_FALSE;++ if (!IsWindows8OrGreater())+ {+ // HACK: Disable framebuffer transparency on Windows 7 when the+ // colorization color is opaque, because otherwise the window+ // contents is blended additively with the previous frame instead+ // of replacing it+ if (FAILED(DwmGetColorizationColor(&color, &opaque)) || opaque)+ return GLFW_FALSE;+ }++ return GLFW_TRUE; } void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled)@@ -1965,14 +2113,14 @@ void _glfwPlatformWaitEventsTimeout(double timeout) {- MsgWaitForMultipleObjects(0, NULL, FALSE, (DWORD) (timeout * 1e3), QS_ALLEVENTS);+ MsgWaitForMultipleObjects(0, NULL, FALSE, (DWORD) (timeout * 1e3), QS_ALLINPUT); _glfwPlatformPollEvents(); } void _glfwPlatformPostEmptyEvent(void) {- PostMessage(_glfw.win32.helperWindowHandle, WM_NULL, 0, 0);+ PostMessageW(_glfw.win32.helperWindowHandle, WM_NULL, 0, 0); } void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos)@@ -2004,14 +2152,40 @@ void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) {- if (mode == GLFW_CURSOR_DISABLED)+ if (_glfwPlatformWindowFocused(window)) {- if (_glfwPlatformWindowFocused(window))- disableCursor(window);+ if (mode == GLFW_CURSOR_DISABLED)+ {+ _glfwPlatformGetCursorPos(window,+ &_glfw.win32.restoreCursorPosX,+ &_glfw.win32.restoreCursorPosY);+ _glfwCenterCursorInContentArea(window);+ if (window->rawMouseMotion)+ enableRawMouseMotion(window);+ }+ else if (_glfw.win32.disabledCursorWindow == window)+ {+ if (window->rawMouseMotion)+ disableRawMouseMotion(window);+ }++ if (mode == GLFW_CURSOR_DISABLED)+ captureCursor(window);+ else+ releaseCursor();++ if (mode == GLFW_CURSOR_DISABLED)+ _glfw.win32.disabledCursorWindow = window;+ else if (_glfw.win32.disabledCursorWindow == window)+ {+ _glfw.win32.disabledCursorWindow = NULL;+ _glfwPlatformSetCursorPos(window,+ _glfw.win32.restoreCursorPosX,+ _glfw.win32.restoreCursorPosY);+ } }- else if (_glfw.win32.disabledCursorWindow == window)- enableCursor(window);- else if (cursorInContentArea(window))++ if (cursorInContentArea(window)) updateCursorImage(window); } @@ -2020,7 +2194,7 @@ if (scancode < 0 || scancode > (KF_EXTENDED | 0xff) || _glfw.win32.keycodes[scancode] == GLFW_KEY_UNKNOWN) {- _glfwInputError(GLFW_INVALID_VALUE, "Invalid scancode");+ _glfwInputError(GLFW_INVALID_VALUE, "Invalid scancode %i", scancode); return NULL; } @@ -2216,7 +2390,7 @@ memset(&sci, 0, sizeof(sci)); sci.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;- sci.hinstance = GetModuleHandle(NULL);+ sci.hinstance = _glfw.win32.instance; sci.hwnd = window->win32.handle; err = vkCreateWin32SurfaceKHR(instance, &sci, allocator, surface);
glfw/src/window.c view
@@ -205,6 +205,8 @@ window->focusOnShow = wndconfig.focusOnShow; window->cursorMode = GLFW_CURSOR_NORMAL; + window->doublebuffer = fbconfig.doublebuffer;+ window->minwidth = GLFW_DONT_CARE; window->minheight = GLFW_DONT_CARE; window->maxwidth = GLFW_DONT_CARE;@@ -219,30 +221,6 @@ return NULL; } - if (ctxconfig.client != GLFW_NO_API)- {- if (!_glfwRefreshContextAttribs(window, &ctxconfig))- {- glfwDestroyWindow((GLFWwindow*) window);- return NULL;- }- }-- if (window->monitor)- {- if (wndconfig.centerCursor)- _glfwCenterCursorInContentArea(window);- }- else- {- if (wndconfig.visible)- {- _glfwPlatformShowWindow(window);- if (wndconfig.focused)- _glfwPlatformFocusWindow(window);- }- }- return (GLFWwindow*) window; } @@ -502,12 +480,33 @@ GLFWAPI void glfwSetWindowIcon(GLFWwindow* handle, int count, const GLFWimage* images) {+ int i; _GLFWwindow* window = (_GLFWwindow*) handle;+ assert(window != NULL); assert(count >= 0); assert(count == 0 || images != NULL); _GLFW_REQUIRE_INIT();++ if (count < 0)+ {+ _glfwInputError(GLFW_INVALID_VALUE, "Invalid image count for window icon");+ return;+ }++ for (i = 0; i < count; i++)+ {+ assert(images[i].pixels != NULL);++ if (images[i].width <= 0 || images[i].height <= 0)+ {+ _glfwInputError(GLFW_INVALID_VALUE,+ "Invalid image dimensions for window icon");+ return;+ }+ }+ _glfwPlatformSetWindowIcon(window, count, images); } @@ -1099,3 +1098,4 @@ _GLFW_REQUIRE_INIT(); _glfwPlatformPostEmptyEvent(); }+
glfw/src/wl_init.c view
@@ -26,1286 +26,713 @@ // It is fine to use C99 in this file because it will not be built with VS //======================================================================== -#include "internal.h"--#include <assert.h>-#include <errno.h>-#include <limits.h>-#include <linux/input.h>-#include <stdio.h>-#include <stdlib.h>-#include <string.h>-#include <sys/mman.h>-#include <sys/timerfd.h>-#include <unistd.h>-#include <wayland-client.h>---static inline int min(int n1, int n2)-{- return n1 < n2 ? n1 : n2;-}--static _GLFWwindow* findWindowFromDecorationSurface(struct wl_surface* surface,- int* which)-{- int focus;- _GLFWwindow* window = _glfw.windowListHead;- if (!which)- which = &focus;- while (window)- {- if (surface == window->wl.decorations.top.surface)- {- *which = topDecoration;- break;- }- if (surface == window->wl.decorations.left.surface)- {- *which = leftDecoration;- break;- }- if (surface == window->wl.decorations.right.surface)- {- *which = rightDecoration;- break;- }- if (surface == window->wl.decorations.bottom.surface)- {- *which = bottomDecoration;- break;- }- window = window->next;- }- return window;-}--static void pointerHandleEnter(void* data,- struct wl_pointer* pointer,- uint32_t serial,- struct wl_surface* surface,- wl_fixed_t sx,- wl_fixed_t sy)-{- // Happens in the case we just destroyed the surface.- if (!surface)- return;-- int focus = 0;- _GLFWwindow* window = wl_surface_get_user_data(surface);- if (!window)- {- window = findWindowFromDecorationSurface(surface, &focus);- if (!window)- return;- }-- window->wl.decorations.focus = focus;- _glfw.wl.serial = serial;- _glfw.wl.pointerFocus = window;-- window->wl.hovered = GLFW_TRUE;-- _glfwPlatformSetCursor(window, window->wl.currentCursor);- _glfwInputCursorEnter(window, GLFW_TRUE);-}--static void pointerHandleLeave(void* data,- struct wl_pointer* pointer,- uint32_t serial,- struct wl_surface* surface)-{- _GLFWwindow* window = _glfw.wl.pointerFocus;-- if (!window)- return;-- window->wl.hovered = GLFW_FALSE;-- _glfw.wl.serial = serial;- _glfw.wl.pointerFocus = NULL;- _glfwInputCursorEnter(window, GLFW_FALSE);- _glfw.wl.cursorPreviousName = NULL;-}--static void setCursor(_GLFWwindow* window, const char* name)-{- struct wl_buffer* buffer;- struct wl_cursor* cursor;- struct wl_cursor_image* image;- struct wl_surface* surface = _glfw.wl.cursorSurface;- struct wl_cursor_theme* theme = _glfw.wl.cursorTheme;- int scale = 1;-- if (window->wl.scale > 1 && _glfw.wl.cursorThemeHiDPI)- {- // We only support up to scale=2 for now, since libwayland-cursor- // requires us to load a different theme for each size.- scale = 2;- theme = _glfw.wl.cursorThemeHiDPI;- }-- cursor = wl_cursor_theme_get_cursor(theme, name);- if (!cursor)- {- _glfwInputError(GLFW_PLATFORM_ERROR,- "Wayland: Standard cursor not found");- return;- }- // TODO: handle animated cursors too.- image = cursor->images[0];-- if (!image)- return;-- buffer = wl_cursor_image_get_buffer(image);- if (!buffer)- return;- wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.serial,- surface,- image->hotspot_x / scale,- image->hotspot_y / scale);- wl_surface_set_buffer_scale(surface, scale);- wl_surface_attach(surface, buffer, 0, 0);- wl_surface_damage(surface, 0, 0,- image->width, image->height);- wl_surface_commit(surface);- _glfw.wl.cursorPreviousName = name;-}--static void pointerHandleMotion(void* data,- struct wl_pointer* pointer,- uint32_t time,- wl_fixed_t sx,- wl_fixed_t sy)-{- _GLFWwindow* window = _glfw.wl.pointerFocus;- const char* cursorName = NULL;- double x, y;-- if (!window)- return;-- if (window->cursorMode == GLFW_CURSOR_DISABLED)- return;- x = wl_fixed_to_double(sx);- y = wl_fixed_to_double(sy);-- switch (window->wl.decorations.focus)- {- case mainWindow:- window->wl.cursorPosX = x;- window->wl.cursorPosY = y;- _glfwInputCursorPos(window, x, y);- _glfw.wl.cursorPreviousName = NULL;- return;- case topDecoration:- if (y < _GLFW_DECORATION_WIDTH)- cursorName = "n-resize";- else- cursorName = "left_ptr";- break;- case leftDecoration:- if (y < _GLFW_DECORATION_WIDTH)- cursorName = "nw-resize";- else- cursorName = "w-resize";- break;- case rightDecoration:- if (y < _GLFW_DECORATION_WIDTH)- cursorName = "ne-resize";- else- cursorName = "e-resize";- break;- case bottomDecoration:- if (x < _GLFW_DECORATION_WIDTH)- cursorName = "sw-resize";- else if (x > window->wl.width + _GLFW_DECORATION_WIDTH)- cursorName = "se-resize";- else- cursorName = "s-resize";- break;- default:- assert(0);- }- if (_glfw.wl.cursorPreviousName != cursorName)- setCursor(window, cursorName);-}--static void pointerHandleButton(void* data,- struct wl_pointer* pointer,- uint32_t serial,- uint32_t time,- uint32_t button,- uint32_t state)-{- _GLFWwindow* window = _glfw.wl.pointerFocus;- int glfwButton;-- // Both xdg-shell and wl_shell use the same values.- uint32_t edges = WL_SHELL_SURFACE_RESIZE_NONE;-- if (!window)- return;- if (button == BTN_LEFT)- {- switch (window->wl.decorations.focus)- {- case mainWindow:- break;- case topDecoration:- if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH)- edges = WL_SHELL_SURFACE_RESIZE_TOP;- else- {- if (window->wl.xdg.toplevel)- xdg_toplevel_move(window->wl.xdg.toplevel, _glfw.wl.seat, serial);- else- wl_shell_surface_move(window->wl.shellSurface, _glfw.wl.seat, serial);- }- break;- case leftDecoration:- if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH)- edges = WL_SHELL_SURFACE_RESIZE_TOP_LEFT;- else- edges = WL_SHELL_SURFACE_RESIZE_LEFT;- break;- case rightDecoration:- if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH)- edges = WL_SHELL_SURFACE_RESIZE_TOP_RIGHT;- else- edges = WL_SHELL_SURFACE_RESIZE_RIGHT;- break;- case bottomDecoration:- if (window->wl.cursorPosX < _GLFW_DECORATION_WIDTH)- edges = WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT;- else if (window->wl.cursorPosX > window->wl.width + _GLFW_DECORATION_WIDTH)- edges = WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT;- else- edges = WL_SHELL_SURFACE_RESIZE_BOTTOM;- break;- default:- assert(0);- }- if (edges != WL_SHELL_SURFACE_RESIZE_NONE)- {- if (window->wl.xdg.toplevel)- xdg_toplevel_resize(window->wl.xdg.toplevel, _glfw.wl.seat,- serial, edges);- else- wl_shell_surface_resize(window->wl.shellSurface, _glfw.wl.seat,- serial, edges);- }- }- else if (button == BTN_RIGHT)- {- if (window->wl.decorations.focus != mainWindow && window->wl.xdg.toplevel)- {- xdg_toplevel_show_window_menu(window->wl.xdg.toplevel,- _glfw.wl.seat, serial,- window->wl.cursorPosX,- window->wl.cursorPosY);- return;- }- }-- // Don’t pass the button to the user if it was related to a decoration.- if (window->wl.decorations.focus != mainWindow)- return;-- _glfw.wl.serial = serial;-- /* Makes left, right and middle 0, 1 and 2. Overall order follows evdev- * codes. */- glfwButton = button - BTN_LEFT;-- _glfwInputMouseClick(window,- glfwButton,- state == WL_POINTER_BUTTON_STATE_PRESSED- ? GLFW_PRESS- : GLFW_RELEASE,- _glfw.wl.xkb.modifiers);-}--static void pointerHandleAxis(void* data,- struct wl_pointer* pointer,- uint32_t time,- uint32_t axis,- wl_fixed_t value)-{- _GLFWwindow* window = _glfw.wl.pointerFocus;- double x = 0.0, y = 0.0;- // Wayland scroll events are in pointer motion coordinate space (think two- // finger scroll). The factor 10 is commonly used to convert to "scroll- // step means 1.0.- const double scrollFactor = 1.0 / 10.0;-- if (!window)- return;-- assert(axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL ||- axis == WL_POINTER_AXIS_VERTICAL_SCROLL);-- if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL)- x = wl_fixed_to_double(value) * scrollFactor;- else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL)- y = wl_fixed_to_double(value) * scrollFactor;-- _glfwInputScroll(window, x, y);-}--static const struct wl_pointer_listener pointerListener = {- pointerHandleEnter,- pointerHandleLeave,- pointerHandleMotion,- pointerHandleButton,- pointerHandleAxis,-};--static void keyboardHandleKeymap(void* data,- struct wl_keyboard* keyboard,- uint32_t format,- int fd,- uint32_t size)-{- struct xkb_keymap* keymap;- struct xkb_state* state;--#ifdef HAVE_XKBCOMMON_COMPOSE_H- struct xkb_compose_table* composeTable;- struct xkb_compose_state* composeState;-#endif-- char* mapStr;- const char* locale;-- if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1)- {- close(fd);- return;- }-- mapStr = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);- if (mapStr == MAP_FAILED) {- close(fd);- return;- }-- keymap = xkb_keymap_new_from_string(_glfw.wl.xkb.context,- mapStr,- XKB_KEYMAP_FORMAT_TEXT_V1,- 0);- munmap(mapStr, size);- close(fd);-- if (!keymap)- {- _glfwInputError(GLFW_PLATFORM_ERROR,- "Wayland: Failed to compile keymap");- return;- }-- state = xkb_state_new(keymap);- if (!state)- {- _glfwInputError(GLFW_PLATFORM_ERROR,- "Wayland: Failed to create XKB state");- xkb_keymap_unref(keymap);- return;- }-- // Look up the preferred locale, falling back to "C" as default.- locale = getenv("LC_ALL");- if (!locale)- locale = getenv("LC_CTYPE");- if (!locale)- locale = getenv("LANG");- if (!locale)- locale = "C";--#ifdef HAVE_XKBCOMMON_COMPOSE_H- composeTable =- xkb_compose_table_new_from_locale(_glfw.wl.xkb.context, locale,- XKB_COMPOSE_COMPILE_NO_FLAGS);- if (composeTable)- {- composeState =- xkb_compose_state_new(composeTable, XKB_COMPOSE_STATE_NO_FLAGS);- xkb_compose_table_unref(composeTable);- if (composeState)- _glfw.wl.xkb.composeState = composeState;- else- _glfwInputError(GLFW_PLATFORM_ERROR,- "Wayland: Failed to create XKB compose state");- }- else- {- _glfwInputError(GLFW_PLATFORM_ERROR,- "Wayland: Failed to create XKB compose table");- }-#endif-- xkb_keymap_unref(_glfw.wl.xkb.keymap);- xkb_state_unref(_glfw.wl.xkb.state);- _glfw.wl.xkb.keymap = keymap;- _glfw.wl.xkb.state = state;-- _glfw.wl.xkb.controlMask =- 1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Control");- _glfw.wl.xkb.altMask =- 1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod1");- _glfw.wl.xkb.shiftMask =- 1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Shift");- _glfw.wl.xkb.superMask =- 1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod4");- _glfw.wl.xkb.capsLockMask =- 1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Lock");- _glfw.wl.xkb.numLockMask =- 1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod2");-}--static void keyboardHandleEnter(void* data,- struct wl_keyboard* keyboard,- uint32_t serial,- struct wl_surface* surface,- struct wl_array* keys)-{- // Happens in the case we just destroyed the surface.- if (!surface)- return;-- _GLFWwindow* window = wl_surface_get_user_data(surface);- if (!window)- {- window = findWindowFromDecorationSurface(surface, NULL);- if (!window)- return;- }-- _glfw.wl.serial = serial;- _glfw.wl.keyboardFocus = window;- _glfwInputWindowFocus(window, GLFW_TRUE);-}--static void keyboardHandleLeave(void* data,- struct wl_keyboard* keyboard,- uint32_t serial,- struct wl_surface* surface)-{- _GLFWwindow* window = _glfw.wl.keyboardFocus;-- if (!window)- return;-- _glfw.wl.serial = serial;- _glfw.wl.keyboardFocus = NULL;- _glfwInputWindowFocus(window, GLFW_FALSE);-}--static int toGLFWKeyCode(uint32_t key)-{- if (key < sizeof(_glfw.wl.keycodes) / sizeof(_glfw.wl.keycodes[0]))- return _glfw.wl.keycodes[key];-- return GLFW_KEY_UNKNOWN;-}--#ifdef HAVE_XKBCOMMON_COMPOSE_H-static xkb_keysym_t composeSymbol(xkb_keysym_t sym)-{- if (sym == XKB_KEY_NoSymbol || !_glfw.wl.xkb.composeState)- return sym;- if (xkb_compose_state_feed(_glfw.wl.xkb.composeState, sym)- != XKB_COMPOSE_FEED_ACCEPTED)- return sym;- switch (xkb_compose_state_get_status(_glfw.wl.xkb.composeState))- {- case XKB_COMPOSE_COMPOSED:- return xkb_compose_state_get_one_sym(_glfw.wl.xkb.composeState);- case XKB_COMPOSE_COMPOSING:- case XKB_COMPOSE_CANCELLED:- return XKB_KEY_NoSymbol;- case XKB_COMPOSE_NOTHING:- default:- return sym;- }-}-#endif--static GLFWbool inputChar(_GLFWwindow* window, uint32_t key)-{- uint32_t code, numSyms;- long cp;- const xkb_keysym_t *syms;- xkb_keysym_t sym;-- code = key + 8;- numSyms = xkb_state_key_get_syms(_glfw.wl.xkb.state, code, &syms);-- if (numSyms == 1)- {-#ifdef HAVE_XKBCOMMON_COMPOSE_H- sym = composeSymbol(syms[0]);-#else- sym = syms[0];-#endif- cp = _glfwKeySym2Unicode(sym);- if (cp != -1)- {- const int mods = _glfw.wl.xkb.modifiers;- const int plain = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT));- _glfwInputChar(window, cp, mods, plain);- }- }-- return xkb_keymap_key_repeats(_glfw.wl.xkb.keymap, syms[0]);-}--static void keyboardHandleKey(void* data,- struct wl_keyboard* keyboard,- uint32_t serial,- uint32_t time,- uint32_t key,- uint32_t state)-{- int keyCode;- int action;- _GLFWwindow* window = _glfw.wl.keyboardFocus;- GLFWbool shouldRepeat;- struct itimerspec timer = {};-- if (!window)- return;-- keyCode = toGLFWKeyCode(key);- action = state == WL_KEYBOARD_KEY_STATE_PRESSED- ? GLFW_PRESS : GLFW_RELEASE;-- _glfw.wl.serial = serial;- _glfwInputKey(window, keyCode, key, action,- _glfw.wl.xkb.modifiers);-- if (action == GLFW_PRESS)- {- shouldRepeat = inputChar(window, key);-- if (shouldRepeat && _glfw.wl.keyboardRepeatRate > 0)- {- _glfw.wl.keyboardLastKey = keyCode;- _glfw.wl.keyboardLastScancode = key;- if (_glfw.wl.keyboardRepeatRate > 1)- timer.it_interval.tv_nsec = 1000000000 / _glfw.wl.keyboardRepeatRate;- else- timer.it_interval.tv_sec = 1;- timer.it_value.tv_sec = _glfw.wl.keyboardRepeatDelay / 1000;- timer.it_value.tv_nsec = (_glfw.wl.keyboardRepeatDelay % 1000) * 1000000;- }- }- timerfd_settime(_glfw.wl.timerfd, 0, &timer, NULL);-}--static void keyboardHandleModifiers(void* data,- struct wl_keyboard* keyboard,- uint32_t serial,- uint32_t modsDepressed,- uint32_t modsLatched,- uint32_t modsLocked,- uint32_t group)-{- xkb_mod_mask_t mask;- unsigned int modifiers = 0;-- _glfw.wl.serial = serial;-- if (!_glfw.wl.xkb.keymap)- return;-- xkb_state_update_mask(_glfw.wl.xkb.state,- modsDepressed,- modsLatched,- modsLocked,- 0,- 0,- group);-- mask = xkb_state_serialize_mods(_glfw.wl.xkb.state,- XKB_STATE_MODS_DEPRESSED |- XKB_STATE_LAYOUT_DEPRESSED |- XKB_STATE_MODS_LATCHED |- XKB_STATE_LAYOUT_LATCHED);- if (mask & _glfw.wl.xkb.controlMask)- modifiers |= GLFW_MOD_CONTROL;- if (mask & _glfw.wl.xkb.altMask)- modifiers |= GLFW_MOD_ALT;- if (mask & _glfw.wl.xkb.shiftMask)- modifiers |= GLFW_MOD_SHIFT;- if (mask & _glfw.wl.xkb.superMask)- modifiers |= GLFW_MOD_SUPER;- if (mask & _glfw.wl.xkb.capsLockMask)- modifiers |= GLFW_MOD_CAPS_LOCK;- if (mask & _glfw.wl.xkb.numLockMask)- modifiers |= GLFW_MOD_NUM_LOCK;- _glfw.wl.xkb.modifiers = modifiers;-}--#ifdef WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION-static void keyboardHandleRepeatInfo(void* data,- struct wl_keyboard* keyboard,- int32_t rate,- int32_t delay)-{- if (keyboard != _glfw.wl.keyboard)- return;-- _glfw.wl.keyboardRepeatRate = rate;- _glfw.wl.keyboardRepeatDelay = delay;-}-#endif--static const struct wl_keyboard_listener keyboardListener = {- keyboardHandleKeymap,- keyboardHandleEnter,- keyboardHandleLeave,- keyboardHandleKey,- keyboardHandleModifiers,-#ifdef WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION- keyboardHandleRepeatInfo,-#endif-};--static void seatHandleCapabilities(void* data,- struct wl_seat* seat,- enum wl_seat_capability caps)-{- if ((caps & WL_SEAT_CAPABILITY_POINTER) && !_glfw.wl.pointer)- {- _glfw.wl.pointer = wl_seat_get_pointer(seat);- wl_pointer_add_listener(_glfw.wl.pointer, &pointerListener, NULL);- }- else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && _glfw.wl.pointer)- {- wl_pointer_destroy(_glfw.wl.pointer);- _glfw.wl.pointer = NULL;- }-- if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !_glfw.wl.keyboard)- {- _glfw.wl.keyboard = wl_seat_get_keyboard(seat);- wl_keyboard_add_listener(_glfw.wl.keyboard, &keyboardListener, NULL);- }- else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && _glfw.wl.keyboard)- {- wl_keyboard_destroy(_glfw.wl.keyboard);- _glfw.wl.keyboard = NULL;- }-}--static void seatHandleName(void* data,- struct wl_seat* seat,- const char* name)-{-}--static const struct wl_seat_listener seatListener = {- seatHandleCapabilities,- seatHandleName,-};--static void dataOfferHandleOffer(void* data,- struct wl_data_offer* dataOffer,- const char* mimeType)-{-}--static const struct wl_data_offer_listener dataOfferListener = {- dataOfferHandleOffer,-};--static void dataDeviceHandleDataOffer(void* data,- struct wl_data_device* dataDevice,- struct wl_data_offer* id)-{- if (_glfw.wl.dataOffer)- wl_data_offer_destroy(_glfw.wl.dataOffer);-- _glfw.wl.dataOffer = id;- wl_data_offer_add_listener(_glfw.wl.dataOffer, &dataOfferListener, NULL);-}--static void dataDeviceHandleEnter(void* data,- struct wl_data_device* dataDevice,- uint32_t serial,- struct wl_surface *surface,- wl_fixed_t x,- wl_fixed_t y,- struct wl_data_offer *id)-{-}--static void dataDeviceHandleLeave(void* data,- struct wl_data_device* dataDevice)-{-}--static void dataDeviceHandleMotion(void* data,- struct wl_data_device* dataDevice,- uint32_t time,- wl_fixed_t x,- wl_fixed_t y)-{-}--static void dataDeviceHandleDrop(void* data,- struct wl_data_device* dataDevice)-{-}--static void dataDeviceHandleSelection(void* data,- struct wl_data_device* dataDevice,- struct wl_data_offer* id)-{-}--static const struct wl_data_device_listener dataDeviceListener = {- dataDeviceHandleDataOffer,- dataDeviceHandleEnter,- dataDeviceHandleLeave,- dataDeviceHandleMotion,- dataDeviceHandleDrop,- dataDeviceHandleSelection,-};--static void wmBaseHandlePing(void* data,- struct xdg_wm_base* wmBase,- uint32_t serial)-{- xdg_wm_base_pong(wmBase, serial);-}--static const struct xdg_wm_base_listener wmBaseListener = {- wmBaseHandlePing-};--static void registryHandleGlobal(void* data,- struct wl_registry* registry,- uint32_t name,- const char* interface,- uint32_t version)-{- if (strcmp(interface, "wl_compositor") == 0)- {- _glfw.wl.compositorVersion = min(3, version);- _glfw.wl.compositor =- wl_registry_bind(registry, name, &wl_compositor_interface,- _glfw.wl.compositorVersion);- }- else if (strcmp(interface, "wl_subcompositor") == 0)- {- _glfw.wl.subcompositor =- wl_registry_bind(registry, name, &wl_subcompositor_interface, 1);- }- else if (strcmp(interface, "wl_shm") == 0)- {- _glfw.wl.shm =- wl_registry_bind(registry, name, &wl_shm_interface, 1);- }- else if (strcmp(interface, "wl_shell") == 0)- {- _glfw.wl.shell =- wl_registry_bind(registry, name, &wl_shell_interface, 1);- }- else if (strcmp(interface, "wl_output") == 0)- {- _glfwAddOutputWayland(name, version);- }- else if (strcmp(interface, "wl_seat") == 0)- {- if (!_glfw.wl.seat)- {- _glfw.wl.seatVersion = min(4, version);- _glfw.wl.seat =- wl_registry_bind(registry, name, &wl_seat_interface,- _glfw.wl.seatVersion);- wl_seat_add_listener(_glfw.wl.seat, &seatListener, NULL);- }- }- else if (strcmp(interface, "wl_data_device_manager") == 0)- {- if (!_glfw.wl.dataDeviceManager)- {- _glfw.wl.dataDeviceManager =- wl_registry_bind(registry, name,- &wl_data_device_manager_interface, 1);- }- }- else if (strcmp(interface, "xdg_wm_base") == 0)- {- _glfw.wl.wmBase =- wl_registry_bind(registry, name, &xdg_wm_base_interface, 1);- xdg_wm_base_add_listener(_glfw.wl.wmBase, &wmBaseListener, NULL);- }- else if (strcmp(interface, "zxdg_decoration_manager_v1") == 0)- {- _glfw.wl.decorationManager =- wl_registry_bind(registry, name,- &zxdg_decoration_manager_v1_interface,- 1);- }- else if (strcmp(interface, "wp_viewporter") == 0)- {- _glfw.wl.viewporter =- wl_registry_bind(registry, name, &wp_viewporter_interface, 1);- }- else if (strcmp(interface, "zwp_relative_pointer_manager_v1") == 0)- {- _glfw.wl.relativePointerManager =- wl_registry_bind(registry, name,- &zwp_relative_pointer_manager_v1_interface,- 1);- }- else if (strcmp(interface, "zwp_pointer_constraints_v1") == 0)- {- _glfw.wl.pointerConstraints =- wl_registry_bind(registry, name,- &zwp_pointer_constraints_v1_interface,- 1);- }- else if (strcmp(interface, "zwp_idle_inhibit_manager_v1") == 0)- {- _glfw.wl.idleInhibitManager =- wl_registry_bind(registry, name,- &zwp_idle_inhibit_manager_v1_interface,- 1);- }-}--static void registryHandleGlobalRemove(void *data,- struct wl_registry *registry,- uint32_t name)-{- int i;- _GLFWmonitor* monitor;-- for (i = 0; i < _glfw.monitorCount; ++i)- {- monitor = _glfw.monitors[i];- if (monitor->wl.name == name)- {- _glfwInputMonitor(monitor, GLFW_DISCONNECTED, 0);- return;- }- }-}---static const struct wl_registry_listener registryListener = {- registryHandleGlobal,- registryHandleGlobalRemove-};--// Create key code translation tables-//-static void createKeyTables(void)-{- int scancode;-- memset(_glfw.wl.keycodes, -1, sizeof(_glfw.wl.keycodes));- memset(_glfw.wl.scancodes, -1, sizeof(_glfw.wl.scancodes));-- _glfw.wl.keycodes[KEY_GRAVE] = GLFW_KEY_GRAVE_ACCENT;- _glfw.wl.keycodes[KEY_1] = GLFW_KEY_1;- _glfw.wl.keycodes[KEY_2] = GLFW_KEY_2;- _glfw.wl.keycodes[KEY_3] = GLFW_KEY_3;- _glfw.wl.keycodes[KEY_4] = GLFW_KEY_4;- _glfw.wl.keycodes[KEY_5] = GLFW_KEY_5;- _glfw.wl.keycodes[KEY_6] = GLFW_KEY_6;- _glfw.wl.keycodes[KEY_7] = GLFW_KEY_7;- _glfw.wl.keycodes[KEY_8] = GLFW_KEY_8;- _glfw.wl.keycodes[KEY_9] = GLFW_KEY_9;- _glfw.wl.keycodes[KEY_0] = GLFW_KEY_0;- _glfw.wl.keycodes[KEY_SPACE] = GLFW_KEY_SPACE;- _glfw.wl.keycodes[KEY_MINUS] = GLFW_KEY_MINUS;- _glfw.wl.keycodes[KEY_EQUAL] = GLFW_KEY_EQUAL;- _glfw.wl.keycodes[KEY_Q] = GLFW_KEY_Q;- _glfw.wl.keycodes[KEY_W] = GLFW_KEY_W;- _glfw.wl.keycodes[KEY_E] = GLFW_KEY_E;- _glfw.wl.keycodes[KEY_R] = GLFW_KEY_R;- _glfw.wl.keycodes[KEY_T] = GLFW_KEY_T;- _glfw.wl.keycodes[KEY_Y] = GLFW_KEY_Y;- _glfw.wl.keycodes[KEY_U] = GLFW_KEY_U;- _glfw.wl.keycodes[KEY_I] = GLFW_KEY_I;- _glfw.wl.keycodes[KEY_O] = GLFW_KEY_O;- _glfw.wl.keycodes[KEY_P] = GLFW_KEY_P;- _glfw.wl.keycodes[KEY_LEFTBRACE] = GLFW_KEY_LEFT_BRACKET;- _glfw.wl.keycodes[KEY_RIGHTBRACE] = GLFW_KEY_RIGHT_BRACKET;- _glfw.wl.keycodes[KEY_A] = GLFW_KEY_A;- _glfw.wl.keycodes[KEY_S] = GLFW_KEY_S;- _glfw.wl.keycodes[KEY_D] = GLFW_KEY_D;- _glfw.wl.keycodes[KEY_F] = GLFW_KEY_F;- _glfw.wl.keycodes[KEY_G] = GLFW_KEY_G;- _glfw.wl.keycodes[KEY_H] = GLFW_KEY_H;- _glfw.wl.keycodes[KEY_J] = GLFW_KEY_J;- _glfw.wl.keycodes[KEY_K] = GLFW_KEY_K;- _glfw.wl.keycodes[KEY_L] = GLFW_KEY_L;- _glfw.wl.keycodes[KEY_SEMICOLON] = GLFW_KEY_SEMICOLON;- _glfw.wl.keycodes[KEY_APOSTROPHE] = GLFW_KEY_APOSTROPHE;- _glfw.wl.keycodes[KEY_Z] = GLFW_KEY_Z;- _glfw.wl.keycodes[KEY_X] = GLFW_KEY_X;- _glfw.wl.keycodes[KEY_C] = GLFW_KEY_C;- _glfw.wl.keycodes[KEY_V] = GLFW_KEY_V;- _glfw.wl.keycodes[KEY_B] = GLFW_KEY_B;- _glfw.wl.keycodes[KEY_N] = GLFW_KEY_N;- _glfw.wl.keycodes[KEY_M] = GLFW_KEY_M;- _glfw.wl.keycodes[KEY_COMMA] = GLFW_KEY_COMMA;- _glfw.wl.keycodes[KEY_DOT] = GLFW_KEY_PERIOD;- _glfw.wl.keycodes[KEY_SLASH] = GLFW_KEY_SLASH;- _glfw.wl.keycodes[KEY_BACKSLASH] = GLFW_KEY_BACKSLASH;- _glfw.wl.keycodes[KEY_ESC] = GLFW_KEY_ESCAPE;- _glfw.wl.keycodes[KEY_TAB] = GLFW_KEY_TAB;- _glfw.wl.keycodes[KEY_LEFTSHIFT] = GLFW_KEY_LEFT_SHIFT;- _glfw.wl.keycodes[KEY_RIGHTSHIFT] = GLFW_KEY_RIGHT_SHIFT;- _glfw.wl.keycodes[KEY_LEFTCTRL] = GLFW_KEY_LEFT_CONTROL;- _glfw.wl.keycodes[KEY_RIGHTCTRL] = GLFW_KEY_RIGHT_CONTROL;- _glfw.wl.keycodes[KEY_LEFTALT] = GLFW_KEY_LEFT_ALT;- _glfw.wl.keycodes[KEY_RIGHTALT] = GLFW_KEY_RIGHT_ALT;- _glfw.wl.keycodes[KEY_LEFTMETA] = GLFW_KEY_LEFT_SUPER;- _glfw.wl.keycodes[KEY_RIGHTMETA] = GLFW_KEY_RIGHT_SUPER;- _glfw.wl.keycodes[KEY_MENU] = GLFW_KEY_MENU;- _glfw.wl.keycodes[KEY_NUMLOCK] = GLFW_KEY_NUM_LOCK;- _glfw.wl.keycodes[KEY_CAPSLOCK] = GLFW_KEY_CAPS_LOCK;- _glfw.wl.keycodes[KEY_PRINT] = GLFW_KEY_PRINT_SCREEN;- _glfw.wl.keycodes[KEY_SCROLLLOCK] = GLFW_KEY_SCROLL_LOCK;- _glfw.wl.keycodes[KEY_PAUSE] = GLFW_KEY_PAUSE;- _glfw.wl.keycodes[KEY_DELETE] = GLFW_KEY_DELETE;- _glfw.wl.keycodes[KEY_BACKSPACE] = GLFW_KEY_BACKSPACE;- _glfw.wl.keycodes[KEY_ENTER] = GLFW_KEY_ENTER;- _glfw.wl.keycodes[KEY_HOME] = GLFW_KEY_HOME;- _glfw.wl.keycodes[KEY_END] = GLFW_KEY_END;- _glfw.wl.keycodes[KEY_PAGEUP] = GLFW_KEY_PAGE_UP;- _glfw.wl.keycodes[KEY_PAGEDOWN] = GLFW_KEY_PAGE_DOWN;- _glfw.wl.keycodes[KEY_INSERT] = GLFW_KEY_INSERT;- _glfw.wl.keycodes[KEY_LEFT] = GLFW_KEY_LEFT;- _glfw.wl.keycodes[KEY_RIGHT] = GLFW_KEY_RIGHT;- _glfw.wl.keycodes[KEY_DOWN] = GLFW_KEY_DOWN;- _glfw.wl.keycodes[KEY_UP] = GLFW_KEY_UP;- _glfw.wl.keycodes[KEY_F1] = GLFW_KEY_F1;- _glfw.wl.keycodes[KEY_F2] = GLFW_KEY_F2;- _glfw.wl.keycodes[KEY_F3] = GLFW_KEY_F3;- _glfw.wl.keycodes[KEY_F4] = GLFW_KEY_F4;- _glfw.wl.keycodes[KEY_F5] = GLFW_KEY_F5;- _glfw.wl.keycodes[KEY_F6] = GLFW_KEY_F6;- _glfw.wl.keycodes[KEY_F7] = GLFW_KEY_F7;- _glfw.wl.keycodes[KEY_F8] = GLFW_KEY_F8;- _glfw.wl.keycodes[KEY_F9] = GLFW_KEY_F9;- _glfw.wl.keycodes[KEY_F10] = GLFW_KEY_F10;- _glfw.wl.keycodes[KEY_F11] = GLFW_KEY_F11;- _glfw.wl.keycodes[KEY_F12] = GLFW_KEY_F12;- _glfw.wl.keycodes[KEY_F13] = GLFW_KEY_F13;- _glfw.wl.keycodes[KEY_F14] = GLFW_KEY_F14;- _glfw.wl.keycodes[KEY_F15] = GLFW_KEY_F15;- _glfw.wl.keycodes[KEY_F16] = GLFW_KEY_F16;- _glfw.wl.keycodes[KEY_F17] = GLFW_KEY_F17;- _glfw.wl.keycodes[KEY_F18] = GLFW_KEY_F18;- _glfw.wl.keycodes[KEY_F19] = GLFW_KEY_F19;- _glfw.wl.keycodes[KEY_F20] = GLFW_KEY_F20;- _glfw.wl.keycodes[KEY_F21] = GLFW_KEY_F21;- _glfw.wl.keycodes[KEY_F22] = GLFW_KEY_F22;- _glfw.wl.keycodes[KEY_F23] = GLFW_KEY_F23;- _glfw.wl.keycodes[KEY_F24] = GLFW_KEY_F24;- _glfw.wl.keycodes[KEY_KPSLASH] = GLFW_KEY_KP_DIVIDE;- _glfw.wl.keycodes[KEY_KPDOT] = GLFW_KEY_KP_MULTIPLY;- _glfw.wl.keycodes[KEY_KPMINUS] = GLFW_KEY_KP_SUBTRACT;- _glfw.wl.keycodes[KEY_KPPLUS] = GLFW_KEY_KP_ADD;- _glfw.wl.keycodes[KEY_KP0] = GLFW_KEY_KP_0;- _glfw.wl.keycodes[KEY_KP1] = GLFW_KEY_KP_1;- _glfw.wl.keycodes[KEY_KP2] = GLFW_KEY_KP_2;- _glfw.wl.keycodes[KEY_KP3] = GLFW_KEY_KP_3;- _glfw.wl.keycodes[KEY_KP4] = GLFW_KEY_KP_4;- _glfw.wl.keycodes[KEY_KP5] = GLFW_KEY_KP_5;- _glfw.wl.keycodes[KEY_KP6] = GLFW_KEY_KP_6;- _glfw.wl.keycodes[KEY_KP7] = GLFW_KEY_KP_7;- _glfw.wl.keycodes[KEY_KP8] = GLFW_KEY_KP_8;- _glfw.wl.keycodes[KEY_KP9] = GLFW_KEY_KP_9;- _glfw.wl.keycodes[KEY_KPCOMMA] = GLFW_KEY_KP_DECIMAL;- _glfw.wl.keycodes[KEY_KPEQUAL] = GLFW_KEY_KP_EQUAL;- _glfw.wl.keycodes[KEY_KPENTER] = GLFW_KEY_KP_ENTER;-- for (scancode = 0; scancode < 256; scancode++)- {- if (_glfw.wl.keycodes[scancode] > 0)- _glfw.wl.scancodes[_glfw.wl.keycodes[scancode]] = scancode;- }-}---//////////////////////////////////////////////////////////////////////////-////// GLFW platform API //////-//////////////////////////////////////////////////////////////////////////--int _glfwPlatformInit(void)-{- const char *cursorTheme;- const char *cursorSizeStr;- char *cursorSizeEnd;- long cursorSizeLong;- int cursorSize;-- _glfw.wl.cursor.handle = _glfw_dlopen("libwayland-cursor.so.0");- if (!_glfw.wl.cursor.handle)- {- _glfwInputError(GLFW_PLATFORM_ERROR,- "Wayland: Failed to open libwayland-cursor");- return GLFW_FALSE;- }-- _glfw.wl.cursor.theme_load = (PFN_wl_cursor_theme_load)- _glfw_dlsym(_glfw.wl.cursor.handle, "wl_cursor_theme_load");- _glfw.wl.cursor.theme_destroy = (PFN_wl_cursor_theme_destroy)- _glfw_dlsym(_glfw.wl.cursor.handle, "wl_cursor_theme_destroy");- _glfw.wl.cursor.theme_get_cursor = (PFN_wl_cursor_theme_get_cursor)- _glfw_dlsym(_glfw.wl.cursor.handle, "wl_cursor_theme_get_cursor");- _glfw.wl.cursor.image_get_buffer = (PFN_wl_cursor_image_get_buffer)- _glfw_dlsym(_glfw.wl.cursor.handle, "wl_cursor_image_get_buffer");-- _glfw.wl.egl.handle = _glfw_dlopen("libwayland-egl.so.1");- if (!_glfw.wl.egl.handle)- {- _glfwInputError(GLFW_PLATFORM_ERROR,- "Wayland: Failed to open libwayland-egl");- return GLFW_FALSE;- }-- _glfw.wl.egl.window_create = (PFN_wl_egl_window_create)- _glfw_dlsym(_glfw.wl.egl.handle, "wl_egl_window_create");- _glfw.wl.egl.window_destroy = (PFN_wl_egl_window_destroy)- _glfw_dlsym(_glfw.wl.egl.handle, "wl_egl_window_destroy");- _glfw.wl.egl.window_resize = (PFN_wl_egl_window_resize)- _glfw_dlsym(_glfw.wl.egl.handle, "wl_egl_window_resize");-- _glfw.wl.xkb.handle = _glfw_dlopen("libxkbcommon.so.0");- if (!_glfw.wl.xkb.handle)- {- _glfwInputError(GLFW_PLATFORM_ERROR,- "Wayland: Failed to open libxkbcommon");- return GLFW_FALSE;- }-- _glfw.wl.xkb.context_new = (PFN_xkb_context_new)- _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_context_new");- _glfw.wl.xkb.context_unref = (PFN_xkb_context_unref)- _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_context_unref");- _glfw.wl.xkb.keymap_new_from_string = (PFN_xkb_keymap_new_from_string)- _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_keymap_new_from_string");- _glfw.wl.xkb.keymap_unref = (PFN_xkb_keymap_unref)- _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_keymap_unref");- _glfw.wl.xkb.keymap_mod_get_index = (PFN_xkb_keymap_mod_get_index)- _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_keymap_mod_get_index");- _glfw.wl.xkb.keymap_key_repeats = (PFN_xkb_keymap_key_repeats)- _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_keymap_key_repeats");- _glfw.wl.xkb.state_new = (PFN_xkb_state_new)- _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_state_new");- _glfw.wl.xkb.state_unref = (PFN_xkb_state_unref)- _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_state_unref");- _glfw.wl.xkb.state_key_get_syms = (PFN_xkb_state_key_get_syms)- _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_state_key_get_syms");- _glfw.wl.xkb.state_update_mask = (PFN_xkb_state_update_mask)- _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_state_update_mask");- _glfw.wl.xkb.state_serialize_mods = (PFN_xkb_state_serialize_mods)- _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_state_serialize_mods");--#ifdef HAVE_XKBCOMMON_COMPOSE_H- _glfw.wl.xkb.compose_table_new_from_locale = (PFN_xkb_compose_table_new_from_locale)- _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_table_new_from_locale");- _glfw.wl.xkb.compose_table_unref = (PFN_xkb_compose_table_unref)- _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_table_unref");- _glfw.wl.xkb.compose_state_new = (PFN_xkb_compose_state_new)- _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_new");- _glfw.wl.xkb.compose_state_unref = (PFN_xkb_compose_state_unref)- _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_unref");- _glfw.wl.xkb.compose_state_feed = (PFN_xkb_compose_state_feed)- _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_feed");- _glfw.wl.xkb.compose_state_get_status = (PFN_xkb_compose_state_get_status)- _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_get_status");- _glfw.wl.xkb.compose_state_get_one_sym = (PFN_xkb_compose_state_get_one_sym)- _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_get_one_sym");-#endif-- _glfw.wl.display = wl_display_connect(NULL);- if (!_glfw.wl.display)- {- _glfwInputError(GLFW_PLATFORM_ERROR,- "Wayland: Failed to connect to display");- return GLFW_FALSE;- }-- _glfw.wl.registry = wl_display_get_registry(_glfw.wl.display);- wl_registry_add_listener(_glfw.wl.registry, ®istryListener, NULL);-- createKeyTables();-- _glfw.wl.xkb.context = xkb_context_new(0);- if (!_glfw.wl.xkb.context)- {- _glfwInputError(GLFW_PLATFORM_ERROR,- "Wayland: Failed to initialize xkb context");- return GLFW_FALSE;- }-- // Sync so we got all registry objects- wl_display_roundtrip(_glfw.wl.display);-- // Sync so we got all initial output events- wl_display_roundtrip(_glfw.wl.display);--#ifdef __linux__- if (!_glfwInitJoysticksLinux())- return GLFW_FALSE;-#endif-- _glfwInitTimerPOSIX();-- _glfw.wl.timerfd = -1;- if (_glfw.wl.seatVersion >= 4)- _glfw.wl.timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);-- if (_glfw.wl.pointer && _glfw.wl.shm)- {- cursorTheme = getenv("XCURSOR_THEME");- cursorSizeStr = getenv("XCURSOR_SIZE");- cursorSize = 32;- if (cursorSizeStr)- {- errno = 0;- cursorSizeLong = strtol(cursorSizeStr, &cursorSizeEnd, 10);- if (!*cursorSizeEnd && !errno && cursorSizeLong > 0 && cursorSizeLong <= INT_MAX)- cursorSize = (int)cursorSizeLong;- }- _glfw.wl.cursorTheme =- wl_cursor_theme_load(cursorTheme, cursorSize, _glfw.wl.shm);- if (!_glfw.wl.cursorTheme)- {- _glfwInputError(GLFW_PLATFORM_ERROR,- "Wayland: Unable to load default cursor theme");- return GLFW_FALSE;- }- // If this happens to be NULL, we just fallback to the scale=1 version.- _glfw.wl.cursorThemeHiDPI =- wl_cursor_theme_load(cursorTheme, 2 * cursorSize, _glfw.wl.shm);- _glfw.wl.cursorSurface =- wl_compositor_create_surface(_glfw.wl.compositor);- _glfw.wl.cursorTimerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);- }-- if (_glfw.wl.seat && _glfw.wl.dataDeviceManager)- {- _glfw.wl.dataDevice =- wl_data_device_manager_get_data_device(_glfw.wl.dataDeviceManager,- _glfw.wl.seat);- wl_data_device_add_listener(_glfw.wl.dataDevice, &dataDeviceListener, NULL);- _glfw.wl.clipboardString = malloc(4096);- if (!_glfw.wl.clipboardString)- {- _glfwInputError(GLFW_PLATFORM_ERROR,- "Wayland: Unable to allocate clipboard memory");- return GLFW_FALSE;- }- _glfw.wl.clipboardSize = 4096;- }-- return GLFW_TRUE;-}--void _glfwPlatformTerminate(void)-{-#ifdef __linux__- _glfwTerminateJoysticksLinux();-#endif- _glfwTerminateEGL();- if (_glfw.wl.egl.handle)- {- _glfw_dlclose(_glfw.wl.egl.handle);- _glfw.wl.egl.handle = NULL;- }--#ifdef HAVE_XKBCOMMON_COMPOSE_H- if (_glfw.wl.xkb.composeState)- xkb_compose_state_unref(_glfw.wl.xkb.composeState);-#endif- if (_glfw.wl.xkb.keymap)- xkb_keymap_unref(_glfw.wl.xkb.keymap);- if (_glfw.wl.xkb.state)- xkb_state_unref(_glfw.wl.xkb.state);- if (_glfw.wl.xkb.context)- xkb_context_unref(_glfw.wl.xkb.context);- if (_glfw.wl.xkb.handle)- {- _glfw_dlclose(_glfw.wl.xkb.handle);- _glfw.wl.xkb.handle = NULL;- }-- if (_glfw.wl.cursorTheme)- wl_cursor_theme_destroy(_glfw.wl.cursorTheme);- if (_glfw.wl.cursorThemeHiDPI)- wl_cursor_theme_destroy(_glfw.wl.cursorThemeHiDPI);- if (_glfw.wl.cursor.handle)- {- _glfw_dlclose(_glfw.wl.cursor.handle);- _glfw.wl.cursor.handle = NULL;- }-- if (_glfw.wl.cursorSurface)- wl_surface_destroy(_glfw.wl.cursorSurface);- if (_glfw.wl.subcompositor)- wl_subcompositor_destroy(_glfw.wl.subcompositor);- if (_glfw.wl.compositor)- wl_compositor_destroy(_glfw.wl.compositor);- if (_glfw.wl.shm)- wl_shm_destroy(_glfw.wl.shm);- if (_glfw.wl.shell)- wl_shell_destroy(_glfw.wl.shell);- if (_glfw.wl.viewporter)- wp_viewporter_destroy(_glfw.wl.viewporter);- if (_glfw.wl.decorationManager)- zxdg_decoration_manager_v1_destroy(_glfw.wl.decorationManager);- if (_glfw.wl.wmBase)- xdg_wm_base_destroy(_glfw.wl.wmBase);- if (_glfw.wl.dataSource)- wl_data_source_destroy(_glfw.wl.dataSource);- if (_glfw.wl.dataDevice)- wl_data_device_destroy(_glfw.wl.dataDevice);- if (_glfw.wl.dataOffer)- wl_data_offer_destroy(_glfw.wl.dataOffer);- if (_glfw.wl.dataDeviceManager)- wl_data_device_manager_destroy(_glfw.wl.dataDeviceManager);- if (_glfw.wl.pointer)- wl_pointer_destroy(_glfw.wl.pointer);- if (_glfw.wl.keyboard)- wl_keyboard_destroy(_glfw.wl.keyboard);- if (_glfw.wl.seat)- wl_seat_destroy(_glfw.wl.seat);- if (_glfw.wl.relativePointerManager)- zwp_relative_pointer_manager_v1_destroy(_glfw.wl.relativePointerManager);- if (_glfw.wl.pointerConstraints)- zwp_pointer_constraints_v1_destroy(_glfw.wl.pointerConstraints);- if (_glfw.wl.idleInhibitManager)- zwp_idle_inhibit_manager_v1_destroy(_glfw.wl.idleInhibitManager);- if (_glfw.wl.registry)- wl_registry_destroy(_glfw.wl.registry);- if (_glfw.wl.display)- {- wl_display_flush(_glfw.wl.display);- wl_display_disconnect(_glfw.wl.display);- }-- if (_glfw.wl.timerfd >= 0)- close(_glfw.wl.timerfd);- if (_glfw.wl.cursorTimerfd >= 0)- close(_glfw.wl.cursorTimerfd);-- if (_glfw.wl.clipboardString)- free(_glfw.wl.clipboardString);- if (_glfw.wl.clipboardSendString)- free(_glfw.wl.clipboardSendString);+#define _POSIX_C_SOURCE 200809L++#include "internal.h"++#include <errno.h>+#include <limits.h>+#include <linux/input.h>+#include <stdio.h>+#include <stdlib.h>+#include <string.h>+#include <sys/mman.h>+#include <sys/timerfd.h>+#include <unistd.h>+#include <wayland-client.h>+#include <assert.h>++static void wmBaseHandlePing(void* userData,+ struct xdg_wm_base* wmBase,+ uint32_t serial)+{+ xdg_wm_base_pong(wmBase, serial);+}++static const struct xdg_wm_base_listener wmBaseListener =+{+ wmBaseHandlePing+};++static void registryHandleGlobal(void* userData,+ struct wl_registry* registry,+ uint32_t name,+ const char* interface,+ uint32_t version)+{+ if (strcmp(interface, "wl_compositor") == 0)+ {+ _glfw.wl.compositor =+ wl_registry_bind(registry, name, &wl_compositor_interface,+ _glfw_min(3, version));+ }+ else if (strcmp(interface, "wl_subcompositor") == 0)+ {+ _glfw.wl.subcompositor =+ wl_registry_bind(registry, name, &wl_subcompositor_interface, 1);+ }+ else if (strcmp(interface, "wl_shm") == 0)+ {+ _glfw.wl.shm =+ wl_registry_bind(registry, name, &wl_shm_interface, 1);+ }+ else if (strcmp(interface, "wl_output") == 0)+ {+ _glfwAddOutputWayland(name, version);+ }+ else if (strcmp(interface, "wl_seat") == 0)+ {+ if (!_glfw.wl.seat)+ {+ _glfw.wl.seat =+ wl_registry_bind(registry, name, &wl_seat_interface,+ _glfw_min(4, version));+ _glfwAddSeatListenerWayland(_glfw.wl.seat);+ }+ }+ else if (strcmp(interface, "wl_data_device_manager") == 0)+ {+ if (!_glfw.wl.dataDeviceManager)+ {+ _glfw.wl.dataDeviceManager =+ wl_registry_bind(registry, name,+ &wl_data_device_manager_interface, 1);+ }+ }+ else if (strcmp(interface, "xdg_wm_base") == 0)+ {+ _glfw.wl.wmBase =+ wl_registry_bind(registry, name, &xdg_wm_base_interface, 1);+ xdg_wm_base_add_listener(_glfw.wl.wmBase, &wmBaseListener, NULL);+ }+ else if (strcmp(interface, "zxdg_decoration_manager_v1") == 0)+ {+ _glfw.wl.decorationManager =+ wl_registry_bind(registry, name,+ &zxdg_decoration_manager_v1_interface,+ 1);+ }+ else if (strcmp(interface, "wp_viewporter") == 0)+ {+ _glfw.wl.viewporter =+ wl_registry_bind(registry, name, &wp_viewporter_interface, 1);+ }+ else if (strcmp(interface, "zwp_relative_pointer_manager_v1") == 0)+ {+ _glfw.wl.relativePointerManager =+ wl_registry_bind(registry, name,+ &zwp_relative_pointer_manager_v1_interface,+ 1);+ }+ else if (strcmp(interface, "zwp_pointer_constraints_v1") == 0)+ {+ _glfw.wl.pointerConstraints =+ wl_registry_bind(registry, name,+ &zwp_pointer_constraints_v1_interface,+ 1);+ }+ else if (strcmp(interface, "zwp_idle_inhibit_manager_v1") == 0)+ {+ _glfw.wl.idleInhibitManager =+ wl_registry_bind(registry, name,+ &zwp_idle_inhibit_manager_v1_interface,+ 1);+ }+}++static void registryHandleGlobalRemove(void* userData,+ struct wl_registry* registry,+ uint32_t name)+{+ int i;++ for (i = 0; i < _glfw.monitorCount; ++i)+ {+ _GLFWmonitor* monitor = _glfw.monitors[i];+ if (monitor->wl.name == name)+ {+ _glfwInputMonitor(monitor, GLFW_DISCONNECTED, 0);+ return;+ }+ }+}+++static const struct wl_registry_listener registryListener =+{+ registryHandleGlobal,+ registryHandleGlobalRemove+};++void libdecorHandleError(struct libdecor* context,+ enum libdecor_error error,+ const char* message)+{+ _glfwInputError(GLFW_PLATFORM_ERROR,+ "Wayland: libdecor error %u: %s",+ error, message);+}++static const struct libdecor_interface libdecorInterface =+{+ libdecorHandleError+};++static void libdecorReadyCallback(void* userData,+ struct wl_callback* callback,+ uint32_t time)+{+ _glfw.wl.libdecor.ready = GLFW_TRUE;++ assert(_glfw.wl.libdecor.callback == callback);+ wl_callback_destroy(_glfw.wl.libdecor.callback);+ _glfw.wl.libdecor.callback = NULL;+}++static const struct wl_callback_listener libdecorReadyListener =+{+ libdecorReadyCallback+};++// Create key code translation tables+//+static void createKeyTables(void)+{+ int scancode;++ memset(_glfw.wl.keycodes, -1, sizeof(_glfw.wl.keycodes));+ memset(_glfw.wl.scancodes, -1, sizeof(_glfw.wl.scancodes));++ _glfw.wl.keycodes[KEY_GRAVE] = GLFW_KEY_GRAVE_ACCENT;+ _glfw.wl.keycodes[KEY_1] = GLFW_KEY_1;+ _glfw.wl.keycodes[KEY_2] = GLFW_KEY_2;+ _glfw.wl.keycodes[KEY_3] = GLFW_KEY_3;+ _glfw.wl.keycodes[KEY_4] = GLFW_KEY_4;+ _glfw.wl.keycodes[KEY_5] = GLFW_KEY_5;+ _glfw.wl.keycodes[KEY_6] = GLFW_KEY_6;+ _glfw.wl.keycodes[KEY_7] = GLFW_KEY_7;+ _glfw.wl.keycodes[KEY_8] = GLFW_KEY_8;+ _glfw.wl.keycodes[KEY_9] = GLFW_KEY_9;+ _glfw.wl.keycodes[KEY_0] = GLFW_KEY_0;+ _glfw.wl.keycodes[KEY_SPACE] = GLFW_KEY_SPACE;+ _glfw.wl.keycodes[KEY_MINUS] = GLFW_KEY_MINUS;+ _glfw.wl.keycodes[KEY_EQUAL] = GLFW_KEY_EQUAL;+ _glfw.wl.keycodes[KEY_Q] = GLFW_KEY_Q;+ _glfw.wl.keycodes[KEY_W] = GLFW_KEY_W;+ _glfw.wl.keycodes[KEY_E] = GLFW_KEY_E;+ _glfw.wl.keycodes[KEY_R] = GLFW_KEY_R;+ _glfw.wl.keycodes[KEY_T] = GLFW_KEY_T;+ _glfw.wl.keycodes[KEY_Y] = GLFW_KEY_Y;+ _glfw.wl.keycodes[KEY_U] = GLFW_KEY_U;+ _glfw.wl.keycodes[KEY_I] = GLFW_KEY_I;+ _glfw.wl.keycodes[KEY_O] = GLFW_KEY_O;+ _glfw.wl.keycodes[KEY_P] = GLFW_KEY_P;+ _glfw.wl.keycodes[KEY_LEFTBRACE] = GLFW_KEY_LEFT_BRACKET;+ _glfw.wl.keycodes[KEY_RIGHTBRACE] = GLFW_KEY_RIGHT_BRACKET;+ _glfw.wl.keycodes[KEY_A] = GLFW_KEY_A;+ _glfw.wl.keycodes[KEY_S] = GLFW_KEY_S;+ _glfw.wl.keycodes[KEY_D] = GLFW_KEY_D;+ _glfw.wl.keycodes[KEY_F] = GLFW_KEY_F;+ _glfw.wl.keycodes[KEY_G] = GLFW_KEY_G;+ _glfw.wl.keycodes[KEY_H] = GLFW_KEY_H;+ _glfw.wl.keycodes[KEY_J] = GLFW_KEY_J;+ _glfw.wl.keycodes[KEY_K] = GLFW_KEY_K;+ _glfw.wl.keycodes[KEY_L] = GLFW_KEY_L;+ _glfw.wl.keycodes[KEY_SEMICOLON] = GLFW_KEY_SEMICOLON;+ _glfw.wl.keycodes[KEY_APOSTROPHE] = GLFW_KEY_APOSTROPHE;+ _glfw.wl.keycodes[KEY_Z] = GLFW_KEY_Z;+ _glfw.wl.keycodes[KEY_X] = GLFW_KEY_X;+ _glfw.wl.keycodes[KEY_C] = GLFW_KEY_C;+ _glfw.wl.keycodes[KEY_V] = GLFW_KEY_V;+ _glfw.wl.keycodes[KEY_B] = GLFW_KEY_B;+ _glfw.wl.keycodes[KEY_N] = GLFW_KEY_N;+ _glfw.wl.keycodes[KEY_M] = GLFW_KEY_M;+ _glfw.wl.keycodes[KEY_COMMA] = GLFW_KEY_COMMA;+ _glfw.wl.keycodes[KEY_DOT] = GLFW_KEY_PERIOD;+ _glfw.wl.keycodes[KEY_SLASH] = GLFW_KEY_SLASH;+ _glfw.wl.keycodes[KEY_BACKSLASH] = GLFW_KEY_BACKSLASH;+ _glfw.wl.keycodes[KEY_ESC] = GLFW_KEY_ESCAPE;+ _glfw.wl.keycodes[KEY_TAB] = GLFW_KEY_TAB;+ _glfw.wl.keycodes[KEY_LEFTSHIFT] = GLFW_KEY_LEFT_SHIFT;+ _glfw.wl.keycodes[KEY_RIGHTSHIFT] = GLFW_KEY_RIGHT_SHIFT;+ _glfw.wl.keycodes[KEY_LEFTCTRL] = GLFW_KEY_LEFT_CONTROL;+ _glfw.wl.keycodes[KEY_RIGHTCTRL] = GLFW_KEY_RIGHT_CONTROL;+ _glfw.wl.keycodes[KEY_LEFTALT] = GLFW_KEY_LEFT_ALT;+ _glfw.wl.keycodes[KEY_RIGHTALT] = GLFW_KEY_RIGHT_ALT;+ _glfw.wl.keycodes[KEY_LEFTMETA] = GLFW_KEY_LEFT_SUPER;+ _glfw.wl.keycodes[KEY_RIGHTMETA] = GLFW_KEY_RIGHT_SUPER;+ _glfw.wl.keycodes[KEY_COMPOSE] = GLFW_KEY_MENU;+ _glfw.wl.keycodes[KEY_NUMLOCK] = GLFW_KEY_NUM_LOCK;+ _glfw.wl.keycodes[KEY_CAPSLOCK] = GLFW_KEY_CAPS_LOCK;+ _glfw.wl.keycodes[KEY_PRINT] = GLFW_KEY_PRINT_SCREEN;+ _glfw.wl.keycodes[KEY_SCROLLLOCK] = GLFW_KEY_SCROLL_LOCK;+ _glfw.wl.keycodes[KEY_PAUSE] = GLFW_KEY_PAUSE;+ _glfw.wl.keycodes[KEY_DELETE] = GLFW_KEY_DELETE;+ _glfw.wl.keycodes[KEY_BACKSPACE] = GLFW_KEY_BACKSPACE;+ _glfw.wl.keycodes[KEY_ENTER] = GLFW_KEY_ENTER;+ _glfw.wl.keycodes[KEY_HOME] = GLFW_KEY_HOME;+ _glfw.wl.keycodes[KEY_END] = GLFW_KEY_END;+ _glfw.wl.keycodes[KEY_PAGEUP] = GLFW_KEY_PAGE_UP;+ _glfw.wl.keycodes[KEY_PAGEDOWN] = GLFW_KEY_PAGE_DOWN;+ _glfw.wl.keycodes[KEY_INSERT] = GLFW_KEY_INSERT;+ _glfw.wl.keycodes[KEY_LEFT] = GLFW_KEY_LEFT;+ _glfw.wl.keycodes[KEY_RIGHT] = GLFW_KEY_RIGHT;+ _glfw.wl.keycodes[KEY_DOWN] = GLFW_KEY_DOWN;+ _glfw.wl.keycodes[KEY_UP] = GLFW_KEY_UP;+ _glfw.wl.keycodes[KEY_F1] = GLFW_KEY_F1;+ _glfw.wl.keycodes[KEY_F2] = GLFW_KEY_F2;+ _glfw.wl.keycodes[KEY_F3] = GLFW_KEY_F3;+ _glfw.wl.keycodes[KEY_F4] = GLFW_KEY_F4;+ _glfw.wl.keycodes[KEY_F5] = GLFW_KEY_F5;+ _glfw.wl.keycodes[KEY_F6] = GLFW_KEY_F6;+ _glfw.wl.keycodes[KEY_F7] = GLFW_KEY_F7;+ _glfw.wl.keycodes[KEY_F8] = GLFW_KEY_F8;+ _glfw.wl.keycodes[KEY_F9] = GLFW_KEY_F9;+ _glfw.wl.keycodes[KEY_F10] = GLFW_KEY_F10;+ _glfw.wl.keycodes[KEY_F11] = GLFW_KEY_F11;+ _glfw.wl.keycodes[KEY_F12] = GLFW_KEY_F12;+ _glfw.wl.keycodes[KEY_F13] = GLFW_KEY_F13;+ _glfw.wl.keycodes[KEY_F14] = GLFW_KEY_F14;+ _glfw.wl.keycodes[KEY_F15] = GLFW_KEY_F15;+ _glfw.wl.keycodes[KEY_F16] = GLFW_KEY_F16;+ _glfw.wl.keycodes[KEY_F17] = GLFW_KEY_F17;+ _glfw.wl.keycodes[KEY_F18] = GLFW_KEY_F18;+ _glfw.wl.keycodes[KEY_F19] = GLFW_KEY_F19;+ _glfw.wl.keycodes[KEY_F20] = GLFW_KEY_F20;+ _glfw.wl.keycodes[KEY_F21] = GLFW_KEY_F21;+ _glfw.wl.keycodes[KEY_F22] = GLFW_KEY_F22;+ _glfw.wl.keycodes[KEY_F23] = GLFW_KEY_F23;+ _glfw.wl.keycodes[KEY_F24] = GLFW_KEY_F24;+ _glfw.wl.keycodes[KEY_KPSLASH] = GLFW_KEY_KP_DIVIDE;+ _glfw.wl.keycodes[KEY_KPASTERISK] = GLFW_KEY_KP_MULTIPLY;+ _glfw.wl.keycodes[KEY_KPMINUS] = GLFW_KEY_KP_SUBTRACT;+ _glfw.wl.keycodes[KEY_KPPLUS] = GLFW_KEY_KP_ADD;+ _glfw.wl.keycodes[KEY_KP0] = GLFW_KEY_KP_0;+ _glfw.wl.keycodes[KEY_KP1] = GLFW_KEY_KP_1;+ _glfw.wl.keycodes[KEY_KP2] = GLFW_KEY_KP_2;+ _glfw.wl.keycodes[KEY_KP3] = GLFW_KEY_KP_3;+ _glfw.wl.keycodes[KEY_KP4] = GLFW_KEY_KP_4;+ _glfw.wl.keycodes[KEY_KP5] = GLFW_KEY_KP_5;+ _glfw.wl.keycodes[KEY_KP6] = GLFW_KEY_KP_6;+ _glfw.wl.keycodes[KEY_KP7] = GLFW_KEY_KP_7;+ _glfw.wl.keycodes[KEY_KP8] = GLFW_KEY_KP_8;+ _glfw.wl.keycodes[KEY_KP9] = GLFW_KEY_KP_9;+ _glfw.wl.keycodes[KEY_KPDOT] = GLFW_KEY_KP_DECIMAL;+ _glfw.wl.keycodes[KEY_KPEQUAL] = GLFW_KEY_KP_EQUAL;+ _glfw.wl.keycodes[KEY_KPENTER] = GLFW_KEY_KP_ENTER;+ _glfw.wl.keycodes[KEY_102ND] = GLFW_KEY_WORLD_2;++ for (scancode = 0; scancode < 256; scancode++)+ {+ if (_glfw.wl.keycodes[scancode] > 0)+ _glfw.wl.scancodes[_glfw.wl.keycodes[scancode]] = scancode;+ }+}++static GLFWbool loadCursorTheme(void)+{+ int cursorSize = 16;++ const char* sizeString = getenv("XCURSOR_SIZE");+ if (sizeString)+ {+ errno = 0;+ const long cursorSizeLong = strtol(sizeString, NULL, 10);+ if (errno == 0 && cursorSizeLong > 0 && cursorSizeLong < INT_MAX)+ cursorSize = (int) cursorSizeLong;+ }++ const char* themeName = getenv("XCURSOR_THEME");++ _glfw.wl.cursorTheme = wl_cursor_theme_load(themeName, cursorSize, _glfw.wl.shm);+ if (!_glfw.wl.cursorTheme)+ {+ _glfwInputError(GLFW_PLATFORM_ERROR,+ "Wayland: Failed to load default cursor theme");+ return GLFW_FALSE;+ }++ // If this happens to be NULL, we just fallback to the scale=1 version.+ _glfw.wl.cursorThemeHiDPI =+ wl_cursor_theme_load(themeName, cursorSize * 2, _glfw.wl.shm);++ _glfw.wl.cursorSurface = wl_compositor_create_surface(_glfw.wl.compositor);+ _glfw.wl.cursorTimerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);+ return GLFW_TRUE;+}+++//////////////////////////////////////////////////////////////////////////+////// GLFW platform API //////+//////////////////////////////////////////////////////////////////////////++int _glfwPlatformInit(void)+{+ // These must be set before any failure checks+ _glfw.wl.keyRepeatTimerfd = -1;+ _glfw.wl.cursorTimerfd = -1;++ _glfw.wl.tag = glfwGetVersionString();++ _glfw.wl.cursor.handle = _glfw_dlopen("libwayland-cursor.so.0");+ if (!_glfw.wl.cursor.handle)+ {+ _glfwInputError(GLFW_PLATFORM_ERROR,+ "Wayland: Failed to load libwayland-cursor");+ return GLFW_FALSE;+ }++ _glfw.wl.cursor.theme_load = (PFN_wl_cursor_theme_load)+ _glfw_dlsym(_glfw.wl.cursor.handle, "wl_cursor_theme_load");+ _glfw.wl.cursor.theme_destroy = (PFN_wl_cursor_theme_destroy)+ _glfw_dlsym(_glfw.wl.cursor.handle, "wl_cursor_theme_destroy");+ _glfw.wl.cursor.theme_get_cursor = (PFN_wl_cursor_theme_get_cursor)+ _glfw_dlsym(_glfw.wl.cursor.handle, "wl_cursor_theme_get_cursor");+ _glfw.wl.cursor.image_get_buffer = (PFN_wl_cursor_image_get_buffer)+ _glfw_dlsym(_glfw.wl.cursor.handle, "wl_cursor_image_get_buffer");++ _glfw.wl.egl.handle = _glfw_dlopen("libwayland-egl.so.1");+ if (!_glfw.wl.egl.handle)+ {+ _glfwInputError(GLFW_PLATFORM_ERROR,+ "Wayland: Failed to load libwayland-egl");+ return GLFW_FALSE;+ }++ _glfw.wl.egl.window_create = (PFN_wl_egl_window_create)+ _glfw_dlsym(_glfw.wl.egl.handle, "wl_egl_window_create");+ _glfw.wl.egl.window_destroy = (PFN_wl_egl_window_destroy)+ _glfw_dlsym(_glfw.wl.egl.handle, "wl_egl_window_destroy");+ _glfw.wl.egl.window_resize = (PFN_wl_egl_window_resize)+ _glfw_dlsym(_glfw.wl.egl.handle, "wl_egl_window_resize");++ _glfw.wl.xkb.handle = _glfw_dlopen("libxkbcommon.so.0");+ if (!_glfw.wl.xkb.handle)+ {+ _glfwInputError(GLFW_PLATFORM_ERROR,+ "Wayland: Failed to load libxkbcommon");+ return GLFW_FALSE;+ }++ _glfw.wl.xkb.context_new = (PFN_xkb_context_new)+ _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_context_new");+ _glfw.wl.xkb.context_unref = (PFN_xkb_context_unref)+ _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_context_unref");+ _glfw.wl.xkb.keymap_new_from_string = (PFN_xkb_keymap_new_from_string)+ _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_keymap_new_from_string");+ _glfw.wl.xkb.keymap_unref = (PFN_xkb_keymap_unref)+ _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_keymap_unref");+ _glfw.wl.xkb.keymap_mod_get_index = (PFN_xkb_keymap_mod_get_index)+ _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_keymap_mod_get_index");+ _glfw.wl.xkb.keymap_key_repeats = (PFN_xkb_keymap_key_repeats)+ _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_keymap_key_repeats");+ _glfw.wl.xkb.keymap_key_get_syms_by_level = (PFN_xkb_keymap_key_get_syms_by_level)+ _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_keymap_key_get_syms_by_level");+ _glfw.wl.xkb.state_new = (PFN_xkb_state_new)+ _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_state_new");+ _glfw.wl.xkb.state_unref = (PFN_xkb_state_unref)+ _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_state_unref");+ _glfw.wl.xkb.state_key_get_syms = (PFN_xkb_state_key_get_syms)+ _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_state_key_get_syms");+ _glfw.wl.xkb.state_update_mask = (PFN_xkb_state_update_mask)+ _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_state_update_mask");+ _glfw.wl.xkb.state_key_get_layout = (PFN_xkb_state_key_get_layout)+ _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_state_key_get_layout");+ _glfw.wl.xkb.state_mod_index_is_active = (PFN_xkb_state_mod_index_is_active)+ _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_state_mod_index_is_active");++ _glfw.wl.xkb.compose_table_new_from_locale = (PFN_xkb_compose_table_new_from_locale)+ _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_table_new_from_locale");+ _glfw.wl.xkb.compose_table_unref = (PFN_xkb_compose_table_unref)+ _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_table_unref");+ _glfw.wl.xkb.compose_state_new = (PFN_xkb_compose_state_new)+ _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_new");+ _glfw.wl.xkb.compose_state_unref = (PFN_xkb_compose_state_unref)+ _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_unref");+ _glfw.wl.xkb.compose_state_feed = (PFN_xkb_compose_state_feed)+ _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_feed");+ _glfw.wl.xkb.compose_state_get_status = (PFN_xkb_compose_state_get_status)+ _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_get_status");+ _glfw.wl.xkb.compose_state_get_one_sym = (PFN_xkb_compose_state_get_one_sym)+ _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_get_one_sym");++ _glfw.wl.display = wl_display_connect(NULL);+ if (!_glfw.wl.display)+ {+ _glfwInputError(GLFW_PLATFORM_ERROR,+ "Wayland: Failed to connect to display");+ return GLFW_FALSE;+ }++ if (_glfw.hints.init.wl.libdecorMode == GLFW_WAYLAND_PREFER_LIBDECOR)+ _glfw.wl.libdecor.handle = _glfw_dlopen("libdecor-0.so.0");++ if (_glfw.wl.libdecor.handle)+ {+ _glfw.wl.libdecor.libdecor_new_ = (PFN_libdecor_new)+ _glfw_dlsym(_glfw.wl.libdecor.handle, "libdecor_new");+ _glfw.wl.libdecor.libdecor_unref_ = (PFN_libdecor_unref)+ _glfw_dlsym(_glfw.wl.libdecor.handle, "libdecor_unref");+ _glfw.wl.libdecor.libdecor_get_fd_ = (PFN_libdecor_get_fd)+ _glfw_dlsym(_glfw.wl.libdecor.handle, "libdecor_get_fd");+ _glfw.wl.libdecor.libdecor_dispatch_ = (PFN_libdecor_dispatch)+ _glfw_dlsym(_glfw.wl.libdecor.handle, "libdecor_dispatch");+ _glfw.wl.libdecor.libdecor_decorate_ = (PFN_libdecor_decorate)+ _glfw_dlsym(_glfw.wl.libdecor.handle, "libdecor_decorate");+ _glfw.wl.libdecor.libdecor_frame_unref_ = (PFN_libdecor_frame_unref)+ _glfw_dlsym(_glfw.wl.libdecor.handle, "libdecor_frame_unref");+ _glfw.wl.libdecor.libdecor_frame_set_app_id_ = (PFN_libdecor_frame_set_app_id)+ _glfw_dlsym(_glfw.wl.libdecor.handle, "libdecor_frame_set_app_id");+ _glfw.wl.libdecor.libdecor_frame_set_title_ = (PFN_libdecor_frame_set_title)+ _glfw_dlsym(_glfw.wl.libdecor.handle, "libdecor_frame_set_title");+ _glfw.wl.libdecor.libdecor_frame_set_minimized_ = (PFN_libdecor_frame_set_minimized)+ _glfw_dlsym(_glfw.wl.libdecor.handle, "libdecor_frame_set_minimized");+ _glfw.wl.libdecor.libdecor_frame_set_fullscreen_ = (PFN_libdecor_frame_set_fullscreen)+ _glfw_dlsym(_glfw.wl.libdecor.handle, "libdecor_frame_set_fullscreen");+ _glfw.wl.libdecor.libdecor_frame_unset_fullscreen_ = (PFN_libdecor_frame_unset_fullscreen)+ _glfw_dlsym(_glfw.wl.libdecor.handle, "libdecor_frame_unset_fullscreen");+ _glfw.wl.libdecor.libdecor_frame_map_ = (PFN_libdecor_frame_map)+ _glfw_dlsym(_glfw.wl.libdecor.handle, "libdecor_frame_map");+ _glfw.wl.libdecor.libdecor_frame_commit_ = (PFN_libdecor_frame_commit)+ _glfw_dlsym(_glfw.wl.libdecor.handle, "libdecor_frame_commit");+ _glfw.wl.libdecor.libdecor_frame_set_min_content_size_ = (PFN_libdecor_frame_set_min_content_size)+ _glfw_dlsym(_glfw.wl.libdecor.handle, "libdecor_frame_set_min_content_size");+ _glfw.wl.libdecor.libdecor_frame_set_max_content_size_ = (PFN_libdecor_frame_set_max_content_size)+ _glfw_dlsym(_glfw.wl.libdecor.handle, "libdecor_frame_set_max_content_size");+ _glfw.wl.libdecor.libdecor_frame_set_maximized_ = (PFN_libdecor_frame_set_maximized)+ _glfw_dlsym(_glfw.wl.libdecor.handle, "libdecor_frame_set_maximized");+ _glfw.wl.libdecor.libdecor_frame_unset_maximized_ = (PFN_libdecor_frame_unset_maximized)+ _glfw_dlsym(_glfw.wl.libdecor.handle, "libdecor_frame_unset_maximized");+ _glfw.wl.libdecor.libdecor_frame_set_capabilities_ = (PFN_libdecor_frame_set_capabilities)+ _glfw_dlsym(_glfw.wl.libdecor.handle, "libdecor_frame_set_capabilities");+ _glfw.wl.libdecor.libdecor_frame_unset_capabilities_ = (PFN_libdecor_frame_unset_capabilities)+ _glfw_dlsym(_glfw.wl.libdecor.handle, "libdecor_frame_unset_capabilities");+ _glfw.wl.libdecor.libdecor_frame_set_visibility_ = (PFN_libdecor_frame_set_visibility)+ _glfw_dlsym(_glfw.wl.libdecor.handle, "libdecor_frame_set_visibility");+ _glfw.wl.libdecor.libdecor_frame_get_xdg_toplevel_ = (PFN_libdecor_frame_get_xdg_toplevel)+ _glfw_dlsym(_glfw.wl.libdecor.handle, "libdecor_frame_get_xdg_toplevel");+ _glfw.wl.libdecor.libdecor_configuration_get_content_size_ = (PFN_libdecor_configuration_get_content_size)+ _glfw_dlsym(_glfw.wl.libdecor.handle, "libdecor_configuration_get_content_size");+ _glfw.wl.libdecor.libdecor_configuration_get_window_state_ = (PFN_libdecor_configuration_get_window_state)+ _glfw_dlsym(_glfw.wl.libdecor.handle, "libdecor_configuration_get_window_state");+ _glfw.wl.libdecor.libdecor_state_new_ = (PFN_libdecor_state_new)+ _glfw_dlsym(_glfw.wl.libdecor.handle, "libdecor_state_new");+ _glfw.wl.libdecor.libdecor_state_free_ = (PFN_libdecor_state_free)+ _glfw_dlsym(_glfw.wl.libdecor.handle, "libdecor_state_free");++ if (!_glfw.wl.libdecor.libdecor_new_ ||+ !_glfw.wl.libdecor.libdecor_unref_ ||+ !_glfw.wl.libdecor.libdecor_get_fd_ ||+ !_glfw.wl.libdecor.libdecor_dispatch_ ||+ !_glfw.wl.libdecor.libdecor_decorate_ ||+ !_glfw.wl.libdecor.libdecor_frame_unref_ ||+ !_glfw.wl.libdecor.libdecor_frame_set_app_id_ ||+ !_glfw.wl.libdecor.libdecor_frame_set_title_ ||+ !_glfw.wl.libdecor.libdecor_frame_set_minimized_ ||+ !_glfw.wl.libdecor.libdecor_frame_set_fullscreen_ ||+ !_glfw.wl.libdecor.libdecor_frame_unset_fullscreen_ ||+ !_glfw.wl.libdecor.libdecor_frame_map_ ||+ !_glfw.wl.libdecor.libdecor_frame_commit_ ||+ !_glfw.wl.libdecor.libdecor_frame_set_min_content_size_ ||+ !_glfw.wl.libdecor.libdecor_frame_set_max_content_size_ ||+ !_glfw.wl.libdecor.libdecor_frame_set_maximized_ ||+ !_glfw.wl.libdecor.libdecor_frame_unset_maximized_ ||+ !_glfw.wl.libdecor.libdecor_frame_set_capabilities_ ||+ !_glfw.wl.libdecor.libdecor_frame_unset_capabilities_ ||+ !_glfw.wl.libdecor.libdecor_frame_set_visibility_ ||+ !_glfw.wl.libdecor.libdecor_frame_get_xdg_toplevel_ ||+ !_glfw.wl.libdecor.libdecor_configuration_get_content_size_ ||+ !_glfw.wl.libdecor.libdecor_configuration_get_window_state_ ||+ !_glfw.wl.libdecor.libdecor_state_new_ ||+ !_glfw.wl.libdecor.libdecor_state_free_)+ {+ _glfw_dlclose(_glfw.wl.libdecor.handle);+ memset(&_glfw.wl.libdecor, 0, sizeof(_glfw.wl.libdecor));+ }+ }++ _glfw.wl.registry = wl_display_get_registry(_glfw.wl.display);+ wl_registry_add_listener(_glfw.wl.registry, ®istryListener, NULL);++ createKeyTables();++ _glfw.wl.xkb.context = xkb_context_new(0);+ if (!_glfw.wl.xkb.context)+ {+ _glfwInputError(GLFW_PLATFORM_ERROR,+ "Wayland: Failed to initialize xkb context");+ return GLFW_FALSE;+ }++ // Sync so we got all registry objects+ wl_display_roundtrip(_glfw.wl.display);++ // Sync so we got all initial output events+ wl_display_roundtrip(_glfw.wl.display);++#ifdef __linux__+ if (!_glfwInitJoysticksLinux())+ return GLFW_FALSE;+#endif++ _glfwInitTimerPOSIX();++ if (_glfw.wl.libdecor.handle)+ {+ _glfw.wl.libdecor.context = libdecor_new(_glfw.wl.display, &libdecorInterface);+ if (_glfw.wl.libdecor.context)+ {+ // Perform an initial dispatch and flush to get the init started+ libdecor_dispatch(_glfw.wl.libdecor.context, 0);++ // Create sync point to "know" when libdecor is ready for use+ _glfw.wl.libdecor.callback = wl_display_sync(_glfw.wl.display);+ wl_callback_add_listener(_glfw.wl.libdecor.callback,+ &libdecorReadyListener,+ NULL);+ }+ }++#ifdef WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION+ if (wl_seat_get_version(_glfw.wl.seat) >= WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION)+ {+ _glfw.wl.keyRepeatTimerfd =+ timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);+ }+#endif++ if (!_glfw.wl.wmBase)+ {+ _glfwInputError(GLFW_PLATFORM_ERROR,+ "Wayland: Failed to find xdg-shell in your compositor");+ return GLFW_FALSE;+ }++ if (!_glfw.wl.shm)+ {+ _glfwInputError(GLFW_PLATFORM_ERROR,+ "Wayland: Failed to find wl_shm in your compositor");+ return GLFW_FALSE;+ }++ if (!loadCursorTheme())+ return GLFW_FALSE;++ if (_glfw.wl.seat && _glfw.wl.dataDeviceManager)+ {+ _glfw.wl.dataDevice =+ wl_data_device_manager_get_data_device(_glfw.wl.dataDeviceManager,+ _glfw.wl.seat);+ _glfwAddDataDeviceListenerWayland(_glfw.wl.dataDevice);+ }++ return GLFW_TRUE;+}++void _glfwPlatformTerminate(void)+{+#ifdef __linux__+ _glfwTerminateJoysticksLinux();+#endif+ _glfwTerminateEGL();+ _glfwTerminateOSMesa();++ if (_glfw.wl.libdecor.callback)+ wl_callback_destroy(_glfw.wl.libdecor.callback);+ if (_glfw.wl.libdecor.context)+ libdecor_unref(_glfw.wl.libdecor.context);++ if (_glfw.wl.libdecor.handle)+ {+ _glfw_dlclose(_glfw.wl.libdecor.handle);+ _glfw.wl.libdecor.handle = NULL;+ }++ if (_glfw.wl.egl.handle)+ {+ _glfw_dlclose(_glfw.wl.egl.handle);+ _glfw.wl.egl.handle = NULL;+ }++ if (_glfw.wl.xkb.composeState)+ xkb_compose_state_unref(_glfw.wl.xkb.composeState);+ if (_glfw.wl.xkb.keymap)+ xkb_keymap_unref(_glfw.wl.xkb.keymap);+ if (_glfw.wl.xkb.state)+ xkb_state_unref(_glfw.wl.xkb.state);+ if (_glfw.wl.xkb.context)+ xkb_context_unref(_glfw.wl.xkb.context);+ if (_glfw.wl.xkb.handle)+ {+ _glfw_dlclose(_glfw.wl.xkb.handle);+ _glfw.wl.xkb.handle = NULL;+ }++ if (_glfw.wl.cursorTheme)+ wl_cursor_theme_destroy(_glfw.wl.cursorTheme);+ if (_glfw.wl.cursorThemeHiDPI)+ wl_cursor_theme_destroy(_glfw.wl.cursorThemeHiDPI);+ if (_glfw.wl.cursor.handle)+ {+ _glfw_dlclose(_glfw.wl.cursor.handle);+ _glfw.wl.cursor.handle = NULL;+ }++ for (unsigned int i = 0; i < _glfw.wl.offerCount; i++)+ wl_data_offer_destroy(_glfw.wl.offers[i].offer);++ free(_glfw.wl.offers);++ if (_glfw.wl.cursorSurface)+ wl_surface_destroy(_glfw.wl.cursorSurface);+ if (_glfw.wl.subcompositor)+ wl_subcompositor_destroy(_glfw.wl.subcompositor);+ if (_glfw.wl.compositor)+ wl_compositor_destroy(_glfw.wl.compositor);+ if (_glfw.wl.shm)+ wl_shm_destroy(_glfw.wl.shm);+ if (_glfw.wl.viewporter)+ wp_viewporter_destroy(_glfw.wl.viewporter);+ if (_glfw.wl.decorationManager)+ zxdg_decoration_manager_v1_destroy(_glfw.wl.decorationManager);+ if (_glfw.wl.wmBase)+ xdg_wm_base_destroy(_glfw.wl.wmBase);+ if (_glfw.wl.selectionOffer)+ wl_data_offer_destroy(_glfw.wl.selectionOffer);+ if (_glfw.wl.dragOffer)+ wl_data_offer_destroy(_glfw.wl.dragOffer);+ if (_glfw.wl.selectionSource)+ wl_data_source_destroy(_glfw.wl.selectionSource);+ if (_glfw.wl.dataDevice)+ wl_data_device_destroy(_glfw.wl.dataDevice);+ if (_glfw.wl.dataDeviceManager)+ wl_data_device_manager_destroy(_glfw.wl.dataDeviceManager);+ if (_glfw.wl.pointer)+ wl_pointer_destroy(_glfw.wl.pointer);+ if (_glfw.wl.keyboard)+ wl_keyboard_destroy(_glfw.wl.keyboard);+ if (_glfw.wl.seat)+ wl_seat_destroy(_glfw.wl.seat);+ if (_glfw.wl.relativePointerManager)+ zwp_relative_pointer_manager_v1_destroy(_glfw.wl.relativePointerManager);+ if (_glfw.wl.pointerConstraints)+ zwp_pointer_constraints_v1_destroy(_glfw.wl.pointerConstraints);+ if (_glfw.wl.idleInhibitManager)+ zwp_idle_inhibit_manager_v1_destroy(_glfw.wl.idleInhibitManager);+ if (_glfw.wl.registry)+ wl_registry_destroy(_glfw.wl.registry);+ if (_glfw.wl.display)+ {+ wl_display_flush(_glfw.wl.display);+ wl_display_disconnect(_glfw.wl.display);+ }++ if (_glfw.wl.keyRepeatTimerfd >= 0)+ close(_glfw.wl.keyRepeatTimerfd);+ if (_glfw.wl.cursorTimerfd >= 0)+ close(_glfw.wl.cursorTimerfd);++ free(_glfw.wl.clipboardString); } const char* _glfwPlatformGetVersionString(void)
glfw/src/wl_monitor.c view
@@ -35,7 +35,7 @@ #include <math.h> -static void outputHandleGeometry(void* data,+static void outputHandleGeometry(void* userData, struct wl_output* output, int32_t x, int32_t y,@@ -46,26 +46,25 @@ const char* model, int32_t transform) {- struct _GLFWmonitor *monitor = data;- char name[1024];+ struct _GLFWmonitor* monitor = userData; monitor->wl.x = x; monitor->wl.y = y; monitor->widthMM = physicalWidth; monitor->heightMM = physicalHeight; - snprintf(name, sizeof(name), "%s %s", make, model);- monitor->name = _glfw_strdup(name);+ if (strlen(monitor->name) == 0)+ snprintf(monitor->name, sizeof(monitor->name), "%s %s", make, model); } -static void outputHandleMode(void* data,+static void outputHandleMode(void* userData, struct wl_output* output, uint32_t flags, int32_t width, int32_t height, int32_t refresh) {- struct _GLFWmonitor *monitor = data;+ struct _GLFWmonitor* monitor = userData; GLFWvidmode mode; mode.width = width;@@ -84,27 +83,76 @@ monitor->wl.currentMode = monitor->modeCount - 1; } -static void outputHandleDone(void* data, struct wl_output* output)+static void outputHandleDone(void* userData, struct wl_output* output) {- struct _GLFWmonitor *monitor = data;+ struct _GLFWmonitor* monitor = userData; + if (monitor->widthMM <= 0 || monitor->heightMM <= 0)+ {+ // If Wayland does not provide a physical size, assume the default 96 DPI+ const GLFWvidmode* mode = &monitor->modes[monitor->wl.currentMode];+ monitor->widthMM = (int) (mode->width * 25.4f / 96.f);+ monitor->heightMM = (int) (mode->height * 25.4f / 96.f);+ }++ for (int i = 0; i < _glfw.monitorCount; i++)+ {+ if (_glfw.monitors[i] == monitor)+ return;+ }+ _glfwInputMonitor(monitor, GLFW_CONNECTED, _GLFW_INSERT_LAST); } -static void outputHandleScale(void* data,+static void outputHandleScale(void* userData, struct wl_output* output, int32_t factor) {- struct _GLFWmonitor *monitor = data;+ struct _GLFWmonitor* monitor = userData; - monitor->wl.scale = factor;+ monitor->wl.contentScale = factor;++ for (_GLFWwindow* window = _glfw.windowListHead; window; window = window->next)+ {+ for (int i = 0; i < window->wl.scaleCount; i++)+ {+ if (window->wl.scales[i].output == monitor->wl.output)+ {+ window->wl.scales[i].factor = monitor->wl.contentScale;+ _glfwUpdateContentScaleWayland(window);+ break;+ }+ }+ } } -static const struct wl_output_listener outputListener = {+#ifdef WL_OUTPUT_NAME_SINCE_VERSION++void outputHandleName(void* userData, struct wl_output* wl_output, const char* name)+{+ struct _GLFWmonitor* monitor = userData;++ strncpy(monitor->name, name, sizeof(monitor->name) - 1);+}++void outputHandleDescription(void* userData,+ struct wl_output* wl_output,+ const char* description)+{+}++#endif // WL_OUTPUT_NAME_SINCE_VERSION++static const struct wl_output_listener outputListener =+{ outputHandleGeometry, outputHandleMode, outputHandleDone, outputHandleScale,+#ifdef WL_OUTPUT_NAME_SINCE_VERSION+ outputHandleName,+ outputHandleDescription,+#endif }; @@ -114,9 +162,6 @@ void _glfwAddOutputWayland(uint32_t name, uint32_t version) {- _GLFWmonitor *monitor;- struct wl_output *output;- if (version < 2) { _glfwInputError(GLFW_PLATFORM_ERROR,@@ -124,23 +169,26 @@ return; } - // The actual name of this output will be set in the geometry handler.- monitor = _glfwAllocMonitor(NULL, 0, 0);+#ifdef WL_OUTPUT_NAME_SINCE_VERSION+ version = _glfw_min(version, WL_OUTPUT_NAME_SINCE_VERSION);+#else+ version = 2;+#endif - output = wl_registry_bind(_glfw.wl.registry,- name,- &wl_output_interface,- 2);+ struct wl_output* output = wl_registry_bind(_glfw.wl.registry,+ name,+ &wl_output_interface,+ version); if (!output)- {- _glfwFreeMonitor(monitor); return;- } - monitor->wl.scale = 1;+ // The actual name of this output will be set in the geometry handler+ _GLFWmonitor* monitor = _glfwAllocMonitor("", 0, 0);+ monitor->wl.contentScale = 1; monitor->wl.output = output; monitor->wl.name = name; + wl_proxy_set_tag((struct wl_proxy*) output, &_glfw.wl.tag); wl_output_add_listener(output, &outputListener, monitor); } @@ -167,9 +215,9 @@ float* xscale, float* yscale) { if (xscale)- *xscale = (float) monitor->wl.scale;+ *xscale = (float) monitor->wl.contentScale; if (yscale)- *yscale = (float) monitor->wl.scale;+ *yscale = (float) monitor->wl.contentScale; } void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor,
glfw/src/wl_platform.h view
@@ -26,11 +26,11 @@ #include <wayland-client.h> #include <xkbcommon/xkbcommon.h>-#ifdef HAVE_XKBCOMMON_COMPOSE_H #include <xkbcommon/xkbcommon-compose.h>-#endif #include <dlfcn.h> +#include <stdbool.h>+ typedef VkFlags VkWaylandSurfaceCreateFlagsKHR; typedef struct VkWaylandSurfaceCreateInfoKHR@@ -67,7 +67,7 @@ #define _glfw_dlclose(handle) dlclose(handle) #define _glfw_dlsym(handle, name) dlsym(handle, name) -#define _GLFW_EGL_NATIVE_WINDOW ((EGLNativeWindowType) window->wl.native)+#define _GLFW_EGL_NATIVE_WINDOW ((EGLNativeWindowType) window->wl.egl.window) #define _GLFW_EGL_NATIVE_DISPLAY ((EGLNativeDisplayType) _glfw.wl.display) #define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowWayland wl@@ -112,24 +112,27 @@ typedef void (* PFN_xkb_keymap_unref)(struct xkb_keymap*); typedef xkb_mod_index_t (* PFN_xkb_keymap_mod_get_index)(struct xkb_keymap*, const char*); typedef int (* PFN_xkb_keymap_key_repeats)(struct xkb_keymap*, xkb_keycode_t);+typedef int (* PFN_xkb_keymap_key_get_syms_by_level)(struct xkb_keymap*,xkb_keycode_t,xkb_layout_index_t,xkb_level_index_t,const xkb_keysym_t**); typedef struct xkb_state* (* PFN_xkb_state_new)(struct xkb_keymap*); typedef void (* PFN_xkb_state_unref)(struct xkb_state*); typedef int (* PFN_xkb_state_key_get_syms)(struct xkb_state*, xkb_keycode_t, const xkb_keysym_t**); typedef enum xkb_state_component (* PFN_xkb_state_update_mask)(struct xkb_state*, xkb_mod_mask_t, xkb_mod_mask_t, xkb_mod_mask_t, xkb_layout_index_t, xkb_layout_index_t, xkb_layout_index_t);-typedef xkb_mod_mask_t (* PFN_xkb_state_serialize_mods)(struct xkb_state*, enum xkb_state_component);+typedef xkb_layout_index_t (* PFN_xkb_state_key_get_layout)(struct xkb_state*,xkb_keycode_t);+typedef int (* PFN_xkb_state_mod_index_is_active)(struct xkb_state*,xkb_mod_index_t,enum xkb_state_component); #define xkb_context_new _glfw.wl.xkb.context_new #define xkb_context_unref _glfw.wl.xkb.context_unref #define xkb_keymap_new_from_string _glfw.wl.xkb.keymap_new_from_string #define xkb_keymap_unref _glfw.wl.xkb.keymap_unref #define xkb_keymap_mod_get_index _glfw.wl.xkb.keymap_mod_get_index #define xkb_keymap_key_repeats _glfw.wl.xkb.keymap_key_repeats+#define xkb_keymap_key_get_syms_by_level _glfw.wl.xkb.keymap_key_get_syms_by_level #define xkb_state_new _glfw.wl.xkb.state_new #define xkb_state_unref _glfw.wl.xkb.state_unref #define xkb_state_key_get_syms _glfw.wl.xkb.state_key_get_syms #define xkb_state_update_mask _glfw.wl.xkb.state_update_mask-#define xkb_state_serialize_mods _glfw.wl.xkb.state_serialize_mods+#define xkb_state_key_get_layout _glfw.wl.xkb.state_key_get_layout+#define xkb_state_mod_index_is_active _glfw.wl.xkb.state_mod_index_is_active -#ifdef HAVE_XKBCOMMON_COMPOSE_H typedef struct xkb_compose_table* (* PFN_xkb_compose_table_new_from_locale)(struct xkb_context*, const char*, enum xkb_compose_compile_flags); typedef void (* PFN_xkb_compose_table_unref)(struct xkb_compose_table*); typedef struct xkb_compose_state* (* PFN_xkb_compose_state_new)(struct xkb_compose_table*, enum xkb_compose_state_flags);@@ -144,21 +147,130 @@ #define xkb_compose_state_feed _glfw.wl.xkb.compose_state_feed #define xkb_compose_state_get_status _glfw.wl.xkb.compose_state_get_status #define xkb_compose_state_get_one_sym _glfw.wl.xkb.compose_state_get_one_sym-#endif -#define _GLFW_DECORATION_WIDTH 4-#define _GLFW_DECORATION_TOP 24-#define _GLFW_DECORATION_VERTICAL (_GLFW_DECORATION_TOP + _GLFW_DECORATION_WIDTH)-#define _GLFW_DECORATION_HORIZONTAL (2 * _GLFW_DECORATION_WIDTH)+struct libdecor;+struct libdecor_frame;+struct libdecor_state;+struct libdecor_configuration; -typedef enum _GLFWdecorationSideWayland+enum libdecor_error {- mainWindow,- topDecoration,- leftDecoration,- rightDecoration,- bottomDecoration,+ LIBDECOR_ERROR_COMPOSITOR_INCOMPATIBLE,+ LIBDECOR_ERROR_INVALID_FRAME_CONFIGURATION,+}; +enum libdecor_window_state+{+ LIBDECOR_WINDOW_STATE_NONE = 0,+ LIBDECOR_WINDOW_STATE_ACTIVE = 1,+ LIBDECOR_WINDOW_STATE_MAXIMIZED = 2,+ LIBDECOR_WINDOW_STATE_FULLSCREEN = 4,+ LIBDECOR_WINDOW_STATE_TILED_LEFT = 8,+ LIBDECOR_WINDOW_STATE_TILED_RIGHT = 16,+ LIBDECOR_WINDOW_STATE_TILED_TOP = 32,+ LIBDECOR_WINDOW_STATE_TILED_BOTTOM = 64+};++enum libdecor_capabilities+{+ LIBDECOR_ACTION_MOVE = 1,+ LIBDECOR_ACTION_RESIZE = 2,+ LIBDECOR_ACTION_MINIMIZE = 4,+ LIBDECOR_ACTION_FULLSCREEN = 8,+ LIBDECOR_ACTION_CLOSE = 16+};++struct libdecor_interface+{+ void (* error)(struct libdecor*,enum libdecor_error,const char*);+ void (* reserved0)(void);+ void (* reserved1)(void);+ void (* reserved2)(void);+ void (* reserved3)(void);+ void (* reserved4)(void);+ void (* reserved5)(void);+ void (* reserved6)(void);+ void (* reserved7)(void);+ void (* reserved8)(void);+ void (* reserved9)(void);+};++struct libdecor_frame_interface+{+ void (* configure)(struct libdecor_frame*,struct libdecor_configuration*,void*);+ void (* close)(struct libdecor_frame*,void*);+ void (* commit)(struct libdecor_frame*,void*);+ void (* dismiss_popup)(struct libdecor_frame*,const char*,void*);+ void (* reserved0)(void);+ void (* reserved1)(void);+ void (* reserved2)(void);+ void (* reserved3)(void);+ void (* reserved4)(void);+ void (* reserved5)(void);+ void (* reserved6)(void);+ void (* reserved7)(void);+ void (* reserved8)(void);+ void (* reserved9)(void);+};++typedef struct libdecor* (* PFN_libdecor_new)(struct wl_display*,const struct libdecor_interface*);+typedef void (* PFN_libdecor_unref)(struct libdecor*);+typedef int (* PFN_libdecor_get_fd)(struct libdecor*);+typedef int (* PFN_libdecor_dispatch)(struct libdecor*,int);+typedef struct libdecor_frame* (* PFN_libdecor_decorate)(struct libdecor*,struct wl_surface*,const struct libdecor_frame_interface*,void*);+typedef void (* PFN_libdecor_frame_unref)(struct libdecor_frame*);+typedef void (* PFN_libdecor_frame_set_app_id)(struct libdecor_frame*,const char*);+typedef void (* PFN_libdecor_frame_set_title)(struct libdecor_frame*,const char*);+typedef void (* PFN_libdecor_frame_set_minimized)(struct libdecor_frame*);+typedef void (* PFN_libdecor_frame_set_fullscreen)(struct libdecor_frame*,struct wl_output*);+typedef void (* PFN_libdecor_frame_unset_fullscreen)(struct libdecor_frame*);+typedef void (* PFN_libdecor_frame_map)(struct libdecor_frame*);+typedef void (* PFN_libdecor_frame_commit)(struct libdecor_frame*,struct libdecor_state*,struct libdecor_configuration*);+typedef void (* PFN_libdecor_frame_set_min_content_size)(struct libdecor_frame*,int,int);+typedef void (* PFN_libdecor_frame_set_max_content_size)(struct libdecor_frame*,int,int);+typedef void (* PFN_libdecor_frame_set_maximized)(struct libdecor_frame*);+typedef void (* PFN_libdecor_frame_unset_maximized)(struct libdecor_frame*);+typedef void (* PFN_libdecor_frame_set_capabilities)(struct libdecor_frame*,enum libdecor_capabilities);+typedef void (* PFN_libdecor_frame_unset_capabilities)(struct libdecor_frame*,enum libdecor_capabilities);+typedef void (* PFN_libdecor_frame_set_visibility)(struct libdecor_frame*,bool visible);+typedef struct xdg_toplevel* (* PFN_libdecor_frame_get_xdg_toplevel)(struct libdecor_frame*);+typedef bool (* PFN_libdecor_configuration_get_content_size)(struct libdecor_configuration*,struct libdecor_frame*,int*,int*);+typedef bool (* PFN_libdecor_configuration_get_window_state)(struct libdecor_configuration*,enum libdecor_window_state*);+typedef struct libdecor_state* (* PFN_libdecor_state_new)(int,int);+typedef void (* PFN_libdecor_state_free)(struct libdecor_state*);+#define libdecor_new _glfw.wl.libdecor.libdecor_new_+#define libdecor_unref _glfw.wl.libdecor.libdecor_unref_+#define libdecor_get_fd _glfw.wl.libdecor.libdecor_get_fd_+#define libdecor_dispatch _glfw.wl.libdecor.libdecor_dispatch_+#define libdecor_decorate _glfw.wl.libdecor.libdecor_decorate_+#define libdecor_frame_unref _glfw.wl.libdecor.libdecor_frame_unref_+#define libdecor_frame_set_app_id _glfw.wl.libdecor.libdecor_frame_set_app_id_+#define libdecor_frame_set_title _glfw.wl.libdecor.libdecor_frame_set_title_+#define libdecor_frame_set_minimized _glfw.wl.libdecor.libdecor_frame_set_minimized_+#define libdecor_frame_set_fullscreen _glfw.wl.libdecor.libdecor_frame_set_fullscreen_+#define libdecor_frame_unset_fullscreen _glfw.wl.libdecor.libdecor_frame_unset_fullscreen_+#define libdecor_frame_map _glfw.wl.libdecor.libdecor_frame_map_+#define libdecor_frame_commit _glfw.wl.libdecor.libdecor_frame_commit_+#define libdecor_frame_set_min_content_size _glfw.wl.libdecor.libdecor_frame_set_min_content_size_+#define libdecor_frame_set_max_content_size _glfw.wl.libdecor.libdecor_frame_set_max_content_size_+#define libdecor_frame_set_maximized _glfw.wl.libdecor.libdecor_frame_set_maximized_+#define libdecor_frame_unset_maximized _glfw.wl.libdecor.libdecor_frame_unset_maximized_+#define libdecor_frame_set_capabilities _glfw.wl.libdecor.libdecor_frame_set_capabilities_+#define libdecor_frame_unset_capabilities _glfw.wl.libdecor.libdecor_frame_unset_capabilities_+#define libdecor_frame_set_visibility _glfw.wl.libdecor.libdecor_frame_set_visibility_+#define libdecor_frame_get_xdg_toplevel _glfw.wl.libdecor.libdecor_frame_get_xdg_toplevel_+#define libdecor_configuration_get_content_size _glfw.wl.libdecor.libdecor_configuration_get_content_size_+#define libdecor_configuration_get_window_state _glfw.wl.libdecor.libdecor_configuration_get_window_state_+#define libdecor_state_new _glfw.wl.libdecor.libdecor_state_new_+#define libdecor_state_free _glfw.wl.libdecor.libdecor_state_free_++typedef enum _GLFWdecorationSideWayland+{+ GLFW_MAIN_WINDOW,+ GLFW_TOP_DECORATION,+ GLFW_LEFT_DECORATION,+ GLFW_RIGHT_DECORATION,+ GLFW_BOTTOM_DECORATION } _GLFWdecorationSideWayland; typedef struct _GLFWdecorationWayland@@ -166,9 +278,21 @@ struct wl_surface* surface; struct wl_subsurface* subsurface; struct wp_viewport* viewport;- } _GLFWdecorationWayland; +typedef struct _GLFWofferWayland+{+ struct wl_data_offer* offer;+ GLFWbool text_plain_utf8;+ GLFWbool text_uri_list;+} _GLFWofferWayland;++typedef struct _GLFWscaleWayland+{+ struct wl_output* output;+ int factor;+} _GLFWscaleWayland;+ // Wayland-specific per-window data // typedef struct _GLFWwindowWayland@@ -176,19 +300,37 @@ int width, height; GLFWbool visible; GLFWbool maximized;+ GLFWbool activated;+ GLFWbool fullscreen; GLFWbool hovered; GLFWbool transparent; struct wl_surface* surface;- struct wl_egl_window* native;- struct wl_shell_surface* shellSurface; struct wl_callback* callback; struct {+ struct wl_egl_window* window;+ } egl;++ struct {+ int width, height;+ GLFWbool maximized;+ GLFWbool iconified;+ GLFWbool activated;+ GLFWbool fullscreen;+ } pending;++ struct { struct xdg_surface* surface; struct xdg_toplevel* toplevel; struct zxdg_toplevel_decoration_v1* decoration;+ uint32_t decorationMode; } xdg; + struct {+ struct libdecor_frame* frame;+ int mode;+ } libdecor;+ _GLFWcursor* currentCursor; double cursorPosX, cursorPosY; @@ -196,27 +338,21 @@ // We need to track the monitors the window spans on to calculate the // optimal scaling factor.- int scale;- _GLFWmonitor** monitors;- int monitorsCount;- int monitorsSize;+ int contentScale;+ _GLFWscaleWayland* scales;+ int scaleCount;+ int scaleSize; - struct {- struct zwp_relative_pointer_v1* relativePointer;- struct zwp_locked_pointer_v1* lockedPointer;- } pointerLock;+ struct zwp_relative_pointer_v1* relativePointer;+ struct zwp_locked_pointer_v1* lockedPointer; struct zwp_idle_inhibitor_v1* idleInhibitor; - GLFWbool wasFullscreen;- struct {- GLFWbool serverSide; struct wl_buffer* buffer; _GLFWdecorationWayland top, left, right, bottom;- int focus;+ _GLFWdecorationSideWayland focus; } decorations;- } _GLFWwindowWayland; // Wayland-specific global data@@ -227,15 +363,12 @@ struct wl_registry* registry; struct wl_compositor* compositor; struct wl_subcompositor* subcompositor;- struct wl_shell* shell; struct wl_shm* shm; struct wl_seat* seat; struct wl_pointer* pointer; struct wl_keyboard* keyboard; struct wl_data_device_manager* dataDeviceManager; struct wl_data_device* dataDevice;- struct wl_data_offer* dataOffer;- struct wl_data_source* dataSource; struct xdg_wm_base* wmBase; struct zxdg_decoration_manager_v1* decorationManager; struct wp_viewporter* viewporter;@@ -243,44 +376,49 @@ struct zwp_pointer_constraints_v1* pointerConstraints; struct zwp_idle_inhibit_manager_v1* idleInhibitManager; - int compositorVersion;- int seatVersion;+ _GLFWofferWayland* offers;+ unsigned int offerCount; + struct wl_data_offer* selectionOffer;+ struct wl_data_source* selectionSource;++ struct wl_data_offer* dragOffer;+ _GLFWwindow* dragFocus;+ uint32_t dragSerial;++ const char* tag;+ struct wl_cursor_theme* cursorTheme; struct wl_cursor_theme* cursorThemeHiDPI; struct wl_surface* cursorSurface; const char* cursorPreviousName; int cursorTimerfd; uint32_t serial;+ uint32_t pointerEnterSerial; - int32_t keyboardRepeatRate;- int32_t keyboardRepeatDelay;- int keyboardLastKey;- int keyboardLastScancode;+ int keyRepeatTimerfd;+ int32_t keyRepeatRate;+ int32_t keyRepeatDelay;+ int keyRepeatScancode;+ char* clipboardString;- size_t clipboardSize;- char* clipboardSendString;- size_t clipboardSendSize;- int timerfd; short int keycodes[256]; short int scancodes[GLFW_KEY_LAST + 1];+ char keynames[GLFW_KEY_LAST + 1][5]; struct { void* handle; struct xkb_context* context; struct xkb_keymap* keymap; struct xkb_state* state;--#ifdef HAVE_XKBCOMMON_COMPOSE_H struct xkb_compose_state* composeState;-#endif - xkb_mod_mask_t controlMask;- xkb_mod_mask_t altMask;- xkb_mod_mask_t shiftMask;- xkb_mod_mask_t superMask;- xkb_mod_mask_t capsLockMask;- xkb_mod_mask_t numLockMask;+ xkb_mod_index_t controlIndex;+ xkb_mod_index_t altIndex;+ xkb_mod_index_t shiftIndex;+ xkb_mod_index_t superIndex;+ xkb_mod_index_t capsLockIndex;+ xkb_mod_index_t numLockIndex; unsigned int modifiers; PFN_xkb_context_new context_new;@@ -289,13 +427,14 @@ PFN_xkb_keymap_unref keymap_unref; PFN_xkb_keymap_mod_get_index keymap_mod_get_index; PFN_xkb_keymap_key_repeats keymap_key_repeats;+ PFN_xkb_keymap_key_get_syms_by_level keymap_key_get_syms_by_level; PFN_xkb_state_new state_new; PFN_xkb_state_unref state_unref; PFN_xkb_state_key_get_syms state_key_get_syms; PFN_xkb_state_update_mask state_update_mask;- PFN_xkb_state_serialize_mods state_serialize_mods;+ PFN_xkb_state_key_get_layout state_key_get_layout;+ PFN_xkb_state_mod_index_is_active state_mod_index_is_active; -#ifdef HAVE_XKBCOMMON_COMPOSE_H PFN_xkb_compose_table_new_from_locale compose_table_new_from_locale; PFN_xkb_compose_table_unref compose_table_unref; PFN_xkb_compose_state_new compose_state_new;@@ -303,7 +442,6 @@ PFN_xkb_compose_state_feed compose_state_feed; PFN_xkb_compose_state_get_status compose_state_get_status; PFN_xkb_compose_state_get_one_sym compose_state_get_one_sym;-#endif } xkb; _GLFWwindow* pointerFocus;@@ -326,6 +464,37 @@ PFN_wl_egl_window_resize window_resize; } egl; + struct {+ void* handle;+ struct libdecor* context;+ struct wl_callback* callback;+ GLFWbool ready;+ PFN_libdecor_new libdecor_new_;+ PFN_libdecor_unref libdecor_unref_;+ PFN_libdecor_get_fd libdecor_get_fd_;+ PFN_libdecor_dispatch libdecor_dispatch_;+ PFN_libdecor_decorate libdecor_decorate_;+ PFN_libdecor_frame_unref libdecor_frame_unref_;+ PFN_libdecor_frame_set_app_id libdecor_frame_set_app_id_;+ PFN_libdecor_frame_set_title libdecor_frame_set_title_;+ PFN_libdecor_frame_set_minimized libdecor_frame_set_minimized_;+ PFN_libdecor_frame_set_fullscreen libdecor_frame_set_fullscreen_;+ PFN_libdecor_frame_unset_fullscreen libdecor_frame_unset_fullscreen_;+ PFN_libdecor_frame_map libdecor_frame_map_;+ PFN_libdecor_frame_commit libdecor_frame_commit_;+ PFN_libdecor_frame_set_min_content_size libdecor_frame_set_min_content_size_;+ PFN_libdecor_frame_set_max_content_size libdecor_frame_set_max_content_size_;+ PFN_libdecor_frame_set_maximized libdecor_frame_set_maximized_;+ PFN_libdecor_frame_unset_maximized libdecor_frame_unset_maximized_;+ PFN_libdecor_frame_set_capabilities libdecor_frame_set_capabilities_;+ PFN_libdecor_frame_unset_capabilities libdecor_frame_unset_capabilities_;+ PFN_libdecor_frame_set_visibility libdecor_frame_set_visibility_;+ PFN_libdecor_frame_get_xdg_toplevel libdecor_frame_get_xdg_toplevel_;+ PFN_libdecor_configuration_get_content_size libdecor_configuration_get_content_size_;+ PFN_libdecor_configuration_get_window_state libdecor_configuration_get_window_state_;+ PFN_libdecor_state_new libdecor_state_new_;+ PFN_libdecor_state_free libdecor_state_free_;+ } libdecor; } _GLFWlibraryWayland; // Wayland-specific per-monitor data@@ -338,8 +507,7 @@ int x; int y;- int scale;-+ int contentScale; } _GLFWmonitorWayland; // Wayland-specific per-cursor data@@ -354,6 +522,9 @@ int currentImage; } _GLFWcursorWayland; - void _glfwAddOutputWayland(uint32_t name, uint32_t version);+void _glfwUpdateContentScaleWayland(_GLFWwindow* window);++void _glfwAddSeatListenerWayland(struct wl_seat* seat);+void _glfwAddDataDeviceListenerWayland(struct wl_data_device* device);
glfw/src/wl_window.c view
@@ -33,1781 +33,2944 @@ #include <stdio.h> #include <stdlib.h> #include <errno.h>-#include <unistd.h>-#include <string.h>-#include <fcntl.h>-#include <sys/mman.h>-#include <sys/timerfd.h>-#include <poll.h>---static void shellSurfaceHandlePing(void* data,- struct wl_shell_surface* shellSurface,- uint32_t serial)-{- wl_shell_surface_pong(shellSurface, serial);-}--static void shellSurfaceHandleConfigure(void* data,- struct wl_shell_surface* shellSurface,- uint32_t edges,- int32_t width,- int32_t height)-{- _GLFWwindow* window = data;- float aspectRatio;- float targetRatio;-- if (!window->monitor)- {- if (_glfw.wl.viewporter && window->decorated)- {- width -= _GLFW_DECORATION_HORIZONTAL;- height -= _GLFW_DECORATION_VERTICAL;- }- if (width < 1)- width = 1;- if (height < 1)- height = 1;-- if (window->numer != GLFW_DONT_CARE && window->denom != GLFW_DONT_CARE)- {- aspectRatio = (float)width / (float)height;- targetRatio = (float)window->numer / (float)window->denom;- if (aspectRatio < targetRatio)- height = width / targetRatio;- else if (aspectRatio > targetRatio)- width = height * targetRatio;- }-- if (window->minwidth != GLFW_DONT_CARE && width < window->minwidth)- width = window->minwidth;- else if (window->maxwidth != GLFW_DONT_CARE && width > window->maxwidth)- width = window->maxwidth;-- if (window->minheight != GLFW_DONT_CARE && height < window->minheight)- height = window->minheight;- else if (window->maxheight != GLFW_DONT_CARE && height > window->maxheight)- height = window->maxheight;- }-- _glfwInputWindowSize(window, width, height);- _glfwPlatformSetWindowSize(window, width, height);- _glfwInputWindowDamage(window);-}--static void shellSurfaceHandlePopupDone(void* data,- struct wl_shell_surface* shellSurface)-{-}--static const struct wl_shell_surface_listener shellSurfaceListener = {- shellSurfaceHandlePing,- shellSurfaceHandleConfigure,- shellSurfaceHandlePopupDone-};--static int createTmpfileCloexec(char* tmpname)-{- int fd;-- fd = mkostemp(tmpname, O_CLOEXEC);- if (fd >= 0)- unlink(tmpname);-- return fd;-}--/*- * Create a new, unique, anonymous file of the given size, and- * return the file descriptor for it. The file descriptor is set- * CLOEXEC. The file is immediately suitable for mmap()'ing- * the given size at offset zero.- *- * The file should not have a permanent backing store like a disk,- * but may have if XDG_RUNTIME_DIR is not properly implemented in OS.- *- * The file name is deleted from the file system.- *- * The file is suitable for buffer sharing between processes by- * transmitting the file descriptor over Unix sockets using the- * SCM_RIGHTS methods.- *- * posix_fallocate() is used to guarantee that disk space is available- * for the file at the given size. If disk space is insufficient, errno- * is set to ENOSPC. If posix_fallocate() is not supported, program may- * receive SIGBUS on accessing mmap()'ed file contents instead.- */-static int createAnonymousFile(off_t size)-{- static const char template[] = "/glfw-shared-XXXXXX";- const char* path;- char* name;- int fd;- int ret;--#ifdef HAVE_MEMFD_CREATE- fd = memfd_create("glfw-shared", MFD_CLOEXEC | MFD_ALLOW_SEALING);- if (fd >= 0)- {- // We can add this seal before calling posix_fallocate(), as the file- // is currently zero-sized anyway.- //- // There is also no need to check for the return value, we couldn’t do- // anything with it anyway.- fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_SEAL);- }- else-#elif defined(SHM_ANON)- fd = shm_open(SHM_ANON, O_RDWR | O_CLOEXEC, 0600);- if (fd < 0)-#endif- {- path = getenv("XDG_RUNTIME_DIR");- if (!path)- {- errno = ENOENT;- return -1;- }-- name = calloc(strlen(path) + sizeof(template), 1);- strcpy(name, path);- strcat(name, template);-- fd = createTmpfileCloexec(name);- free(name);- if (fd < 0)- return -1;- }--#if defined(SHM_ANON)- // posix_fallocate does not work on SHM descriptors- ret = ftruncate(fd, size);-#else- ret = posix_fallocate(fd, 0, size);-#endif- if (ret != 0)- {- close(fd);- errno = ret;- return -1;- }- return fd;-}--static struct wl_buffer* createShmBuffer(const GLFWimage* image)-{- struct wl_shm_pool* pool;- struct wl_buffer* buffer;- int stride = image->width * 4;- int length = image->width * image->height * 4;- void* data;- int fd, i;-- fd = createAnonymousFile(length);- if (fd < 0)- {- _glfwInputError(GLFW_PLATFORM_ERROR,- "Wayland: Creating a buffer file for %d B failed: %m",- length);- return NULL;- }-- data = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);- if (data == MAP_FAILED)- {- _glfwInputError(GLFW_PLATFORM_ERROR,- "Wayland: mmap failed: %m");- close(fd);- return NULL;- }-- pool = wl_shm_create_pool(_glfw.wl.shm, fd, length);-- close(fd);- unsigned char* source = (unsigned char*) image->pixels;- unsigned char* target = data;- for (i = 0; i < image->width * image->height; i++, source += 4)- {- unsigned int alpha = source[3];-- *target++ = (unsigned char) ((source[2] * alpha) / 255);- *target++ = (unsigned char) ((source[1] * alpha) / 255);- *target++ = (unsigned char) ((source[0] * alpha) / 255);- *target++ = (unsigned char) alpha;- }-- buffer =- wl_shm_pool_create_buffer(pool, 0,- image->width,- image->height,- stride, WL_SHM_FORMAT_ARGB8888);- munmap(data, length);- wl_shm_pool_destroy(pool);-- return buffer;-}--static void createDecoration(_GLFWdecorationWayland* decoration,- struct wl_surface* parent,- struct wl_buffer* buffer, GLFWbool opaque,- int x, int y,- int width, int height)-{- struct wl_region* region;-- decoration->surface = wl_compositor_create_surface(_glfw.wl.compositor);- decoration->subsurface =- wl_subcompositor_get_subsurface(_glfw.wl.subcompositor,- decoration->surface, parent);- wl_subsurface_set_position(decoration->subsurface, x, y);- decoration->viewport = wp_viewporter_get_viewport(_glfw.wl.viewporter,- decoration->surface);- wp_viewport_set_destination(decoration->viewport, width, height);- wl_surface_attach(decoration->surface, buffer, 0, 0);-- if (opaque)- {- region = wl_compositor_create_region(_glfw.wl.compositor);- wl_region_add(region, 0, 0, width, height);- wl_surface_set_opaque_region(decoration->surface, region);- wl_surface_commit(decoration->surface);- wl_region_destroy(region);- }- else- wl_surface_commit(decoration->surface);-}--static void createDecorations(_GLFWwindow* window)-{- unsigned char data[] = { 224, 224, 224, 255 };- const GLFWimage image = { 1, 1, data };- GLFWbool opaque = (data[3] == 255);-- if (!_glfw.wl.viewporter || !window->decorated || window->wl.decorations.serverSide)- return;-- if (!window->wl.decorations.buffer)- window->wl.decorations.buffer = createShmBuffer(&image);- if (!window->wl.decorations.buffer)- return;-- createDecoration(&window->wl.decorations.top, window->wl.surface,- window->wl.decorations.buffer, opaque,- 0, -_GLFW_DECORATION_TOP,- window->wl.width, _GLFW_DECORATION_TOP);- createDecoration(&window->wl.decorations.left, window->wl.surface,- window->wl.decorations.buffer, opaque,- -_GLFW_DECORATION_WIDTH, -_GLFW_DECORATION_TOP,- _GLFW_DECORATION_WIDTH, window->wl.height + _GLFW_DECORATION_TOP);- createDecoration(&window->wl.decorations.right, window->wl.surface,- window->wl.decorations.buffer, opaque,- window->wl.width, -_GLFW_DECORATION_TOP,- _GLFW_DECORATION_WIDTH, window->wl.height + _GLFW_DECORATION_TOP);- createDecoration(&window->wl.decorations.bottom, window->wl.surface,- window->wl.decorations.buffer, opaque,- -_GLFW_DECORATION_WIDTH, window->wl.height,- window->wl.width + _GLFW_DECORATION_HORIZONTAL, _GLFW_DECORATION_WIDTH);-}--static void destroyDecoration(_GLFWdecorationWayland* decoration)-{- if (decoration->surface)- wl_surface_destroy(decoration->surface);- if (decoration->subsurface)- wl_subsurface_destroy(decoration->subsurface);- if (decoration->viewport)- wp_viewport_destroy(decoration->viewport);- decoration->surface = NULL;- decoration->subsurface = NULL;- decoration->viewport = NULL;-}--static void destroyDecorations(_GLFWwindow* window)-{- destroyDecoration(&window->wl.decorations.top);- destroyDecoration(&window->wl.decorations.left);- destroyDecoration(&window->wl.decorations.right);- destroyDecoration(&window->wl.decorations.bottom);-}--static void xdgDecorationHandleConfigure(void* data,- struct zxdg_toplevel_decoration_v1* decoration,- uint32_t mode)-{- _GLFWwindow* window = data;-- window->wl.decorations.serverSide = (mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);-- if (!window->wl.decorations.serverSide)- createDecorations(window);-}--static const struct zxdg_toplevel_decoration_v1_listener xdgDecorationListener = {- xdgDecorationHandleConfigure,-};--// Makes the surface considered as XRGB instead of ARGB.-static void setOpaqueRegion(_GLFWwindow* window)-{- struct wl_region* region;-- region = wl_compositor_create_region(_glfw.wl.compositor);- if (!region)- return;-- wl_region_add(region, 0, 0, window->wl.width, window->wl.height);- wl_surface_set_opaque_region(window->wl.surface, region);- wl_surface_commit(window->wl.surface);- wl_region_destroy(region);-}---static void resizeWindow(_GLFWwindow* window)-{- int scale = window->wl.scale;- int scaledWidth = window->wl.width * scale;- int scaledHeight = window->wl.height * scale;- wl_egl_window_resize(window->wl.native, scaledWidth, scaledHeight, 0, 0);- if (!window->wl.transparent)- setOpaqueRegion(window);- _glfwInputFramebufferSize(window, scaledWidth, scaledHeight);- _glfwInputWindowContentScale(window, scale, scale);-- if (!window->wl.decorations.top.surface)- return;-- // Top decoration.- wp_viewport_set_destination(window->wl.decorations.top.viewport,- window->wl.width, _GLFW_DECORATION_TOP);- wl_surface_commit(window->wl.decorations.top.surface);-- // Left decoration.- wp_viewport_set_destination(window->wl.decorations.left.viewport,- _GLFW_DECORATION_WIDTH, window->wl.height + _GLFW_DECORATION_TOP);- wl_surface_commit(window->wl.decorations.left.surface);-- // Right decoration.- wl_subsurface_set_position(window->wl.decorations.right.subsurface,- window->wl.width, -_GLFW_DECORATION_TOP);- wp_viewport_set_destination(window->wl.decorations.right.viewport,- _GLFW_DECORATION_WIDTH, window->wl.height + _GLFW_DECORATION_TOP);- wl_surface_commit(window->wl.decorations.right.surface);-- // Bottom decoration.- wl_subsurface_set_position(window->wl.decorations.bottom.subsurface,- -_GLFW_DECORATION_WIDTH, window->wl.height);- wp_viewport_set_destination(window->wl.decorations.bottom.viewport,- window->wl.width + _GLFW_DECORATION_HORIZONTAL, _GLFW_DECORATION_WIDTH);- wl_surface_commit(window->wl.decorations.bottom.surface);-}--static void checkScaleChange(_GLFWwindow* window)-{- int scale = 1;- int i;- int monitorScale;-- // Check if we will be able to set the buffer scale or not.- if (_glfw.wl.compositorVersion < 3)- return;-- // Get the scale factor from the highest scale monitor.- for (i = 0; i < window->wl.monitorsCount; ++i)- {- monitorScale = window->wl.monitors[i]->wl.scale;- if (scale < monitorScale)- scale = monitorScale;- }-- // Only change the framebuffer size if the scale changed.- if (scale != window->wl.scale)- {- window->wl.scale = scale;- wl_surface_set_buffer_scale(window->wl.surface, scale);- resizeWindow(window);- }-}--static void surfaceHandleEnter(void *data,- struct wl_surface *surface,- struct wl_output *output)-{- _GLFWwindow* window = data;- _GLFWmonitor* monitor = wl_output_get_user_data(output);-- if (window->wl.monitorsCount + 1 > window->wl.monitorsSize)- {- ++window->wl.monitorsSize;- window->wl.monitors =- realloc(window->wl.monitors,- window->wl.monitorsSize * sizeof(_GLFWmonitor*));- }-- window->wl.monitors[window->wl.monitorsCount++] = monitor;-- checkScaleChange(window);-}--static void surfaceHandleLeave(void *data,- struct wl_surface *surface,- struct wl_output *output)-{- _GLFWwindow* window = data;- _GLFWmonitor* monitor = wl_output_get_user_data(output);- GLFWbool found;- int i;-- for (i = 0, found = GLFW_FALSE; i < window->wl.monitorsCount - 1; ++i)- {- if (monitor == window->wl.monitors[i])- found = GLFW_TRUE;- if (found)- window->wl.monitors[i] = window->wl.monitors[i + 1];- }- window->wl.monitors[--window->wl.monitorsCount] = NULL;-- checkScaleChange(window);-}--static const struct wl_surface_listener surfaceListener = {- surfaceHandleEnter,- surfaceHandleLeave-};--static void setIdleInhibitor(_GLFWwindow* window, GLFWbool enable)-{- if (enable && !window->wl.idleInhibitor && _glfw.wl.idleInhibitManager)- {- window->wl.idleInhibitor =- zwp_idle_inhibit_manager_v1_create_inhibitor(- _glfw.wl.idleInhibitManager, window->wl.surface);- if (!window->wl.idleInhibitor)- _glfwInputError(GLFW_PLATFORM_ERROR,- "Wayland: Idle inhibitor creation failed");- }- else if (!enable && window->wl.idleInhibitor)- {- zwp_idle_inhibitor_v1_destroy(window->wl.idleInhibitor);- window->wl.idleInhibitor = NULL;- }-}--static GLFWbool createSurface(_GLFWwindow* window,- const _GLFWwndconfig* wndconfig)-{- window->wl.surface = wl_compositor_create_surface(_glfw.wl.compositor);- if (!window->wl.surface)- return GLFW_FALSE;-- wl_surface_add_listener(window->wl.surface,- &surfaceListener,- window);-- wl_surface_set_user_data(window->wl.surface, window);-- window->wl.native = wl_egl_window_create(window->wl.surface,- wndconfig->width,- wndconfig->height);- if (!window->wl.native)- return GLFW_FALSE;-- window->wl.width = wndconfig->width;- window->wl.height = wndconfig->height;- window->wl.scale = 1;-- if (!window->wl.transparent)- setOpaqueRegion(window);-- return GLFW_TRUE;-}--static void setFullscreen(_GLFWwindow* window, _GLFWmonitor* monitor,- int refreshRate)-{- if (window->wl.xdg.toplevel)- {- xdg_toplevel_set_fullscreen(- window->wl.xdg.toplevel,- monitor->wl.output);- }- else if (window->wl.shellSurface)- {- wl_shell_surface_set_fullscreen(- window->wl.shellSurface,- WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,- refreshRate * 1000, // Convert Hz to mHz.- monitor->wl.output);- }- setIdleInhibitor(window, GLFW_TRUE);- if (!window->wl.decorations.serverSide)- destroyDecorations(window);-}--static GLFWbool createShellSurface(_GLFWwindow* window)-{- if (!_glfw.wl.shell)- {- _glfwInputError(GLFW_PLATFORM_ERROR,- "Wayland: wl_shell protocol not available");- return GLFW_FALSE;- }-- window->wl.shellSurface = wl_shell_get_shell_surface(_glfw.wl.shell,- window->wl.surface);- if (!window->wl.shellSurface)- {- _glfwInputError(GLFW_PLATFORM_ERROR,- "Wayland: Shell surface creation failed");- return GLFW_FALSE;- }-- wl_shell_surface_add_listener(window->wl.shellSurface,- &shellSurfaceListener,- window);-- if (window->wl.title)- wl_shell_surface_set_title(window->wl.shellSurface, window->wl.title);-- if (window->monitor)- {- setFullscreen(window, window->monitor, 0);- }- else if (window->wl.maximized)- {- wl_shell_surface_set_maximized(window->wl.shellSurface, NULL);- setIdleInhibitor(window, GLFW_FALSE);- createDecorations(window);- }- else- {- wl_shell_surface_set_toplevel(window->wl.shellSurface);- setIdleInhibitor(window, GLFW_FALSE);- createDecorations(window);- }-- wl_surface_commit(window->wl.surface);-- return GLFW_TRUE;-}--static void xdgToplevelHandleConfigure(void* data,- struct xdg_toplevel* toplevel,- int32_t width,- int32_t height,- struct wl_array* states)-{- _GLFWwindow* window = data;- float aspectRatio;- float targetRatio;- uint32_t* state;- GLFWbool maximized = GLFW_FALSE;- GLFWbool fullscreen = GLFW_FALSE;- GLFWbool activated = GLFW_FALSE;-- wl_array_for_each(state, states)- {- switch (*state)- {- case XDG_TOPLEVEL_STATE_MAXIMIZED:- maximized = GLFW_TRUE;- break;- case XDG_TOPLEVEL_STATE_FULLSCREEN:- fullscreen = GLFW_TRUE;- break;- case XDG_TOPLEVEL_STATE_RESIZING:- break;- case XDG_TOPLEVEL_STATE_ACTIVATED:- activated = GLFW_TRUE;- break;- }- }-- if (width != 0 && height != 0)- {- if (!maximized && !fullscreen)- {- if (window->numer != GLFW_DONT_CARE && window->denom != GLFW_DONT_CARE)- {- aspectRatio = (float)width / (float)height;- targetRatio = (float)window->numer / (float)window->denom;- if (aspectRatio < targetRatio)- height = width / targetRatio;- else if (aspectRatio > targetRatio)- width = height * targetRatio;- }- }-- _glfwInputWindowSize(window, width, height);- _glfwPlatformSetWindowSize(window, width, height);- _glfwInputWindowDamage(window);- }-- if (window->wl.wasFullscreen && window->autoIconify)- {- if (!activated || !fullscreen)- {- _glfwPlatformIconifyWindow(window);- window->wl.wasFullscreen = GLFW_FALSE;- }- }- if (fullscreen && activated)- window->wl.wasFullscreen = GLFW_TRUE;- _glfwInputWindowFocus(window, activated);-}--static void xdgToplevelHandleClose(void* data,- struct xdg_toplevel* toplevel)-{- _GLFWwindow* window = data;- _glfwInputWindowCloseRequest(window);-}--static const struct xdg_toplevel_listener xdgToplevelListener = {- xdgToplevelHandleConfigure,- xdgToplevelHandleClose-};--static void xdgSurfaceHandleConfigure(void* data,- struct xdg_surface* surface,- uint32_t serial)-{- xdg_surface_ack_configure(surface, serial);-}--static const struct xdg_surface_listener xdgSurfaceListener = {- xdgSurfaceHandleConfigure-};--static void setXdgDecorations(_GLFWwindow* window)-{- if (_glfw.wl.decorationManager)- {- window->wl.xdg.decoration =- zxdg_decoration_manager_v1_get_toplevel_decoration(- _glfw.wl.decorationManager, window->wl.xdg.toplevel);- zxdg_toplevel_decoration_v1_add_listener(window->wl.xdg.decoration,- &xdgDecorationListener,- window);- zxdg_toplevel_decoration_v1_set_mode(- window->wl.xdg.decoration,- ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);- }- else- {- window->wl.decorations.serverSide = GLFW_FALSE;- createDecorations(window);- }-}--static GLFWbool createXdgSurface(_GLFWwindow* window)-{- window->wl.xdg.surface = xdg_wm_base_get_xdg_surface(_glfw.wl.wmBase,- window->wl.surface);- if (!window->wl.xdg.surface)- {- _glfwInputError(GLFW_PLATFORM_ERROR,- "Wayland: xdg-surface creation failed");- return GLFW_FALSE;- }-- xdg_surface_add_listener(window->wl.xdg.surface,- &xdgSurfaceListener,- window);-- window->wl.xdg.toplevel = xdg_surface_get_toplevel(window->wl.xdg.surface);- if (!window->wl.xdg.toplevel)- {- _glfwInputError(GLFW_PLATFORM_ERROR,- "Wayland: xdg-toplevel creation failed");- return GLFW_FALSE;- }-- xdg_toplevel_add_listener(window->wl.xdg.toplevel,- &xdgToplevelListener,- window);-- if (window->wl.title)- xdg_toplevel_set_title(window->wl.xdg.toplevel, window->wl.title);-- if (window->minwidth != GLFW_DONT_CARE && window->minheight != GLFW_DONT_CARE)- xdg_toplevel_set_min_size(window->wl.xdg.toplevel,- window->minwidth, window->minheight);- if (window->maxwidth != GLFW_DONT_CARE && window->maxheight != GLFW_DONT_CARE)- xdg_toplevel_set_max_size(window->wl.xdg.toplevel,- window->maxwidth, window->maxheight);-- if (window->monitor)- {- xdg_toplevel_set_fullscreen(window->wl.xdg.toplevel,- window->monitor->wl.output);- setIdleInhibitor(window, GLFW_TRUE);- }- else if (window->wl.maximized)- {- xdg_toplevel_set_maximized(window->wl.xdg.toplevel);- setIdleInhibitor(window, GLFW_FALSE);- setXdgDecorations(window);- }- else- {- setIdleInhibitor(window, GLFW_FALSE);- setXdgDecorations(window);- }-- wl_surface_commit(window->wl.surface);- wl_display_roundtrip(_glfw.wl.display);-- return GLFW_TRUE;-}--static void setCursorImage(_GLFWwindow* window,- _GLFWcursorWayland* cursorWayland)-{- struct itimerspec timer = {};- struct wl_cursor* wlCursor = cursorWayland->cursor;- struct wl_cursor_image* image;- struct wl_buffer* buffer;- struct wl_surface* surface = _glfw.wl.cursorSurface;- int scale = 1;-- if (!wlCursor)- buffer = cursorWayland->buffer;- else- {- if (window->wl.scale > 1 && cursorWayland->cursorHiDPI)- {- wlCursor = cursorWayland->cursorHiDPI;- scale = 2;- }-- image = wlCursor->images[cursorWayland->currentImage];- buffer = wl_cursor_image_get_buffer(image);- if (!buffer)- return;-- timer.it_value.tv_sec = image->delay / 1000;- timer.it_value.tv_nsec = (image->delay % 1000) * 1000000;- timerfd_settime(_glfw.wl.cursorTimerfd, 0, &timer, NULL);-- cursorWayland->width = image->width;- cursorWayland->height = image->height;- cursorWayland->xhot = image->hotspot_x;- cursorWayland->yhot = image->hotspot_y;- }-- wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.serial,- surface,- cursorWayland->xhot / scale,- cursorWayland->yhot / scale);- wl_surface_set_buffer_scale(surface, scale);- wl_surface_attach(surface, buffer, 0, 0);- wl_surface_damage(surface, 0, 0,- cursorWayland->width, cursorWayland->height);- wl_surface_commit(surface);-}--static void incrementCursorImage(_GLFWwindow* window)-{- _GLFWcursor* cursor;-- if (!window || window->wl.decorations.focus != mainWindow)- return;-- cursor = window->wl.currentCursor;- if (cursor && cursor->wl.cursor)- {- cursor->wl.currentImage += 1;- cursor->wl.currentImage %= cursor->wl.cursor->image_count;- setCursorImage(window, &cursor->wl);- }-}--static void handleEvents(int timeout)-{- struct wl_display* display = _glfw.wl.display;- struct pollfd fds[] = {- { wl_display_get_fd(display), POLLIN },- { _glfw.wl.timerfd, POLLIN },- { _glfw.wl.cursorTimerfd, POLLIN },- };- ssize_t read_ret;- uint64_t repeats, i;-- while (wl_display_prepare_read(display) != 0)- wl_display_dispatch_pending(display);-- // If an error different from EAGAIN happens, we have likely been- // disconnected from the Wayland session, try to handle that the best we- // can.- if (wl_display_flush(display) < 0 && errno != EAGAIN)- {- _GLFWwindow* window = _glfw.windowListHead;- while (window)- {- _glfwInputWindowCloseRequest(window);- window = window->next;- }- wl_display_cancel_read(display);- return;- }-- if (poll(fds, 3, timeout) > 0)- {- if (fds[0].revents & POLLIN)- {- wl_display_read_events(display);- wl_display_dispatch_pending(display);- }- else- {- wl_display_cancel_read(display);- }-- if (fds[1].revents & POLLIN)- {- read_ret = read(_glfw.wl.timerfd, &repeats, sizeof(repeats));- if (read_ret != 8)- return;-- for (i = 0; i < repeats; ++i)- _glfwInputKey(_glfw.wl.keyboardFocus, _glfw.wl.keyboardLastKey,- _glfw.wl.keyboardLastScancode, GLFW_REPEAT,- _glfw.wl.xkb.modifiers);- }-- if (fds[2].revents & POLLIN)- {- read_ret = read(_glfw.wl.cursorTimerfd, &repeats, sizeof(repeats));- if (read_ret != 8)- return;-- incrementCursorImage(_glfw.wl.pointerFocus);- }- }- else- {- wl_display_cancel_read(display);- }-}--// Translates a GLFW standard cursor to a theme cursor name-//-static char *translateCursorShape(int shape)-{- switch (shape)- {- case GLFW_ARROW_CURSOR:- return "left_ptr";- case GLFW_IBEAM_CURSOR:- return "xterm";- case GLFW_CROSSHAIR_CURSOR:- return "crosshair";- case GLFW_HAND_CURSOR:- return "hand2";- case GLFW_HRESIZE_CURSOR:- return "sb_h_double_arrow";- case GLFW_VRESIZE_CURSOR:- return "sb_v_double_arrow";- }- return NULL;-}--//////////////////////////////////////////////////////////////////////////-////// GLFW platform API //////-//////////////////////////////////////////////////////////////////////////--int _glfwPlatformCreateWindow(_GLFWwindow* window,- const _GLFWwndconfig* wndconfig,- const _GLFWctxconfig* ctxconfig,- const _GLFWfbconfig* fbconfig)-{- window->wl.transparent = fbconfig->transparent;-- if (!createSurface(window, wndconfig))- return GLFW_FALSE;-- if (ctxconfig->client != GLFW_NO_API)- {- if (ctxconfig->source == GLFW_EGL_CONTEXT_API ||- ctxconfig->source == GLFW_NATIVE_CONTEXT_API)- {- if (!_glfwInitEGL())- return GLFW_FALSE;- if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig))- return GLFW_FALSE;- }- else if (ctxconfig->source == GLFW_OSMESA_CONTEXT_API)- {- if (!_glfwInitOSMesa())- return GLFW_FALSE;- if (!_glfwCreateContextOSMesa(window, ctxconfig, fbconfig))- return GLFW_FALSE;- }- }-- if (wndconfig->title)- window->wl.title = _glfw_strdup(wndconfig->title);-- if (wndconfig->visible)- {- if (_glfw.wl.wmBase)- {- if (!createXdgSurface(window))- return GLFW_FALSE;- }- else- {- if (!createShellSurface(window))- return GLFW_FALSE;- }-- window->wl.visible = GLFW_TRUE;- }- else- {- window->wl.xdg.surface = NULL;- window->wl.xdg.toplevel = NULL;- window->wl.shellSurface = NULL;- window->wl.visible = GLFW_FALSE;- }-- window->wl.currentCursor = NULL;-- window->wl.monitors = calloc(1, sizeof(_GLFWmonitor*));- window->wl.monitorsCount = 0;- window->wl.monitorsSize = 1;-- return GLFW_TRUE;-}--void _glfwPlatformDestroyWindow(_GLFWwindow* window)-{- if (window == _glfw.wl.pointerFocus)- {- _glfw.wl.pointerFocus = NULL;- _glfwInputCursorEnter(window, GLFW_FALSE);- }- if (window == _glfw.wl.keyboardFocus)- {- _glfw.wl.keyboardFocus = NULL;- _glfwInputWindowFocus(window, GLFW_FALSE);- }-- if (window->wl.idleInhibitor)- zwp_idle_inhibitor_v1_destroy(window->wl.idleInhibitor);-- if (window->context.destroy)- window->context.destroy(window);-- destroyDecorations(window);- if (window->wl.xdg.decoration)- zxdg_toplevel_decoration_v1_destroy(window->wl.xdg.decoration);-- if (window->wl.decorations.buffer)- wl_buffer_destroy(window->wl.decorations.buffer);-- if (window->wl.native)- wl_egl_window_destroy(window->wl.native);-- if (window->wl.shellSurface)- wl_shell_surface_destroy(window->wl.shellSurface);-- if (window->wl.xdg.toplevel)- xdg_toplevel_destroy(window->wl.xdg.toplevel);-- if (window->wl.xdg.surface)- xdg_surface_destroy(window->wl.xdg.surface);-- if (window->wl.surface)- wl_surface_destroy(window->wl.surface);-- free(window->wl.title);- free(window->wl.monitors);-}--void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title)-{- if (window->wl.title)- free(window->wl.title);- window->wl.title = _glfw_strdup(title);- if (window->wl.xdg.toplevel)- xdg_toplevel_set_title(window->wl.xdg.toplevel, title);- else if (window->wl.shellSurface)- wl_shell_surface_set_title(window->wl.shellSurface, title);-}--void _glfwPlatformSetWindowIcon(_GLFWwindow* window,- int count, const GLFWimage* images)-{- _glfwInputError(GLFW_PLATFORM_ERROR,- "Wayland: Setting window icon not supported");-}--void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos)-{- // A Wayland client is not aware of its position, so just warn and leave it- // as (0, 0)-- _glfwInputError(GLFW_PLATFORM_ERROR,- "Wayland: Window position retrieval not supported");-}--void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos)-{- // A Wayland client can not set its position, so just warn-- _glfwInputError(GLFW_PLATFORM_ERROR,- "Wayland: Window position setting not supported");-}--void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height)-{- if (width)- *width = window->wl.width;- if (height)- *height = window->wl.height;-}--void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height)-{- window->wl.width = width;- window->wl.height = height;- resizeWindow(window);-}--void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window,- int minwidth, int minheight,- int maxwidth, int maxheight)-{- if (_glfw.wl.wmBase)- {- if (window->wl.xdg.toplevel)- {- if (minwidth == GLFW_DONT_CARE || minheight == GLFW_DONT_CARE)- minwidth = minheight = 0;- if (maxwidth == GLFW_DONT_CARE || maxheight == GLFW_DONT_CARE)- maxwidth = maxheight = 0;- xdg_toplevel_set_min_size(window->wl.xdg.toplevel, minwidth, minheight);- xdg_toplevel_set_max_size(window->wl.xdg.toplevel, maxwidth, maxheight);- wl_surface_commit(window->wl.surface);- }- }- else- {- // TODO: find out how to trigger a resize.- // The actual limits are checked in the wl_shell_surface::configure handler.- }-}--void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window,- int numer, int denom)-{- // TODO: find out how to trigger a resize.- // The actual limits are checked in the wl_shell_surface::configure handler.-}--void _glfwPlatformGetFramebufferSize(_GLFWwindow* window,- int* width, int* height)-{- _glfwPlatformGetWindowSize(window, width, height);- *width *= window->wl.scale;- *height *= window->wl.scale;-}--void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,- int* left, int* top,- int* right, int* bottom)-{- if (window->decorated && !window->monitor && !window->wl.decorations.serverSide)- {- if (top)- *top = _GLFW_DECORATION_TOP;- if (left)- *left = _GLFW_DECORATION_WIDTH;- if (right)- *right = _GLFW_DECORATION_WIDTH;- if (bottom)- *bottom = _GLFW_DECORATION_WIDTH;- }-}--void _glfwPlatformGetWindowContentScale(_GLFWwindow* window,- float* xscale, float* yscale)-{- if (xscale)- *xscale = (float) window->wl.scale;- if (yscale)- *yscale = (float) window->wl.scale;-}--void _glfwPlatformIconifyWindow(_GLFWwindow* window)-{- if (_glfw.wl.wmBase)- {- if (window->wl.xdg.toplevel)- xdg_toplevel_set_minimized(window->wl.xdg.toplevel);- }- else- {- _glfwInputError(GLFW_PLATFORM_ERROR,- "Wayland: Iconify window not supported on wl_shell");- }-}--void _glfwPlatformRestoreWindow(_GLFWwindow* window)-{- if (window->wl.xdg.toplevel)- {- if (window->monitor)- xdg_toplevel_unset_fullscreen(window->wl.xdg.toplevel);- if (window->wl.maximized)- xdg_toplevel_unset_maximized(window->wl.xdg.toplevel);- // There is no way to unset minimized, or even to know if we are- // minimized, so there is nothing to do here.- }- else if (window->wl.shellSurface)- {- if (window->monitor || window->wl.maximized)- wl_shell_surface_set_toplevel(window->wl.shellSurface);- }- _glfwInputWindowMonitor(window, NULL);- window->wl.maximized = GLFW_FALSE;-}--void _glfwPlatformMaximizeWindow(_GLFWwindow* window)-{- if (window->wl.xdg.toplevel)- {- xdg_toplevel_set_maximized(window->wl.xdg.toplevel);- }- else if (window->wl.shellSurface)- {- // Let the compositor select the best output.- wl_shell_surface_set_maximized(window->wl.shellSurface, NULL);- }- window->wl.maximized = GLFW_TRUE;-}--void _glfwPlatformShowWindow(_GLFWwindow* window)-{- if (!window->wl.visible)- {- if (_glfw.wl.wmBase)- createXdgSurface(window);- else if (!window->wl.shellSurface)- createShellSurface(window);- window->wl.visible = GLFW_TRUE;- }-}--void _glfwPlatformHideWindow(_GLFWwindow* window)-{- if (window->wl.xdg.toplevel)- {- xdg_toplevel_destroy(window->wl.xdg.toplevel);- xdg_surface_destroy(window->wl.xdg.surface);- window->wl.xdg.toplevel = NULL;- window->wl.xdg.surface = NULL;- }- else if (window->wl.shellSurface)- {- wl_shell_surface_destroy(window->wl.shellSurface);- window->wl.shellSurface = NULL;- }- window->wl.visible = GLFW_FALSE;-}--void _glfwPlatformRequestWindowAttention(_GLFWwindow* window)-{- // TODO- _glfwInputError(GLFW_PLATFORM_ERROR,- "Wayland: Window attention request not implemented yet");-}--void _glfwPlatformFocusWindow(_GLFWwindow* window)-{- _glfwInputError(GLFW_PLATFORM_ERROR,- "Wayland: Focusing a window requires user interaction");-}--void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,- _GLFWmonitor* monitor,- int xpos, int ypos,- int width, int height,- int refreshRate)-{- if (monitor)- {- setFullscreen(window, monitor, refreshRate);- }- else- {- if (window->wl.xdg.toplevel)- xdg_toplevel_unset_fullscreen(window->wl.xdg.toplevel);- else if (window->wl.shellSurface)- wl_shell_surface_set_toplevel(window->wl.shellSurface);- setIdleInhibitor(window, GLFW_FALSE);- if (!_glfw.wl.decorationManager)- createDecorations(window);- }- _glfwInputWindowMonitor(window, monitor);-}--int _glfwPlatformWindowFocused(_GLFWwindow* window)-{- return _glfw.wl.keyboardFocus == window;-}--int _glfwPlatformWindowIconified(_GLFWwindow* window)-{- // wl_shell doesn't have any iconified concept, and xdg-shell doesn’t give- // any way to request whether a surface is iconified.- return GLFW_FALSE;-}--int _glfwPlatformWindowVisible(_GLFWwindow* window)-{- return window->wl.visible;-}--int _glfwPlatformWindowMaximized(_GLFWwindow* window)-{- return window->wl.maximized;-}--int _glfwPlatformWindowHovered(_GLFWwindow* window)-{- return window->wl.hovered;-}--int _glfwPlatformFramebufferTransparent(_GLFWwindow* window)-{- return window->wl.transparent;-}--void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled)-{- // TODO- _glfwInputError(GLFW_PLATFORM_ERROR,- "Wayland: Window attribute setting not implemented yet");-}--void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled)-{- if (!window->monitor)- {- if (enabled)- createDecorations(window);- else- destroyDecorations(window);- }-}--void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled)-{- // TODO- _glfwInputError(GLFW_PLATFORM_ERROR,- "Wayland: Window attribute setting not implemented yet");-}--float _glfwPlatformGetWindowOpacity(_GLFWwindow* window)-{- return 1.f;-}--void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity)-{-}--void _glfwPlatformSetRawMouseMotion(_GLFWwindow *window, GLFWbool enabled)-{- // This is handled in relativePointerHandleRelativeMotion-}--GLFWbool _glfwPlatformRawMouseMotionSupported(void)-{- return GLFW_TRUE;-}--void _glfwPlatformPollEvents(void)-{- handleEvents(0);-}--void _glfwPlatformWaitEvents(void)-{- handleEvents(-1);-}--void _glfwPlatformWaitEventsTimeout(double timeout)-{- handleEvents((int) (timeout * 1e3));-}--void _glfwPlatformPostEmptyEvent(void)-{- wl_display_sync(_glfw.wl.display);-}--void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos)-{- if (xpos)- *xpos = window->wl.cursorPosX;- if (ypos)- *ypos = window->wl.cursorPosY;-}--static GLFWbool isPointerLocked(_GLFWwindow* window);--void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y)-{- if (isPointerLocked(window))- {- zwp_locked_pointer_v1_set_cursor_position_hint(- window->wl.pointerLock.lockedPointer,- wl_fixed_from_double(x), wl_fixed_from_double(y));- wl_surface_commit(window->wl.surface);- }-}--void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode)-{- _glfwPlatformSetCursor(window, window->wl.currentCursor);-}--const char* _glfwPlatformGetScancodeName(int scancode)-{- // TODO- return NULL;-}--int _glfwPlatformGetKeyScancode(int key)-{- return _glfw.wl.scancodes[key];-}--int _glfwPlatformCreateCursor(_GLFWcursor* cursor,- const GLFWimage* image,- int xhot, int yhot)-{- cursor->wl.buffer = createShmBuffer(image);- if (!cursor->wl.buffer)- return GLFW_FALSE;-- cursor->wl.width = image->width;- cursor->wl.height = image->height;- cursor->wl.xhot = xhot;- cursor->wl.yhot = yhot;- return GLFW_TRUE;-}--int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape)-{- struct wl_cursor* standardCursor;-- standardCursor = wl_cursor_theme_get_cursor(_glfw.wl.cursorTheme,- translateCursorShape(shape));- if (!standardCursor)- {- _glfwInputError(GLFW_PLATFORM_ERROR,- "Wayland: Standard cursor \"%s\" not found",- translateCursorShape(shape));- return GLFW_FALSE;- }-- cursor->wl.cursor = standardCursor;- cursor->wl.currentImage = 0;-- if (_glfw.wl.cursorThemeHiDPI)- {- standardCursor = wl_cursor_theme_get_cursor(_glfw.wl.cursorThemeHiDPI,- translateCursorShape(shape));- cursor->wl.cursorHiDPI = standardCursor;- }-- return GLFW_TRUE;-}--void _glfwPlatformDestroyCursor(_GLFWcursor* cursor)-{- // If it's a standard cursor we don't need to do anything here- if (cursor->wl.cursor)- return;-- if (cursor->wl.buffer)- wl_buffer_destroy(cursor->wl.buffer);-}--static void relativePointerHandleRelativeMotion(void* data,- struct zwp_relative_pointer_v1* pointer,- uint32_t timeHi,- uint32_t timeLo,- wl_fixed_t dx,- wl_fixed_t dy,- wl_fixed_t dxUnaccel,- wl_fixed_t dyUnaccel)-{- _GLFWwindow* window = data;- double xpos = window->virtualCursorPosX;- double ypos = window->virtualCursorPosY;-- if (window->cursorMode != GLFW_CURSOR_DISABLED)- return;-- if (window->rawMouseMotion)- {- xpos += wl_fixed_to_double(dxUnaccel);- ypos += wl_fixed_to_double(dyUnaccel);- }- else- {- xpos += wl_fixed_to_double(dx);- ypos += wl_fixed_to_double(dy);- }-- _glfwInputCursorPos(window, xpos, ypos);-}--static const struct zwp_relative_pointer_v1_listener relativePointerListener = {- relativePointerHandleRelativeMotion-};--static void lockedPointerHandleLocked(void* data,- struct zwp_locked_pointer_v1* lockedPointer)-{-}--static void unlockPointer(_GLFWwindow* window)-{- struct zwp_relative_pointer_v1* relativePointer =- window->wl.pointerLock.relativePointer;- struct zwp_locked_pointer_v1* lockedPointer =- window->wl.pointerLock.lockedPointer;-- zwp_relative_pointer_v1_destroy(relativePointer);- zwp_locked_pointer_v1_destroy(lockedPointer);-- window->wl.pointerLock.relativePointer = NULL;- window->wl.pointerLock.lockedPointer = NULL;-}--static void lockPointer(_GLFWwindow* window);--static void lockedPointerHandleUnlocked(void* data,- struct zwp_locked_pointer_v1* lockedPointer)-{-}--static const struct zwp_locked_pointer_v1_listener lockedPointerListener = {- lockedPointerHandleLocked,- lockedPointerHandleUnlocked-};--static void lockPointer(_GLFWwindow* window)-{- struct zwp_relative_pointer_v1* relativePointer;- struct zwp_locked_pointer_v1* lockedPointer;-- if (!_glfw.wl.relativePointerManager)- {- _glfwInputError(GLFW_PLATFORM_ERROR,- "Wayland: no relative pointer manager");- return;- }-- relativePointer =- zwp_relative_pointer_manager_v1_get_relative_pointer(- _glfw.wl.relativePointerManager,- _glfw.wl.pointer);- zwp_relative_pointer_v1_add_listener(relativePointer,- &relativePointerListener,- window);-- lockedPointer =- zwp_pointer_constraints_v1_lock_pointer(- _glfw.wl.pointerConstraints,- window->wl.surface,- _glfw.wl.pointer,- NULL,- ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);- zwp_locked_pointer_v1_add_listener(lockedPointer,- &lockedPointerListener,- window);-- window->wl.pointerLock.relativePointer = relativePointer;- window->wl.pointerLock.lockedPointer = lockedPointer;-- wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.serial,- NULL, 0, 0);-}--static GLFWbool isPointerLocked(_GLFWwindow* window)-{- return window->wl.pointerLock.lockedPointer != NULL;-}--void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)-{- struct wl_cursor* defaultCursor;- struct wl_cursor* defaultCursorHiDPI = NULL;-- if (!_glfw.wl.pointer)- return;-- window->wl.currentCursor = cursor;-- // If we're not in the correct window just save the cursor- // the next time the pointer enters the window the cursor will change- if (window != _glfw.wl.pointerFocus || window->wl.decorations.focus != mainWindow)- return;-- // Unlock possible pointer lock if no longer disabled.- if (window->cursorMode != GLFW_CURSOR_DISABLED && isPointerLocked(window))- unlockPointer(window);-- if (window->cursorMode == GLFW_CURSOR_NORMAL)- {- if (cursor)- setCursorImage(window, &cursor->wl);- else- {- defaultCursor = wl_cursor_theme_get_cursor(_glfw.wl.cursorTheme,- "left_ptr");- if (!defaultCursor)- {- _glfwInputError(GLFW_PLATFORM_ERROR,- "Wayland: Standard cursor not found");- return;- }- if (_glfw.wl.cursorThemeHiDPI)- defaultCursorHiDPI =- wl_cursor_theme_get_cursor(_glfw.wl.cursorThemeHiDPI,- "left_ptr");- _GLFWcursorWayland cursorWayland = {- defaultCursor,- defaultCursorHiDPI,- NULL,- 0, 0,- 0, 0,- 0- };- setCursorImage(window, &cursorWayland);- }- }- else if (window->cursorMode == GLFW_CURSOR_DISABLED)- {- if (!isPointerLocked(window))- lockPointer(window);- }- else if (window->cursorMode == GLFW_CURSOR_HIDDEN)- {- wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.serial, NULL, 0, 0);- }-}--static void dataSourceHandleTarget(void* data,- struct wl_data_source* dataSource,- const char* mimeType)-{- if (_glfw.wl.dataSource != dataSource)- {- _glfwInputError(GLFW_PLATFORM_ERROR,- "Wayland: Unknown clipboard data source");- return;- }-}--static void dataSourceHandleSend(void* data,- struct wl_data_source* dataSource,- const char* mimeType,- int fd)-{- const char* string = _glfw.wl.clipboardSendString;- size_t len = _glfw.wl.clipboardSendSize;- int ret;-- if (_glfw.wl.dataSource != dataSource)- {- _glfwInputError(GLFW_PLATFORM_ERROR,- "Wayland: Unknown clipboard data source");- return;- }-- if (!string)- {- _glfwInputError(GLFW_PLATFORM_ERROR,- "Wayland: Copy requested from an invalid string");- return;- }-- if (strcmp(mimeType, "text/plain;charset=utf-8") != 0)- {- _glfwInputError(GLFW_PLATFORM_ERROR,- "Wayland: Wrong MIME type asked from clipboard");- close(fd);- return;- }-- while (len > 0)- {- ret = write(fd, string, len);- if (ret == -1 && errno == EINTR)- continue;- if (ret == -1)- {- // TODO: also report errno maybe.- _glfwInputError(GLFW_PLATFORM_ERROR,- "Wayland: Error while writing the clipboard");- close(fd);- return;- }- len -= ret;- }- close(fd);-}--static void dataSourceHandleCancelled(void* data,- struct wl_data_source* dataSource)-{- wl_data_source_destroy(dataSource);-- if (_glfw.wl.dataSource != dataSource)- {- _glfwInputError(GLFW_PLATFORM_ERROR,- "Wayland: Unknown clipboard data source");- return;- }-- _glfw.wl.dataSource = NULL;-}--static const struct wl_data_source_listener dataSourceListener = {- dataSourceHandleTarget,- dataSourceHandleSend,- dataSourceHandleCancelled,-};--void _glfwPlatformSetClipboardString(const char* string)-{- if (_glfw.wl.dataSource)- {- wl_data_source_destroy(_glfw.wl.dataSource);- _glfw.wl.dataSource = NULL;- }-- if (_glfw.wl.clipboardSendString)- {- free(_glfw.wl.clipboardSendString);- _glfw.wl.clipboardSendString = NULL;- }-- _glfw.wl.clipboardSendString = strdup(string);- if (!_glfw.wl.clipboardSendString)- {- _glfwInputError(GLFW_PLATFORM_ERROR,- "Wayland: Impossible to allocate clipboard string");- return;- }- _glfw.wl.clipboardSendSize = strlen(string);- _glfw.wl.dataSource =- wl_data_device_manager_create_data_source(_glfw.wl.dataDeviceManager);- if (!_glfw.wl.dataSource)- {- _glfwInputError(GLFW_PLATFORM_ERROR,- "Wayland: Impossible to create clipboard source");- free(_glfw.wl.clipboardSendString);- return;- }- wl_data_source_add_listener(_glfw.wl.dataSource,- &dataSourceListener,- NULL);- wl_data_source_offer(_glfw.wl.dataSource, "text/plain;charset=utf-8");- wl_data_device_set_selection(_glfw.wl.dataDevice,- _glfw.wl.dataSource,- _glfw.wl.serial);-}--static GLFWbool growClipboardString(void)-{- char* clipboard = _glfw.wl.clipboardString;-- clipboard = realloc(clipboard, _glfw.wl.clipboardSize * 2);- if (!clipboard)- {- _glfwInputError(GLFW_PLATFORM_ERROR,- "Wayland: Impossible to grow clipboard string");- return GLFW_FALSE;- }- _glfw.wl.clipboardString = clipboard;- _glfw.wl.clipboardSize = _glfw.wl.clipboardSize * 2;- return GLFW_TRUE;-}--const char* _glfwPlatformGetClipboardString(void)-{- int fds[2];- int ret;- size_t len = 0;-- if (!_glfw.wl.dataOffer)- {- _glfwInputError(GLFW_FORMAT_UNAVAILABLE,- "No clipboard data has been sent yet");- return NULL;- }-- ret = pipe2(fds, O_CLOEXEC);- if (ret < 0)- {- // TODO: also report errno maybe?- _glfwInputError(GLFW_PLATFORM_ERROR,- "Wayland: Impossible to create clipboard pipe fds");- return NULL;- }-- wl_data_offer_receive(_glfw.wl.dataOffer, "text/plain;charset=utf-8", fds[1]);- close(fds[1]);-- // XXX: this is a huge hack, this function shouldn’t be synchronous!- handleEvents(-1);-- while (1)- {- // Grow the clipboard if we need to paste something bigger, there is no- // shrink operation yet.- if (len + 4096 > _glfw.wl.clipboardSize)- {- if (!growClipboardString())- {- close(fds[0]);- return NULL;- }- }-- // Then read from the fd to the clipboard, handling all known errors.- ret = read(fds[0], _glfw.wl.clipboardString + len, 4096);- if (ret == 0)- break;- if (ret == -1 && errno == EINTR)- continue;- if (ret == -1)- {- // TODO: also report errno maybe.- _glfwInputError(GLFW_PLATFORM_ERROR,- "Wayland: Impossible to read from clipboard fd");- close(fds[0]);- return NULL;- }- len += ret;- }- close(fds[0]);- if (len + 1 > _glfw.wl.clipboardSize)- {- if (!growClipboardString())- return NULL;- }- _glfw.wl.clipboardString[len] = '\0';+#include <assert.h>+#include <unistd.h>+#include <string.h>+#include <fcntl.h>+#include <sys/mman.h>+#include <sys/timerfd.h>+#include <poll.h>+#include <signal.h>+#include <time.h>++#define GLFW_BORDER_SIZE 4+#define GLFW_CAPTION_HEIGHT 24++static int createTmpfileCloexec(char* tmpname)+{+ int fd;++ fd = mkostemp(tmpname, O_CLOEXEC);+ if (fd >= 0)+ unlink(tmpname);++ return fd;+}++/*+ * Create a new, unique, anonymous file of the given size, and+ * return the file descriptor for it. The file descriptor is set+ * CLOEXEC. The file is immediately suitable for mmap()'ing+ * the given size at offset zero.+ *+ * The file should not have a permanent backing store like a disk,+ * but may have if XDG_RUNTIME_DIR is not properly implemented in OS.+ *+ * The file name is deleted from the file system.+ *+ * The file is suitable for buffer sharing between processes by+ * transmitting the file descriptor over Unix sockets using the+ * SCM_RIGHTS methods.+ *+ * posix_fallocate() is used to guarantee that disk space is available+ * for the file at the given size. If disk space is insufficient, errno+ * is set to ENOSPC. If posix_fallocate() is not supported, program may+ * receive SIGBUS on accessing mmap()'ed file contents instead.+ */+static int createAnonymousFile(off_t size)+{+ static const char template[] = "/glfw-shared-XXXXXX";+ const char* path;+ char* name;+ int fd;+ int ret;++#ifdef HAVE_MEMFD_CREATE+ fd = memfd_create("glfw-shared", MFD_CLOEXEC | MFD_ALLOW_SEALING);+ if (fd >= 0)+ {+ // We can add this seal before calling posix_fallocate(), as the file+ // is currently zero-sized anyway.+ //+ // There is also no need to check for the return value, we couldn’t do+ // anything with it anyway.+ fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_SEAL);+ }+ else+#elif defined(SHM_ANON)+ fd = shm_open(SHM_ANON, O_RDWR | O_CLOEXEC, 0600);+ if (fd < 0)+#endif+ {+ path = getenv("XDG_RUNTIME_DIR");+ if (!path)+ {+ errno = ENOENT;+ return -1;+ }++ name = calloc(strlen(path) + sizeof(template), 1);+ strcpy(name, path);+ strcat(name, template);++ fd = createTmpfileCloexec(name);+ free(name);+ if (fd < 0)+ return -1;+ }++#if defined(SHM_ANON)+ // posix_fallocate does not work on SHM descriptors+ ret = ftruncate(fd, size);+#else+ ret = posix_fallocate(fd, 0, size);+#endif+ if (ret != 0)+ {+ close(fd);+ errno = ret;+ return -1;+ }+ return fd;+}++static struct wl_buffer* createShmBuffer(const GLFWimage* image)+{+ const int stride = image->width * 4;+ const int length = image->width * image->height * 4;++ const int fd = createAnonymousFile(length);+ if (fd < 0)+ {+ _glfwInputError(GLFW_PLATFORM_ERROR,+ "Wayland: Failed to create buffer file of size %d: %s",+ length, strerror(errno));+ return NULL;+ }++ void* data = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);+ if (data == MAP_FAILED)+ {+ _glfwInputError(GLFW_PLATFORM_ERROR,+ "Wayland: Failed to map file: %s", strerror(errno));+ close(fd);+ return NULL;+ }++ struct wl_shm_pool* pool = wl_shm_create_pool(_glfw.wl.shm, fd, length);++ close(fd);++ unsigned char* source = (unsigned char*) image->pixels;+ unsigned char* target = data;+ for (int i = 0; i < image->width * image->height; i++, source += 4)+ {+ unsigned int alpha = source[3];++ *target++ = (unsigned char) ((source[2] * alpha) / 255);+ *target++ = (unsigned char) ((source[1] * alpha) / 255);+ *target++ = (unsigned char) ((source[0] * alpha) / 255);+ *target++ = (unsigned char) alpha;+ }++ struct wl_buffer* buffer =+ wl_shm_pool_create_buffer(pool, 0,+ image->width,+ image->height,+ stride, WL_SHM_FORMAT_ARGB8888);+ munmap(data, length);+ wl_shm_pool_destroy(pool);++ return buffer;+}++// Wait for data to arrive on any of the specified file descriptors+//+static GLFWbool waitForData(struct pollfd* fds, nfds_t count, double* timeout)+{+ for (;;)+ {+ if (timeout)+ {+ const uint64_t base = _glfwPlatformGetTimerValue();++#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__CYGWIN__)+ const time_t seconds = (time_t) *timeout;+ const long nanoseconds = (long) ((*timeout - seconds) * 1e9);+ const struct timespec ts = { seconds, nanoseconds };+ const int result = ppoll(fds, count, &ts, NULL);+#elif defined(__NetBSD__)+ const time_t seconds = (time_t) *timeout;+ const long nanoseconds = (long) ((*timeout - seconds) * 1e9);+ const struct timespec ts = { seconds, nanoseconds };+ const int result = pollts(fds, count, &ts, NULL);+#else+ const int milliseconds = (int) (*timeout * 1e3);+ const int result = poll(fds, count, milliseconds);+#endif+ const int error = errno; // clock_gettime may overwrite our error++ *timeout -= (_glfwPlatformGetTimerValue() - base) /+ (double) _glfwPlatformGetTimerFrequency();++ if (result > 0)+ return GLFW_TRUE;+ else if (result == -1 && error != EINTR && error != EAGAIN)+ return GLFW_FALSE;+ else if (*timeout <= 0.0)+ return GLFW_FALSE;+ }+ else+ {+ const int result = poll(fds, count, -1);+ if (result > 0)+ return GLFW_TRUE;+ else if (result == -1 && errno != EINTR && errno != EAGAIN)+ return GLFW_FALSE;+ }+ }+}++static void createFallbackDecoration(_GLFWwindow* window,+ _GLFWdecorationWayland* decoration,+ struct wl_surface* parent,+ struct wl_buffer* buffer,+ int x, int y,+ int width, int height)+{+ decoration->surface = wl_compositor_create_surface(_glfw.wl.compositor);+ wl_surface_set_user_data(decoration->surface, window);+ wl_proxy_set_tag((struct wl_proxy*) decoration->surface, &_glfw.wl.tag);+ decoration->subsurface =+ wl_subcompositor_get_subsurface(_glfw.wl.subcompositor,+ decoration->surface, parent);+ wl_subsurface_set_position(decoration->subsurface, x, y);+ decoration->viewport = wp_viewporter_get_viewport(_glfw.wl.viewporter,+ decoration->surface);+ wp_viewport_set_destination(decoration->viewport, width, height);+ wl_surface_attach(decoration->surface, buffer, 0, 0);++ struct wl_region* region = wl_compositor_create_region(_glfw.wl.compositor);+ wl_region_add(region, 0, 0, width, height);+ wl_surface_set_opaque_region(decoration->surface, region);+ wl_surface_commit(decoration->surface);+ wl_region_destroy(region);+}++static void createFallbackDecorations(_GLFWwindow* window)+{+ unsigned char data[] = { 224, 224, 224, 255 };+ const GLFWimage image = { 1, 1, data };++ if (!_glfw.wl.viewporter)+ return;++ if (!window->wl.decorations.buffer)+ window->wl.decorations.buffer = createShmBuffer(&image);+ if (!window->wl.decorations.buffer)+ return;++ createFallbackDecoration(window, &window->wl.decorations.top, window->wl.surface,+ window->wl.decorations.buffer,+ 0, -GLFW_CAPTION_HEIGHT,+ window->wl.width, GLFW_CAPTION_HEIGHT);+ createFallbackDecoration(window, &window->wl.decorations.left, window->wl.surface,+ window->wl.decorations.buffer,+ -GLFW_BORDER_SIZE, -GLFW_CAPTION_HEIGHT,+ GLFW_BORDER_SIZE, window->wl.height + GLFW_CAPTION_HEIGHT);+ createFallbackDecoration(window, &window->wl.decorations.right, window->wl.surface,+ window->wl.decorations.buffer,+ window->wl.width, -GLFW_CAPTION_HEIGHT,+ GLFW_BORDER_SIZE, window->wl.height + GLFW_CAPTION_HEIGHT);+ createFallbackDecoration(window, &window->wl.decorations.bottom, window->wl.surface,+ window->wl.decorations.buffer,+ -GLFW_BORDER_SIZE, window->wl.height,+ window->wl.width + GLFW_BORDER_SIZE * 2, GLFW_BORDER_SIZE);+}++static void destroyFallbackDecoration(_GLFWdecorationWayland* decoration)+{+ if (decoration->subsurface)+ wl_subsurface_destroy(decoration->subsurface);+ if (decoration->surface)+ wl_surface_destroy(decoration->surface);+ if (decoration->viewport)+ wp_viewport_destroy(decoration->viewport);+ decoration->surface = NULL;+ decoration->subsurface = NULL;+ decoration->viewport = NULL;+}++static void destroyFallbackDecorations(_GLFWwindow* window)+{+ destroyFallbackDecoration(&window->wl.decorations.top);+ destroyFallbackDecoration(&window->wl.decorations.left);+ destroyFallbackDecoration(&window->wl.decorations.right);+ destroyFallbackDecoration(&window->wl.decorations.bottom);+}++static void xdgDecorationHandleConfigure(void* userData,+ struct zxdg_toplevel_decoration_v1* decoration,+ uint32_t mode)+{+ _GLFWwindow* window = userData;++ window->wl.xdg.decorationMode = mode;++ if (mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE)+ {+ if (window->decorated && !window->monitor)+ createFallbackDecorations(window);+ }+ else+ destroyFallbackDecorations(window);+}++static const struct zxdg_toplevel_decoration_v1_listener xdgDecorationListener =+{+ xdgDecorationHandleConfigure,+};++// Makes the surface considered as XRGB instead of ARGB.+static void setContentAreaOpaque(_GLFWwindow* window)+{+ struct wl_region* region;++ region = wl_compositor_create_region(_glfw.wl.compositor);+ if (!region)+ return;++ wl_region_add(region, 0, 0, window->wl.width, window->wl.height);+ wl_surface_set_opaque_region(window->wl.surface, region);+ wl_region_destroy(region);+}+++static void resizeWindow(_GLFWwindow* window)+{+ int scale = window->wl.contentScale;+ int scaledWidth = window->wl.width * scale;+ int scaledHeight = window->wl.height * scale;++ if (window->wl.egl.window)+ wl_egl_window_resize(window->wl.egl.window, scaledWidth, scaledHeight, 0, 0);+ if (!window->wl.transparent)+ setContentAreaOpaque(window);+ _glfwInputFramebufferSize(window, scaledWidth, scaledHeight);++ if (!window->wl.decorations.top.surface)+ return;++ wp_viewport_set_destination(window->wl.decorations.top.viewport,+ window->wl.width, GLFW_CAPTION_HEIGHT);+ wl_surface_commit(window->wl.decorations.top.surface);++ wp_viewport_set_destination(window->wl.decorations.left.viewport,+ GLFW_BORDER_SIZE, window->wl.height + GLFW_CAPTION_HEIGHT);+ wl_surface_commit(window->wl.decorations.left.surface);++ wl_subsurface_set_position(window->wl.decorations.right.subsurface,+ window->wl.width, -GLFW_CAPTION_HEIGHT);+ wp_viewport_set_destination(window->wl.decorations.right.viewport,+ GLFW_BORDER_SIZE, window->wl.height + GLFW_CAPTION_HEIGHT);+ wl_surface_commit(window->wl.decorations.right.surface);++ wl_subsurface_set_position(window->wl.decorations.bottom.subsurface,+ -GLFW_BORDER_SIZE, window->wl.height);+ wp_viewport_set_destination(window->wl.decorations.bottom.viewport,+ window->wl.width + GLFW_BORDER_SIZE * 2, GLFW_BORDER_SIZE);+ wl_surface_commit(window->wl.decorations.bottom.surface);+}++void _glfwUpdateContentScaleWayland(_GLFWwindow* window)+{+ if (wl_compositor_get_version(_glfw.wl.compositor) <+ WL_SURFACE_SET_BUFFER_SCALE_SINCE_VERSION)+ {+ return;+ }++ // Get the scale factor from the highest scale monitor.+ int maxScale = 1;++ for (int i = 0; i < window->wl.scaleCount; i++)+ maxScale = _glfw_max(window->wl.scales[i].factor, maxScale);++ // Only change the framebuffer size if the scale changed.+ if (window->wl.contentScale != maxScale)+ {+ window->wl.contentScale = maxScale;+ wl_surface_set_buffer_scale(window->wl.surface, maxScale);+ _glfwInputWindowContentScale(window, maxScale, maxScale);+ resizeWindow(window);++ if (window->wl.visible)+ _glfwInputWindowDamage(window);+ }+}++static void surfaceHandleEnter(void* userData,+ struct wl_surface* surface,+ struct wl_output* output)+{+ if (wl_proxy_get_tag((struct wl_proxy*) output) != &_glfw.wl.tag)+ return;++ _GLFWwindow* window = userData;+ _GLFWmonitor* monitor = wl_output_get_user_data(output);+ if (!window || !monitor)+ return;++ if (window->wl.scaleCount + 1 > window->wl.scaleSize)+ {+ window->wl.scaleSize++;+ window->wl.scales =+ realloc(window->wl.scales,+ window->wl.scaleSize * sizeof(_GLFWscaleWayland));+ }++ window->wl.scaleCount++;+ window->wl.scales[window->wl.scaleCount - 1].factor = monitor->wl.contentScale;+ window->wl.scales[window->wl.scaleCount - 1].output = output;++ _glfwUpdateContentScaleWayland(window);+}++static void surfaceHandleLeave(void* userData,+ struct wl_surface* surface,+ struct wl_output* output)+{+ if (wl_proxy_get_tag((struct wl_proxy*) output) != &_glfw.wl.tag)+ return;++ _GLFWwindow* window = userData;++ for (int i = 0; i < window->wl.scaleCount; i++)+ {+ if (window->wl.scales[i].output == output)+ {+ window->wl.scales[i] = window->wl.scales[window->wl.scaleCount - 1];+ window->wl.scaleCount--;+ break;+ }+ }++ _glfwUpdateContentScaleWayland(window);+}++static const struct wl_surface_listener surfaceListener =+{+ surfaceHandleEnter,+ surfaceHandleLeave+};++static void setIdleInhibitor(_GLFWwindow* window, GLFWbool enable)+{+ if (enable && !window->wl.idleInhibitor && _glfw.wl.idleInhibitManager)+ {+ window->wl.idleInhibitor =+ zwp_idle_inhibit_manager_v1_create_inhibitor(+ _glfw.wl.idleInhibitManager, window->wl.surface);+ if (!window->wl.idleInhibitor)+ _glfwInputError(GLFW_PLATFORM_ERROR,+ "Wayland: Failed to create idle inhibitor");+ }+ else if (!enable && window->wl.idleInhibitor)+ {+ zwp_idle_inhibitor_v1_destroy(window->wl.idleInhibitor);+ window->wl.idleInhibitor = NULL;+ }+}++// Make the specified window and its video mode active on its monitor+//+static void acquireMonitor(_GLFWwindow* window)+{+ if (window->wl.libdecor.frame)+ {+ libdecor_frame_set_fullscreen(window->wl.libdecor.frame,+ window->monitor->wl.output);+ }+ else if (window->wl.xdg.toplevel)+ {+ xdg_toplevel_set_fullscreen(window->wl.xdg.toplevel,+ window->monitor->wl.output);+ }++ setIdleInhibitor(window, GLFW_TRUE);++ if (window->wl.decorations.top.surface)+ destroyFallbackDecorations(window);+}++// Remove the window and restore the original video mode+//+static void releaseMonitor(_GLFWwindow* window)+{+ if (window->wl.libdecor.frame)+ libdecor_frame_unset_fullscreen(window->wl.libdecor.frame);+ else if (window->wl.xdg.toplevel)+ xdg_toplevel_unset_fullscreen(window->wl.xdg.toplevel);++ setIdleInhibitor(window, GLFW_FALSE);++ if (!window->wl.libdecor.frame &&+ window->wl.xdg.decorationMode != ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE)+ {+ if (window->decorated)+ createFallbackDecorations(window);+ }+}++static void xdgToplevelHandleConfigure(void* userData,+ struct xdg_toplevel* toplevel,+ int32_t width,+ int32_t height,+ struct wl_array* states)+{+ _GLFWwindow* window = userData;+ uint32_t* state;++ window->wl.pending.activated = GLFW_FALSE;+ window->wl.pending.maximized = GLFW_FALSE;+ window->wl.pending.fullscreen = GLFW_FALSE;++ wl_array_for_each(state, states)+ {+ switch (*state)+ {+ case XDG_TOPLEVEL_STATE_MAXIMIZED:+ window->wl.pending.maximized = GLFW_TRUE;+ break;+ case XDG_TOPLEVEL_STATE_FULLSCREEN:+ window->wl.pending.fullscreen = GLFW_TRUE;+ break;+ case XDG_TOPLEVEL_STATE_RESIZING:+ break;+ case XDG_TOPLEVEL_STATE_ACTIVATED:+ window->wl.pending.activated = GLFW_TRUE;+ break;+ }+ }++ if (width && height)+ {+ if (window->wl.decorations.top.surface)+ {+ window->wl.pending.width = _glfw_max(0, width - GLFW_BORDER_SIZE * 2);+ window->wl.pending.height =+ _glfw_max(0, height - GLFW_BORDER_SIZE - GLFW_CAPTION_HEIGHT);+ }+ else+ {+ window->wl.pending.width = width;+ window->wl.pending.height = height;+ }+ }+ else+ {+ window->wl.pending.width = window->wl.width;+ window->wl.pending.height = window->wl.height;+ }+}++static void xdgToplevelHandleClose(void* userData,+ struct xdg_toplevel* toplevel)+{+ _GLFWwindow* window = userData;+ _glfwInputWindowCloseRequest(window);+}++static const struct xdg_toplevel_listener xdgToplevelListener =+{+ xdgToplevelHandleConfigure,+ xdgToplevelHandleClose+};++static void xdgSurfaceHandleConfigure(void* userData,+ struct xdg_surface* surface,+ uint32_t serial)+{+ _GLFWwindow* window = userData;++ xdg_surface_ack_configure(surface, serial);++ if (window->wl.activated != window->wl.pending.activated)+ {+ window->wl.activated = window->wl.pending.activated;+ if (!window->wl.activated)+ {+ if (window->monitor && window->autoIconify)+ xdg_toplevel_set_minimized(window->wl.xdg.toplevel);+ }+ }++ if (window->wl.maximized != window->wl.pending.maximized)+ {+ window->wl.maximized = window->wl.pending.maximized;+ _glfwInputWindowMaximize(window, window->wl.maximized);+ }++ window->wl.fullscreen = window->wl.pending.fullscreen;++ int width = window->wl.pending.width;+ int height = window->wl.pending.height;++ if (!window->wl.maximized && !window->wl.fullscreen)+ {+ if (window->numer != GLFW_DONT_CARE && window->denom != GLFW_DONT_CARE)+ {+ const float aspectRatio = (float) width / (float) height;+ const float targetRatio = (float) window->numer / (float) window->denom;+ if (aspectRatio < targetRatio)+ height = width / targetRatio;+ else if (aspectRatio > targetRatio)+ width = height * targetRatio;+ }+ }++ if (width != window->wl.width || height != window->wl.height)+ {+ window->wl.width = width;+ window->wl.height = height;+ resizeWindow(window);++ _glfwInputWindowSize(window, width, height);++ if (window->wl.visible)+ _glfwInputWindowDamage(window);+ }++ if (!window->wl.visible)+ {+ // Allow the window to be mapped only if it either has no XDG+ // decorations or they have already received a configure event+ if (!window->wl.xdg.decoration || window->wl.xdg.decorationMode)+ {+ window->wl.visible = GLFW_TRUE;+ _glfwInputWindowDamage(window);+ }+ }+}++static const struct xdg_surface_listener xdgSurfaceListener =+{+ xdgSurfaceHandleConfigure+};++void libdecorFrameHandleConfigure(struct libdecor_frame* frame,+ struct libdecor_configuration* config,+ void* userData)+{+ _GLFWwindow* window = userData;+ int width, height;++ enum libdecor_window_state windowState;+ GLFWbool fullscreen, activated, maximized;++ if (libdecor_configuration_get_window_state(config, &windowState))+ {+ fullscreen = (windowState & LIBDECOR_WINDOW_STATE_FULLSCREEN) != 0;+ activated = (windowState & LIBDECOR_WINDOW_STATE_ACTIVE) != 0;+ maximized = (windowState & LIBDECOR_WINDOW_STATE_MAXIMIZED) != 0;+ }+ else+ {+ fullscreen = window->wl.fullscreen;+ activated = window->wl.activated;+ maximized = window->wl.maximized;+ }++ if (!libdecor_configuration_get_content_size(config, frame, &width, &height))+ {+ width = window->wl.width;+ height = window->wl.height;+ }++ if (!maximized && !fullscreen)+ {+ if (window->numer != GLFW_DONT_CARE && window->denom != GLFW_DONT_CARE)+ {+ const float aspectRatio = (float) width / (float) height;+ const float targetRatio = (float) window->numer / (float) window->denom;+ if (aspectRatio < targetRatio)+ height = width / targetRatio;+ else if (aspectRatio > targetRatio)+ width = height * targetRatio;+ }+ }++ struct libdecor_state* frameState = libdecor_state_new(width, height);+ libdecor_frame_commit(frame, frameState, config);+ libdecor_state_free(frameState);++ if (window->wl.activated != activated)+ {+ window->wl.activated = activated;+ if (!window->wl.activated)+ {+ if (window->monitor && window->autoIconify)+ libdecor_frame_set_minimized(window->wl.libdecor.frame);+ }+ }++ if (window->wl.maximized != maximized)+ {+ window->wl.maximized = maximized;+ _glfwInputWindowMaximize(window, window->wl.maximized);+ }++ window->wl.fullscreen = fullscreen;++ GLFWbool damaged = GLFW_FALSE;++ if (!window->wl.visible)+ {+ window->wl.visible = GLFW_TRUE;+ damaged = GLFW_TRUE;+ }++ if (width != window->wl.width || height != window->wl.height)+ {+ window->wl.width = width;+ window->wl.height = height;+ resizeWindow(window);++ _glfwInputWindowSize(window, width, height);+ damaged = GLFW_TRUE;+ }++ if (damaged)+ _glfwInputWindowDamage(window);+ else+ wl_surface_commit(window->wl.surface);+}++void libdecorFrameHandleClose(struct libdecor_frame* frame, void* userData)+{+ _GLFWwindow* window = userData;+ _glfwInputWindowCloseRequest(window);+}++void libdecorFrameHandleCommit(struct libdecor_frame* frame, void* userData)+{+ _GLFWwindow* window = userData;+ wl_surface_commit(window->wl.surface);+}++void libdecorFrameHandleDismissPopup(struct libdecor_frame* frame,+ const char* seatName,+ void* userData)+{+}++static const struct libdecor_frame_interface libdecorFrameInterface =+{+ libdecorFrameHandleConfigure,+ libdecorFrameHandleClose,+ libdecorFrameHandleCommit,+ libdecorFrameHandleDismissPopup+};++static GLFWbool createLibdecorFrame(_GLFWwindow* window)+{+ // Allow libdecor to finish initialization of itself and its plugin+ while (!_glfw.wl.libdecor.ready)+ _glfwPlatformWaitEvents();++ window->wl.libdecor.frame = libdecor_decorate(_glfw.wl.libdecor.context,+ window->wl.surface,+ &libdecorFrameInterface,+ window);+ if (!window->wl.libdecor.frame)+ {+ _glfwInputError(GLFW_PLATFORM_ERROR,+ "Wayland: Failed to create libdecor frame");+ return GLFW_FALSE;+ }++ struct libdecor_state* frameState =+ libdecor_state_new(window->wl.width, window->wl.height);+ libdecor_frame_commit(window->wl.libdecor.frame, frameState, NULL);+ libdecor_state_free(frameState);++ if (strlen(window->wl.title))+ libdecor_frame_set_title(window->wl.libdecor.frame, window->wl.title);++ if (window->minwidth != GLFW_DONT_CARE &&+ window->minheight != GLFW_DONT_CARE)+ {+ libdecor_frame_set_min_content_size(window->wl.libdecor.frame,+ window->minwidth,+ window->minheight);+ }++ if (window->maxwidth != GLFW_DONT_CARE &&+ window->maxheight != GLFW_DONT_CARE)+ {+ libdecor_frame_set_max_content_size(window->wl.libdecor.frame,+ window->maxwidth,+ window->maxheight);+ }++ if (!window->resizable)+ {+ libdecor_frame_unset_capabilities(window->wl.libdecor.frame,+ LIBDECOR_ACTION_RESIZE);+ }++ if (window->monitor)+ {+ libdecor_frame_set_fullscreen(window->wl.libdecor.frame,+ window->monitor->wl.output);+ setIdleInhibitor(window, GLFW_TRUE);+ }+ else+ {+ if (window->wl.maximized)+ libdecor_frame_set_maximized(window->wl.libdecor.frame);++ if (!window->decorated)+ libdecor_frame_set_visibility(window->wl.libdecor.frame, false);++ setIdleInhibitor(window, GLFW_FALSE);+ }++ libdecor_frame_map(window->wl.libdecor.frame);+ wl_display_roundtrip(_glfw.wl.display);+ return GLFW_TRUE;+}++static GLFWbool createXdgShellObjects(_GLFWwindow* window)+{+ window->wl.xdg.surface = xdg_wm_base_get_xdg_surface(_glfw.wl.wmBase,+ window->wl.surface);+ if (!window->wl.xdg.surface)+ {+ _glfwInputError(GLFW_PLATFORM_ERROR,+ "Wayland: Failed to create xdg-surface for window");+ return GLFW_FALSE;+ }++ xdg_surface_add_listener(window->wl.xdg.surface, &xdgSurfaceListener, window);++ window->wl.xdg.toplevel = xdg_surface_get_toplevel(window->wl.xdg.surface);+ if (!window->wl.xdg.toplevel)+ {+ _glfwInputError(GLFW_PLATFORM_ERROR,+ "Wayland: Failed to create xdg-toplevel for window");+ return GLFW_FALSE;+ }++ xdg_toplevel_add_listener(window->wl.xdg.toplevel, &xdgToplevelListener, window);++ if (window->wl.title)+ xdg_toplevel_set_title(window->wl.xdg.toplevel, window->wl.title);++ if (window->monitor)+ {+ xdg_toplevel_set_fullscreen(window->wl.xdg.toplevel, window->monitor->wl.output);+ setIdleInhibitor(window, GLFW_TRUE);+ }+ else+ {+ if (window->wl.maximized)+ xdg_toplevel_set_maximized(window->wl.xdg.toplevel);++ setIdleInhibitor(window, GLFW_FALSE);+ }++ if (_glfw.wl.decorationManager)+ {+ window->wl.xdg.decoration =+ zxdg_decoration_manager_v1_get_toplevel_decoration(+ _glfw.wl.decorationManager, window->wl.xdg.toplevel);+ zxdg_toplevel_decoration_v1_add_listener(window->wl.xdg.decoration,+ &xdgDecorationListener,+ window);++ uint32_t mode;++ if (window->decorated)+ mode = ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE;+ else+ mode = ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE;++ zxdg_toplevel_decoration_v1_set_mode(window->wl.xdg.decoration, mode);+ }+ else+ {+ if (window->decorated && !window->monitor)+ createFallbackDecorations(window);+ }++ if (window->minwidth != GLFW_DONT_CARE && window->minheight != GLFW_DONT_CARE)+ {+ int minwidth = window->minwidth;+ int minheight = window->minheight;++ if (window->wl.decorations.top.surface)+ {+ minwidth += GLFW_BORDER_SIZE * 2;+ minheight += GLFW_CAPTION_HEIGHT + GLFW_BORDER_SIZE;+ }++ xdg_toplevel_set_min_size(window->wl.xdg.toplevel, minwidth, minheight);+ }++ if (window->maxwidth != GLFW_DONT_CARE && window->maxheight != GLFW_DONT_CARE)+ {+ int maxwidth = window->maxwidth;+ int maxheight = window->maxheight;++ if (window->wl.decorations.top.surface)+ {+ maxwidth += GLFW_BORDER_SIZE * 2;+ maxheight += GLFW_CAPTION_HEIGHT + GLFW_BORDER_SIZE;+ }++ xdg_toplevel_set_max_size(window->wl.xdg.toplevel, maxwidth, maxheight);+ }++ wl_surface_commit(window->wl.surface);+ wl_display_roundtrip(_glfw.wl.display);+ return GLFW_TRUE;+}++static GLFWbool createShellObjects(_GLFWwindow* window)+{+ if (_glfw.wl.libdecor.context)+ {+ if (createLibdecorFrame(window))+ return GLFW_TRUE;+ }++ return createXdgShellObjects(window);+}++static void destroyShellObjects(_GLFWwindow* window)+{+ destroyFallbackDecorations(window);++ if (window->wl.libdecor.frame)+ libdecor_frame_unref(window->wl.libdecor.frame);++ if (window->wl.xdg.decoration)+ zxdg_toplevel_decoration_v1_destroy(window->wl.xdg.decoration);++ if (window->wl.xdg.toplevel)+ xdg_toplevel_destroy(window->wl.xdg.toplevel);++ if (window->wl.xdg.surface)+ xdg_surface_destroy(window->wl.xdg.surface);++ window->wl.libdecor.frame = NULL;+ window->wl.xdg.decoration = NULL;+ window->wl.xdg.decorationMode = 0;+ window->wl.xdg.toplevel = NULL;+ window->wl.xdg.surface = NULL;+}++static GLFWbool createNativeSurface(_GLFWwindow* window,+ const _GLFWwndconfig* wndconfig,+ const _GLFWfbconfig* fbconfig)+{+ window->wl.surface = wl_compositor_create_surface(_glfw.wl.compositor);+ if (!window->wl.surface)+ {+ _glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: Failed to create window surface");+ return GLFW_FALSE;+ }++ wl_proxy_set_tag((struct wl_proxy*) window->wl.surface, &_glfw.wl.tag);+ wl_surface_add_listener(window->wl.surface,+ &surfaceListener,+ window);++ window->wl.width = wndconfig->width;+ window->wl.height = wndconfig->height;+ window->wl.contentScale = 1;+ window->wl.title = _glfw_strdup(wndconfig->title);++ window->wl.maximized = wndconfig->maximized;++ window->wl.transparent = fbconfig->transparent;+ if (!window->wl.transparent)+ setContentAreaOpaque(window);++ return GLFW_TRUE;+}++static void setCursorImage(_GLFWwindow* window,+ _GLFWcursorWayland* cursorWayland)+{+ struct itimerspec timer = {0};+ struct wl_cursor* wlCursor = cursorWayland->cursor;+ struct wl_cursor_image* image;+ struct wl_buffer* buffer;+ struct wl_surface* surface = _glfw.wl.cursorSurface;+ int scale = 1;++ if (!wlCursor)+ buffer = cursorWayland->buffer;+ else+ {+ if (window->wl.contentScale > 1 && cursorWayland->cursorHiDPI)+ {+ wlCursor = cursorWayland->cursorHiDPI;+ scale = 2;+ }++ image = wlCursor->images[cursorWayland->currentImage];+ buffer = wl_cursor_image_get_buffer(image);+ if (!buffer)+ return;++ timer.it_value.tv_sec = image->delay / 1000;+ timer.it_value.tv_nsec = (image->delay % 1000) * 1000000;+ timerfd_settime(_glfw.wl.cursorTimerfd, 0, &timer, NULL);++ cursorWayland->width = image->width;+ cursorWayland->height = image->height;+ cursorWayland->xhot = image->hotspot_x;+ cursorWayland->yhot = image->hotspot_y;+ }++ wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerEnterSerial,+ surface,+ cursorWayland->xhot / scale,+ cursorWayland->yhot / scale);+ wl_surface_set_buffer_scale(surface, scale);+ wl_surface_attach(surface, buffer, 0, 0);+ wl_surface_damage(surface, 0, 0,+ cursorWayland->width, cursorWayland->height);+ wl_surface_commit(surface);+}++static void incrementCursorImage(_GLFWwindow* window)+{+ _GLFWcursor* cursor;++ if (!window || window->wl.decorations.focus != GLFW_MAIN_WINDOW)+ return;++ cursor = window->wl.currentCursor;+ if (cursor && cursor->wl.cursor)+ {+ cursor->wl.currentImage += 1;+ cursor->wl.currentImage %= cursor->wl.cursor->image_count;+ setCursorImage(window, &cursor->wl);+ }+}++static GLFWbool flushDisplay(void)+{+ while (wl_display_flush(_glfw.wl.display) == -1)+ {+ if (errno != EAGAIN)+ return GLFW_FALSE;++ struct pollfd fd = { wl_display_get_fd(_glfw.wl.display), POLLOUT };++ while (poll(&fd, 1, -1) == -1)+ {+ if (errno != EINTR && errno != EAGAIN)+ return GLFW_FALSE;+ }+ }++ return GLFW_TRUE;+}++static int translateKey(uint32_t scancode)+{+ if (scancode < sizeof(_glfw.wl.keycodes) / sizeof(_glfw.wl.keycodes[0]))+ return _glfw.wl.keycodes[scancode];++ return GLFW_KEY_UNKNOWN;+}++static xkb_keysym_t composeSymbol(xkb_keysym_t sym)+{+ if (sym == XKB_KEY_NoSymbol || !_glfw.wl.xkb.composeState)+ return sym;+ if (xkb_compose_state_feed(_glfw.wl.xkb.composeState, sym)+ != XKB_COMPOSE_FEED_ACCEPTED)+ return sym;+ switch (xkb_compose_state_get_status(_glfw.wl.xkb.composeState))+ {+ case XKB_COMPOSE_COMPOSED:+ return xkb_compose_state_get_one_sym(_glfw.wl.xkb.composeState);+ case XKB_COMPOSE_COMPOSING:+ case XKB_COMPOSE_CANCELLED:+ return XKB_KEY_NoSymbol;+ case XKB_COMPOSE_NOTHING:+ default:+ return sym;+ }+}++static void inputText(_GLFWwindow* window, uint32_t scancode)+{+ const xkb_keysym_t* keysyms;+ const xkb_keycode_t keycode = scancode + 8;++ if (xkb_state_key_get_syms(_glfw.wl.xkb.state, keycode, &keysyms) == 1)+ {+ const xkb_keysym_t keysym = composeSymbol(keysyms[0]);+ const uint32_t codepoint = _glfwKeySym2Unicode(keysym);+ if (codepoint != GLFW_INVALID_CODEPOINT)+ {+ const int mods = _glfw.wl.xkb.modifiers;+ const int plain = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT));+ _glfwInputChar(window, codepoint, mods, plain);+ }+ }+}++static void handleEvents(double* timeout)+{+#if defined(__linux__)+ _glfwDetectJoystickConnectionLinux();+#endif++ GLFWbool event = GLFW_FALSE;+ struct pollfd fds[4] =+ {+ { wl_display_get_fd(_glfw.wl.display), POLLIN },+ { _glfw.wl.keyRepeatTimerfd, POLLIN },+ { _glfw.wl.cursorTimerfd, POLLIN },+ { -1, POLLIN }+ };++ if (_glfw.wl.libdecor.context)+ fds[3].fd = libdecor_get_fd(_glfw.wl.libdecor.context);++ while (!event)+ {+ while (wl_display_prepare_read(_glfw.wl.display) != 0)+ {+ if (wl_display_dispatch_pending(_glfw.wl.display) > 0)+ return;+ }++ // If an error other than EAGAIN happens, we have likely been disconnected+ // from the Wayland session; try to handle that the best we can.+ if (!flushDisplay())+ {+ wl_display_cancel_read(_glfw.wl.display);++ _GLFWwindow* window = _glfw.windowListHead;+ while (window)+ {+ _glfwInputWindowCloseRequest(window);+ window = window->next;+ }++ return;+ }++ if (!waitForData(fds, sizeof(fds) / sizeof(fds[0]), timeout))+ {+ wl_display_cancel_read(_glfw.wl.display);+ return;+ }++ if (fds[0].revents & POLLIN)+ {+ wl_display_read_events(_glfw.wl.display);+ if (wl_display_dispatch_pending(_glfw.wl.display) > 0)+ event = GLFW_TRUE;+ }+ else+ wl_display_cancel_read(_glfw.wl.display);++ if (fds[1].revents & POLLIN)+ {+ uint64_t repeats;++ if (read(_glfw.wl.keyRepeatTimerfd, &repeats, sizeof(repeats)) == 8)+ {+ for (uint64_t i = 0; i < repeats; i++)+ {+ _glfwInputKey(_glfw.wl.keyboardFocus,+ translateKey(_glfw.wl.keyRepeatScancode),+ _glfw.wl.keyRepeatScancode,+ GLFW_PRESS,+ _glfw.wl.xkb.modifiers);+ inputText(_glfw.wl.keyboardFocus, _glfw.wl.keyRepeatScancode);+ }++ event = GLFW_TRUE;+ }+ }++ if (fds[2].revents & POLLIN)+ {+ uint64_t repeats;++ if (read(_glfw.wl.cursorTimerfd, &repeats, sizeof(repeats)) == 8)+ incrementCursorImage(_glfw.wl.pointerFocus);+ }++ if (fds[3].revents & POLLIN)+ {+ if (libdecor_dispatch(_glfw.wl.libdecor.context, 0) > 0)+ event = GLFW_TRUE;+ }+ }+}++// Reads the specified data offer as the specified MIME type+//+static char* readDataOfferAsString(struct wl_data_offer* offer, const char* mimeType)+{+ int fds[2];++ if (pipe2(fds, O_CLOEXEC) == -1)+ {+ _glfwInputError(GLFW_PLATFORM_ERROR,+ "Wayland: Failed to create pipe for data offer: %s",+ strerror(errno));+ return NULL;+ }++ wl_data_offer_receive(offer, mimeType, fds[1]);+ flushDisplay();+ close(fds[1]);++ char* string = NULL;+ size_t size = 0;+ size_t length = 0;++ for (;;)+ {+ const size_t readSize = 4096;+ const size_t requiredSize = length + readSize + 1;+ if (requiredSize > size)+ {+ char* longer = realloc(string, requiredSize);+ if (!longer)+ {+ _glfwInputError(GLFW_OUT_OF_MEMORY, NULL);+ close(fds[0]);+ return NULL;+ }++ string = longer;+ size = requiredSize;+ }++ const ssize_t result = read(fds[0], string + length, readSize);+ if (result == 0)+ break;+ else if (result == -1)+ {+ if (errno == EINTR)+ continue;++ _glfwInputError(GLFW_PLATFORM_ERROR,+ "Wayland: Failed to read from data offer pipe: %s",+ strerror(errno));+ close(fds[0]);+ return NULL;+ }++ length += result;+ }++ close(fds[0]);++ string[length] = '\0';+ return string;+}++static void pointerHandleEnter(void* userData,+ struct wl_pointer* pointer,+ uint32_t serial,+ struct wl_surface* surface,+ wl_fixed_t sx,+ wl_fixed_t sy)+{+ // Happens in the case we just destroyed the surface.+ if (!surface)+ return;++ if (wl_proxy_get_tag((struct wl_proxy*) surface) != &_glfw.wl.tag)+ return;++ _GLFWwindow* window = wl_surface_get_user_data(surface);++ if (surface == window->wl.decorations.top.surface)+ window->wl.decorations.focus = GLFW_TOP_DECORATION;+ else if (surface == window->wl.decorations.left.surface)+ window->wl.decorations.focus = GLFW_LEFT_DECORATION;+ else if (surface == window->wl.decorations.right.surface)+ window->wl.decorations.focus = GLFW_RIGHT_DECORATION;+ else if (surface == window->wl.decorations.bottom.surface)+ window->wl.decorations.focus = GLFW_BOTTOM_DECORATION;+ else+ window->wl.decorations.focus = GLFW_MAIN_WINDOW;++ _glfw.wl.serial = serial;+ _glfw.wl.pointerEnterSerial = serial;+ _glfw.wl.pointerFocus = window;++ window->wl.hovered = GLFW_TRUE;++ _glfwPlatformSetCursor(window, window->wl.currentCursor);+ _glfwInputCursorEnter(window, GLFW_TRUE);+}++static void pointerHandleLeave(void* userData,+ struct wl_pointer* pointer,+ uint32_t serial,+ struct wl_surface* surface)+{+ if (!surface)+ return;++ if (wl_proxy_get_tag((struct wl_proxy*) surface) != &_glfw.wl.tag)+ return;++ _GLFWwindow* window = _glfw.wl.pointerFocus;+ if (!window)+ return;++ window->wl.hovered = GLFW_FALSE;++ _glfw.wl.serial = serial;+ _glfw.wl.pointerFocus = NULL;+ _glfw.wl.cursorPreviousName = NULL;+ _glfwInputCursorEnter(window, GLFW_FALSE);+}++static void pointerHandleMotion(void* userData,+ struct wl_pointer* pointer,+ uint32_t time,+ wl_fixed_t sx,+ wl_fixed_t sy)+{+ _GLFWwindow* window = _glfw.wl.pointerFocus;+ if (!window)+ return;++ if (window->cursorMode == GLFW_CURSOR_DISABLED)+ return;++ const double xpos = wl_fixed_to_double(sx);+ const double ypos = wl_fixed_to_double(sy);+ window->wl.cursorPosX = xpos;+ window->wl.cursorPosY = ypos;++ const char* cursorName = NULL;++ switch (window->wl.decorations.focus)+ {+ case GLFW_MAIN_WINDOW:+ _glfw.wl.cursorPreviousName = NULL;+ _glfwInputCursorPos(window, xpos, ypos);+ return;+ case GLFW_TOP_DECORATION:+ if (ypos < GLFW_BORDER_SIZE)+ cursorName = "n-resize";+ else+ cursorName = "left_ptr";+ break;+ case GLFW_LEFT_DECORATION:+ if (ypos < GLFW_BORDER_SIZE)+ cursorName = "nw-resize";+ else+ cursorName = "w-resize";+ break;+ case GLFW_RIGHT_DECORATION:+ if (ypos < GLFW_BORDER_SIZE)+ cursorName = "ne-resize";+ else+ cursorName = "e-resize";+ break;+ case GLFW_BOTTOM_DECORATION:+ if (xpos < GLFW_BORDER_SIZE)+ cursorName = "sw-resize";+ else if (xpos > window->wl.width + GLFW_BORDER_SIZE)+ cursorName = "se-resize";+ else+ cursorName = "s-resize";+ break;+ default:+ assert(0);+ }++ if (_glfw.wl.cursorPreviousName != cursorName)+ {+ struct wl_surface* surface = _glfw.wl.cursorSurface;+ struct wl_cursor_theme* theme = _glfw.wl.cursorTheme;+ int scale = 1;++ if (window->wl.contentScale > 1 && _glfw.wl.cursorThemeHiDPI)+ {+ // We only support up to scale=2 for now, since libwayland-cursor+ // requires us to load a different theme for each size.+ scale = 2;+ theme = _glfw.wl.cursorThemeHiDPI;+ }++ struct wl_cursor* cursor = wl_cursor_theme_get_cursor(theme, cursorName);+ if (!cursor)+ return;++ // TODO: handle animated cursors too.+ struct wl_cursor_image* image = cursor->images[0];+ if (!image)+ return;++ struct wl_buffer* buffer = wl_cursor_image_get_buffer(image);+ if (!buffer)+ return;++ wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerEnterSerial,+ surface,+ image->hotspot_x / scale,+ image->hotspot_y / scale);+ wl_surface_set_buffer_scale(surface, scale);+ wl_surface_attach(surface, buffer, 0, 0);+ wl_surface_damage(surface, 0, 0, image->width, image->height);+ wl_surface_commit(surface);++ _glfw.wl.cursorPreviousName = cursorName;+ }+}++static void pointerHandleButton(void* userData,+ struct wl_pointer* pointer,+ uint32_t serial,+ uint32_t time,+ uint32_t button,+ uint32_t state)+{+ _GLFWwindow* window = _glfw.wl.pointerFocus;+ int glfwButton;++ uint32_t edges = XDG_TOPLEVEL_RESIZE_EDGE_NONE;++ if (!window)+ return;+ if (button == BTN_LEFT)+ {+ switch (window->wl.decorations.focus)+ {+ case GLFW_MAIN_WINDOW:+ break;+ case GLFW_TOP_DECORATION:+ if (window->wl.cursorPosY < GLFW_BORDER_SIZE)+ edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP;+ else+ {+ xdg_toplevel_move(window->wl.xdg.toplevel, _glfw.wl.seat, serial);+ }+ break;+ case GLFW_LEFT_DECORATION:+ if (window->wl.cursorPosY < GLFW_BORDER_SIZE)+ edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT;+ else+ edges = XDG_TOPLEVEL_RESIZE_EDGE_LEFT;+ break;+ case GLFW_RIGHT_DECORATION:+ if (window->wl.cursorPosY < GLFW_BORDER_SIZE)+ edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT;+ else+ edges = XDG_TOPLEVEL_RESIZE_EDGE_RIGHT;+ break;+ case GLFW_BOTTOM_DECORATION:+ if (window->wl.cursorPosX < GLFW_BORDER_SIZE)+ edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT;+ else if (window->wl.cursorPosX > window->wl.width + GLFW_BORDER_SIZE)+ edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT;+ else+ edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM;+ break;+ default:+ assert(0);+ }+ if (edges != XDG_TOPLEVEL_RESIZE_EDGE_NONE)+ {+ xdg_toplevel_resize(window->wl.xdg.toplevel, _glfw.wl.seat,+ serial, edges);+ return;+ }+ }+ else if (button == BTN_RIGHT)+ {+ if (window->wl.decorations.focus != GLFW_MAIN_WINDOW &&+ window->wl.xdg.toplevel)+ {+ xdg_toplevel_show_window_menu(window->wl.xdg.toplevel,+ _glfw.wl.seat, serial,+ window->wl.cursorPosX,+ window->wl.cursorPosY);+ return;+ }+ }++ // Don’t pass the button to the user if it was related to a decoration.+ if (window->wl.decorations.focus != GLFW_MAIN_WINDOW)+ return;++ _glfw.wl.serial = serial;++ /* Makes left, right and middle 0, 1 and 2. Overall order follows evdev+ * codes. */+ glfwButton = button - BTN_LEFT;++ _glfwInputMouseClick(window,+ glfwButton,+ state == WL_POINTER_BUTTON_STATE_PRESSED+ ? GLFW_PRESS+ : GLFW_RELEASE,+ _glfw.wl.xkb.modifiers);+}++static void pointerHandleAxis(void* userData,+ struct wl_pointer* pointer,+ uint32_t time,+ uint32_t axis,+ wl_fixed_t value)+{+ _GLFWwindow* window = _glfw.wl.pointerFocus;+ double x = 0.0, y = 0.0;+ // Wayland scroll events are in pointer motion coordinate space (think two+ // finger scroll). The factor 10 is commonly used to convert to "scroll+ // step means 1.0.+ const double scrollFactor = 1.0 / 10.0;++ if (!window)+ return;++ assert(axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL ||+ axis == WL_POINTER_AXIS_VERTICAL_SCROLL);++ if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL)+ x = -wl_fixed_to_double(value) * scrollFactor;+ else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL)+ y = -wl_fixed_to_double(value) * scrollFactor;++ _glfwInputScroll(window, x, y);+}++static const struct wl_pointer_listener pointerListener =+{+ pointerHandleEnter,+ pointerHandleLeave,+ pointerHandleMotion,+ pointerHandleButton,+ pointerHandleAxis,+};++static void keyboardHandleKeymap(void* userData,+ struct wl_keyboard* keyboard,+ uint32_t format,+ int fd,+ uint32_t size)+{+ struct xkb_keymap* keymap;+ struct xkb_state* state;+ struct xkb_compose_table* composeTable;+ struct xkb_compose_state* composeState;+ char* mapStr;+ const char* locale;++ if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1)+ {+ close(fd);+ return;+ }++ mapStr = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);+ if (mapStr == MAP_FAILED) {+ close(fd);+ return;+ }++ keymap = xkb_keymap_new_from_string(_glfw.wl.xkb.context,+ mapStr,+ XKB_KEYMAP_FORMAT_TEXT_V1,+ 0);+ munmap(mapStr, size);+ close(fd);++ if (!keymap)+ {+ _glfwInputError(GLFW_PLATFORM_ERROR,+ "Wayland: Failed to compile keymap");+ return;+ }++ state = xkb_state_new(keymap);+ if (!state)+ {+ _glfwInputError(GLFW_PLATFORM_ERROR,+ "Wayland: Failed to create XKB state");+ xkb_keymap_unref(keymap);+ return;+ }++ // Look up the preferred locale, falling back to "C" as default.+ locale = getenv("LC_ALL");+ if (!locale)+ locale = getenv("LC_CTYPE");+ if (!locale)+ locale = getenv("LANG");+ if (!locale)+ locale = "C";++ composeTable =+ xkb_compose_table_new_from_locale(_glfw.wl.xkb.context, locale,+ XKB_COMPOSE_COMPILE_NO_FLAGS);+ if (composeTable)+ {+ composeState =+ xkb_compose_state_new(composeTable, XKB_COMPOSE_STATE_NO_FLAGS);+ xkb_compose_table_unref(composeTable);+ if (composeState)+ _glfw.wl.xkb.composeState = composeState;+ else+ _glfwInputError(GLFW_PLATFORM_ERROR,+ "Wayland: Failed to create XKB compose state");+ }+ else+ {+ _glfwInputError(GLFW_PLATFORM_ERROR,+ "Wayland: Failed to create XKB compose table");+ }++ xkb_keymap_unref(_glfw.wl.xkb.keymap);+ xkb_state_unref(_glfw.wl.xkb.state);+ _glfw.wl.xkb.keymap = keymap;+ _glfw.wl.xkb.state = state;++ _glfw.wl.xkb.controlIndex = xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Control");+ _glfw.wl.xkb.altIndex = xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod1");+ _glfw.wl.xkb.shiftIndex = xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Shift");+ _glfw.wl.xkb.superIndex = xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod4");+ _glfw.wl.xkb.capsLockIndex = xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Lock");+ _glfw.wl.xkb.numLockIndex = xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod2");+}++static void keyboardHandleEnter(void* userData,+ struct wl_keyboard* keyboard,+ uint32_t serial,+ struct wl_surface* surface,+ struct wl_array* keys)+{+ // Happens in the case we just destroyed the surface.+ if (!surface)+ return;++ if (wl_proxy_get_tag((struct wl_proxy*) surface) != &_glfw.wl.tag)+ return;++ _GLFWwindow* window = wl_surface_get_user_data(surface);+ if (surface != window->wl.surface)+ return;++ _glfw.wl.serial = serial;+ _glfw.wl.keyboardFocus = window;+ _glfwInputWindowFocus(window, GLFW_TRUE);+}++static void keyboardHandleLeave(void* userData,+ struct wl_keyboard* keyboard,+ uint32_t serial,+ struct wl_surface* surface)+{+ _GLFWwindow* window = _glfw.wl.keyboardFocus;++ if (!window)+ return;++ struct itimerspec timer = {0};+ timerfd_settime(_glfw.wl.keyRepeatTimerfd, 0, &timer, NULL);++ _glfw.wl.serial = serial;+ _glfw.wl.keyboardFocus = NULL;+ _glfwInputWindowFocus(window, GLFW_FALSE);+}++static void keyboardHandleKey(void* userData,+ struct wl_keyboard* keyboard,+ uint32_t serial,+ uint32_t time,+ uint32_t scancode,+ uint32_t state)+{+ _GLFWwindow* window = _glfw.wl.keyboardFocus;+ if (!window)+ return;++ const int key = translateKey(scancode);+ const int action =+ state == WL_KEYBOARD_KEY_STATE_PRESSED ? GLFW_PRESS : GLFW_RELEASE;++ _glfw.wl.serial = serial;++ struct itimerspec timer = {0};++ if (action == GLFW_PRESS)+ {+ const xkb_keycode_t keycode = scancode + 8;++ if (xkb_keymap_key_repeats(_glfw.wl.xkb.keymap, keycode) &&+ _glfw.wl.keyRepeatRate > 0)+ {+ _glfw.wl.keyRepeatScancode = scancode;+ if (_glfw.wl.keyRepeatRate > 1)+ timer.it_interval.tv_nsec = 1000000000 / _glfw.wl.keyRepeatRate;+ else+ timer.it_interval.tv_sec = 1;++ timer.it_value.tv_sec = _glfw.wl.keyRepeatDelay / 1000;+ timer.it_value.tv_nsec = (_glfw.wl.keyRepeatDelay % 1000) * 1000000;+ }+ }++ timerfd_settime(_glfw.wl.keyRepeatTimerfd, 0, &timer, NULL);++ _glfwInputKey(window, key, scancode, action, _glfw.wl.xkb.modifiers);++ if (action == GLFW_PRESS)+ inputText(window, scancode);+}++static void keyboardHandleModifiers(void* userData,+ struct wl_keyboard* keyboard,+ uint32_t serial,+ uint32_t modsDepressed,+ uint32_t modsLatched,+ uint32_t modsLocked,+ uint32_t group)+{+ _glfw.wl.serial = serial;++ if (!_glfw.wl.xkb.keymap)+ return;++ xkb_state_update_mask(_glfw.wl.xkb.state,+ modsDepressed,+ modsLatched,+ modsLocked,+ 0,+ 0,+ group);++ _glfw.wl.xkb.modifiers = 0;++ struct+ {+ xkb_mod_index_t index;+ unsigned int bit;+ } modifiers[] =+ {+ { _glfw.wl.xkb.controlIndex, GLFW_MOD_CONTROL },+ { _glfw.wl.xkb.altIndex, GLFW_MOD_ALT },+ { _glfw.wl.xkb.shiftIndex, GLFW_MOD_SHIFT },+ { _glfw.wl.xkb.superIndex, GLFW_MOD_SUPER },+ { _glfw.wl.xkb.capsLockIndex, GLFW_MOD_CAPS_LOCK },+ { _glfw.wl.xkb.numLockIndex, GLFW_MOD_NUM_LOCK }+ };++ for (size_t i = 0; i < sizeof(modifiers) / sizeof(modifiers[0]); i++)+ {+ if (xkb_state_mod_index_is_active(_glfw.wl.xkb.state,+ modifiers[i].index,+ XKB_STATE_MODS_EFFECTIVE) == 1)+ {+ _glfw.wl.xkb.modifiers |= modifiers[i].bit;+ }+ }+}++#ifdef WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION+static void keyboardHandleRepeatInfo(void* userData,+ struct wl_keyboard* keyboard,+ int32_t rate,+ int32_t delay)+{+ if (keyboard != _glfw.wl.keyboard)+ return;++ _glfw.wl.keyRepeatRate = rate;+ _glfw.wl.keyRepeatDelay = delay;+}+#endif++static const struct wl_keyboard_listener keyboardListener =+{+ keyboardHandleKeymap,+ keyboardHandleEnter,+ keyboardHandleLeave,+ keyboardHandleKey,+ keyboardHandleModifiers,+#ifdef WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION+ keyboardHandleRepeatInfo,+#endif+};++static void seatHandleCapabilities(void* userData,+ struct wl_seat* seat,+ enum wl_seat_capability caps)+{+ if ((caps & WL_SEAT_CAPABILITY_POINTER) && !_glfw.wl.pointer)+ {+ _glfw.wl.pointer = wl_seat_get_pointer(seat);+ wl_pointer_add_listener(_glfw.wl.pointer, &pointerListener, NULL);+ }+ else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && _glfw.wl.pointer)+ {+ wl_pointer_destroy(_glfw.wl.pointer);+ _glfw.wl.pointer = NULL;+ }++ if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !_glfw.wl.keyboard)+ {+ _glfw.wl.keyboard = wl_seat_get_keyboard(seat);+ wl_keyboard_add_listener(_glfw.wl.keyboard, &keyboardListener, NULL);+ }+ else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && _glfw.wl.keyboard)+ {+ wl_keyboard_destroy(_glfw.wl.keyboard);+ _glfw.wl.keyboard = NULL;+ }+}++static void seatHandleName(void* userData,+ struct wl_seat* seat,+ const char* name)+{+}++static const struct wl_seat_listener seatListener =+{+ seatHandleCapabilities,+ seatHandleName,+};++static void dataOfferHandleOffer(void* userData,+ struct wl_data_offer* offer,+ const char* mimeType)+{+ for (unsigned int i = 0; i < _glfw.wl.offerCount; i++)+ {+ if (_glfw.wl.offers[i].offer == offer)+ {+ if (strcmp(mimeType, "text/plain;charset=utf-8") == 0)+ _glfw.wl.offers[i].text_plain_utf8 = GLFW_TRUE;+ else if (strcmp(mimeType, "text/uri-list") == 0)+ _glfw.wl.offers[i].text_uri_list = GLFW_TRUE;++ break;+ }+ }+}++static const struct wl_data_offer_listener dataOfferListener =+{+ dataOfferHandleOffer+};++static void dataDeviceHandleDataOffer(void* userData,+ struct wl_data_device* device,+ struct wl_data_offer* offer)+{+ _GLFWofferWayland* offers =+ realloc(_glfw.wl.offers,+ sizeof(_GLFWofferWayland) * (_glfw.wl.offerCount + 1));+ if (!offers)+ {+ _glfwInputError(GLFW_OUT_OF_MEMORY, NULL);+ return;+ }++ _glfw.wl.offers = offers;+ _glfw.wl.offerCount++;++ _glfw.wl.offers[_glfw.wl.offerCount - 1] = (_GLFWofferWayland) { offer };+ wl_data_offer_add_listener(offer, &dataOfferListener, NULL);+}++static void dataDeviceHandleEnter(void* userData,+ struct wl_data_device* device,+ uint32_t serial,+ struct wl_surface* surface,+ wl_fixed_t x,+ wl_fixed_t y,+ struct wl_data_offer* offer)+{+ if (_glfw.wl.dragOffer)+ {+ wl_data_offer_destroy(_glfw.wl.dragOffer);+ _glfw.wl.dragOffer = NULL;+ _glfw.wl.dragFocus = NULL;+ }++ for (unsigned int i = 0; i < _glfw.wl.offerCount; i++)+ {+ if (_glfw.wl.offers[i].offer == offer)+ {+ _GLFWwindow* window = NULL;++ if (surface)+ {+ if (wl_proxy_get_tag((struct wl_proxy*) surface) == &_glfw.wl.tag)+ window = wl_surface_get_user_data(surface);+ }++ if (surface == window->wl.surface && _glfw.wl.offers[i].text_uri_list)+ {+ _glfw.wl.dragOffer = offer;+ _glfw.wl.dragFocus = window;+ _glfw.wl.dragSerial = serial;+ }++ _glfw.wl.offers[i] = _glfw.wl.offers[_glfw.wl.offerCount - 1];+ _glfw.wl.offerCount--;+ break;+ }+ }++ if (wl_proxy_get_tag((struct wl_proxy*) surface) != &_glfw.wl.tag)+ return;++ if (_glfw.wl.dragOffer)+ wl_data_offer_accept(offer, serial, "text/uri-list");+ else+ {+ wl_data_offer_accept(offer, serial, NULL);+ wl_data_offer_destroy(offer);+ }+}++static void dataDeviceHandleLeave(void* userData,+ struct wl_data_device* device)+{+ if (_glfw.wl.dragOffer)+ {+ wl_data_offer_destroy(_glfw.wl.dragOffer);+ _glfw.wl.dragOffer = NULL;+ _glfw.wl.dragFocus = NULL;+ }+}++static void dataDeviceHandleMotion(void* userData,+ struct wl_data_device* device,+ uint32_t time,+ wl_fixed_t x,+ wl_fixed_t y)+{+}++static void dataDeviceHandleDrop(void* userData,+ struct wl_data_device* device)+{+ if (!_glfw.wl.dragOffer)+ return;++ char* string = readDataOfferAsString(_glfw.wl.dragOffer, "text/uri-list");+ if (string)+ {+ int count;+ char** paths = _glfwParseUriList(string, &count);+ if (paths)+ _glfwInputDrop(_glfw.wl.dragFocus, count, (const char**) paths);++ for (int i = 0; i < count; i++)+ free(paths[i]);++ free(paths);+ }++ free(string);+}++static void dataDeviceHandleSelection(void* userData,+ struct wl_data_device* device,+ struct wl_data_offer* offer)+{+ if (_glfw.wl.selectionOffer)+ {+ wl_data_offer_destroy(_glfw.wl.selectionOffer);+ _glfw.wl.selectionOffer = NULL;+ }++ for (unsigned int i = 0; i < _glfw.wl.offerCount; i++)+ {+ if (_glfw.wl.offers[i].offer == offer)+ {+ if (_glfw.wl.offers[i].text_plain_utf8)+ _glfw.wl.selectionOffer = offer;+ else+ wl_data_offer_destroy(offer);++ _glfw.wl.offers[i] = _glfw.wl.offers[_glfw.wl.offerCount - 1];+ _glfw.wl.offerCount--;+ break;+ }+ }+}++const struct wl_data_device_listener dataDeviceListener =+{+ dataDeviceHandleDataOffer,+ dataDeviceHandleEnter,+ dataDeviceHandleLeave,+ dataDeviceHandleMotion,+ dataDeviceHandleDrop,+ dataDeviceHandleSelection,+};++// Translates a GLFW standard cursor to a theme cursor name+//+static char *translateCursorShape(int shape)+{+ switch (shape)+ {+ case GLFW_ARROW_CURSOR:+ return "left_ptr";+ case GLFW_IBEAM_CURSOR:+ return "xterm";+ case GLFW_CROSSHAIR_CURSOR:+ return "crosshair";+ case GLFW_HAND_CURSOR:+ return "hand2";+ case GLFW_HRESIZE_CURSOR:+ return "sb_h_double_arrow";+ case GLFW_VRESIZE_CURSOR:+ return "sb_v_double_arrow";+ }+ return NULL;+}++void _glfwAddSeatListenerWayland(struct wl_seat* seat)+{+ wl_seat_add_listener(seat, &seatListener, NULL);+}++void _glfwAddDataDeviceListenerWayland(struct wl_data_device* device)+{+ wl_data_device_add_listener(device, &dataDeviceListener, NULL);+}+++//////////////////////////////////////////////////////////////////////////+////// GLFW platform API //////+//////////////////////////////////////////////////////////////////////////++int _glfwPlatformCreateWindow(_GLFWwindow* window,+ const _GLFWwndconfig* wndconfig,+ const _GLFWctxconfig* ctxconfig,+ const _GLFWfbconfig* fbconfig)+{+ if (!createNativeSurface(window, wndconfig, fbconfig))+ return GLFW_FALSE;++ if (ctxconfig->client != GLFW_NO_API)+ {+ if (ctxconfig->source == GLFW_EGL_CONTEXT_API ||+ ctxconfig->source == GLFW_NATIVE_CONTEXT_API)+ {+ window->wl.egl.window = wl_egl_window_create(window->wl.surface,+ wndconfig->width,+ wndconfig->height);+ if (!window->wl.egl.window)+ {+ _glfwInputError(GLFW_PLATFORM_ERROR,+ "Wayland: Failed to create EGL window");+ return GLFW_FALSE;+ }++ if (!_glfwInitEGL())+ return GLFW_FALSE;+ if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig))+ return GLFW_FALSE;+ }+ else if (ctxconfig->source == GLFW_OSMESA_CONTEXT_API)+ {+ if (!_glfwInitOSMesa())+ return GLFW_FALSE;+ if (!_glfwCreateContextOSMesa(window, ctxconfig, fbconfig))+ return GLFW_FALSE;+ }++ if (!_glfwRefreshContextAttribs(window, ctxconfig))+ return GLFW_FALSE;+ }++ if (window->monitor || wndconfig->visible)+ {+ if (!createShellObjects(window))+ return GLFW_FALSE;+ }++ return GLFW_TRUE;+}++void _glfwPlatformDestroyWindow(_GLFWwindow* window)+{+ if (window == _glfw.wl.pointerFocus)+ _glfw.wl.pointerFocus = NULL;++ if (window == _glfw.wl.keyboardFocus)+ _glfw.wl.keyboardFocus = NULL;++ if (window->wl.idleInhibitor)+ zwp_idle_inhibitor_v1_destroy(window->wl.idleInhibitor);++ if (window->wl.relativePointer)+ zwp_relative_pointer_v1_destroy(window->wl.relativePointer);++ if (window->wl.lockedPointer)+ zwp_locked_pointer_v1_destroy(window->wl.lockedPointer);++ if (window->context.destroy)+ window->context.destroy(window);++ destroyShellObjects(window);++ if (window->wl.decorations.buffer)+ wl_buffer_destroy(window->wl.decorations.buffer);++ if (window->wl.egl.window)+ wl_egl_window_destroy(window->wl.egl.window);++ if (window->wl.surface)+ wl_surface_destroy(window->wl.surface);++ free(window->wl.title);+ free(window->wl.scales);+}++void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title)+{+ if (window->wl.title)+ free(window->wl.title);+ window->wl.title = _glfw_strdup(title);++ if (window->wl.libdecor.frame)+ libdecor_frame_set_title(window->wl.libdecor.frame, title);+ else if (window->wl.xdg.toplevel)+ xdg_toplevel_set_title(window->wl.xdg.toplevel, title);+}++void _glfwPlatformSetWindowIcon(_GLFWwindow* window,+ int count, const GLFWimage* images)+{+ _glfwInputError(GLFW_PLATFORM_ERROR,+ "Wayland: Setting window icon not supported");+}++void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos)+{+ // A Wayland client is not aware of its position, so just warn and leave it+ // as (0, 0)++ _glfwInputError(GLFW_PLATFORM_ERROR,+ "Wayland: Window position retrieval not supported");+}++void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos)+{+ // A Wayland client can not set its position, so just warn++ _glfwInputError(GLFW_PLATFORM_ERROR,+ "Wayland: Window position setting not supported");+}++void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height)+{+ if (width)+ *width = window->wl.width;+ if (height)+ *height = window->wl.height;+}++void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height)+{+ if (window->monitor)+ {+ // Video mode setting is not available on Wayland+ }+ else+ {+ window->wl.width = width;+ window->wl.height = height;+ resizeWindow(window);++ if (window->wl.libdecor.frame)+ {+ struct libdecor_state* frameState = libdecor_state_new(width, height);+ libdecor_frame_commit(window->wl.libdecor.frame, frameState, NULL);+ libdecor_state_free(frameState);+ }++ if (window->wl.visible)+ _glfwInputWindowDamage(window);+ }+}++void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window,+ int minwidth, int minheight,+ int maxwidth, int maxheight)+{+ if (window->wl.libdecor.frame)+ {+ if (minwidth == GLFW_DONT_CARE || minheight == GLFW_DONT_CARE)+ minwidth = minheight = 0;++ if (maxwidth == GLFW_DONT_CARE || maxheight == GLFW_DONT_CARE)+ maxwidth = maxheight = 0;++ libdecor_frame_set_min_content_size(window->wl.libdecor.frame,+ minwidth, minheight);+ libdecor_frame_set_max_content_size(window->wl.libdecor.frame,+ maxwidth, maxheight);+ }+ else if (window->wl.xdg.toplevel)+ {+ if (minwidth == GLFW_DONT_CARE || minheight == GLFW_DONT_CARE)+ minwidth = minheight = 0;+ else+ {+ if (window->wl.decorations.top.surface)+ {+ minwidth += GLFW_BORDER_SIZE * 2;+ minheight += GLFW_CAPTION_HEIGHT + GLFW_BORDER_SIZE;+ }+ }++ if (maxwidth == GLFW_DONT_CARE || maxheight == GLFW_DONT_CARE)+ maxwidth = maxheight = 0;+ else+ {+ if (window->wl.decorations.top.surface)+ {+ maxwidth += GLFW_BORDER_SIZE * 2;+ maxheight += GLFW_CAPTION_HEIGHT + GLFW_BORDER_SIZE;+ }+ }++ xdg_toplevel_set_min_size(window->wl.xdg.toplevel, minwidth, minheight);+ xdg_toplevel_set_max_size(window->wl.xdg.toplevel, maxwidth, maxheight);+ wl_surface_commit(window->wl.surface);+ }+}++void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window,+ int numer, int denom)+{+ if (window->wl.maximized || window->wl.fullscreen)+ return;++ int width = window->wl.width, height = window->wl.height;++ if (numer != GLFW_DONT_CARE && denom != GLFW_DONT_CARE)+ {+ const float aspectRatio = (float) width / (float) height;+ const float targetRatio = (float) numer / (float) denom;+ if (aspectRatio < targetRatio)+ height /= targetRatio;+ else if (aspectRatio > targetRatio)+ width *= targetRatio;+ }++ if (width != window->wl.width || height != window->wl.height)+ {+ window->wl.width = width;+ window->wl.height = height;+ resizeWindow(window);++ if (window->wl.libdecor.frame)+ {+ struct libdecor_state* frameState = libdecor_state_new(width, height);+ libdecor_frame_commit(window->wl.libdecor.frame, frameState, NULL);+ libdecor_state_free(frameState);+ }++ _glfwInputWindowSize(window, width, height);++ if (window->wl.visible)+ _glfwInputWindowDamage(window);+ }+}++void _glfwPlatformGetFramebufferSize(_GLFWwindow* window,+ int* width, int* height)+{+ _glfwPlatformGetWindowSize(window, width, height);+ if (width)+ *width *= window->wl.contentScale;+ if (height)+ *height *= window->wl.contentScale;+}++void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,+ int* left, int* top,+ int* right, int* bottom)+{+ if (window->wl.decorations.top.surface)+ {+ if (top)+ *top = GLFW_CAPTION_HEIGHT;+ if (left)+ *left = GLFW_BORDER_SIZE;+ if (right)+ *right = GLFW_BORDER_SIZE;+ if (bottom)+ *bottom = GLFW_BORDER_SIZE;+ }+}++void _glfwPlatformGetWindowContentScale(_GLFWwindow* window,+ float* xscale, float* yscale)+{+ if (xscale)+ *xscale = (float) window->wl.contentScale;+ if (yscale)+ *yscale = (float) window->wl.contentScale;+}++void _glfwPlatformIconifyWindow(_GLFWwindow* window)+{+ if (window->wl.libdecor.frame)+ libdecor_frame_set_minimized(window->wl.libdecor.frame);+ else if (window->wl.xdg.toplevel)+ xdg_toplevel_set_minimized(window->wl.xdg.toplevel);+}++void _glfwPlatformRestoreWindow(_GLFWwindow* window)+{+ if (window->monitor)+ {+ // There is no way to unset minimized, or even to know if we are+ // minimized, so there is nothing to do here.+ }+ else+ {+ // We assume we are not minimized and act only on maximization++ if (window->wl.maximized)+ {+ if (window->wl.libdecor.frame)+ libdecor_frame_unset_maximized(window->wl.libdecor.frame);+ else if (window->wl.xdg.toplevel)+ xdg_toplevel_unset_maximized(window->wl.xdg.toplevel);+ else+ window->wl.maximized = GLFW_FALSE;+ }+ }+}++void _glfwPlatformMaximizeWindow(_GLFWwindow* window)+{+ if (window->wl.libdecor.frame)+ libdecor_frame_set_maximized(window->wl.libdecor.frame);+ else if (window->wl.xdg.toplevel)+ xdg_toplevel_set_maximized(window->wl.xdg.toplevel);+ else+ window->wl.maximized = GLFW_TRUE;+}++void _glfwPlatformShowWindow(_GLFWwindow* window)+{+ if (!window->wl.libdecor.frame && !window->wl.xdg.toplevel)+ {+ // NOTE: The XDG/shell surface is created here so command-line applications+ // with off-screen windows do not appear in for example the Unity dock+ createShellObjects(window);+ }+}++void _glfwPlatformHideWindow(_GLFWwindow* window)+{+ if (window->wl.visible)+ {+ window->wl.visible = GLFW_FALSE;+ destroyShellObjects(window);++ wl_surface_attach(window->wl.surface, NULL, 0, 0);+ wl_surface_commit(window->wl.surface);+ }+}++void _glfwPlatformRequestWindowAttention(_GLFWwindow* window)+{+ // TODO+ _glfwInputError(GLFW_PLATFORM_ERROR,+ "Wayland: Window attention request not implemented yet");+}++void _glfwPlatformFocusWindow(_GLFWwindow* window)+{+ _glfwInputError(GLFW_PLATFORM_ERROR,+ "Wayland: Focusing a window requires user interaction");+}++void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,+ _GLFWmonitor* monitor,+ int xpos, int ypos,+ int width, int height,+ int refreshRate)+{+ if (window->monitor == monitor)+ {+ if (!monitor)+ _glfwPlatformSetWindowSize(window, width, height);++ return;+ }++ if (window->monitor)+ releaseMonitor(window);++ _glfwInputWindowMonitor(window, monitor);++ if (window->monitor)+ acquireMonitor(window);+ else+ _glfwPlatformSetWindowSize(window, width, height);+}++int _glfwPlatformWindowFocused(_GLFWwindow* window)+{+ return _glfw.wl.keyboardFocus == window;+}++int _glfwPlatformWindowIconified(_GLFWwindow* window)+{+ // xdg-shell doesn’t give any way to request whether a surface is iconified+ return GLFW_FALSE;+}++int _glfwPlatformWindowVisible(_GLFWwindow* window)+{+ return window->wl.visible;+}++int _glfwPlatformWindowMaximized(_GLFWwindow* window)+{+ return window->wl.maximized;+}++int _glfwPlatformWindowHovered(_GLFWwindow* window)+{+ return window->wl.hovered;+}++int _glfwPlatformFramebufferTransparent(_GLFWwindow* window)+{+ return window->wl.transparent;+}++void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled)+{+ if (window->wl.libdecor.frame)+ {+ if (enabled)+ {+ libdecor_frame_set_capabilities(window->wl.libdecor.frame,+ LIBDECOR_ACTION_RESIZE);+ }+ else+ {+ libdecor_frame_unset_capabilities(window->wl.libdecor.frame,+ LIBDECOR_ACTION_RESIZE);+ }+ }+ else+ {+ // TODO+ _glfwInputError(GLFW_PLATFORM_ERROR,+ "Wayland: Window attribute setting not implemented yet");+ }+}++void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled)+{+ if (window->wl.libdecor.frame)+ {+ libdecor_frame_set_visibility(window->wl.libdecor.frame, enabled);+ }+ else if (window->wl.xdg.decoration)+ {+ uint32_t mode;++ if (enabled)+ mode = ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE;+ else+ mode = ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE;++ zxdg_toplevel_decoration_v1_set_mode(window->wl.xdg.decoration, mode);+ }+ else if (window->wl.xdg.toplevel)+ {+ if (enabled)+ createFallbackDecorations(window);+ else+ destroyFallbackDecorations(window);+ }+}++void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled)+{+ // TODO+ _glfwInputError(GLFW_PLATFORM_ERROR,+ "Wayland: Window attribute setting not implemented yet");+}++float _glfwPlatformGetWindowOpacity(_GLFWwindow* window)+{+ return 1.f;+}++void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity)+{+}++void _glfwPlatformSetRawMouseMotion(_GLFWwindow* window, GLFWbool enabled)+{+ // This is handled in relativePointerHandleRelativeMotion+}++GLFWbool _glfwPlatformRawMouseMotionSupported(void)+{+ return GLFW_TRUE;+}++void _glfwPlatformPollEvents(void)+{+ double timeout = 0.0;+ handleEvents(&timeout);+}++void _glfwPlatformWaitEvents(void)+{+ handleEvents(NULL);+}++void _glfwPlatformWaitEventsTimeout(double timeout)+{+ handleEvents(&timeout);+}++void _glfwPlatformPostEmptyEvent(void)+{+ wl_display_sync(_glfw.wl.display);+ flushDisplay();+}++void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos)+{+ if (xpos)+ *xpos = window->wl.cursorPosX;+ if (ypos)+ *ypos = window->wl.cursorPosY;+}++void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y)+{+}++void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode)+{+ _glfwPlatformSetCursor(window, window->wl.currentCursor);+}++const char* _glfwPlatformGetScancodeName(int scancode)+{+ if (scancode < 0 || scancode > 255 ||+ _glfw.wl.keycodes[scancode] == GLFW_KEY_UNKNOWN)+ {+ _glfwInputError(GLFW_INVALID_VALUE,+ "Wayland: Invalid scancode %i",+ scancode);+ return NULL;+ }++ const int key = _glfw.wl.keycodes[scancode];+ const xkb_keycode_t keycode = scancode + 8;+ const xkb_layout_index_t layout =+ xkb_state_key_get_layout(_glfw.wl.xkb.state, keycode);+ if (layout == XKB_LAYOUT_INVALID)+ {+ _glfwInputError(GLFW_PLATFORM_ERROR,+ "Wayland: Failed to retrieve layout for key name");+ return NULL;+ }++ const xkb_keysym_t* keysyms = NULL;+ xkb_keymap_key_get_syms_by_level(_glfw.wl.xkb.keymap,+ keycode,+ layout,+ 0,+ &keysyms);+ if (keysyms == NULL)+ {+ _glfwInputError(GLFW_PLATFORM_ERROR,+ "Wayland: Failed to retrieve keysym for key name");+ return NULL;+ }++ const uint32_t codepoint = _glfwKeySym2Unicode(keysyms[0]);+ if (codepoint == GLFW_INVALID_CODEPOINT)+ {+ _glfwInputError(GLFW_PLATFORM_ERROR,+ "Wayland: Failed to retrieve codepoint for key name");+ return NULL;+ }++ const size_t count = _glfwEncodeUTF8(_glfw.wl.keynames[key], codepoint);+ if (count == 0)+ {+ _glfwInputError(GLFW_PLATFORM_ERROR,+ "Wayland: Failed to encode codepoint for key name");+ return NULL;+ }++ _glfw.wl.keynames[key][count] = '\0';+ return _glfw.wl.keynames[key];+}++int _glfwPlatformGetKeyScancode(int key)+{+ return _glfw.wl.scancodes[key];+}++int _glfwPlatformCreateCursor(_GLFWcursor* cursor,+ const GLFWimage* image,+ int xhot, int yhot)+{+ cursor->wl.buffer = createShmBuffer(image);+ if (!cursor->wl.buffer)+ return GLFW_FALSE;++ cursor->wl.width = image->width;+ cursor->wl.height = image->height;+ cursor->wl.xhot = xhot;+ cursor->wl.yhot = yhot;+ return GLFW_TRUE;+}++int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape)+{+ struct wl_cursor* standardCursor;++ standardCursor = wl_cursor_theme_get_cursor(_glfw.wl.cursorTheme,+ translateCursorShape(shape));+ if (!standardCursor)+ {+ _glfwInputError(GLFW_PLATFORM_ERROR,+ "Wayland: Standard cursor \"%s\" not found",+ translateCursorShape(shape));+ return GLFW_FALSE;+ }++ cursor->wl.cursor = standardCursor;+ cursor->wl.currentImage = 0;++ if (_glfw.wl.cursorThemeHiDPI)+ {+ standardCursor = wl_cursor_theme_get_cursor(_glfw.wl.cursorThemeHiDPI,+ translateCursorShape(shape));+ cursor->wl.cursorHiDPI = standardCursor;+ }++ return GLFW_TRUE;+}++void _glfwPlatformDestroyCursor(_GLFWcursor* cursor)+{+ // If it's a standard cursor we don't need to do anything here+ if (cursor->wl.cursor)+ return;++ if (cursor->wl.buffer)+ wl_buffer_destroy(cursor->wl.buffer);+}++static void relativePointerHandleRelativeMotion(void* userData,+ struct zwp_relative_pointer_v1* pointer,+ uint32_t timeHi,+ uint32_t timeLo,+ wl_fixed_t dx,+ wl_fixed_t dy,+ wl_fixed_t dxUnaccel,+ wl_fixed_t dyUnaccel)+{+ _GLFWwindow* window = userData;+ double xpos = window->virtualCursorPosX;+ double ypos = window->virtualCursorPosY;++ if (window->cursorMode != GLFW_CURSOR_DISABLED)+ return;++ if (window->rawMouseMotion)+ {+ xpos += wl_fixed_to_double(dxUnaccel);+ ypos += wl_fixed_to_double(dyUnaccel);+ }+ else+ {+ xpos += wl_fixed_to_double(dx);+ ypos += wl_fixed_to_double(dy);+ }++ _glfwInputCursorPos(window, xpos, ypos);+}++static const struct zwp_relative_pointer_v1_listener relativePointerListener =+{+ relativePointerHandleRelativeMotion+};++static void lockedPointerHandleLocked(void* userData,+ struct zwp_locked_pointer_v1* lockedPointer)+{+}++static void lockedPointerHandleUnlocked(void* userData,+ struct zwp_locked_pointer_v1* lockedPointer)+{+}++static const struct zwp_locked_pointer_v1_listener lockedPointerListener =+{+ lockedPointerHandleLocked,+ lockedPointerHandleUnlocked+};++static void lockPointer(_GLFWwindow* window)+{+ if (!_glfw.wl.relativePointerManager)+ {+ _glfwInputError(GLFW_PLATFORM_ERROR,+ "Wayland: no relative pointer manager");+ return;+ }++ window->wl.relativePointer =+ zwp_relative_pointer_manager_v1_get_relative_pointer(+ _glfw.wl.relativePointerManager,+ _glfw.wl.pointer);+ zwp_relative_pointer_v1_add_listener(window->wl.relativePointer,+ &relativePointerListener,+ window);++ window->wl.lockedPointer =+ zwp_pointer_constraints_v1_lock_pointer(+ _glfw.wl.pointerConstraints,+ window->wl.surface,+ _glfw.wl.pointer,+ NULL,+ ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);+ zwp_locked_pointer_v1_add_listener(window->wl.lockedPointer,+ &lockedPointerListener,+ window);+}++static void unlockPointer(_GLFWwindow* window)+{+ zwp_relative_pointer_v1_destroy(window->wl.relativePointer);+ window->wl.relativePointer = NULL;++ zwp_locked_pointer_v1_destroy(window->wl.lockedPointer);+ window->wl.lockedPointer = NULL;+}++void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)+{+ if (!_glfw.wl.pointer)+ return;++ window->wl.currentCursor = cursor;++ // If we're not in the correct window just save the cursor+ // the next time the pointer enters the window the cursor will change+ if (window != _glfw.wl.pointerFocus ||+ window->wl.decorations.focus != GLFW_MAIN_WINDOW)+ {+ return;+ }++ // Update pointer lock to match cursor mode+ if (window->cursorMode == GLFW_CURSOR_DISABLED)+ {+ if (!window->wl.lockedPointer)+ lockPointer(window);+ }+ else if (window->cursorMode == GLFW_CURSOR_NORMAL ||+ window->cursorMode == GLFW_CURSOR_HIDDEN)+ {+ if (window->wl.lockedPointer)+ unlockPointer(window);+ }++ if (window->cursorMode == GLFW_CURSOR_NORMAL)+ {+ if (cursor)+ setCursorImage(window, &cursor->wl);+ else+ {+ struct wl_cursor* defaultCursor =+ wl_cursor_theme_get_cursor(_glfw.wl.cursorTheme, "left_ptr");+ if (!defaultCursor)+ {+ _glfwInputError(GLFW_PLATFORM_ERROR,+ "Wayland: Standard cursor not found");+ return;+ }++ struct wl_cursor* defaultCursorHiDPI = NULL;+ if (_glfw.wl.cursorThemeHiDPI)+ {+ defaultCursorHiDPI =+ wl_cursor_theme_get_cursor(_glfw.wl.cursorThemeHiDPI, "left_ptr");+ }++ _GLFWcursorWayland cursorWayland =+ {+ defaultCursor,+ defaultCursorHiDPI,+ NULL,+ 0, 0,+ 0, 0,+ 0+ };++ setCursorImage(window, &cursorWayland);+ }+ }+ else if (window->cursorMode == GLFW_CURSOR_HIDDEN ||+ window->cursorMode == GLFW_CURSOR_DISABLED)+ {+ wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerEnterSerial, NULL, 0, 0);+ }+}++static void dataSourceHandleTarget(void* userData,+ struct wl_data_source* source,+ const char* mimeType)+{+ if (_glfw.wl.selectionSource != source)+ {+ _glfwInputError(GLFW_PLATFORM_ERROR,+ "Wayland: Unknown clipboard data source");+ return;+ }+}++static void dataSourceHandleSend(void* userData,+ struct wl_data_source* source,+ const char* mimeType,+ int fd)+{+ // Ignore it if this is an outdated or invalid request+ if (_glfw.wl.selectionSource != source ||+ strcmp(mimeType, "text/plain;charset=utf-8") != 0)+ {+ close(fd);+ return;+ }++ char* string = _glfw.wl.clipboardString;+ size_t length = strlen(string);++ while (length > 0)+ {+ const ssize_t result = write(fd, string, length);+ if (result == -1)+ {+ if (errno == EINTR)+ continue;++ _glfwInputError(GLFW_PLATFORM_ERROR,+ "Wayland: Error while writing the clipboard: %s",+ strerror(errno));+ break;+ }++ length -= result;+ string += result;+ }++ close(fd);+}++static void dataSourceHandleCancelled(void* userData,+ struct wl_data_source* source)+{+ wl_data_source_destroy(source);++ if (_glfw.wl.selectionSource != source)+ return;++ _glfw.wl.selectionSource = NULL;+}++static const struct wl_data_source_listener dataSourceListener =+{+ dataSourceHandleTarget,+ dataSourceHandleSend,+ dataSourceHandleCancelled,+};++void _glfwPlatformSetClipboardString(const char* string)+{+ if (_glfw.wl.selectionSource)+ {+ wl_data_source_destroy(_glfw.wl.selectionSource);+ _glfw.wl.selectionSource = NULL;+ }++ char* copy = _glfw_strdup(string);+ if (!copy)+ {+ _glfwInputError(GLFW_OUT_OF_MEMORY, NULL);+ return;+ }++ free(_glfw.wl.clipboardString);+ _glfw.wl.clipboardString = copy;++ _glfw.wl.selectionSource =+ wl_data_device_manager_create_data_source(_glfw.wl.dataDeviceManager);+ if (!_glfw.wl.selectionSource)+ {+ _glfwInputError(GLFW_PLATFORM_ERROR,+ "Wayland: Failed to create clipboard data source");+ return;+ }+ wl_data_source_add_listener(_glfw.wl.selectionSource,+ &dataSourceListener,+ NULL);+ wl_data_source_offer(_glfw.wl.selectionSource, "text/plain;charset=utf-8");+ wl_data_device_set_selection(_glfw.wl.dataDevice,+ _glfw.wl.selectionSource,+ _glfw.wl.serial);+}++const char* _glfwPlatformGetClipboardString(void)+{+ if (!_glfw.wl.selectionOffer)+ {+ _glfwInputError(GLFW_FORMAT_UNAVAILABLE,+ "Wayland: No clipboard data available");+ return NULL;+ }++ if (_glfw.wl.selectionSource)+ return _glfw.wl.clipboardString;++ free(_glfw.wl.clipboardString);+ _glfw.wl.clipboardString =+ readDataOfferAsString(_glfw.wl.selectionOffer, "text/plain;charset=utf-8"); return _glfw.wl.clipboardString; }
glfw/src/x11_init.c view
@@ -36,26 +36,21 @@ #include <limits.h> #include <stdio.h> #include <locale.h>+#include <unistd.h>+#include <fcntl.h>+#include <errno.h>+#include <assert.h> -// Translate an X11 key code to a GLFW key code.+// Translate the X11 KeySyms for a key to a GLFW key code+// NOTE: This is only used as a fallback, in case the XKB method fails+// It is layout-dependent and will fail partially on most non-US layouts //-static int translateKeyCode(int scancode)+static int translateKeySyms(const KeySym* keysyms, int width) {- int keySym;-- // Valid key code range is [8,255], according to the Xlib manual- if (scancode < 8 || scancode > 255)- return GLFW_KEY_UNKNOWN;-- if (_glfw.x11.xkb.available)+ if (width > 1) {- // Try secondary keysym, for numeric keypad keys- // Note: This way we always force "NumLock = ON", which is intentional- // since the returned key code should correspond to a physical- // location.- keySym = XkbKeycodeToKeysym(_glfw.x11.display, scancode, _glfw.x11.xkb.group, 1);- switch (keySym)+ switch (keysyms[1]) { case XK_KP_0: return GLFW_KEY_KP_0; case XK_KP_1: return GLFW_KEY_KP_1;@@ -73,22 +68,9 @@ case XK_KP_Enter: return GLFW_KEY_KP_ENTER; default: break; }-- // Now try primary keysym for function keys (non-printable keys)- // These should not depend on the current keyboard layout- keySym = XkbKeycodeToKeysym(_glfw.x11.display, scancode, _glfw.x11.xkb.group, 0); }- else- {- int dummy;- KeySym* keySyms; - keySyms = XGetKeyboardMapping(_glfw.x11.display, scancode, 1, &dummy);- keySym = keySyms[0];- XFree(keySyms);- }-- switch (keySym)+ switch (keysyms[0]) { case XK_Escape: return GLFW_KEY_ESCAPE; case XK_Tab: return GLFW_KEY_TAB;@@ -232,7 +214,7 @@ // static void createKeyTables(void) {- int scancode, key;+ int scancode, scancodeMin, scancodeMax; memset(_glfw.x11.keycodes, -1, sizeof(_glfw.x11.keycodes)); memset(_glfw.x11.scancodes, -1, sizeof(_glfw.x11.scancodes));@@ -242,89 +224,217 @@ // Use XKB to determine physical key locations independently of the // current keyboard layout - char name[XkbKeyNameLength + 1]; XkbDescPtr desc = XkbGetMap(_glfw.x11.display, 0, XkbUseCoreKbd);- XkbGetNames(_glfw.x11.display, XkbKeyNamesMask, desc);+ XkbGetNames(_glfw.x11.display, XkbKeyNamesMask | XkbKeyAliasesMask, desc); + scancodeMin = desc->min_key_code;+ scancodeMax = desc->max_key_code;++ const struct+ {+ int key;+ char* name;+ } keymap[] =+ {+ { GLFW_KEY_GRAVE_ACCENT, "TLDE" },+ { GLFW_KEY_1, "AE01" },+ { GLFW_KEY_2, "AE02" },+ { GLFW_KEY_3, "AE03" },+ { GLFW_KEY_4, "AE04" },+ { GLFW_KEY_5, "AE05" },+ { GLFW_KEY_6, "AE06" },+ { GLFW_KEY_7, "AE07" },+ { GLFW_KEY_8, "AE08" },+ { GLFW_KEY_9, "AE09" },+ { GLFW_KEY_0, "AE10" },+ { GLFW_KEY_MINUS, "AE11" },+ { GLFW_KEY_EQUAL, "AE12" },+ { GLFW_KEY_Q, "AD01" },+ { GLFW_KEY_W, "AD02" },+ { GLFW_KEY_E, "AD03" },+ { GLFW_KEY_R, "AD04" },+ { GLFW_KEY_T, "AD05" },+ { GLFW_KEY_Y, "AD06" },+ { GLFW_KEY_U, "AD07" },+ { GLFW_KEY_I, "AD08" },+ { GLFW_KEY_O, "AD09" },+ { GLFW_KEY_P, "AD10" },+ { GLFW_KEY_LEFT_BRACKET, "AD11" },+ { GLFW_KEY_RIGHT_BRACKET, "AD12" },+ { GLFW_KEY_A, "AC01" },+ { GLFW_KEY_S, "AC02" },+ { GLFW_KEY_D, "AC03" },+ { GLFW_KEY_F, "AC04" },+ { GLFW_KEY_G, "AC05" },+ { GLFW_KEY_H, "AC06" },+ { GLFW_KEY_J, "AC07" },+ { GLFW_KEY_K, "AC08" },+ { GLFW_KEY_L, "AC09" },+ { GLFW_KEY_SEMICOLON, "AC10" },+ { GLFW_KEY_APOSTROPHE, "AC11" },+ { GLFW_KEY_Z, "AB01" },+ { GLFW_KEY_X, "AB02" },+ { GLFW_KEY_C, "AB03" },+ { GLFW_KEY_V, "AB04" },+ { GLFW_KEY_B, "AB05" },+ { GLFW_KEY_N, "AB06" },+ { GLFW_KEY_M, "AB07" },+ { GLFW_KEY_COMMA, "AB08" },+ { GLFW_KEY_PERIOD, "AB09" },+ { GLFW_KEY_SLASH, "AB10" },+ { GLFW_KEY_BACKSLASH, "BKSL" },+ { GLFW_KEY_WORLD_1, "LSGT" },+ { GLFW_KEY_SPACE, "SPCE" },+ { GLFW_KEY_ESCAPE, "ESC" },+ { GLFW_KEY_ENTER, "RTRN" },+ { GLFW_KEY_TAB, "TAB" },+ { GLFW_KEY_BACKSPACE, "BKSP" },+ { GLFW_KEY_INSERT, "INS" },+ { GLFW_KEY_DELETE, "DELE" },+ { GLFW_KEY_RIGHT, "RGHT" },+ { GLFW_KEY_LEFT, "LEFT" },+ { GLFW_KEY_DOWN, "DOWN" },+ { GLFW_KEY_UP, "UP" },+ { GLFW_KEY_PAGE_UP, "PGUP" },+ { GLFW_KEY_PAGE_DOWN, "PGDN" },+ { GLFW_KEY_HOME, "HOME" },+ { GLFW_KEY_END, "END" },+ { GLFW_KEY_CAPS_LOCK, "CAPS" },+ { GLFW_KEY_SCROLL_LOCK, "SCLK" },+ { GLFW_KEY_NUM_LOCK, "NMLK" },+ { GLFW_KEY_PRINT_SCREEN, "PRSC" },+ { GLFW_KEY_PAUSE, "PAUS" },+ { GLFW_KEY_F1, "FK01" },+ { GLFW_KEY_F2, "FK02" },+ { GLFW_KEY_F3, "FK03" },+ { GLFW_KEY_F4, "FK04" },+ { GLFW_KEY_F5, "FK05" },+ { GLFW_KEY_F6, "FK06" },+ { GLFW_KEY_F7, "FK07" },+ { GLFW_KEY_F8, "FK08" },+ { GLFW_KEY_F9, "FK09" },+ { GLFW_KEY_F10, "FK10" },+ { GLFW_KEY_F11, "FK11" },+ { GLFW_KEY_F12, "FK12" },+ { GLFW_KEY_F13, "FK13" },+ { GLFW_KEY_F14, "FK14" },+ { GLFW_KEY_F15, "FK15" },+ { GLFW_KEY_F16, "FK16" },+ { GLFW_KEY_F17, "FK17" },+ { GLFW_KEY_F18, "FK18" },+ { GLFW_KEY_F19, "FK19" },+ { GLFW_KEY_F20, "FK20" },+ { GLFW_KEY_F21, "FK21" },+ { GLFW_KEY_F22, "FK22" },+ { GLFW_KEY_F23, "FK23" },+ { GLFW_KEY_F24, "FK24" },+ { GLFW_KEY_F25, "FK25" },+ { GLFW_KEY_KP_0, "KP0" },+ { GLFW_KEY_KP_1, "KP1" },+ { GLFW_KEY_KP_2, "KP2" },+ { GLFW_KEY_KP_3, "KP3" },+ { GLFW_KEY_KP_4, "KP4" },+ { GLFW_KEY_KP_5, "KP5" },+ { GLFW_KEY_KP_6, "KP6" },+ { GLFW_KEY_KP_7, "KP7" },+ { GLFW_KEY_KP_8, "KP8" },+ { GLFW_KEY_KP_9, "KP9" },+ { GLFW_KEY_KP_DECIMAL, "KPDL" },+ { GLFW_KEY_KP_DIVIDE, "KPDV" },+ { GLFW_KEY_KP_MULTIPLY, "KPMU" },+ { GLFW_KEY_KP_SUBTRACT, "KPSU" },+ { GLFW_KEY_KP_ADD, "KPAD" },+ { GLFW_KEY_KP_ENTER, "KPEN" },+ { GLFW_KEY_KP_EQUAL, "KPEQ" },+ { GLFW_KEY_LEFT_SHIFT, "LFSH" },+ { GLFW_KEY_LEFT_CONTROL, "LCTL" },+ { GLFW_KEY_LEFT_ALT, "LALT" },+ { GLFW_KEY_LEFT_SUPER, "LWIN" },+ { GLFW_KEY_RIGHT_SHIFT, "RTSH" },+ { GLFW_KEY_RIGHT_CONTROL, "RCTL" },+ { GLFW_KEY_RIGHT_ALT, "RALT" },+ { GLFW_KEY_RIGHT_ALT, "LVL3" },+ { GLFW_KEY_RIGHT_ALT, "MDSW" },+ { GLFW_KEY_RIGHT_SUPER, "RWIN" },+ { GLFW_KEY_MENU, "MENU" }+ };+ // Find the X11 key code -> GLFW key code mapping- for (scancode = desc->min_key_code; scancode <= desc->max_key_code; scancode++)+ for (scancode = scancodeMin; scancode <= scancodeMax; scancode++) {- memcpy(name, desc->names->keys[scancode].name, XkbKeyNameLength);- name[XkbKeyNameLength] = '\0';+ int key = GLFW_KEY_UNKNOWN; - // Map the key name to a GLFW key code. Note: We only map printable- // keys here, and we use the US keyboard layout. The rest of the- // keys (function keys) are mapped using traditional KeySym- // translations.- if (strcmp(name, "TLDE") == 0) key = GLFW_KEY_GRAVE_ACCENT;- else if (strcmp(name, "AE01") == 0) key = GLFW_KEY_1;- else if (strcmp(name, "AE02") == 0) key = GLFW_KEY_2;- else if (strcmp(name, "AE03") == 0) key = GLFW_KEY_3;- else if (strcmp(name, "AE04") == 0) key = GLFW_KEY_4;- else if (strcmp(name, "AE05") == 0) key = GLFW_KEY_5;- else if (strcmp(name, "AE06") == 0) key = GLFW_KEY_6;- else if (strcmp(name, "AE07") == 0) key = GLFW_KEY_7;- else if (strcmp(name, "AE08") == 0) key = GLFW_KEY_8;- else if (strcmp(name, "AE09") == 0) key = GLFW_KEY_9;- else if (strcmp(name, "AE10") == 0) key = GLFW_KEY_0;- else if (strcmp(name, "AE11") == 0) key = GLFW_KEY_MINUS;- else if (strcmp(name, "AE12") == 0) key = GLFW_KEY_EQUAL;- else if (strcmp(name, "AD01") == 0) key = GLFW_KEY_Q;- else if (strcmp(name, "AD02") == 0) key = GLFW_KEY_W;- else if (strcmp(name, "AD03") == 0) key = GLFW_KEY_E;- else if (strcmp(name, "AD04") == 0) key = GLFW_KEY_R;- else if (strcmp(name, "AD05") == 0) key = GLFW_KEY_T;- else if (strcmp(name, "AD06") == 0) key = GLFW_KEY_Y;- else if (strcmp(name, "AD07") == 0) key = GLFW_KEY_U;- else if (strcmp(name, "AD08") == 0) key = GLFW_KEY_I;- else if (strcmp(name, "AD09") == 0) key = GLFW_KEY_O;- else if (strcmp(name, "AD10") == 0) key = GLFW_KEY_P;- else if (strcmp(name, "AD11") == 0) key = GLFW_KEY_LEFT_BRACKET;- else if (strcmp(name, "AD12") == 0) key = GLFW_KEY_RIGHT_BRACKET;- else if (strcmp(name, "AC01") == 0) key = GLFW_KEY_A;- else if (strcmp(name, "AC02") == 0) key = GLFW_KEY_S;- else if (strcmp(name, "AC03") == 0) key = GLFW_KEY_D;- else if (strcmp(name, "AC04") == 0) key = GLFW_KEY_F;- else if (strcmp(name, "AC05") == 0) key = GLFW_KEY_G;- else if (strcmp(name, "AC06") == 0) key = GLFW_KEY_H;- else if (strcmp(name, "AC07") == 0) key = GLFW_KEY_J;- else if (strcmp(name, "AC08") == 0) key = GLFW_KEY_K;- else if (strcmp(name, "AC09") == 0) key = GLFW_KEY_L;- else if (strcmp(name, "AC10") == 0) key = GLFW_KEY_SEMICOLON;- else if (strcmp(name, "AC11") == 0) key = GLFW_KEY_APOSTROPHE;- else if (strcmp(name, "AB01") == 0) key = GLFW_KEY_Z;- else if (strcmp(name, "AB02") == 0) key = GLFW_KEY_X;- else if (strcmp(name, "AB03") == 0) key = GLFW_KEY_C;- else if (strcmp(name, "AB04") == 0) key = GLFW_KEY_V;- else if (strcmp(name, "AB05") == 0) key = GLFW_KEY_B;- else if (strcmp(name, "AB06") == 0) key = GLFW_KEY_N;- else if (strcmp(name, "AB07") == 0) key = GLFW_KEY_M;- else if (strcmp(name, "AB08") == 0) key = GLFW_KEY_COMMA;- else if (strcmp(name, "AB09") == 0) key = GLFW_KEY_PERIOD;- else if (strcmp(name, "AB10") == 0) key = GLFW_KEY_SLASH;- else if (strcmp(name, "BKSL") == 0) key = GLFW_KEY_BACKSLASH;- else if (strcmp(name, "LSGT") == 0) key = GLFW_KEY_WORLD_1;- else key = GLFW_KEY_UNKNOWN;+ // Map the key name to a GLFW key code. Note: We use the US+ // keyboard layout. Because function keys aren't mapped correctly+ // when using traditional KeySym translations, they are mapped+ // here instead.+ for (int i = 0; i < sizeof(keymap) / sizeof(keymap[0]); i++)+ {+ if (strncmp(desc->names->keys[scancode].name,+ keymap[i].name,+ XkbKeyNameLength) == 0)+ {+ key = keymap[i].key;+ break;+ }+ } - if ((scancode >= 0) && (scancode < 256))- _glfw.x11.keycodes[scancode] = key;+ // Fall back to key aliases in case the key name did not match+ for (int i = 0; i < desc->names->num_key_aliases; i++)+ {+ if (key != GLFW_KEY_UNKNOWN)+ break;++ if (strncmp(desc->names->key_aliases[i].real,+ desc->names->keys[scancode].name,+ XkbKeyNameLength) != 0)+ {+ continue;+ }++ for (int j = 0; j < sizeof(keymap) / sizeof(keymap[0]); j++)+ {+ if (strncmp(desc->names->key_aliases[i].alias,+ keymap[j].name,+ XkbKeyNameLength) == 0)+ {+ key = keymap[j].key;+ break;+ }+ }+ }++ _glfw.x11.keycodes[scancode] = key; } XkbFreeNames(desc, XkbKeyNamesMask, True); XkbFreeKeyboard(desc, 0, True); }+ else+ XDisplayKeycodes(_glfw.x11.display, &scancodeMin, &scancodeMax); - for (scancode = 0; scancode < 256; scancode++)+ int width;+ KeySym* keysyms = XGetKeyboardMapping(_glfw.x11.display,+ scancodeMin,+ scancodeMax - scancodeMin + 1,+ &width);++ for (scancode = scancodeMin; scancode <= scancodeMax; scancode++) { // Translate the un-translated key codes using traditional X11 KeySym // lookups if (_glfw.x11.keycodes[scancode] < 0)- _glfw.x11.keycodes[scancode] = translateKeyCode(scancode);+ {+ const size_t base = (scancode - scancodeMin) * width;+ _glfw.x11.keycodes[scancode] = translateKeySyms(&keysyms[base], width);+ } // Store the reverse translation for faster key name lookup if (_glfw.x11.keycodes[scancode] > 0) _glfw.x11.scancodes[_glfw.x11.keycodes[scancode]] = scancode; }++ XFree(keysyms); } // Check whether the IM has a usable style@@ -352,13 +462,13 @@ // Check whether the specified atom is supported //-static Atom getSupportedAtom(Atom* supportedAtoms,- unsigned long atomCount,- const char* atomName)+static Atom getAtomIfSupported(Atom* supportedAtoms,+ unsigned long atomCount,+ const char* atomName) { const Atom atom = XInternAtom(_glfw.x11.display, atomName, False); - for (unsigned int i = 0; i < atomCount; i++)+ for (unsigned long i = 0; i < atomCount; i++) { if (supportedAtoms[i] == atom) return atom;@@ -426,33 +536,33 @@ // See which of the atoms we support that are supported by the WM _glfw.x11.NET_WM_STATE =- getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE");+ getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_STATE"); _glfw.x11.NET_WM_STATE_ABOVE =- getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_ABOVE");+ getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_STATE_ABOVE"); _glfw.x11.NET_WM_STATE_FULLSCREEN =- getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_FULLSCREEN");+ getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_STATE_FULLSCREEN"); _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT =- getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_MAXIMIZED_VERT");+ getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_STATE_MAXIMIZED_VERT"); _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ =- getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_MAXIMIZED_HORZ");+ getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_STATE_MAXIMIZED_HORZ"); _glfw.x11.NET_WM_STATE_DEMANDS_ATTENTION =- getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_DEMANDS_ATTENTION");+ getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_STATE_DEMANDS_ATTENTION"); _glfw.x11.NET_WM_FULLSCREEN_MONITORS =- getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_FULLSCREEN_MONITORS");+ getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_FULLSCREEN_MONITORS"); _glfw.x11.NET_WM_WINDOW_TYPE =- getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_WINDOW_TYPE");+ getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_WINDOW_TYPE"); _glfw.x11.NET_WM_WINDOW_TYPE_NORMAL =- getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_WINDOW_TYPE_NORMAL");+ getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_WINDOW_TYPE_NORMAL"); _glfw.x11.NET_WORKAREA =- getSupportedAtom(supportedAtoms, atomCount, "_NET_WORKAREA");+ getAtomIfSupported(supportedAtoms, atomCount, "_NET_WORKAREA"); _glfw.x11.NET_CURRENT_DESKTOP =- getSupportedAtom(supportedAtoms, atomCount, "_NET_CURRENT_DESKTOP");+ getAtomIfSupported(supportedAtoms, atomCount, "_NET_CURRENT_DESKTOP"); _glfw.x11.NET_ACTIVE_WINDOW =- getSupportedAtom(supportedAtoms, atomCount, "_NET_ACTIVE_WINDOW");+ getAtomIfSupported(supportedAtoms, atomCount, "_NET_ACTIVE_WINDOW"); _glfw.x11.NET_FRAME_EXTENTS =- getSupportedAtom(supportedAtoms, atomCount, "_NET_FRAME_EXTENTS");+ getAtomIfSupported(supportedAtoms, atomCount, "_NET_FRAME_EXTENTS"); _glfw.x11.NET_REQUEST_FRAME_EXTENTS =- getSupportedAtom(supportedAtoms, atomCount, "_NET_REQUEST_FRAME_EXTENTS");+ getAtomIfSupported(supportedAtoms, atomCount, "_NET_REQUEST_FRAME_EXTENTS"); if (supportedAtoms) XFree(supportedAtoms);@@ -462,7 +572,11 @@ // static GLFWbool initExtensions(void) {+#if defined(__OpenBSD__) || defined(__NetBSD__)+ _glfw.x11.vidmode.handle = _glfw_dlopen("libXxf86vm.so");+#else _glfw.x11.vidmode.handle = _glfw_dlopen("libXxf86vm.so.1");+#endif if (_glfw.x11.vidmode.handle) { _glfw.x11.vidmode.QueryExtension = (PFN_XF86VidModeQueryExtension)@@ -482,6 +596,8 @@ #if defined(__CYGWIN__) _glfw.x11.xi.handle = _glfw_dlopen("libXi-6.so");+#elif defined(__OpenBSD__) || defined(__NetBSD__)+ _glfw.x11.xi.handle = _glfw_dlopen("libXi.so"); #else _glfw.x11.xi.handle = _glfw_dlopen("libXi.so.6"); #endif@@ -512,6 +628,8 @@ #if defined(__CYGWIN__) _glfw.x11.randr.handle = _glfw_dlopen("libXrandr-2.so");+#elif defined(__OpenBSD__) || defined(__NetBSD__)+ _glfw.x11.randr.handle = _glfw_dlopen("libXrandr.so"); #else _glfw.x11.randr.handle = _glfw_dlopen("libXrandr.so.2"); #endif@@ -604,6 +722,8 @@ #if defined(__CYGWIN__) _glfw.x11.xcursor.handle = _glfw_dlopen("libXcursor-1.so");+#elif defined(__OpenBSD__) || defined(__NetBSD__)+ _glfw.x11.xcursor.handle = _glfw_dlopen("libXcursor.so"); #else _glfw.x11.xcursor.handle = _glfw_dlopen("libXcursor.so.1"); #endif@@ -619,6 +739,8 @@ #if defined(__CYGWIN__) _glfw.x11.xinerama.handle = _glfw_dlopen("libXinerama-1.so");+#elif defined(__OpenBSD__) || defined(__NetBSD__)+ _glfw.x11.xinerama.handle = _glfw_dlopen("libXinerama.so"); #else _glfw.x11.xinerama.handle = _glfw_dlopen("libXinerama.so.1"); #endif@@ -660,17 +782,18 @@ _glfw.x11.xkb.detectable = GLFW_TRUE; } - _glfw.x11.xkb.group = 0; XkbStateRec state; if (XkbGetState(_glfw.x11.display, XkbUseCoreKbd, &state) == Success)- {- XkbSelectEventDetails(_glfw.x11.display, XkbUseCoreKbd, XkbStateNotify, XkbAllStateComponentsMask, XkbGroupStateMask); _glfw.x11.xkb.group = (unsigned int)state.group;- }++ XkbSelectEventDetails(_glfw.x11.display, XkbUseCoreKbd, XkbStateNotify,+ XkbGroupStateMask, XkbGroupStateMask); } #if defined(__CYGWIN__) _glfw.x11.x11xcb.handle = _glfw_dlopen("libX11-xcb-1.so");+#elif defined(__OpenBSD__) || defined(__NetBSD__)+ _glfw.x11.x11xcb.handle = _glfw_dlopen("libX11-xcb.so"); #else _glfw.x11.x11xcb.handle = _glfw_dlopen("libX11-xcb.so.1"); #endif@@ -682,6 +805,8 @@ #if defined(__CYGWIN__) _glfw.x11.xrender.handle = _glfw_dlopen("libXrender-1.so");+#elif defined(__OpenBSD__) || defined(__NetBSD__)+ _glfw.x11.xrender.handle = _glfw_dlopen("libXrender.so"); #else _glfw.x11.xrender.handle = _glfw_dlopen("libXrender.so.1"); #endif@@ -847,10 +972,44 @@ CWEventMask, &wa); } +// Create the pipe for empty events without assumuing the OS has pipe2(2)+//+static GLFWbool createEmptyEventPipe(void)+{+ if (pipe(_glfw.x11.emptyEventPipe) != 0)+ {+ _glfwInputError(GLFW_PLATFORM_ERROR,+ "X11: Failed to create empty event pipe: %s",+ strerror(errno));+ return GLFW_FALSE;+ }++ for (int i = 0; i < 2; i++)+ {+ const int sf = fcntl(_glfw.x11.emptyEventPipe[i], F_GETFL, 0);+ const int df = fcntl(_glfw.x11.emptyEventPipe[i], F_GETFD, 0);++ if (sf == -1 || df == -1 ||+ fcntl(_glfw.x11.emptyEventPipe[i], F_SETFL, sf | O_NONBLOCK) == -1 ||+ fcntl(_glfw.x11.emptyEventPipe[i], F_SETFD, df | FD_CLOEXEC) == -1)+ {+ _glfwInputError(GLFW_PLATFORM_ERROR,+ "X11: Failed to set flags for empty event pipe: %s",+ strerror(errno));+ return GLFW_FALSE;+ }+ }++ return GLFW_TRUE;+}+ // X error handler // static int errorHandler(Display *display, XErrorEvent* event) {+ if (_glfw.x11.display != display)+ return 0;+ _glfw.x11.errorCode = event->error_code; return 0; }@@ -864,8 +1023,9 @@ // void _glfwGrabErrorHandlerX11(void) {+ assert(_glfw.x11.errorHandler == NULL); _glfw.x11.errorCode = Success;- XSetErrorHandler(errorHandler);+ _glfw.x11.errorHandler = XSetErrorHandler(errorHandler); } // Clears the X error handler callback@@ -874,7 +1034,8 @@ { // Synchronize to make sure all commands are processed XSync(_glfw.x11.display, False);- XSetErrorHandler(NULL);+ XSetErrorHandler(_glfw.x11.errorHandler);+ _glfw.x11.errorHandler = NULL; } // Reports the specified error, appending information about the last X error@@ -931,15 +1092,12 @@ int _glfwPlatformInit(void) {-#if !defined(X_HAVE_UTF8_STRING)- // HACK: If the current locale is "C" and the Xlib UTF-8 functions are- // unavailable, apply the environment's locale in the hope that it's- // both available and not "C"- // This is done because the "C" locale breaks wide character input,- // which is what we fall back on when UTF-8 support is missing+ // HACK: If the application has left the locale as "C" then both wide+ // character text input and explicit UTF-8 input via XIM will break+ // This sets the CTYPE part of the current locale from the environment+ // in the hope that it is set to something more sane than "C" if (strcmp(setlocale(LC_CTYPE, NULL), "C") == 0) setlocale(LC_CTYPE, "");-#endif XInitThreads(); XrmInitialize();@@ -968,6 +1126,9 @@ getSystemContentScale(&_glfw.x11.contentScaleX, &_glfw.x11.contentScaleY); + if (!createEmptyEventPipe())+ return GLFW_FALSE;+ if (!initExtensions()) return GLFW_FALSE; @@ -1077,6 +1238,7 @@ _glfw.x11.xi.handle = NULL; } + _glfwTerminateOSMesa(); // NOTE: These need to be unloaded after XCloseDisplay, as they register // cleanup callbacks that get called by that function _glfwTerminateEGL();@@ -1085,6 +1247,12 @@ #if defined(__linux__) _glfwTerminateJoysticksLinux(); #endif++ if (_glfw.x11.emptyEventPipe[0] || _glfw.x11.emptyEventPipe[1])+ {+ close(_glfw.x11.emptyEventPipe[0]);+ close(_glfw.x11.emptyEventPipe[1]);+ } } const char* _glfwPlatformGetVersionString(void)
glfw/src/x11_monitor.c view
@@ -164,7 +164,7 @@ if (widthMM <= 0 || heightMM <= 0) { // HACK: If RandR does not provide a physical size, assume the- // X11 default 96 DPI and calcuate from the CRTC viewport+ // X11 default 96 DPI and calculate from the CRTC viewport // NOTE: These members are affected by rotation, unlike the mode // info and output info members widthMM = (int) (ci->width * 25.4f / 96.f);
glfw/src/x11_platform.h view
@@ -199,9 +199,9 @@ // The last position the cursor was warped to by GLFW int warpCursorPosX, warpCursorPosY; - // The time of the last KeyPress event- Time lastKeyTime;-+ // The time of the last KeyPress event per keycode, for discarding+ // duplicate key events generated for some keys by ibus+ Time keyPressTimes[256]; } _GLFWwindowX11; // X11-specific global data@@ -222,6 +222,8 @@ XContext context; // XIM input method XIM im;+ // The previous X error handler, to be restored later+ XErrorHandler errorHandler; // Most recent error code received by X error handler int errorCode; // Primary selection string (while the primary selection is owned)@@ -238,6 +240,7 @@ double restoreCursorPosX, restoreCursorPosY; // The window whose disabled cursor mode is active _GLFWwindow* disabledCursorWindow;+ int emptyEventPipe[2]; // Window manager atoms Atom NET_SUPPORTED;@@ -404,7 +407,6 @@ PFN_XRenderQueryVersion QueryVersion; PFN_XRenderFindVisualFormat FindVisualFormat; } xrender;- } _GLFWlibraryX11; // X11-specific per-monitor data@@ -418,7 +420,6 @@ // Index of corresponding Xinerama screen, // for EWMH full screen window placement int index;- } _GLFWmonitorX11; // X11-specific per-cursor data@@ -426,7 +427,6 @@ typedef struct _GLFWcursorX11 { Cursor handle;- } _GLFWcursorX11;
glfw/src/x11_window.c view
@@ -27,12 +27,16 @@ // It is fine to use C99 in this file because it will not be built with VS //======================================================================== +#define _GNU_SOURCE+ #include "internal.h" #include <X11/cursorfont.h> #include <X11/Xmd.h> -#include <sys/select.h>+#include <poll.h>+#include <signal.h>+#include <time.h> #include <string.h> #include <stdio.h>@@ -56,53 +60,129 @@ #define _GLFW_XDND_VERSION 5 --// Wait for data to arrive using select-// This avoids blocking other threads via the per-display Xlib lock that also-// covers GLX functions+// Wait for data to arrive on any of the specified file descriptors //-static GLFWbool waitForEvent(double* timeout)+static GLFWbool waitForData(struct pollfd* fds, nfds_t count, double* timeout) {- fd_set fds;- const int fd = ConnectionNumber(_glfw.x11.display);- int count = fd + 1;--#if defined(__linux__)- if (_glfw.linjs.inotify > fd)- count = _glfw.linjs.inotify + 1;-#endif for (;;) {- FD_ZERO(&fds);- FD_SET(fd, &fds);-#if defined(__linux__)- if (_glfw.linjs.inotify > 0)- FD_SET(_glfw.linjs.inotify, &fds);-#endif- if (timeout) {- const long seconds = (long) *timeout;- const long microseconds = (long) ((*timeout - seconds) * 1e6);- struct timeval tv = { seconds, microseconds }; const uint64_t base = _glfwPlatformGetTimerValue(); - const int result = select(count, &fds, NULL, NULL, &tv);- const int error = errno;+#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__CYGWIN__)+ const time_t seconds = (time_t) *timeout;+ const long nanoseconds = (long) ((*timeout - seconds) * 1e9);+ const struct timespec ts = { seconds, nanoseconds };+ const int result = ppoll(fds, count, &ts, NULL);+#elif defined(__NetBSD__)+ const time_t seconds = (time_t) *timeout;+ const long nanoseconds = (long) ((*timeout - seconds) * 1e9);+ const struct timespec ts = { seconds, nanoseconds };+ const int result = pollts(fds, count, &ts, NULL);+#else+ const int milliseconds = (int) (*timeout * 1e3);+ const int result = poll(fds, count, milliseconds);+#endif+ const int error = errno; // clock_gettime may overwrite our error *timeout -= (_glfwPlatformGetTimerValue() - base) / (double) _glfwPlatformGetTimerFrequency(); if (result > 0) return GLFW_TRUE;- if ((result == -1 && error == EINTR) || *timeout <= 0.0)+ else if (result == -1 && error != EINTR && error != EAGAIN) return GLFW_FALSE;+ else if (*timeout <= 0.0)+ return GLFW_FALSE; }- else if (select(count, &fds, NULL, NULL, NULL) != -1 || errno != EINTR)- return GLFW_TRUE;+ else+ {+ const int result = poll(fds, count, -1);+ if (result > 0)+ return GLFW_TRUE;+ else if (result == -1 && errno != EINTR && errno != EAGAIN)+ return GLFW_FALSE;+ } } } +// Wait for event data to arrive on the X11 display socket+// This avoids blocking other threads via the per-display Xlib lock that also+// covers GLX functions+//+static GLFWbool waitForX11Event(double* timeout)+{+ struct pollfd fd = { ConnectionNumber(_glfw.x11.display), POLLIN };++ while (!XPending(_glfw.x11.display))+ {+ if (!waitForData(&fd, 1, timeout))+ return GLFW_FALSE;+ }++ return GLFW_TRUE;+}++// Wait for event data to arrive on any event file descriptor+// This avoids blocking other threads via the per-display Xlib lock that also+// covers GLX functions+//+static GLFWbool waitForAnyEvent(double* timeout)+{+ nfds_t count = 2;+ struct pollfd fds[3] =+ {+ { ConnectionNumber(_glfw.x11.display), POLLIN },+ { _glfw.x11.emptyEventPipe[0], POLLIN }+ };++#if defined(__linux__)+ if (_glfw.linjs.inotify > 0)+ fds[count++] = (struct pollfd) { _glfw.linjs.inotify, POLLIN };+#endif++ while (!XPending(_glfw.x11.display))+ {+ if (!waitForData(fds, count, timeout))+ return GLFW_FALSE;++ for (int i = 1; i < count; i++)+ {+ if (fds[i].revents & POLLIN)+ return GLFW_TRUE;+ }+ }++ return GLFW_TRUE;+}++// Writes a byte to the empty event pipe+//+static void writeEmptyEvent(void)+{+ for (;;)+ {+ const char byte = 0;+ const ssize_t result = write(_glfw.x11.emptyEventPipe[1], &byte, 1);+ if (result == 1 || (result == -1 && errno != EINTR))+ break;+ }+}++// Drains available data from the empty event pipe+//+static void drainEmptyEvents(void)+{+ for (;;)+ {+ char dummy[64];+ const ssize_t result = read(_glfw.x11.emptyEventPipe[0], dummy, sizeof(dummy));+ if (result == -1 && errno != EINTR)+ break;+ }+}+ // Waits until a VisibilityNotify event arrives for the specified window or the // timeout period elapses (ICCCM section 4.2.2) //@@ -116,7 +196,7 @@ VisibilityNotify, &dummy)) {- if (!waitForEvent(&timeout))+ if (!waitForX11Event(&timeout)) return GLFW_FALSE; } @@ -241,6 +321,11 @@ { XSizeHints* hints = XAllocSizeHints(); + long supplied;+ XGetWMNormalHints(_glfw.x11.display, window->x11.handle, hints, &supplied);++ hints->flags &= ~(PMinSize | PMaxSize | PAspect);+ if (!window->monitor) { if (window->resizable)@@ -277,9 +362,6 @@ } } - hints->flags |= PWinGravity;- hints->win_gravity = StaticGravity;- XSetWMNormalHints(_glfw.x11.display, window->x11.handle, hints); XFree(hints); }@@ -378,96 +460,14 @@ } } -// Splits and translates a text/uri-list into separate file paths-// NOTE: This function destroys the provided string-//-static char** parseUriList(char* text, int* count)-{- const char* prefix = "file://";- char** paths = NULL;- char* line;-- *count = 0;-- while ((line = strtok(text, "\r\n")))- {- text = NULL;-- if (line[0] == '#')- continue;-- if (strncmp(line, prefix, strlen(prefix)) == 0)- {- line += strlen(prefix);- // TODO: Validate hostname- while (*line != '/')- line++;- }-- (*count)++;-- char* path = calloc(strlen(line) + 1, 1);- paths = realloc(paths, *count * sizeof(char*));- paths[*count - 1] = path;-- while (*line)- {- if (line[0] == '%' && line[1] && line[2])- {- const char digits[3] = { line[1], line[2], '\0' };- *path = strtol(digits, NULL, 16);- line += 2;- }- else- *path = *line;-- path++;- line++;- }- }-- return paths;-}--// Encode a Unicode code point to a UTF-8 stream-// Based on cutef8 by Jeff Bezanson (Public Domain)-//-static size_t encodeUTF8(char* s, unsigned int ch)-{- size_t count = 0;-- if (ch < 0x80)- s[count++] = (char) ch;- else if (ch < 0x800)- {- s[count++] = (ch >> 6) | 0xc0;- s[count++] = (ch & 0x3f) | 0x80;- }- else if (ch < 0x10000)- {- s[count++] = (ch >> 12) | 0xe0;- s[count++] = ((ch >> 6) & 0x3f) | 0x80;- s[count++] = (ch & 0x3f) | 0x80;- }- else if (ch < 0x110000)- {- s[count++] = (ch >> 18) | 0xf0;- s[count++] = ((ch >> 12) & 0x3f) | 0x80;- s[count++] = ((ch >> 6) & 0x3f) | 0x80;- s[count++] = (ch & 0x3f) | 0x80;- }-- return count;-}- // Decode a Unicode code point from a UTF-8 stream // Based on cutef8 by Jeff Bezanson (Public Domain) // #if defined(X_HAVE_UTF8_STRING)-static unsigned int decodeUTF8(const char** s)+static uint32_t decodeUTF8(const char** s) {- unsigned int ch = 0, count = 0;- static const unsigned int offsets[] =+ uint32_t codepoint = 0, count = 0;+ static const uint32_t offsets[] = { 0x00000000u, 0x00003080u, 0x000e2080u, 0x03c82080u, 0xfa082080u, 0x82082080u@@ -475,13 +475,13 @@ do {- ch = (ch << 6) + (unsigned char) **s;+ codepoint = (codepoint << 6) + (unsigned char) **s; (*s)++; count++; } while ((**s & 0xc0) == 0x80); assert(count <= 6);- return ch - offsets[count - 1];+ return codepoint - offsets[count - 1]; } #endif /*X_HAVE_UTF8_STRING*/ @@ -499,7 +499,7 @@ char* tp = target; for (sp = source; *sp; sp++)- tp += encodeUTF8(tp, *sp);+ tp += _glfwEncodeUTF8(tp, *sp); return target; }@@ -525,6 +525,25 @@ } } +// Grabs the cursor and confines it to the window+//+static void captureCursor(_GLFWwindow* window)+{+ XGrabPointer(_glfw.x11.display, window->x11.handle, True,+ ButtonPressMask | ButtonReleaseMask | PointerMotionMask,+ GrabModeAsync, GrabModeAsync,+ window->x11.handle,+ None,+ CurrentTime);+}++// Ungrabs the cursor+//+static void releaseCursor(void)+{+ XUngrabPointer(_glfw.x11.display, CurrentTime);+}+ // Enable XI2 raw mouse motion events // static void enableRawMouseMotion(_GLFWwindow* window)@@ -567,12 +586,7 @@ &_glfw.x11.restoreCursorPosY); updateCursorImage(window); _glfwCenterCursorInContentArea(window);- XGrabPointer(_glfw.x11.display, window->x11.handle, True,- ButtonPressMask | ButtonReleaseMask | PointerMotionMask,- GrabModeAsync, GrabModeAsync,- window->x11.handle,- _glfw.x11.hiddenCursorHandle,- CurrentTime);+ captureCursor(window); } // Exit disabled cursor mode for the specified window@@ -583,7 +597,7 @@ disableRawMouseMotion(window); _glfw.x11.disabledCursorWindow = NULL;- XUngrabPointer(_glfw.x11.display, CurrentTime);+ releaseCursor(); _glfwPlatformSetCursorPos(window, _glfw.x11.restoreCursorPosX, _glfw.x11.restoreCursorPosY);@@ -728,8 +742,29 @@ XFree(hints); } - updateNormalHints(window, width, height);+ // Set ICCCM WM_NORMAL_HINTS property+ {+ XSizeHints* hints = XAllocSizeHints();+ if (!hints)+ {+ _glfwInputError(GLFW_OUT_OF_MEMORY, "X11: Failed to allocate size hints");+ return GLFW_FALSE;+ } + if (!wndconfig->resizable)+ {+ hints->flags |= (PMinSize | PMaxSize);+ hints->min_width = hints->max_width = width;+ hints->min_height = hints->max_height = height;+ }++ hints->flags |= PWinGravity;+ hints->win_gravity = StaticGravity;++ XSetWMNormalHints(_glfw.x11.display, window->x11.handle, hints);+ XFree(hints);+ }+ // Set ICCCM WM_CLASS property { XClassHint* hint = XAllocClassHint();@@ -931,20 +966,6 @@ return None; } -static void handleSelectionClear(XEvent* event)-{- if (event->xselectionclear.selection == _glfw.x11.PRIMARY)- {- free(_glfw.x11.primarySelectionString);- _glfw.x11.primarySelectionString = NULL;- }- else- {- free(_glfw.x11.clipboardString);- _glfw.x11.clipboardString = NULL;- }-}- static void handleSelectionRequest(XEvent* event) { const XSelectionRequestEvent* request = &event->xselectionrequest;@@ -1002,7 +1023,7 @@ SelectionNotify, ¬ification)) {- waitForEvent(NULL);+ waitForX11Event(NULL); } if (notification.xselection.property == None)@@ -1038,7 +1059,7 @@ isSelPropNewValueNotify, (XPointer) ¬ification)) {- waitForEvent(NULL);+ waitForX11Event(NULL); } XFree(data);@@ -1065,13 +1086,16 @@ if (!itemCount) {- if (targets[i] == XA_STRING)+ if (string) {- *selectionString = convertLatin1toUTF8(string);- free(string);+ if (targets[i] == XA_STRING)+ {+ *selectionString = convertLatin1toUTF8(string);+ free(string);+ }+ else+ *selectionString = string; }- else- *selectionString = string; break; }@@ -1195,6 +1219,8 @@ { _glfw.x11.xkb.group = ((XkbEvent*) event)->state.group; }++ return; } } @@ -1236,12 +1262,7 @@ return; } - if (event->type == SelectionClear)- {- handleSelectionClear(event);- return;- }- else if (event->type == SelectionRequest)+ if (event->type == SelectionRequest) { handleSelectionRequest(event); return;@@ -1273,16 +1294,20 @@ if (window->x11.ic) {- // HACK: Ignore duplicate key press events generated by ibus- // These have the same timestamp as the original event- // Corresponding release events are filtered out- // implicitly by the GLFW key repeat logic- if (window->x11.lastKeyTime < event->xkey.time)+ // HACK: Do not report the key press events duplicated by XIM+ // Duplicate key releases are filtered out implicitly by+ // the GLFW key repeat logic in _glfwInputKey+ // A timestamp per key is used to handle simultaneous keys+ // NOTE: Always allow the first event for each key through+ // (the server never sends a timestamp of zero)+ // NOTE: Timestamp difference is compared to handle wrap-around+ Time diff = event->xkey.time - window->x11.keyPressTimes[keycode];+ if (diff == event->xkey.time || (diff > 0 && diff < ((Time)1 << 31))) { if (keycode) _glfwInputKey(window, key, keycode, GLFW_PRESS, mods); - window->x11.lastKeyTime = event->xkey.time;+ window->x11.keyPressTimes[keycode] = event->xkey.time; } if (!filtered)@@ -1353,9 +1378,9 @@ _glfwInputKey(window, key, keycode, GLFW_PRESS, mods); - const long character = _glfwKeySym2Unicode(keysym);- if (character != -1)- _glfwInputChar(window, character, mods, plain);+ const uint32_t codepoint = _glfwKeySym2Unicode(keysym);+ if (codepoint != GLFW_INVALID_CODEPOINT)+ _glfwInputChar(window, codepoint, mods, plain); } return;@@ -1557,6 +1582,8 @@ // the position into root (screen) coordinates if (!event->xany.send_event && window->x11.parent != _glfw.x11.root) {+ _glfwGrabErrorHandlerX11();+ Window dummy; XTranslateCoordinates(_glfw.x11.display, window->x11.parent,@@ -1564,6 +1591,10 @@ xpos, ypos, &xpos, &ypos, &dummy);++ _glfwReleaseErrorHandlerX11();+ if (_glfw.x11.errorCode == BadWindow)+ return; } if (xpos != window->x11.xpos || ypos != window->x11.ypos)@@ -1747,7 +1778,7 @@ if (result) { int i, count;- char** paths = parseUriList(data, &count);+ char** paths = _glfwParseUriList(data, &count); _glfwInputDrop(window, count, (const char**) paths); @@ -1936,10 +1967,6 @@ handleSelectionRequest(&event); break; - case SelectionClear:- handleSelectionClear(&event);- break;- case SelectionNotify: { if (event.xselection.target == _glfw.x11.SAVE_TARGETS)@@ -1957,7 +1984,7 @@ } } - waitForEvent(NULL);+ waitForX11Event(NULL); } } @@ -1971,7 +1998,7 @@ const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig) {- Visual* visual;+ Visual* visual = NULL; int depth; if (ctxconfig->client != GLFW_NO_API)@@ -1997,8 +2024,7 @@ } } - if (ctxconfig->client == GLFW_NO_API ||- ctxconfig->source == GLFW_OSMESA_CONTEXT_API)+ if (!visual) { visual = DefaultVisual(_glfw.x11.display, _glfw.x11.screen); depth = DefaultDepth(_glfw.x11.display, _glfw.x11.screen);@@ -2024,6 +2050,9 @@ if (!_glfwCreateContextOSMesa(window, ctxconfig, fbconfig)) return GLFW_FALSE; }++ if (!_glfwRefreshContextAttribs(window, ctxconfig))+ return GLFW_FALSE; } if (window->monitor)@@ -2031,7 +2060,19 @@ _glfwPlatformShowWindow(window); updateWindowMode(window); acquireMonitor(window);++ if (wndconfig->centerCursor)+ _glfwCenterCursorInContentArea(window); }+ else+ {+ if (wndconfig->visible)+ {+ _glfwPlatformShowWindow(window);+ if (wndconfig->focused)+ _glfwPlatformFocusWindow(window);+ }+ } XFlush(_glfw.x11.display); return GLFW_TRUE;@@ -2040,7 +2081,7 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window) { if (_glfw.x11.disabledCursorWindow == window)- _glfw.x11.disabledCursorWindow = NULL;+ enableCursor(window); if (window->monitor) releaseMonitor(window);@@ -2112,8 +2153,8 @@ for (i = 0; i < count; i++) longCount += 2 + images[i].width * images[i].height; - long* icon = calloc(longCount, sizeof(long));- long* target = icon;+ unsigned long* icon = calloc(longCount, sizeof(unsigned long));+ unsigned long* target = icon; for (i = 0; i < count; i++) {@@ -2122,13 +2163,19 @@ for (j = 0; j < images[i].width * images[i].height; j++) {- *target++ = (images[i].pixels[j * 4 + 0] << 16) |- (images[i].pixels[j * 4 + 1] << 8) |- (images[i].pixels[j * 4 + 2] << 0) |- (images[i].pixels[j * 4 + 3] << 24);+ *target++ = (((unsigned long) images[i].pixels[j * 4 + 0]) << 16) |+ (((unsigned long) images[i].pixels[j * 4 + 1]) << 8) |+ (((unsigned long) images[i].pixels[j * 4 + 2]) << 0) |+ (((unsigned long) images[i].pixels[j * 4 + 3]) << 24); } } + // NOTE: XChangeProperty expects 32-bit values like the image data above to be+ // placed in the 32 least significant bits of individual longs. This is+ // true even if long is 64-bit and a WM protocol calls for "packed" data.+ // This is because of a historical mistake that then became part of the Xlib+ // ABI. Xlib will pack these values into a regular array of 32-bit values+ // before sending it over the wire. XChangeProperty(_glfw.x11.display, window->x11.handle, _glfw.x11.NET_WM_ICON, XA_CARDINAL, 32,@@ -2270,7 +2317,7 @@ isFrameExtentsEvent, (XPointer) window)) {- if (!waitForEvent(&timeout))+ if (!waitForX11Event(&timeout)) { _glfwInputError(GLFW_PLATFORM_ERROR, "X11: The window manager has a broken _NET_REQUEST_FRAME_EXTENTS implementation; please report this issue");@@ -2489,7 +2536,11 @@ } if (window->monitor)+ {+ _glfwPlatformSetWindowDecorated(window, window->decorated);+ _glfwPlatformSetWindowFloating(window, window->floating); releaseMonitor(window);+ } _glfwInputWindowMonitor(window, monitor); updateNormalHints(window, width, height);@@ -2580,13 +2631,19 @@ int rootX, rootY, childX, childY; unsigned int mask; - if (!XQueryPointer(_glfw.x11.display, w,- &root, &w, &rootX, &rootY, &childX, &childY, &mask))- {- return GLFW_FALSE;- }+ _glfwGrabErrorHandlerX11(); - if (w == window->x11.handle)+ const Bool result = XQueryPointer(_glfw.x11.display, w,+ &root, &w, &rootX, &rootY,+ &childX, &childY, &mask);++ _glfwReleaseErrorHandlerX11();++ if (_glfw.x11.errorCode == BadWindow)+ w = _glfw.x11.root;+ else if (!result)+ return GLFW_FALSE;+ else if (w == window->x11.handle) return GLFW_TRUE; } @@ -2665,14 +2722,14 @@ break; } - if (i < count)- return;-- XChangeProperty(_glfw.x11.display, window->x11.handle,- _glfw.x11.NET_WM_STATE, XA_ATOM, 32,- PropModeAppend,- (unsigned char*) &_glfw.x11.NET_WM_STATE_ABOVE,- 1);+ if (i == count)+ {+ XChangeProperty(_glfw.x11.display, window->x11.handle,+ _glfw.x11.NET_WM_STATE, XA_ATOM, 32,+ PropModeAppend,+ (unsigned char*) &_glfw.x11.NET_WM_STATE_ABOVE,+ 1);+ } } else if (states) {@@ -2682,15 +2739,15 @@ break; } - if (i == count)- return;-- states[i] = states[count - 1];- count--;+ if (i < count)+ {+ states[i] = states[count - 1];+ count--; - XChangeProperty(_glfw.x11.display, window->x11.handle,- _glfw.x11.NET_WM_STATE, XA_ATOM, 32,- PropModeReplace, (unsigned char*) states, count);+ XChangeProperty(_glfw.x11.display, window->x11.handle,+ _glfw.x11.NET_WM_STATE, XA_ATOM, 32,+ PropModeReplace, (unsigned char*) states, count);+ } } if (states)@@ -2752,7 +2809,7 @@ void _glfwPlatformPollEvents(void) {- _GLFWwindow* window;+ drainEmptyEvents(); #if defined(__linux__) _glfwDetectJoystickConnectionLinux();@@ -2766,7 +2823,7 @@ processEvent(&event); } - window = _glfw.x11.disabledCursorWindow;+ _GLFWwindow* window = _glfw.x11.disabledCursorWindow; if (window) { int width, height;@@ -2786,32 +2843,19 @@ void _glfwPlatformWaitEvents(void) {- while (!XPending(_glfw.x11.display))- waitForEvent(NULL);-+ waitForAnyEvent(NULL); _glfwPlatformPollEvents(); } void _glfwPlatformWaitEventsTimeout(double timeout) {- while (!XPending(_glfw.x11.display))- {- if (!waitForEvent(&timeout))- break;- }-+ waitForAnyEvent(&timeout); _glfwPlatformPollEvents(); } void _glfwPlatformPostEmptyEvent(void) {- XEvent event = { ClientMessage };- event.xclient.window = _glfw.x11.helperWindowHandle;- event.xclient.format = 32; // Data is 32-bit longs- event.xclient.message_type = _glfw.x11.NULL_;-- XSendEvent(_glfw.x11.display, _glfw.x11.helperWindowHandle, False, 0, &event);- XFlush(_glfw.x11.display);+ writeEmptyEvent(); } void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos)@@ -2844,16 +2888,40 @@ void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) {- if (mode == GLFW_CURSOR_DISABLED)+ if (_glfwPlatformWindowFocused(window)) {- if (_glfwPlatformWindowFocused(window))- disableCursor(window);+ if (mode == GLFW_CURSOR_DISABLED)+ {+ _glfwPlatformGetCursorPos(window,+ &_glfw.x11.restoreCursorPosX,+ &_glfw.x11.restoreCursorPosY);+ _glfwCenterCursorInContentArea(window);+ if (window->rawMouseMotion)+ enableRawMouseMotion(window);+ }+ else if (_glfw.x11.disabledCursorWindow == window)+ {+ if (window->rawMouseMotion)+ disableRawMouseMotion(window);+ }++ if (mode == GLFW_CURSOR_DISABLED)+ captureCursor(window);+ else+ releaseCursor();++ if (mode == GLFW_CURSOR_DISABLED)+ _glfw.x11.disabledCursorWindow = window;+ else if (_glfw.x11.disabledCursorWindow == window)+ {+ _glfw.x11.disabledCursorWindow = NULL;+ _glfwPlatformSetCursorPos(window,+ _glfw.x11.restoreCursorPosX,+ _glfw.x11.restoreCursorPosY);+ } }- else if (_glfw.x11.disabledCursorWindow == window)- enableCursor(window);- else- updateCursorImage(window); + updateCursorImage(window); XFlush(_glfw.x11.display); } @@ -2865,7 +2933,7 @@ if (scancode < 0 || scancode > 0xff || _glfw.x11.keycodes[scancode] == GLFW_KEY_UNKNOWN) {- _glfwInputError(GLFW_INVALID_VALUE, "Invalid scancode");+ _glfwInputError(GLFW_INVALID_VALUE, "Invalid scancode %i", scancode); return NULL; } @@ -2875,11 +2943,11 @@ if (keysym == NoSymbol) return NULL; - const long ch = _glfwKeySym2Unicode(keysym);- if (ch == -1)+ const uint32_t codepoint = _glfwKeySym2Unicode(keysym);+ if (codepoint == GLFW_INVALID_CODEPOINT) return NULL; - const size_t count = encodeUTF8(_glfw.x11.keynames[key], (unsigned int) ch);+ const size_t count = _glfwEncodeUTF8(_glfw.x11.keynames[key], codepoint); if (count == 0) return NULL; @@ -2950,8 +3018,9 @@ void _glfwPlatformSetClipboardString(const char* string) {+ char* copy = _glfw_strdup(string); free(_glfw.x11.clipboardString);- _glfw.x11.clipboardString = _glfw_strdup(string);+ _glfw.x11.clipboardString = copy; XSetSelectionOwner(_glfw.x11.display, _glfw.x11.CLIPBOARD,
glfw/src/xkb_unicode.c view
@@ -907,7 +907,7 @@ // Convert XKB KeySym to Unicode //-long _glfwKeySym2Unicode(unsigned int keysym)+uint32_t _glfwKeySym2Unicode(unsigned int keysym) { int min = 0; int max = sizeof(keysymtab) / sizeof(struct codepair) - 1;@@ -937,6 +937,6 @@ } // No matching Unicode value found- return -1;+ return GLFW_INVALID_CODEPOINT; }