#ifndef __EMSCRIPTEN__ // forked from https://github.com/SasLuca/glfw-single-header (CC0-1.0 licensed) // Define _GLFW_IMPLEMENTATION to unroll the implementation into a single compilation unit. // Also, before including do define one of these: // _GLFW_COCOA // _GLFW_WIN32 // _GLFW_X11 // _GLFW_WAYLAND // _GLFW_OSMESA #ifdef _MSC_VER #pragma comment(lib, "gdi32") //< @r-lyeh #pragma comment(lib, "user32") //< @r-lyeh #pragma comment(lib, "shell32") //< @r-lyeh #endif /************************************************************************* * GLFW 3.3.7 - www.glfw.org * A library for OpenGL, window and input *------------------------------------------------------------------------ * Copyright (c) 2002-2006 Marcus Geelnard * Copyright (c) 2006-2019 Camilla Löwy * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would * be appreciated but is not required. * * 2. Altered source versions must be plainly marked as such, and must not * be misrepresented as being the original software. * * 3. This notice may not be removed or altered from any source * distribution. * *************************************************************************/ #ifndef _glfw3_h_ #define _glfw3_h_ #ifdef __cplusplus extern "C" { #endif /************************************************************************* * Doxygen documentation *************************************************************************/ /*! @file glfw3.h * @brief The header of the GLFW 3 API. * * This is the header file of the GLFW 3 API. It defines all its types and * declares all its functions. * * For more information about how to use this file, see @ref build_include. */ /*! @defgroup context Context reference * @brief Functions and types related to OpenGL and OpenGL ES contexts. * * 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 support reference * @brief Functions and types related to Vulkan. * * This is the reference documentation for Vulkan related functions and types. * For more task-oriented information, see the @ref vulkan_guide. */ /*! @defgroup init Initialization, version and error reference * @brief Functions and types related to initialization and error handling. * * This is the reference documentation for initialization and termination of * the library, version management and error handling. For more task-oriented * information, see the @ref intro_guide. */ /*! @defgroup input Input reference * @brief Functions and types related to input handling. * * This is the reference documentation for input related functions and types. * For more task-oriented information, see the @ref input_guide. */ /*! @defgroup monitor Monitor reference * @brief Functions and types related to monitors. * * This is the reference documentation for monitor related functions and types. * For more task-oriented information, see the @ref monitor_guide. */ /*! @defgroup window Window reference * @brief Functions and types related to windows. * * This is the reference documentation for window related functions and types, * including creation, deletion and event polling. For more task-oriented * information, see the @ref window_guide. */ /************************************************************************* * Compiler- and platform-specific preprocessor work *************************************************************************/ /* If we are we on Windows, we want a single define for it. */ #if !defined(_WIN32) && (defined(__WIN32__) || defined(WIN32) || defined(__MINGW32__)) #define _WIN32 #endif /* _WIN32 */ /* Include because most Windows GLU headers need wchar_t and * the macOS OpenGL header blocks the definition of ptrdiff_t by glext.h. * Include it unconditionally to avoid surprising side-effects. */ #include /* Include because it is needed by Vulkan and related functions. * Include it unconditionally to avoid surprising side-effects. */ #include #if defined(GLFW_INCLUDE_VULKAN) #include #endif /* Vulkan header */ /* The Vulkan header may have indirectly included windows.h (because of * VK_USE_PLATFORM_WIN32_KHR) so we offer our replacement symbols after it. */ /* It is customary to use APIENTRY for OpenGL function pointer declarations on * all platforms. Additionally, the Windows OpenGL header needs APIENTRY. */ #if !defined(APIENTRY) #if defined(_WIN32) #define APIENTRY __stdcall #else #define APIENTRY #endif #define GLFW_APIENTRY_DEFINED #endif /* APIENTRY */ /* Some Windows OpenGL headers need this. */ #if !defined(WINGDIAPI) && defined(_WIN32) #define WINGDIAPI __declspec(dllimport) #define GLFW_WINGDIAPI_DEFINED #endif /* WINGDIAPI */ /* Some Windows GLU headers need this. */ #if !defined(CALLBACK) && defined(_WIN32) #define CALLBACK __stdcall #define GLFW_CALLBACK_DEFINED #endif /* CALLBACK */ /* Include the chosen OpenGL or OpenGL ES headers. */ #if defined(GLFW_INCLUDE_ES1) #include #if defined(GLFW_INCLUDE_GLEXT) #include #endif #elif defined(GLFW_INCLUDE_ES2) #include #if defined(GLFW_INCLUDE_GLEXT) #include #endif #elif defined(GLFW_INCLUDE_ES3) #include #if defined(GLFW_INCLUDE_GLEXT) #include #endif #elif defined(GLFW_INCLUDE_ES31) #include #if defined(GLFW_INCLUDE_GLEXT) #include #endif #elif defined(GLFW_INCLUDE_ES32) #include #if defined(GLFW_INCLUDE_GLEXT) #include #endif #elif defined(GLFW_INCLUDE_GLCOREARB) #if defined(__APPLE__) #include #if defined(GLFW_INCLUDE_GLEXT) #include #endif /*GLFW_INCLUDE_GLEXT*/ #else /*__APPLE__*/ #include #if defined(GLFW_INCLUDE_GLEXT) #include #endif #endif /*__APPLE__*/ #elif defined(GLFW_INCLUDE_GLU) #if defined(__APPLE__) #if defined(GLFW_INCLUDE_GLU) #include #endif #else /*__APPLE__*/ #if defined(GLFW_INCLUDE_GLU) #include #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 #else /*__APPLE__*/ #include #if defined(GLFW_INCLUDE_GLEXT) #include #endif #endif /*__APPLE__*/ #endif /* OpenGL and OpenGL ES headers */ #if defined(GLFW_DLL) && defined(_GLFW_BUILD_DLL) /* GLFW_DLL must be defined by applications that are linking against the DLL * version of the GLFW library. _GLFW_BUILD_DLL is defined by the GLFW * configuration header when compiling the DLL version of the library. */ #error "You must not have both GLFW_DLL and _GLFW_BUILD_DLL defined" #endif /* GLFWAPI is used to declare public API functions for export * from the DLL / shared library / dynamic library. */ #if defined(_WIN32) && defined(_GLFW_BUILD_DLL) /* 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 */ #define GLFWAPI __declspec(dllimport) #elif defined(__GNUC__) && defined(_GLFW_BUILD_DLL) /* We are building GLFW as a shared / dynamic library */ #define GLFWAPI __attribute__((visibility("default"))) #else /* We are building or calling GLFW as a static library */ #define GLFWAPI #endif /************************************************************************* * GLFW API tokens *************************************************************************/ /*! @name GLFW version macros * @{ */ /*! @brief The major version number of the GLFW header. * * 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 header. * * 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 header. * * 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 7 /*! @} */ /*! @brief One. * * This is only semantic sugar for the number 1. You can instead use `1` or * `true` or `_True` or `GL_TRUE` or `VK_TRUE` or anything else that is equal * to one. * * @ingroup init */ #define GLFW_TRUE 1 /*! @brief Zero. * * This is only semantic sugar for the number 0. You can instead use `0` or * `false` or `_False` or `GL_FALSE` or `VK_FALSE` or anything else that is * equal to zero. * * @ingroup init */ #define GLFW_FALSE 0 /*! @name Key and button actions * @{ */ /*! @brief The key or mouse button was released. * * The key or mouse button was released. * * @ingroup input */ #define GLFW_RELEASE 0 /*! @brief The key or mouse button was pressed. * * The key or mouse button was pressed. * * @ingroup input */ #define GLFW_PRESS 1 /*! @brief The key was held down until it repeated. * * The key was held down until it repeated. * * @ingroup input */ #define GLFW_REPEAT 2 /*! @} */ /*! @defgroup hat_state Joystick hat states * @brief Joystick hat states. * * See [joystick hat input](@ref joystick_hat) for how these are used. * * @ingroup input * @{ */ #define GLFW_HAT_CENTERED 0 #define GLFW_HAT_UP 1 #define GLFW_HAT_RIGHT 2 #define GLFW_HAT_DOWN 4 #define GLFW_HAT_LEFT 8 #define GLFW_HAT_RIGHT_UP (GLFW_HAT_RIGHT | GLFW_HAT_UP) #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) /*! @} */ /*! @defgroup keys Keyboard keys * @brief Keyboard key IDs. * * See [key input](@ref input_key) for how these are used. * * These key codes are inspired by the _USB HID Usage Tables v1.12_ (p. 53-60), * but re-arranged to map to 7-bit ASCII for printable keys (function keys are * put in the 256+ range). * * The naming of the key codes follow these rules: * - The US keyboard layout is used * - Names of printable alpha-numeric characters are used (e.g. "A", "R", * "3", etc.) * - For non-alphanumeric characters, Unicode:ish names are used (e.g. * "COMMA", "LEFT_SQUARE_BRACKET", etc.). Note that some names do not * correspond to the Unicode standard (usually for brevity) * - Keys that lack a clear US mapping are named "WORLD_x" * - For non-printable keys, custom names are used (e.g. "F4", * "BACKSPACE", etc.) * * @ingroup input * @{ */ /* The unknown key */ #define GLFW_KEY_UNKNOWN -1 /* Printable keys */ #define GLFW_KEY_SPACE 32 #define GLFW_KEY_APOSTROPHE 39 /* ' */ #define GLFW_KEY_COMMA 44 /* , */ #define GLFW_KEY_MINUS 45 /* - */ #define GLFW_KEY_PERIOD 46 /* . */ #define GLFW_KEY_SLASH 47 /* / */ #define GLFW_KEY_0 48 #define GLFW_KEY_1 49 #define GLFW_KEY_2 50 #define GLFW_KEY_3 51 #define GLFW_KEY_4 52 #define GLFW_KEY_5 53 #define GLFW_KEY_6 54 #define GLFW_KEY_7 55 #define GLFW_KEY_8 56 #define GLFW_KEY_9 57 #define GLFW_KEY_SEMICOLON 59 /* ; */ #define GLFW_KEY_EQUAL 61 /* = */ #define GLFW_KEY_A 65 #define GLFW_KEY_B 66 #define GLFW_KEY_C 67 #define GLFW_KEY_D 68 #define GLFW_KEY_E 69 #define GLFW_KEY_F 70 #define GLFW_KEY_G 71 #define GLFW_KEY_H 72 #define GLFW_KEY_I 73 #define GLFW_KEY_J 74 #define GLFW_KEY_K 75 #define GLFW_KEY_L 76 #define GLFW_KEY_M 77 #define GLFW_KEY_N 78 #define GLFW_KEY_O 79 #define GLFW_KEY_P 80 #define GLFW_KEY_Q 81 #define GLFW_KEY_R 82 #define GLFW_KEY_S 83 #define GLFW_KEY_T 84 #define GLFW_KEY_U 85 #define GLFW_KEY_V 86 #define GLFW_KEY_W 87 #define GLFW_KEY_X 88 #define GLFW_KEY_Y 89 #define GLFW_KEY_Z 90 #define GLFW_KEY_LEFT_BRACKET 91 /* [ */ #define GLFW_KEY_BACKSLASH 92 /* \ */ #define GLFW_KEY_RIGHT_BRACKET 93 /* ] */ #define GLFW_KEY_GRAVE_ACCENT 96 /* ` */ #define GLFW_KEY_WORLD_1 161 /* non-US #1 */ #define GLFW_KEY_WORLD_2 162 /* non-US #2 */ /* Function keys */ #define GLFW_KEY_ESCAPE 256 #define GLFW_KEY_ENTER 257 #define GLFW_KEY_TAB 258 #define GLFW_KEY_BACKSPACE 259 #define GLFW_KEY_INSERT 260 #define GLFW_KEY_DELETE 261 #define GLFW_KEY_RIGHT 262 #define GLFW_KEY_LEFT 263 #define GLFW_KEY_DOWN 264 #define GLFW_KEY_UP 265 #define GLFW_KEY_PAGE_UP 266 #define GLFW_KEY_PAGE_DOWN 267 #define GLFW_KEY_HOME 268 #define GLFW_KEY_END 269 #define GLFW_KEY_CAPS_LOCK 280 #define GLFW_KEY_SCROLL_LOCK 281 #define GLFW_KEY_NUM_LOCK 282 #define GLFW_KEY_PRINT_SCREEN 283 #define GLFW_KEY_PAUSE 284 #define GLFW_KEY_F1 290 #define GLFW_KEY_F2 291 #define GLFW_KEY_F3 292 #define GLFW_KEY_F4 293 #define GLFW_KEY_F5 294 #define GLFW_KEY_F6 295 #define GLFW_KEY_F7 296 #define GLFW_KEY_F8 297 #define GLFW_KEY_F9 298 #define GLFW_KEY_F10 299 #define GLFW_KEY_F11 300 #define GLFW_KEY_F12 301 #define GLFW_KEY_F13 302 #define GLFW_KEY_F14 303 #define GLFW_KEY_F15 304 #define GLFW_KEY_F16 305 #define GLFW_KEY_F17 306 #define GLFW_KEY_F18 307 #define GLFW_KEY_F19 308 #define GLFW_KEY_F20 309 #define GLFW_KEY_F21 310 #define GLFW_KEY_F22 311 #define GLFW_KEY_F23 312 #define GLFW_KEY_F24 313 #define GLFW_KEY_F25 314 #define GLFW_KEY_KP_0 320 #define GLFW_KEY_KP_1 321 #define GLFW_KEY_KP_2 322 #define GLFW_KEY_KP_3 323 #define GLFW_KEY_KP_4 324 #define GLFW_KEY_KP_5 325 #define GLFW_KEY_KP_6 326 #define GLFW_KEY_KP_7 327 #define GLFW_KEY_KP_8 328 #define GLFW_KEY_KP_9 329 #define GLFW_KEY_KP_DECIMAL 330 #define GLFW_KEY_KP_DIVIDE 331 #define GLFW_KEY_KP_MULTIPLY 332 #define GLFW_KEY_KP_SUBTRACT 333 #define GLFW_KEY_KP_ADD 334 #define GLFW_KEY_KP_ENTER 335 #define GLFW_KEY_KP_EQUAL 336 #define GLFW_KEY_LEFT_SHIFT 340 #define GLFW_KEY_LEFT_CONTROL 341 #define GLFW_KEY_LEFT_ALT 342 #define GLFW_KEY_LEFT_SUPER 343 #define GLFW_KEY_RIGHT_SHIFT 344 #define GLFW_KEY_RIGHT_CONTROL 345 #define GLFW_KEY_RIGHT_ALT 346 #define GLFW_KEY_RIGHT_SUPER 347 #define GLFW_KEY_MENU 348 #define GLFW_KEY_LAST GLFW_KEY_MENU /*! @} */ /*! @defgroup mods Modifier key flags * @brief Modifier key flags. * * See [key input](@ref input_key) for how these are used. * * @ingroup input * @{ */ /*! @brief If this bit is set one or more Shift keys were held down. * * If this bit is set one or more Shift keys were held down. */ #define GLFW_MOD_SHIFT 0x0001 /*! @brief If this bit is set one or more Control keys were held down. * * If this bit is set one or more Control keys were held down. */ #define GLFW_MOD_CONTROL 0x0002 /*! @brief If this bit is set one or more Alt keys were held down. * * If this bit is set one or more Alt keys were held down. */ #define GLFW_MOD_ALT 0x0004 /*! @brief If this bit is set one or more Super keys were held down. * * If this bit is set one or more Super keys were held down. */ #define GLFW_MOD_SUPER 0x0008 /*! @brief If this bit is set the Caps Lock key is enabled. * * If this bit is set the Caps Lock key is enabled and the @ref * GLFW_LOCK_KEY_MODS input mode is set. */ #define GLFW_MOD_CAPS_LOCK 0x0010 /*! @brief If this bit is set the Num Lock key is enabled. * * If this bit is set the Num Lock key is enabled and the @ref * GLFW_LOCK_KEY_MODS input mode is set. */ #define GLFW_MOD_NUM_LOCK 0x0020 /*! @} */ /*! @defgroup buttons Mouse buttons * @brief Mouse button IDs. * * See [mouse button input](@ref input_mouse_button) for how these are used. * * @ingroup input * @{ */ #define GLFW_MOUSE_BUTTON_1 0 #define GLFW_MOUSE_BUTTON_2 1 #define GLFW_MOUSE_BUTTON_3 2 #define GLFW_MOUSE_BUTTON_4 3 #define GLFW_MOUSE_BUTTON_5 4 #define GLFW_MOUSE_BUTTON_6 5 #define GLFW_MOUSE_BUTTON_7 6 #define GLFW_MOUSE_BUTTON_8 7 #define GLFW_MOUSE_BUTTON_LAST GLFW_MOUSE_BUTTON_8 #define GLFW_MOUSE_BUTTON_LEFT GLFW_MOUSE_BUTTON_1 #define GLFW_MOUSE_BUTTON_RIGHT GLFW_MOUSE_BUTTON_2 #define GLFW_MOUSE_BUTTON_MIDDLE GLFW_MOUSE_BUTTON_3 /*! @} */ /*! @defgroup joysticks Joysticks * @brief Joystick IDs. * * See [joystick input](@ref joystick) for how these are used. * * @ingroup input * @{ */ #define GLFW_JOYSTICK_1 0 #define GLFW_JOYSTICK_2 1 #define GLFW_JOYSTICK_3 2 #define GLFW_JOYSTICK_4 3 #define GLFW_JOYSTICK_5 4 #define GLFW_JOYSTICK_6 5 #define GLFW_JOYSTICK_7 6 #define GLFW_JOYSTICK_8 7 #define GLFW_JOYSTICK_9 8 #define GLFW_JOYSTICK_10 9 #define GLFW_JOYSTICK_11 10 #define GLFW_JOYSTICK_12 11 #define GLFW_JOYSTICK_13 12 #define GLFW_JOYSTICK_14 13 #define GLFW_JOYSTICK_15 14 #define GLFW_JOYSTICK_16 15 #define GLFW_JOYSTICK_LAST GLFW_JOYSTICK_16 /*! @} */ /*! @defgroup gamepad_buttons Gamepad buttons * @brief Gamepad buttons. * * See @ref gamepad for how these are used. * * @ingroup input * @{ */ #define GLFW_GAMEPAD_BUTTON_A 0 #define GLFW_GAMEPAD_BUTTON_B 1 #define GLFW_GAMEPAD_BUTTON_X 2 #define GLFW_GAMEPAD_BUTTON_Y 3 #define GLFW_GAMEPAD_BUTTON_LEFT_BUMPER 4 #define GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER 5 #define GLFW_GAMEPAD_BUTTON_BACK 6 #define GLFW_GAMEPAD_BUTTON_START 7 #define GLFW_GAMEPAD_BUTTON_GUIDE 8 #define GLFW_GAMEPAD_BUTTON_LEFT_THUMB 9 #define GLFW_GAMEPAD_BUTTON_RIGHT_THUMB 10 #define GLFW_GAMEPAD_BUTTON_DPAD_UP 11 #define GLFW_GAMEPAD_BUTTON_DPAD_RIGHT 12 #define GLFW_GAMEPAD_BUTTON_DPAD_DOWN 13 #define GLFW_GAMEPAD_BUTTON_DPAD_LEFT 14 #define GLFW_GAMEPAD_BUTTON_LAST GLFW_GAMEPAD_BUTTON_DPAD_LEFT #define GLFW_GAMEPAD_BUTTON_CROSS GLFW_GAMEPAD_BUTTON_A #define GLFW_GAMEPAD_BUTTON_CIRCLE GLFW_GAMEPAD_BUTTON_B #define GLFW_GAMEPAD_BUTTON_SQUARE GLFW_GAMEPAD_BUTTON_X #define GLFW_GAMEPAD_BUTTON_TRIANGLE GLFW_GAMEPAD_BUTTON_Y /*! @} */ /*! @defgroup gamepad_axes Gamepad axes * @brief Gamepad axes. * * See @ref gamepad for how these are used. * * @ingroup input * @{ */ #define GLFW_GAMEPAD_AXIS_LEFT_X 0 #define GLFW_GAMEPAD_AXIS_LEFT_Y 1 #define GLFW_GAMEPAD_AXIS_RIGHT_X 2 #define GLFW_GAMEPAD_AXIS_RIGHT_Y 3 #define GLFW_GAMEPAD_AXIS_LEFT_TRIGGER 4 #define GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER 5 #define GLFW_GAMEPAD_AXIS_LAST GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER /*! @} */ /*! @defgroup errors Error codes * @brief Error codes. * * See [error handling](@ref error_handling) for how these are used. * * @ingroup init * @{ */ /*! @brief No error has occurred. * * No error has occurred. * * @analysis Yay. */ #define GLFW_NO_ERROR 0 /*! @brief GLFW has not been initialized. * * This occurs if a GLFW function was called that must not be called unless the * library is [initialized](@ref intro_init). * * @analysis Application programmer error. Initialize GLFW before calling any * function that requires initialization. */ #define GLFW_NOT_INITIALIZED 0x00010001 /*! @brief No context is current for this thread. * * This occurs if a GLFW function was called that needs and operates on the * current OpenGL or OpenGL ES context but no context is current on the calling * thread. One such function is @ref glfwSwapInterval. * * @analysis Application programmer error. Ensure a context is current before * calling functions that require a current context. */ #define GLFW_NO_CURRENT_CONTEXT 0x00010002 /*! @brief One of the arguments to the function was an invalid enum value. * * One of the arguments to the function was an invalid enum value, for example * requesting @ref GLFW_RED_BITS with @ref glfwGetWindowAttrib. * * @analysis Application programmer error. Fix the offending call. */ #define GLFW_INVALID_ENUM 0x00010003 /*! @brief One of the arguments to the function was an invalid value. * * One of the arguments to the function was an invalid value, for example * requesting a non-existent OpenGL or OpenGL ES version like 2.7. * * Requesting a valid but unavailable OpenGL or OpenGL ES version will instead * result in a @ref GLFW_VERSION_UNAVAILABLE error. * * @analysis Application programmer error. Fix the offending call. */ #define GLFW_INVALID_VALUE 0x00010004 /*! @brief A memory allocation failed. * * A memory allocation failed. * * @analysis A bug in GLFW or the underlying operating system. Report the bug * to our [issue tracker](https://github.com/glfw/glfw/issues). */ #define GLFW_OUT_OF_MEMORY 0x00010005 /*! @brief GLFW could not find support for the requested API on the system. * * GLFW could not find support for the requested API on the system. * * @analysis The installed graphics driver does not support the requested * API, or does not support it via the chosen context creation backend. * Below are a few examples. * * @par * Some pre-installed Windows graphics drivers do not support OpenGL. AMD only * supports OpenGL ES via EGL, while Nvidia and Intel only support it via * a WGL or GLX extension. macOS does not provide OpenGL ES at all. The Mesa * EGL, OpenGL and OpenGL ES libraries do not interface with the Nvidia binary * driver. Older graphics drivers do not support Vulkan. */ #define GLFW_API_UNAVAILABLE 0x00010006 /*! @brief The requested OpenGL or OpenGL ES version is not available. * * The requested OpenGL or OpenGL ES version (including any requested context * or framebuffer hints) is not available on this machine. * * @analysis The machine does not support your requirements. If your * application is sufficiently flexible, downgrade your requirements and try * again. Otherwise, inform the user that their machine does not match your * requirements. * * @par * Future invalid OpenGL and OpenGL ES versions, for example OpenGL 4.8 if 5.0 * comes out before the 4.x series gets that far, also fail with this error and * not @ref GLFW_INVALID_VALUE, because GLFW cannot know what future versions * will exist. */ #define GLFW_VERSION_UNAVAILABLE 0x00010007 /*! @brief A platform-specific error occurred that does not match any of the * more specific categories. * * A platform-specific error occurred that does not match any of the more * specific categories. * * @analysis A bug or configuration error in GLFW, the underlying operating * system or its drivers, or a lack of required resources. Report the issue to * our [issue tracker](https://github.com/glfw/glfw/issues). */ #define GLFW_PLATFORM_ERROR 0x00010008 /*! @brief The requested format is not supported or available. * * If emitted during window creation, the requested pixel format is not * supported. * * If emitted when querying the clipboard, the contents of the clipboard could * not be converted to the requested format. * * @analysis If emitted during window creation, one or more * [hard constraints](@ref window_hints_hard) did not match any of the * available pixel formats. If your application is sufficiently flexible, * downgrade your requirements and try again. Otherwise, inform the user that * their machine does not match your requirements. * * @par * If emitted when querying the clipboard, ignore the error or report it to * the user, as appropriate. */ #define GLFW_FORMAT_UNAVAILABLE 0x00010009 /*! @brief The specified window does not have an OpenGL or OpenGL ES context. * * A window that does not have an OpenGL or OpenGL ES context was passed to * a function that requires it to have one. * * @analysis Application programmer error. Fix the offending call. */ #define GLFW_NO_WINDOW_CONTEXT 0x0001000A /*! @} */ /*! @addtogroup window * @{ */ /*! @brief Input focus window hint and attribute * * Input focus [window hint](@ref GLFW_FOCUSED_hint) or * [window attribute](@ref GLFW_FOCUSED_attrib). */ #define GLFW_FOCUSED 0x00020001 /*! @brief Window iconification window attribute * * Window iconification [window attribute](@ref GLFW_ICONIFIED_attrib). */ #define GLFW_ICONIFIED 0x00020002 /*! @brief Window resize-ability window hint and attribute * * Window resize-ability [window hint](@ref GLFW_RESIZABLE_hint) and * [window attribute](@ref GLFW_RESIZABLE_attrib). */ #define GLFW_RESIZABLE 0x00020003 /*! @brief Window visibility window hint and attribute * * Window visibility [window hint](@ref GLFW_VISIBLE_hint) and * [window attribute](@ref GLFW_VISIBLE_attrib). */ #define GLFW_VISIBLE 0x00020004 /*! @brief Window decoration window hint and attribute * * Window decoration [window hint](@ref GLFW_DECORATED_hint) and * [window attribute](@ref GLFW_DECORATED_attrib). */ #define GLFW_DECORATED 0x00020005 /*! @brief Window auto-iconification window hint and attribute * * Window auto-iconification [window hint](@ref GLFW_AUTO_ICONIFY_hint) and * [window attribute](@ref GLFW_AUTO_ICONIFY_attrib). */ #define GLFW_AUTO_ICONIFY 0x00020006 /*! @brief Window decoration window hint and attribute * * Window decoration [window hint](@ref GLFW_FLOATING_hint) and * [window attribute](@ref GLFW_FLOATING_attrib). */ #define GLFW_FLOATING 0x00020007 /*! @brief Window maximization window hint and attribute * * Window maximization [window hint](@ref GLFW_MAXIMIZED_hint) and * [window attribute](@ref GLFW_MAXIMIZED_attrib). */ #define GLFW_MAXIMIZED 0x00020008 /*! @brief Cursor centering window hint * * Cursor centering [window hint](@ref GLFW_CENTER_CURSOR_hint). */ #define GLFW_CENTER_CURSOR 0x00020009 /*! @brief Window framebuffer transparency hint and attribute * * Window framebuffer transparency * [window hint](@ref GLFW_TRANSPARENT_FRAMEBUFFER_hint) and * [window attribute](@ref GLFW_TRANSPARENT_FRAMEBUFFER_attrib). */ #define GLFW_TRANSPARENT_FRAMEBUFFER 0x0002000A /*! @brief Mouse cursor hover window attribute. * * Mouse cursor hover [window attribute](@ref GLFW_HOVERED_attrib). */ #define GLFW_HOVERED 0x0002000B /*! @brief Input focus on calling show window hint and attribute * * Input focus [window hint](@ref GLFW_FOCUS_ON_SHOW_hint) or * [window attribute](@ref GLFW_FOCUS_ON_SHOW_attrib). */ #define GLFW_FOCUS_ON_SHOW 0x0002000C /*! @brief Framebuffer bit depth hint. * * Framebuffer bit depth [hint](@ref GLFW_RED_BITS). */ #define GLFW_RED_BITS 0x00021001 /*! @brief Framebuffer bit depth hint. * * Framebuffer bit depth [hint](@ref GLFW_GREEN_BITS). */ #define GLFW_GREEN_BITS 0x00021002 /*! @brief Framebuffer bit depth hint. * * Framebuffer bit depth [hint](@ref GLFW_BLUE_BITS). */ #define GLFW_BLUE_BITS 0x00021003 /*! @brief Framebuffer bit depth hint. * * Framebuffer bit depth [hint](@ref GLFW_ALPHA_BITS). */ #define GLFW_ALPHA_BITS 0x00021004 /*! @brief Framebuffer bit depth hint. * * Framebuffer bit depth [hint](@ref GLFW_DEPTH_BITS). */ #define GLFW_DEPTH_BITS 0x00021005 /*! @brief Framebuffer bit depth hint. * * Framebuffer bit depth [hint](@ref GLFW_STENCIL_BITS). */ #define GLFW_STENCIL_BITS 0x00021006 /*! @brief Framebuffer bit depth hint. * * Framebuffer bit depth [hint](@ref GLFW_ACCUM_RED_BITS). */ #define GLFW_ACCUM_RED_BITS 0x00021007 /*! @brief Framebuffer bit depth hint. * * Framebuffer bit depth [hint](@ref GLFW_ACCUM_GREEN_BITS). */ #define GLFW_ACCUM_GREEN_BITS 0x00021008 /*! @brief Framebuffer bit depth hint. * * Framebuffer bit depth [hint](@ref GLFW_ACCUM_BLUE_BITS). */ #define GLFW_ACCUM_BLUE_BITS 0x00021009 /*! @brief Framebuffer bit depth hint. * * Framebuffer bit depth [hint](@ref GLFW_ACCUM_ALPHA_BITS). */ #define GLFW_ACCUM_ALPHA_BITS 0x0002100A /*! @brief Framebuffer auxiliary buffer hint. * * Framebuffer auxiliary buffer [hint](@ref GLFW_AUX_BUFFERS). */ #define GLFW_AUX_BUFFERS 0x0002100B /*! @brief OpenGL stereoscopic rendering hint. * * OpenGL stereoscopic rendering [hint](@ref GLFW_STEREO). */ #define GLFW_STEREO 0x0002100C /*! @brief Framebuffer MSAA samples hint. * * Framebuffer MSAA samples [hint](@ref GLFW_SAMPLES). */ #define GLFW_SAMPLES 0x0002100D /*! @brief Framebuffer sRGB hint. * * Framebuffer sRGB [hint](@ref GLFW_SRGB_CAPABLE). */ #define GLFW_SRGB_CAPABLE 0x0002100E /*! @brief Monitor refresh rate hint. * * Monitor refresh rate [hint](@ref GLFW_REFRESH_RATE). */ #define GLFW_REFRESH_RATE 0x0002100F /*! @brief Framebuffer double buffering hint. * * Framebuffer double buffering [hint](@ref GLFW_DOUBLEBUFFER). */ #define GLFW_DOUBLEBUFFER 0x00021010 /*! @brief Context client API hint and attribute. * * Context client API [hint](@ref GLFW_CLIENT_API_hint) and * [attribute](@ref GLFW_CLIENT_API_attrib). */ #define GLFW_CLIENT_API 0x00022001 /*! @brief Context client API major version hint and attribute. * * Context client API major version [hint](@ref GLFW_CONTEXT_VERSION_MAJOR_hint) * and [attribute](@ref GLFW_CONTEXT_VERSION_MAJOR_attrib). */ #define GLFW_CONTEXT_VERSION_MAJOR 0x00022002 /*! @brief Context client API minor version hint and attribute. * * Context client API minor version [hint](@ref GLFW_CONTEXT_VERSION_MINOR_hint) * and [attribute](@ref GLFW_CONTEXT_VERSION_MINOR_attrib). */ #define GLFW_CONTEXT_VERSION_MINOR 0x00022003 /*! @brief Context client API revision number attribute. * * Context client API revision number * [attribute](@ref GLFW_CONTEXT_REVISION_attrib). */ #define GLFW_CONTEXT_REVISION 0x00022004 /*! @brief Context robustness hint and attribute. * * Context client API revision number [hint](@ref GLFW_CONTEXT_ROBUSTNESS_hint) * and [attribute](@ref GLFW_CONTEXT_ROBUSTNESS_attrib). */ #define GLFW_CONTEXT_ROBUSTNESS 0x00022005 /*! @brief OpenGL forward-compatibility hint and attribute. * * OpenGL forward-compatibility [hint](@ref GLFW_OPENGL_FORWARD_COMPAT_hint) * and [attribute](@ref GLFW_OPENGL_FORWARD_COMPAT_attrib). */ #define GLFW_OPENGL_FORWARD_COMPAT 0x00022006 /*! @brief Debug mode context hint and attribute. * * Debug mode context [hint](@ref GLFW_OPENGL_DEBUG_CONTEXT_hint) and * [attribute](@ref GLFW_OPENGL_DEBUG_CONTEXT_attrib). */ #define GLFW_OPENGL_DEBUG_CONTEXT 0x00022007 /*! @brief OpenGL profile hint and attribute. * * OpenGL profile [hint](@ref GLFW_OPENGL_PROFILE_hint) and * [attribute](@ref GLFW_OPENGL_PROFILE_attrib). */ #define GLFW_OPENGL_PROFILE 0x00022008 /*! @brief Context flush-on-release hint and attribute. * * Context flush-on-release [hint](@ref GLFW_CONTEXT_RELEASE_BEHAVIOR_hint) and * [attribute](@ref GLFW_CONTEXT_RELEASE_BEHAVIOR_attrib). */ #define GLFW_CONTEXT_RELEASE_BEHAVIOR 0x00022009 /*! @brief Context error suppression hint and attribute. * * Context error suppression [hint](@ref GLFW_CONTEXT_NO_ERROR_hint) and * [attribute](@ref GLFW_CONTEXT_NO_ERROR_attrib). */ #define GLFW_CONTEXT_NO_ERROR 0x0002200A /*! @brief Context creation API hint and attribute. * * Context creation API [hint](@ref GLFW_CONTEXT_CREATION_API_hint) and * [attribute](@ref GLFW_CONTEXT_CREATION_API_attrib). */ #define GLFW_CONTEXT_CREATION_API 0x0002200B /*! @brief Window content area scaling window * [window hint](@ref GLFW_SCALE_TO_MONITOR). */ #define GLFW_SCALE_TO_MONITOR 0x0002200C /*! @brief macOS specific * [window hint](@ref GLFW_COCOA_RETINA_FRAMEBUFFER_hint). */ #define GLFW_COCOA_RETINA_FRAMEBUFFER 0x00023001 /*! @brief macOS specific * [window hint](@ref GLFW_COCOA_FRAME_NAME_hint). */ #define GLFW_COCOA_FRAME_NAME 0x00023002 /*! @brief macOS specific * [window hint](@ref GLFW_COCOA_GRAPHICS_SWITCHING_hint). */ #define GLFW_COCOA_GRAPHICS_SWITCHING 0x00023003 /*! @brief X11 specific * [window hint](@ref GLFW_X11_CLASS_NAME_hint). */ #define GLFW_X11_CLASS_NAME 0x00024001 /*! @brief X11 specific * [window hint](@ref GLFW_X11_CLASS_NAME_hint). */ #define GLFW_X11_INSTANCE_NAME 0x00024002 /*! @} */ #define GLFW_NO_API 0 #define GLFW_OPENGL_API 0x00030001 #define GLFW_OPENGL_ES_API 0x00030002 #define GLFW_NO_ROBUSTNESS 0 #define GLFW_NO_RESET_NOTIFICATION 0x00031001 #define GLFW_LOSE_CONTEXT_ON_RESET 0x00031002 #define GLFW_OPENGL_ANY_PROFILE 0 #define GLFW_OPENGL_CORE_PROFILE 0x00032001 #define GLFW_OPENGL_COMPAT_PROFILE 0x00032002 #define GLFW_CURSOR 0x00033001 #define GLFW_STICKY_KEYS 0x00033002 #define GLFW_STICKY_MOUSE_BUTTONS 0x00033003 #define GLFW_LOCK_KEY_MODS 0x00033004 #define GLFW_RAW_MOUSE_MOTION 0x00033005 #define GLFW_CURSOR_NORMAL 0x00034001 #define GLFW_CURSOR_HIDDEN 0x00034002 #define GLFW_CURSOR_DISABLED 0x00034003 #define GLFW_ANY_RELEASE_BEHAVIOR 0 #define GLFW_RELEASE_BEHAVIOR_FLUSH 0x00035001 #define GLFW_RELEASE_BEHAVIOR_NONE 0x00035002 #define GLFW_NATIVE_CONTEXT_API 0x00036001 #define GLFW_EGL_CONTEXT_API 0x00036002 #define GLFW_OSMESA_CONTEXT_API 0x00036003 /*! @defgroup shapes Standard cursor shapes * @brief Standard system cursor shapes. * * See [standard cursor creation](@ref cursor_standard) for how these are used. * * @ingroup input * @{ */ /*! @brief The regular arrow cursor shape. * * The regular arrow cursor. */ #define GLFW_ARROW_CURSOR 0x00036001 /*! @brief The text input I-beam cursor shape. * * The text input I-beam cursor shape. */ #define GLFW_IBEAM_CURSOR 0x00036002 /*! @brief The crosshair shape. * * The crosshair shape. */ #define GLFW_CROSSHAIR_CURSOR 0x00036003 /*! @brief The hand shape. * * The hand shape. */ #define GLFW_HAND_CURSOR 0x00036004 /*! @brief The horizontal resize arrow shape. * * The horizontal resize arrow shape. */ #define GLFW_HRESIZE_CURSOR 0x00036005 /*! @brief The vertical resize arrow shape. * * The vertical resize arrow shape. */ #define GLFW_VRESIZE_CURSOR 0x00036006 /*! @} */ #define GLFW_CONNECTED 0x00040001 #define GLFW_DISCONNECTED 0x00040002 /*! @addtogroup init * @{ */ /*! @brief Joystick hat buttons init hint. * * Joystick hat buttons [init hint](@ref GLFW_JOYSTICK_HAT_BUTTONS). */ #define GLFW_JOYSTICK_HAT_BUTTONS 0x00050001 /*! @brief macOS specific init hint. * * macOS specific [init hint](@ref GLFW_COCOA_CHDIR_RESOURCES_hint). */ #define GLFW_COCOA_CHDIR_RESOURCES 0x00051001 /*! @brief macOS specific init hint. * * macOS specific [init hint](@ref GLFW_COCOA_MENUBAR_hint). */ #define GLFW_COCOA_MENUBAR 0x00051002 /*! @} */ #define GLFW_DONT_CARE -1 /************************************************************************* * GLFW API types *************************************************************************/ /*! @brief Client API function pointer type. * * Generic function pointer used for returning client API function pointers * without forcing a cast from a regular pointer. * * @sa @ref context_glext * @sa @ref glfwGetProcAddress * * @since Added in version 3.0. * * @ingroup context */ typedef void (*GLFWglproc)(void); /*! @brief Vulkan API function pointer type. * * Generic function pointer used for returning Vulkan API function pointers * without forcing a cast from a regular pointer. * * @sa @ref vulkan_proc * @sa @ref glfwGetInstanceProcAddress * * @since Added in version 3.2. * * @ingroup vulkan */ typedef void (*GLFWvkproc)(void); /*! @brief Opaque monitor object. * * Opaque monitor object. * * @see @ref monitor_object * * @since Added in version 3.0. * * @ingroup monitor */ typedef struct GLFWmonitor GLFWmonitor; /*! @brief Opaque window object. * * Opaque window object. * * @see @ref window_object * * @since Added in version 3.0. * * @ingroup window */ typedef struct GLFWwindow GLFWwindow; /*! @brief Opaque cursor object. * * Opaque cursor object. * * @see @ref cursor_object * * @since Added in version 3.1. * * @ingroup input */ typedef struct GLFWcursor GLFWcursor; /*! @brief The function pointer type for error callbacks. * * This is the function pointer type for error callbacks. An error callback * function has the following signature: * @code * void callback_name(int error_code, const char* description) * @endcode * * @param[in] error_code An [error code](@ref errors). Future releases may add * more error codes. * @param[in] description A UTF-8 encoded string describing the error. * * @pointer_lifetime The error description string is valid until the callback * function returns. * * @sa @ref error_handling * @sa @ref glfwSetErrorCallback * * @since Added in version 3.0. * * @ingroup init */ typedef void (* GLFWerrorfun)(int error_code, const char* description); /*! @brief The function pointer type for window position callbacks. * * This is the function pointer type for window position callbacks. A window * position callback function has the following signature: * @code * void callback_name(GLFWwindow* window, int xpos, int ypos) * @endcode * * @param[in] window The window that was moved. * @param[in] xpos The new x-coordinate, in screen coordinates, of the * upper-left corner of the content area of the window. * @param[in] ypos The new y-coordinate, in screen coordinates, of the * upper-left corner of the content area of the window. * * @sa @ref window_pos * @sa @ref glfwSetWindowPosCallback * * @since Added in version 3.0. * * @ingroup window */ typedef void (* GLFWwindowposfun)(GLFWwindow* window, int xpos, int ypos); /*! @brief The function pointer type for window size callbacks. * * This is the function pointer type for window size callbacks. A window size * callback function has the following signature: * @code * void callback_name(GLFWwindow* window, int width, int height) * @endcode * * @param[in] window The window that was resized. * @param[in] width The new width, in screen coordinates, of the window. * @param[in] height The new height, in screen coordinates, of the window. * * @sa @ref window_size * @sa @ref glfwSetWindowSizeCallback * * @since Added in version 1.0. * @glfw3 Added window handle parameter. * * @ingroup window */ typedef void (* GLFWwindowsizefun)(GLFWwindow* window, int width, int height); /*! @brief The function pointer type for window close callbacks. * * This is the function pointer type for window close callbacks. A window * close callback function has the following signature: * @code * void function_name(GLFWwindow* window) * @endcode * * @param[in] window The window that the user attempted to close. * * @sa @ref window_close * @sa @ref glfwSetWindowCloseCallback * * @since Added in version 2.5. * @glfw3 Added window handle parameter. * * @ingroup window */ typedef void (* GLFWwindowclosefun)(GLFWwindow* window); /*! @brief The function pointer type for window content refresh callbacks. * * This is the function pointer type for window content refresh callbacks. * A window content refresh callback function has the following signature: * @code * void function_name(GLFWwindow* window); * @endcode * * @param[in] window The window whose content needs to be refreshed. * * @sa @ref window_refresh * @sa @ref glfwSetWindowRefreshCallback * * @since Added in version 2.5. * @glfw3 Added window handle parameter. * * @ingroup window */ typedef void (* GLFWwindowrefreshfun)(GLFWwindow* window); /*! @brief The function pointer type for window focus callbacks. * * This is the function pointer type for window focus callbacks. A window * focus callback function has the following signature: * @code * void function_name(GLFWwindow* window, int focused) * @endcode * * @param[in] window The window that gained or lost input focus. * @param[in] focused `GLFW_TRUE` if the window was given input focus, or * `GLFW_FALSE` if it lost it. * * @sa @ref window_focus * @sa @ref glfwSetWindowFocusCallback * * @since Added in version 3.0. * * @ingroup window */ typedef void (* GLFWwindowfocusfun)(GLFWwindow* window, int focused); /*! @brief The function pointer type for window iconify callbacks. * * This is the function pointer type for window iconify callbacks. A window * iconify callback function has the following signature: * @code * void function_name(GLFWwindow* window, int iconified) * @endcode * * @param[in] window The window that was iconified or restored. * @param[in] iconified `GLFW_TRUE` if the window was iconified, or * `GLFW_FALSE` if it was restored. * * @sa @ref window_iconify * @sa @ref glfwSetWindowIconifyCallback * * @since Added in version 3.0. * * @ingroup window */ typedef void (* GLFWwindowiconifyfun)(GLFWwindow* window, int iconified); /*! @brief The function pointer type for window maximize callbacks. * * This is the function pointer type for window maximize callbacks. A window * maximize callback function has the following signature: * @code * void function_name(GLFWwindow* window, int maximized) * @endcode * * @param[in] window The window that was maximized or restored. * @param[in] maximized `GLFW_TRUE` if the window was maximized, or * `GLFW_FALSE` if it was restored. * * @sa @ref window_maximize * @sa glfwSetWindowMaximizeCallback * * @since Added in version 3.3. * * @ingroup window */ typedef void (* GLFWwindowmaximizefun)(GLFWwindow* window, int maximized); /*! @brief The function pointer type for framebuffer size callbacks. * * This is the function pointer type for framebuffer size callbacks. * A framebuffer size callback function has the following signature: * @code * void function_name(GLFWwindow* window, int width, int height) * @endcode * * @param[in] window The window whose framebuffer was resized. * @param[in] width The new width, in pixels, of the framebuffer. * @param[in] height The new height, in pixels, of the framebuffer. * * @sa @ref window_fbsize * @sa @ref glfwSetFramebufferSizeCallback * * @since Added in version 3.0. * * @ingroup window */ typedef void (* GLFWframebuffersizefun)(GLFWwindow* window, int width, int height); /*! @brief The function pointer type for window content scale callbacks. * * This is the function pointer type for window content scale callbacks. * A window content scale callback function has the following signature: * @code * void function_name(GLFWwindow* window, float xscale, float yscale) * @endcode * * @param[in] window The window whose content scale changed. * @param[in] xscale The new x-axis content scale of the window. * @param[in] yscale The new y-axis content scale of the window. * * @sa @ref window_scale * @sa @ref glfwSetWindowContentScaleCallback * * @since Added in version 3.3. * * @ingroup window */ typedef void (* GLFWwindowcontentscalefun)(GLFWwindow* window, float xscale, float yscale); /*! @brief The function pointer type for mouse button callbacks. * * This is the function pointer type for mouse button callback functions. * A mouse button callback function has the following signature: * @code * void function_name(GLFWwindow* window, int button, int action, int mods) * @endcode * * @param[in] window The window that received the event. * @param[in] button The [mouse button](@ref buttons) that was pressed or * released. * @param[in] action One of `GLFW_PRESS` or `GLFW_RELEASE`. Future releases * may add more actions. * @param[in] mods Bit field describing which [modifier keys](@ref mods) were * held down. * * @sa @ref input_mouse_button * @sa @ref glfwSetMouseButtonCallback * * @since Added in version 1.0. * @glfw3 Added window handle and modifier mask parameters. * * @ingroup input */ typedef void (* GLFWmousebuttonfun)(GLFWwindow* window, int button, int action, int mods); /*! @brief The function pointer type for cursor position callbacks. * * This is the function pointer type for cursor position callbacks. A cursor * position callback function has the following signature: * @code * void function_name(GLFWwindow* window, double xpos, double ypos); * @endcode * * @param[in] window The window that received the event. * @param[in] xpos The new cursor x-coordinate, relative to the left edge of * the content area. * @param[in] ypos The new cursor y-coordinate, relative to the top edge of the * content area. * * @sa @ref cursor_pos * @sa @ref glfwSetCursorPosCallback * * @since Added in version 3.0. Replaces `GLFWmouseposfun`. * * @ingroup input */ typedef void (* GLFWcursorposfun)(GLFWwindow* window, double xpos, double ypos); /*! @brief The function pointer type for cursor enter/leave callbacks. * * This is the function pointer type for cursor enter/leave callbacks. * A cursor enter/leave callback function has the following signature: * @code * void function_name(GLFWwindow* window, int entered) * @endcode * * @param[in] window The window that received the event. * @param[in] entered `GLFW_TRUE` if the cursor entered the window's content * area, or `GLFW_FALSE` if it left it. * * @sa @ref cursor_enter * @sa @ref glfwSetCursorEnterCallback * * @since Added in version 3.0. * * @ingroup input */ typedef void (* GLFWcursorenterfun)(GLFWwindow* window, int entered); /*! @brief The function pointer type for scroll callbacks. * * This is the function pointer type for scroll callbacks. A scroll callback * function has the following signature: * @code * void function_name(GLFWwindow* window, double xoffset, double yoffset) * @endcode * * @param[in] window The window that received the event. * @param[in] xoffset The scroll offset along the x-axis. * @param[in] yoffset The scroll offset along the y-axis. * * @sa @ref scrolling * @sa @ref glfwSetScrollCallback * * @since Added in version 3.0. Replaces `GLFWmousewheelfun`. * * @ingroup input */ typedef void (* GLFWscrollfun)(GLFWwindow* window, double xoffset, double yoffset); /*! @brief The function pointer type for keyboard key callbacks. * * This is the function pointer type for keyboard key callbacks. A keyboard * key callback function has the following signature: * @code * void function_name(GLFWwindow* window, int key, int scancode, int action, int mods) * @endcode * * @param[in] window The window that received the event. * @param[in] key The [keyboard key](@ref keys) that was pressed or released. * @param[in] scancode The system-specific scancode of the key. * @param[in] action `GLFW_PRESS`, `GLFW_RELEASE` or `GLFW_REPEAT`. Future * releases may add more actions. * @param[in] mods Bit field describing which [modifier keys](@ref mods) were * held down. * * @sa @ref input_key * @sa @ref glfwSetKeyCallback * * @since Added in version 1.0. * @glfw3 Added window handle, scancode and modifier mask parameters. * * @ingroup input */ typedef void (* GLFWkeyfun)(GLFWwindow* window, int key, int scancode, int action, int mods); /*! @brief The function pointer type for Unicode character callbacks. * * This is the function pointer type for Unicode character callbacks. * A Unicode character callback function has the following signature: * @code * void function_name(GLFWwindow* window, unsigned int codepoint) * @endcode * * @param[in] window The window that received the event. * @param[in] codepoint The Unicode code point of the character. * * @sa @ref input_char * @sa @ref glfwSetCharCallback * * @since Added in version 2.4. * @glfw3 Added window handle parameter. * * @ingroup input */ typedef void (* GLFWcharfun)(GLFWwindow* window, unsigned int codepoint); /*! @brief The function pointer type for Unicode character with modifiers * callbacks. * * This is the function pointer type for Unicode character with modifiers * callbacks. It is called for each input character, regardless of what * modifier keys are held down. A Unicode character with modifiers callback * function has the following signature: * @code * void function_name(GLFWwindow* window, unsigned int codepoint, int mods) * @endcode * * @param[in] window The window that received the event. * @param[in] codepoint The Unicode code point of the character. * @param[in] mods Bit field describing which [modifier keys](@ref mods) were * held down. * * @sa @ref input_char * @sa @ref glfwSetCharModsCallback * * @deprecated Scheduled for removal in version 4.0. * * @since Added in version 3.1. * * @ingroup input */ typedef void (* GLFWcharmodsfun)(GLFWwindow* window, unsigned int codepoint, int mods); /*! @brief The function pointer type for path drop callbacks. * * This is the function pointer type for path drop callbacks. A path drop * callback function has the following signature: * @code * void function_name(GLFWwindow* window, int path_count, const char* paths[]) * @endcode * * @param[in] window The window that received the event. * @param[in] path_count The number of dropped paths. * @param[in] paths The UTF-8 encoded file and/or directory path names. * * @pointer_lifetime The path array and its strings are valid until the * callback function returns. * * @sa @ref path_drop * @sa @ref glfwSetDropCallback * * @since Added in version 3.1. * * @ingroup input */ typedef void (* GLFWdropfun)(GLFWwindow* window, int path_count, const char* paths[]); /*! @brief The function pointer type for monitor configuration callbacks. * * This is the function pointer type for monitor configuration callbacks. * A monitor callback function has the following signature: * @code * void function_name(GLFWmonitor* monitor, int event) * @endcode * * @param[in] monitor The monitor that was connected or disconnected. * @param[in] event One of `GLFW_CONNECTED` or `GLFW_DISCONNECTED`. Future * releases may add more events. * * @sa @ref monitor_event * @sa @ref glfwSetMonitorCallback * * @since Added in version 3.0. * * @ingroup monitor */ typedef void (* GLFWmonitorfun)(GLFWmonitor* monitor, int event); /*! @brief The function pointer type for joystick configuration callbacks. * * This is the function pointer type for joystick configuration callbacks. * A joystick configuration callback function has the following signature: * @code * void function_name(int jid, int event) * @endcode * * @param[in] jid The joystick that was connected or disconnected. * @param[in] event One of `GLFW_CONNECTED` or `GLFW_DISCONNECTED`. Future * releases may add more events. * * @sa @ref joystick_event * @sa @ref glfwSetJoystickCallback * * @since Added in version 3.2. * * @ingroup input */ typedef void (* GLFWjoystickfun)(int jid, int event); /*! @brief Video mode type. * * This describes a single video mode. * * @sa @ref monitor_modes * @sa @ref glfwGetVideoMode * @sa @ref glfwGetVideoModes * * @since Added in version 1.0. * @glfw3 Added refresh rate member. * * @ingroup monitor */ typedef struct GLFWvidmode { /*! The width, in screen coordinates, of the video mode. */ int width; /*! The height, in screen coordinates, of the video mode. */ int height; /*! The bit depth of the red channel of the video mode. */ int redBits; /*! The bit depth of the green channel of the video mode. */ int greenBits; /*! The bit depth of the blue channel of the video mode. */ int blueBits; /*! The refresh rate, in Hz, of the video mode. */ int refreshRate; } GLFWvidmode; /*! @brief Gamma ramp. * * This describes the gamma ramp for a monitor. * * @sa @ref monitor_gamma * @sa @ref glfwGetGammaRamp * @sa @ref glfwSetGammaRamp * * @since Added in version 3.0. * * @ingroup monitor */ typedef struct GLFWgammaramp { /*! An array of value describing the response of the red channel. */ unsigned short* red; /*! An array of value describing the response of the green channel. */ unsigned short* green; /*! An array of value describing the response of the blue channel. */ unsigned short* blue; /*! The number of elements in each array. */ unsigned int size; } GLFWgammaramp; /*! @brief Image data. * * This describes a single 2D image. See the documentation for each related * function what the expected pixel format is. * * @sa @ref cursor_custom * @sa @ref window_icon * * @since Added in version 2.1. * @glfw3 Removed format and bytes-per-pixel members. * * @ingroup window */ typedef struct GLFWimage { /*! The width, in pixels, of this image. */ int width; /*! The height, in pixels, of this image. */ int height; /*! The pixel data of this image, arranged left-to-right, top-to-bottom. */ unsigned char* pixels; } GLFWimage; /*! @brief Gamepad input state * * This describes the input state of a gamepad. * * @sa @ref gamepad * @sa @ref glfwGetGamepadState * * @since Added in version 3.3. * * @ingroup input */ typedef struct GLFWgamepadstate { /*! The states of each [gamepad button](@ref gamepad_buttons), `GLFW_PRESS` * or `GLFW_RELEASE`. */ unsigned char buttons[15]; /*! The states of each [gamepad axis](@ref gamepad_axes), in the range -1.0 * to 1.0 inclusive. */ float axes[6]; } GLFWgamepadstate; /************************************************************************* * GLFW API functions *************************************************************************/ /*! @brief Initializes the GLFW library. * * This function initializes the GLFW library. Before most GLFW functions can * be used, GLFW must be initialized, and before an application terminates GLFW * should be terminated in order to free any resources allocated during or * after initialization. * * If this function fails, it calls @ref glfwTerminate before returning. If it * succeeds, you should call @ref glfwTerminate before the application exits. * * Additional calls to this function after successful initialization but before * termination will return `GLFW_TRUE` immediately. * * @return `GLFW_TRUE` if successful, or `GLFW_FALSE` if an * [error](@ref error_handling) occurred. * * @errors Possible errors include @ref GLFW_PLATFORM_ERROR. * * @remark @macos This function will change the current directory of the * application to the `Contents/Resources` subdirectory of the application's * 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 * @sa @ref glfwTerminate * * @since Added in version 1.0. * * @ingroup init */ GLFWAPI int glfwInit(void); /*! @brief Terminates the GLFW library. * * This function destroys all remaining windows and cursors, restores any * modified gamma ramps and frees any other allocated resources. Once this * function is called, you must again call @ref glfwInit successfully before * you will be able to use most GLFW functions. * * If GLFW has been successfully initialized, this function should be called * before the application exits. If initialization fails, there is no need to * 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. * * @warning The contexts of any remaining windows must not be current on any * other thread when this function is called. * * @reentrancy This function must not be called from a callback. * * @thread_safety This function must only be called from the main thread. * * @sa @ref intro_init * @sa @ref glfwInit * * @since Added in version 1.0. * * @ingroup init */ GLFWAPI void glfwTerminate(void); /*! @brief Sets the specified init hint to the desired value. * * This function sets hints for the next initialization of GLFW. * * The values you set hints to are never reset by GLFW, but they only take * effect during initialization. Once GLFW has been initialized, any values * you set will be ignored until the library is terminated and initialized * again. * * Some hints are platform specific. These may be set on any platform but they * will only affect their specific platform. Other platforms will ignore them. * Setting these hints requires no platform specific headers or functions. * * @param[in] hint The [init hint](@ref init_hints) to set. * @param[in] value The new value of the init hint. * * @errors Possible errors include @ref GLFW_INVALID_ENUM and @ref * GLFW_INVALID_VALUE. * * @remarks This function may be called before @ref glfwInit. * * @thread_safety This function must only be called from the main thread. * * @sa init_hints * @sa glfwInit * * @since Added in version 3.3. * * @ingroup init */ GLFWAPI void glfwInitHint(int hint, int value); /*! @brief Retrieves the version of the GLFW library. * * This function retrieves the major, minor and revision numbers of the GLFW * library. It is intended for when you are using GLFW as a shared library and * want to ensure that you are using the minimum required version. * * Any or all of the version arguments may be `NULL`. * * @param[out] major Where to store the major version number, or `NULL`. * @param[out] minor Where to store the minor version number, or `NULL`. * @param[out] rev Where to store the revision number, or `NULL`. * * @errors None. * * @remark This function may be called before @ref glfwInit. * * @thread_safety This function may be called from any thread. * * @sa @ref intro_version * @sa @ref glfwGetVersionString * * @since Added in version 1.0. * * @ingroup init */ GLFWAPI void glfwGetVersion(int* major, int* minor, int* rev); /*! @brief Returns a string describing the compile-time configuration. * * This function returns the compile-time generated * [version string](@ref intro_version_string) of the GLFW library binary. It * describes the version, platform, compiler and any platform-specific * compile-time options. It should not be confused with the OpenGL or OpenGL * ES version string, queried with `glGetString`. * * __Do not use the version string__ to parse the GLFW library version. The * @ref glfwGetVersion function provides the version of the running library * binary in numerical format. * * @return The ASCII encoded GLFW version string. * * @errors None. * * @remark This function may be called before @ref glfwInit. * * @pointer_lifetime The returned string is static and compile-time generated. * * @thread_safety This function may be called from any thread. * * @sa @ref intro_version * @sa @ref glfwGetVersion * * @since Added in version 3.0. * * @ingroup init */ GLFWAPI const char* glfwGetVersionString(void); /*! @brief Returns and clears the last error for the calling thread. * * This function returns and clears the [error code](@ref errors) of the last * error that occurred on the calling thread, and optionally a UTF-8 encoded * human-readable description of it. If no error has occurred since the last * call, it returns @ref GLFW_NO_ERROR (zero) and the description pointer is * set to `NULL`. * * @param[in] description Where to store the error description pointer, or `NULL`. * @return The last error code for the calling thread, or @ref GLFW_NO_ERROR * (zero). * * @errors None. * * @pointer_lifetime The returned string is allocated and freed by GLFW. You * should not free it yourself. It is guaranteed to be valid only until the * next error occurs or the library is terminated. * * @remark This function may be called before @ref glfwInit. * * @thread_safety This function may be called from any thread. * * @sa @ref error_handling * @sa @ref glfwSetErrorCallback * * @since Added in version 3.3. * * @ingroup init */ GLFWAPI int glfwGetError(const char** description); /*! @brief Sets the error callback. * * This function sets the error callback, which is called with an error code * and a human-readable description each time a GLFW error occurs. * * The error code is set before the callback is called. Calling @ref * glfwGetError from the error callback will return the same value as the error * code argument. * * The error callback is called on the thread where the error occurred. If you * are using GLFW from multiple threads, your error callback needs to be * written accordingly. * * Because the description string may have been generated specifically for that * error, it is not guaranteed to be valid after the callback has returned. If * you wish to use it after the callback returns, you need to make a copy. * * Once set, the error callback remains set even after the library has been * terminated. * * @param[in] callback The new callback, or `NULL` to remove the currently set * callback. * @return The previously set callback, or `NULL` if no callback was set. * * @callback_signature * @code * void callback_name(int error_code, const char* description) * @endcode * For more information about the callback parameters, see the * [callback pointer type](@ref GLFWerrorfun). * * @errors None. * * @remark This function may be called before @ref glfwInit. * * @thread_safety This function must only be called from the main thread. * * @sa @ref error_handling * @sa @ref glfwGetError * * @since Added in version 3.0. * * @ingroup init */ GLFWAPI GLFWerrorfun glfwSetErrorCallback(GLFWerrorfun callback); /*! @brief Returns the currently connected monitors. * * This function returns an array of handles for all currently connected * monitors. The primary monitor is always first in the returned array. If no * monitors were found, this function returns `NULL`. * * @param[out] count Where to store the number of monitors in the returned * array. This is set to zero if an error occurred. * @return An array of monitor handles, or `NULL` if no monitors were found or * if an [error](@ref error_handling) occurred. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @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 * monitor configuration changes or the library is terminated. * * @thread_safety This function must only be called from the main thread. * * @sa @ref monitor_monitors * @sa @ref monitor_event * @sa @ref glfwGetPrimaryMonitor * * @since Added in version 3.0. * * @ingroup monitor */ GLFWAPI GLFWmonitor** glfwGetMonitors(int* count); /*! @brief Returns the primary monitor. * * This function returns the primary monitor. This is usually the monitor * where elements like the task bar or global menu bar are located. * * @return The primary monitor, or `NULL` if no monitors were found or if an * [error](@ref error_handling) occurred. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function must only be called from the main thread. * * @remark The primary monitor is always first in the array returned by @ref * glfwGetMonitors. * * @sa @ref monitor_monitors * @sa @ref glfwGetMonitors * * @since Added in version 3.0. * * @ingroup monitor */ GLFWAPI GLFWmonitor* glfwGetPrimaryMonitor(void); /*! @brief Returns the position of the monitor's viewport on the virtual screen. * * This function returns the position, in screen coordinates, of the upper-left * corner of the specified monitor. * * Any or all of the position arguments may be `NULL`. If an error occurs, all * non-`NULL` position arguments will be set to zero. * * @param[in] monitor The monitor to query. * @param[out] xpos Where to store the monitor x-coordinate, or `NULL`. * @param[out] ypos Where to store the monitor y-coordinate, or `NULL`. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_PLATFORM_ERROR. * * @thread_safety This function must only be called from the main thread. * * @sa @ref monitor_properties * * @since Added in version 3.0. * * @ingroup monitor */ GLFWAPI void glfwGetMonitorPos(GLFWmonitor* monitor, int* xpos, int* ypos); /*! @brief Retrieves the work area of the monitor. * * This function returns the position, in screen coordinates, of the upper-left * corner of the work area of the specified monitor along with the work area * size in screen coordinates. The work area is defined as the area of the * monitor not occluded by the operating system task bar where present. If no * task bar exists then the work area is the monitor resolution in screen * coordinates. * * Any or all of the position and size arguments may be `NULL`. If an error * occurs, all non-`NULL` position and size arguments will be set to zero. * * @param[in] monitor The monitor to query. * @param[out] xpos Where to store the monitor x-coordinate, or `NULL`. * @param[out] ypos Where to store the monitor y-coordinate, or `NULL`. * @param[out] width Where to store the monitor width, or `NULL`. * @param[out] height Where to store the monitor height, or `NULL`. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_PLATFORM_ERROR. * * @thread_safety This function must only be called from the main thread. * * @sa @ref monitor_workarea * * @since Added in version 3.3. * * @ingroup monitor */ GLFWAPI void glfwGetMonitorWorkarea(GLFWmonitor* monitor, int* xpos, int* ypos, int* width, int* height); /*! @brief Returns the physical size of the monitor. * * This function returns the size, in millimetres, of the display area of the * specified monitor. * * Some systems do not provide accurate monitor size information, either * because the monitor * [EDID](https://en.wikipedia.org/wiki/Extended_display_identification_data) * data is incorrect or because the driver does not report it accurately. * * Any or all of the size arguments may be `NULL`. If an error occurs, all * non-`NULL` size arguments will be set to zero. * * @param[in] monitor The monitor to query. * @param[out] widthMM Where to store the width, in millimetres, of the * monitor's display area, or `NULL`. * @param[out] heightMM Where to store the height, in millimetres, of the * monitor's display area, or `NULL`. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @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. * * @sa @ref monitor_properties * * @since Added in version 3.0. * * @ingroup monitor */ GLFWAPI void glfwGetMonitorPhysicalSize(GLFWmonitor* monitor, int* widthMM, int* heightMM); /*! @brief Retrieves the content scale for the specified monitor. * * This function retrieves the content scale for the specified monitor. The * content scale is the ratio between the current DPI and the platform's * default DPI. This is especially important for text and any UI elements. If * the pixel dimensions of your UI scaled by this look appropriate on your * machine then it should appear at a reasonable size on other machines * regardless of their DPI and scaling settings. This relies on the system DPI * and scaling settings being somewhat correct. * * The content scale may depend on both the monitor resolution and pixel * density and on user settings. It may be very different from the raw DPI * calculated from the physical size and current resolution. * * @param[in] monitor The monitor to query. * @param[out] xscale Where to store the x-axis content scale, or `NULL`. * @param[out] yscale Where to store the y-axis content scale, or `NULL`. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_PLATFORM_ERROR. * * @thread_safety This function must only be called from the main thread. * * @sa @ref monitor_scale * @sa @ref glfwGetWindowContentScale * * @since Added in version 3.3. * * @ingroup monitor */ GLFWAPI void glfwGetMonitorContentScale(GLFWmonitor* monitor, float* xscale, float* yscale); /*! @brief Returns the name of the specified monitor. * * This function returns a human-readable name, encoded as UTF-8, of the * specified monitor. The name typically reflects the make and model of the * monitor and is not guaranteed to be unique among the connected monitors. * * @param[in] monitor The monitor to query. * @return The UTF-8 encoded name of the monitor, or `NULL` if an * [error](@ref error_handling) occurred. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @pointer_lifetime The returned string is allocated and freed by GLFW. You * should not free it yourself. It is valid until the specified monitor is * disconnected or the library is terminated. * * @thread_safety This function must only be called from the main thread. * * @sa @ref monitor_properties * * @since Added in version 3.0. * * @ingroup monitor */ GLFWAPI const char* glfwGetMonitorName(GLFWmonitor* monitor); /*! @brief Sets the user pointer of the specified monitor. * * This function sets the user-defined pointer of the specified monitor. The * current value is retained until the monitor is disconnected. The initial * value is `NULL`. * * This function may be called from the monitor callback, even for a monitor * that is being disconnected. * * @param[in] monitor The monitor whose pointer to set. * @param[in] pointer The new value. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function may be called from any thread. Access is not * synchronized. * * @sa @ref monitor_userptr * @sa @ref glfwGetMonitorUserPointer * * @since Added in version 3.3. * * @ingroup monitor */ GLFWAPI void glfwSetMonitorUserPointer(GLFWmonitor* monitor, void* pointer); /*! @brief Returns the user pointer of the specified monitor. * * This function returns the current value of the user-defined pointer of the * specified monitor. The initial value is `NULL`. * * This function may be called from the monitor callback, even for a monitor * that is being disconnected. * * @param[in] monitor The monitor whose pointer to return. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function may be called from any thread. Access is not * synchronized. * * @sa @ref monitor_userptr * @sa @ref glfwSetMonitorUserPointer * * @since Added in version 3.3. * * @ingroup monitor */ GLFWAPI void* glfwGetMonitorUserPointer(GLFWmonitor* monitor); /*! @brief Sets the monitor configuration callback. * * This function sets the monitor configuration callback, or removes the * currently set callback. This is called when a monitor is connected to or * disconnected from the system. * * @param[in] callback The new callback, or `NULL` to remove the currently set * callback. * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * * @callback_signature * @code * void function_name(GLFWmonitor* monitor, int event) * @endcode * For more information about the callback parameters, see the * [function pointer type](@ref GLFWmonitorfun). * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function must only be called from the main thread. * * @sa @ref monitor_event * * @since Added in version 3.0. * * @ingroup monitor */ GLFWAPI GLFWmonitorfun glfwSetMonitorCallback(GLFWmonitorfun callback); /*! @brief Returns the available video modes for the specified monitor. * * 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), 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 * array. This is set to zero if an error occurred. * @return An array of video modes, or `NULL` if an * [error](@ref error_handling) occurred. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_PLATFORM_ERROR. * * @pointer_lifetime The returned array is allocated and freed by GLFW. You * should not free it yourself. It is valid until the specified monitor is * disconnected, this function is called again for that monitor or the library * is terminated. * * @thread_safety This function must only be called from the main thread. * * @sa @ref monitor_modes * @sa @ref glfwGetVideoMode * * @since Added in version 1.0. * @glfw3 Changed to return an array of modes for a specific monitor. * * @ingroup monitor */ GLFWAPI const GLFWvidmode* glfwGetVideoModes(GLFWmonitor* monitor, int* count); /*! @brief Returns the current mode of the specified monitor. * * This function returns the current video mode of the specified monitor. If * you have created a full screen window for that monitor, the return value * will depend on whether that window is iconified. * * @param[in] monitor The monitor to query. * @return The current mode of the monitor, or `NULL` if an * [error](@ref error_handling) occurred. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_PLATFORM_ERROR. * * @pointer_lifetime The returned array is allocated and freed by GLFW. You * should not free it yourself. It is valid until the specified monitor is * disconnected or the library is terminated. * * @thread_safety This function must only be called from the main thread. * * @sa @ref monitor_modes * @sa @ref glfwGetVideoModes * * @since Added in version 3.0. Replaces `glfwGetDesktopMode`. * * @ingroup monitor */ GLFWAPI const GLFWvidmode* glfwGetVideoMode(GLFWmonitor* monitor); /*! @brief Generates a gamma ramp and sets it for the specified monitor. * * This function generates an appropriately sized gamma ramp from the specified * exponent and then calls @ref glfwSetGammaRamp with it. The value must be * a finite number greater than zero. * * The software controlled gamma ramp is applied _in addition_ to the hardware * gamma correction, which today is usually an approximation of sRGB gamma. * This means that setting a perfectly linear ramp, or gamma 1.0, will produce * the default (usually sRGB-like) behavior. * * For gamma correct rendering with OpenGL or OpenGL ES, see the @ref * GLFW_SRGB_CAPABLE hint. * * @param[in] monitor The monitor whose gamma ramp to set. * @param[in] gamma The desired exponent. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref * GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR. * * @remark @wayland Gamma handling is a privileged protocol, this function * will thus never be implemented and emits @ref GLFW_PLATFORM_ERROR. * * @thread_safety This function must only be called from the main thread. * * @sa @ref monitor_gamma * * @since Added in version 3.0. * * @ingroup monitor */ GLFWAPI void glfwSetGamma(GLFWmonitor* monitor, float gamma); /*! @brief Returns the current gamma ramp for the specified monitor. * * This function returns the current gamma ramp of the specified monitor. * * @param[in] monitor The monitor to query. * @return The current gamma ramp, or `NULL` if an * [error](@ref error_handling) occurred. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_PLATFORM_ERROR. * * @remark @wayland Gamma handling is a privileged protocol, this function * will thus never be implemented and emits @ref GLFW_PLATFORM_ERROR while * returning `NULL`. * * @pointer_lifetime The returned structure and its arrays are allocated and * freed by GLFW. You should not free them yourself. They are valid until the * specified monitor is disconnected, this function is called again for that * monitor or the library is terminated. * * @thread_safety This function must only be called from the main thread. * * @sa @ref monitor_gamma * * @since Added in version 3.0. * * @ingroup monitor */ GLFWAPI const GLFWgammaramp* glfwGetGammaRamp(GLFWmonitor* monitor); /*! @brief Sets the current gamma ramp for the specified monitor. * * This function sets the current gamma ramp for the specified monitor. The * original gamma ramp for that monitor is saved by GLFW the first time this * function is called and is restored by @ref glfwTerminate. * * The software controlled gamma ramp is applied _in addition_ to the hardware * gamma correction, which today is usually an approximation of sRGB gamma. * This means that setting a perfectly linear ramp, or gamma 1.0, will produce * the default (usually sRGB-like) behavior. * * For gamma correct rendering with OpenGL or OpenGL ES, see the @ref * GLFW_SRGB_CAPABLE hint. * * @param[in] monitor The monitor whose gamma ramp to set. * @param[in] ramp The gamma ramp to use. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_PLATFORM_ERROR. * * @remark The size of the specified gamma ramp should match the size of the * current ramp for that monitor. * * @remark @win32 The gamma ramp size must be 256. * * @remark @wayland Gamma handling is a privileged protocol, this function * will thus never be implemented and emits @ref GLFW_PLATFORM_ERROR. * * @pointer_lifetime The specified gamma ramp is copied before this function * returns. * * @thread_safety This function must only be called from the main thread. * * @sa @ref monitor_gamma * * @since Added in version 3.0. * * @ingroup monitor */ GLFWAPI void glfwSetGammaRamp(GLFWmonitor* monitor, const GLFWgammaramp* ramp); /*! @brief Resets all window hints to their default values. * * This function resets all window hints to their * [default values](@ref window_hints_values). * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function must only be called from the main thread. * * @sa @ref window_hints * @sa @ref glfwWindowHint * @sa @ref glfwWindowHintString * * @since Added in version 3.0. * * @ingroup window */ GLFWAPI void glfwDefaultWindowHints(void); /*! @brief Sets the specified window hint to the desired value. * * This function sets hints for the next call to @ref glfwCreateWindow. The * hints, once set, retain their values until changed by a call to this * function or @ref glfwDefaultWindowHints, or until the library is terminated. * * Only integer value hints can be set with this function. String value hints * are set with @ref glfwWindowHintString. * * This function does not check whether the specified hint values are valid. * If you set hints to invalid values this will instead be reported by the next * call to @ref glfwCreateWindow. * * Some hints are platform specific. These may be set on any platform but they * will only affect their specific platform. Other platforms will ignore them. * Setting these hints requires no platform specific headers or functions. * * @param[in] hint The [window hint](@ref window_hints) to set. * @param[in] value The new value of the window hint. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_INVALID_ENUM. * * @thread_safety This function must only be called from the main thread. * * @sa @ref window_hints * @sa @ref glfwWindowHintString * @sa @ref glfwDefaultWindowHints * * @since Added in version 3.0. Replaces `glfwOpenWindowHint`. * * @ingroup window */ GLFWAPI void glfwWindowHint(int hint, int value); /*! @brief Sets the specified window hint to the desired value. * * This function sets hints for the next call to @ref glfwCreateWindow. The * hints, once set, retain their values until changed by a call to this * function or @ref glfwDefaultWindowHints, or until the library is terminated. * * Only string type hints can be set with this function. Integer value hints * are set with @ref glfwWindowHint. * * This function does not check whether the specified hint values are valid. * If you set hints to invalid values this will instead be reported by the next * call to @ref glfwCreateWindow. * * Some hints are platform specific. These may be set on any platform but they * will only affect their specific platform. Other platforms will ignore them. * Setting these hints requires no platform specific headers or functions. * * @param[in] hint The [window hint](@ref window_hints) to set. * @param[in] value The new value of the window hint. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_INVALID_ENUM. * * @pointer_lifetime The specified string is copied before this function * returns. * * @thread_safety This function must only be called from the main thread. * * @sa @ref window_hints * @sa @ref glfwWindowHint * @sa @ref glfwDefaultWindowHints * * @since Added in version 3.3. * * @ingroup window */ GLFWAPI void glfwWindowHintString(int hint, const char* value); /*! @brief Creates a window and its associated context. * * This function creates a window and its associated OpenGL or OpenGL ES * context. Most of the options controlling how the window and its context * should be created are specified with [window hints](@ref window_hints). * * Successful creation does not change which context is current. Before you * can use the newly created context, you need to * [make it current](@ref context_current). For information about the `share` * parameter, see @ref context_sharing. * * The created window, framebuffer and context may differ from what you * requested, as not all parameters and hints are * [hard constraints](@ref window_hints_hard). This includes the size of the * window, especially for full screen windows. To query the actual attributes * of the created window, framebuffer and context, see @ref * glfwGetWindowAttrib, @ref glfwGetWindowSize and @ref glfwGetFramebufferSize. * * To create a full screen window, you need to specify the monitor the window * will cover. If no monitor is specified, the window will be windowed mode. * Unless you have a way for the user to choose a specific monitor, it is * recommended that you pick the primary monitor. For more information on how * to query connected monitors, see @ref monitor_monitors. * * For full screen windows, the specified size becomes the resolution of the * window's _desired video mode_. As long as a full screen window is not * iconified, the supported video mode most closely matching the desired video * mode is set for the specified monitor. For more information about full * screen windows, including the creation of so called _windowed full screen_ * or _borderless full screen_ windows, see @ref window_windowed_full_screen. * * Once you have created the window, you can switch it between windowed and * full screen mode with @ref glfwSetWindowMonitor. This will not affect its * OpenGL or OpenGL ES context. * * By default, newly created windows use the placement recommended by the * window system. To create the window at a specific position, make it * initially invisible using the [GLFW_VISIBLE](@ref GLFW_VISIBLE_hint) window * hint, set its [position](@ref window_pos) and then [show](@ref window_hide) * it. * * As long as at least one full screen window is not iconified, the screensaver * is prohibited from starting. * * Window systems put limits on window sizes. Very large or very small window * dimensions may be overridden by the window system on creation. Check the * actual [size](@ref window_size) after creation. * * The [swap interval](@ref buffer_swap) is not set during window creation and * the initial value may vary depending on driver settings and defaults. * * @param[in] width The desired width, in screen coordinates, of the window. * This must be greater than zero. * @param[in] height The desired height, in screen coordinates, of the window. * This must be greater than zero. * @param[in] title The initial, UTF-8 encoded window title. * @param[in] monitor The monitor to use for full screen mode, or `NULL` for * windowed mode. * @param[in] share The window whose context to share resources with, or `NULL` * to not share resources. * @return The handle of the created window, or `NULL` if an * [error](@ref error_handling) occurred. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref * GLFW_INVALID_ENUM, @ref GLFW_INVALID_VALUE, @ref GLFW_API_UNAVAILABLE, @ref * GLFW_VERSION_UNAVAILABLE, @ref GLFW_FORMAT_UNAVAILABLE and @ref * GLFW_PLATFORM_ERROR. * * @remark @win32 Window creation will fail if the Microsoft GDI software * OpenGL implementation is the only one available. * * @remark @win32 If the executable has an icon resource named `GLFW_ICON,` it * will be set as the initial icon for the window. If no such icon is present, * the `IDI_APPLICATION` icon will be used instead. To set a different icon, * see @ref glfwSetWindowIcon. * * @remark @win32 The context to share resources with must not be current on * any other thread. * * @remark @macos The OS only supports forward-compatible core profile contexts * for OpenGL versions 3.2 and later. Before creating an OpenGL context of * version 3.2 or later you must set the * [GLFW_OPENGL_FORWARD_COMPAT](@ref GLFW_OPENGL_FORWARD_COMPAT_hint) and * [GLFW_OPENGL_PROFILE](@ref GLFW_OPENGL_PROFILE_hint) hints accordingly. * OpenGL 3.0 and 3.1 contexts are not supported at all on macOS. * * @remark @macos The GLFW window has no icon, as it is not a document * window, but the dock icon will be the same as the application bundle's icon. * For more information on bundles, see the * [Bundle Programming Guide](https://developer.apple.com/library/mac/documentation/CoreFoundation/Conceptual/CFBundles/) * in the Mac Developer Library. * * @remark @macos The first time a window is created the menu bar is created. * If GLFW finds a `MainMenu.nib` it is loaded and assumed to contain a menu * bar. Otherwise a minimal menu bar is created manually with common commands * like Hide, Quit and About. The About entry opens a minimal about dialog * with information from the application's bundle. Menu bar creation can be * disabled entirely with the @ref GLFW_COCOA_MENUBAR init hint. * * @remark @macos On OS X 10.10 and later the window frame will not be rendered * at full resolution on Retina displays unless the * [GLFW_COCOA_RETINA_FRAMEBUFFER](@ref GLFW_COCOA_RETINA_FRAMEBUFFER_hint) * hint is `GLFW_TRUE` and the `NSHighResolutionCapable` key is enabled in the * application bundle's `Info.plist`. For more information, see * [High Resolution Guidelines for OS X](https://developer.apple.com/library/mac/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Explained/Explained.html) * in the Mac Developer Library. The GLFW test and example programs use * a custom `Info.plist` template for this, which can be found as * `CMake/MacOSXBundleInfo.plist.in` in the source tree. * * @remark @macos When activating frame autosaving with * [GLFW_COCOA_FRAME_NAME](@ref GLFW_COCOA_FRAME_NAME_hint), the specified * window size and position may be overridden by previously saved values. * * @remark @x11 Some window managers will not respect the placement of * initially hidden windows. * * @remark @x11 Due to the asynchronous nature of X11, it may take a moment for * a window to reach its requested state. This means you may not be able to * query the final size, position or other attributes directly after window * creation. * * @remark @x11 The class part of the `WM_CLASS` window property will by * default be set to the window title passed to this function. The instance * part will use the contents of the `RESOURCE_NAME` environment variable, if * present and not empty, or fall back to the window title. Set the * [GLFW_X11_CLASS_NAME](@ref GLFW_X11_CLASS_NAME_hint) and * [GLFW_X11_INSTANCE_NAME](@ref GLFW_X11_INSTANCE_NAME_hint) window hints to * override this. * * @remark @wayland Compositors should implement the xdg-decoration protocol * for GLFW to decorate the window properly. If this protocol isn't * supported, or if the compositor prefers client-side decorations, a very * simple fallback frame will be drawn using the wp_viewporter protocol. A * compositor can still emit close, maximize or fullscreen events, using for * instance a keybind mechanism. If neither of these protocols is supported, * the window won't be decorated. * * @remark @wayland A full screen window will not attempt to change the mode, * no matter what the requested size or refresh rate. * * @remark @wayland Screensaver inhibition requires the idle-inhibit protocol * to be implemented in the user's compositor. * * @thread_safety This function must only be called from the main thread. * * @sa @ref window_creation * @sa @ref glfwDestroyWindow * * @since Added in version 3.0. Replaces `glfwOpenWindow`. * * @ingroup window */ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, const char* title, GLFWmonitor* monitor, GLFWwindow* share); /*! @brief Destroys the specified window and its context. * * This function destroys the specified window and its context. On calling * this function, no further callbacks will be called for that window. * * If the context of the specified window is current on the main thread, it is * detached before being destroyed. * * @param[in] window The window to destroy. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_PLATFORM_ERROR. * * @note The context of the specified window must not be current on any other * thread when this function is called. * * @reentrancy This function must not be called from a callback. * * @thread_safety This function must only be called from the main thread. * * @sa @ref window_creation * @sa @ref glfwCreateWindow * * @since Added in version 3.0. Replaces `glfwCloseWindow`. * * @ingroup window */ GLFWAPI void glfwDestroyWindow(GLFWwindow* window); /*! @brief Checks the close flag of the specified window. * * This function returns the value of the close flag of the specified window. * * @param[in] window The window to query. * @return The value of the close flag. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function may be called from any thread. Access is not * synchronized. * * @sa @ref window_close * * @since Added in version 3.0. * * @ingroup window */ GLFWAPI int glfwWindowShouldClose(GLFWwindow* window); /*! @brief Sets the close flag of the specified window. * * This function sets the value of the close flag of the specified window. * This can be used to override the user's attempt to close the window, or * to signal that it should be closed. * * @param[in] window The window whose flag to change. * @param[in] value The new value. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function may be called from any thread. Access is not * synchronized. * * @sa @ref window_close * * @since Added in version 3.0. * * @ingroup window */ GLFWAPI void glfwSetWindowShouldClose(GLFWwindow* window, int value); /*! @brief Sets the title of the specified window. * * This function sets the window title, encoded as UTF-8, of the specified * window. * * @param[in] window The window whose title to change. * @param[in] title The UTF-8 encoded window title. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_PLATFORM_ERROR. * * @remark @macos The window title will not be updated until the next time you * process events. * * @thread_safety This function must only be called from the main thread. * * @sa @ref window_title * * @since Added in version 1.0. * @glfw3 Added window handle parameter. * * @ingroup window */ GLFWAPI void glfwSetWindowTitle(GLFWwindow* window, const char* title); /*! @brief Sets the icon for the specified window. * * This function sets the icon of the specified window. If passed an array of * candidate images, those of or closest to the sizes desired by the system are * selected. If no images are specified, the window reverts to its default * icon. * * The pixels are 32-bit, little-endian, non-premultiplied RGBA, i.e. eight * bits per channel with the red channel first. They are arranged canonically * as packed sequential rows, starting from the top-left corner. * * The desired image sizes varies depending on platform and system settings. * The selected images will be rescaled as needed. Good sizes include 16x16, * 32x32 and 48x48. * * @param[in] window The window whose icon to set. * @param[in] count The number of images in the specified array, or zero to * revert to the default window icon. * @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. * * @pointer_lifetime The specified image data is copied before this function * returns. * * @remark @macos The GLFW window has no icon, as it is not a document * window, so this function does nothing. The dock icon will be the same as * the application bundle's icon. For more information on bundles, see the * [Bundle Programming Guide](https://developer.apple.com/library/mac/documentation/CoreFoundation/Conceptual/CFBundles/) * in the Mac Developer Library. * * @remark @wayland There is no existing protocol to change an icon, the * window will thus inherit the one defined in the application's desktop file. * This function always emits @ref GLFW_PLATFORM_ERROR. * * @thread_safety This function must only be called from the main thread. * * @sa @ref window_icon * * @since Added in version 3.2. * * @ingroup window */ GLFWAPI void glfwSetWindowIcon(GLFWwindow* window, int count, const GLFWimage* images); /*! @brief Retrieves the position of the content area of the specified window. * * This function retrieves the position, in screen coordinates, of the * upper-left corner of the content area of the specified window. * * Any or all of the position arguments may be `NULL`. If an error occurs, all * non-`NULL` position arguments will be set to zero. * * @param[in] window The window to query. * @param[out] xpos Where to store the x-coordinate of the upper-left corner of * the content area, or `NULL`. * @param[out] ypos Where to store the y-coordinate of the upper-left corner of * the content area, or `NULL`. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_PLATFORM_ERROR. * * @remark @wayland There is no way for an application to retrieve the global * position of its windows, this function will always emit @ref * GLFW_PLATFORM_ERROR. * * @thread_safety This function must only be called from the main thread. * * @sa @ref window_pos * @sa @ref glfwSetWindowPos * * @since Added in version 3.0. * * @ingroup window */ GLFWAPI void glfwGetWindowPos(GLFWwindow* window, int* xpos, int* ypos); /*! @brief Sets the position of the content area of the specified window. * * This function sets the position, in screen coordinates, of the upper-left * corner of the content area of the specified windowed mode window. If the * window is a full screen window, this function does nothing. * * __Do not use this function__ to move an already visible window unless you * have very good reasons for doing so, as it will confuse and annoy the user. * * The window manager may put limits on what positions are allowed. GLFW * cannot and should not override these limits. * * @param[in] window The window to query. * @param[in] xpos The x-coordinate of the upper-left corner of the content area. * @param[in] ypos The y-coordinate of the upper-left corner of the content area. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_PLATFORM_ERROR. * * @remark @wayland There is no way for an application to set the global * position of its windows, this function will always emit @ref * GLFW_PLATFORM_ERROR. * * @thread_safety This function must only be called from the main thread. * * @sa @ref window_pos * @sa @ref glfwGetWindowPos * * @since Added in version 1.0. * @glfw3 Added window handle parameter. * * @ingroup window */ GLFWAPI void glfwSetWindowPos(GLFWwindow* window, int xpos, int ypos); /*! @brief Retrieves the size of the content area of the specified window. * * This function retrieves the size, in screen coordinates, of the content area * of the specified window. If you wish to retrieve the size of the * framebuffer of the window in pixels, see @ref glfwGetFramebufferSize. * * Any or all of the size arguments may be `NULL`. If an error occurs, all * non-`NULL` size arguments will be set to zero. * * @param[in] window The window whose size to retrieve. * @param[out] width Where to store the width, in screen coordinates, of the * content area, or `NULL`. * @param[out] height Where to store the height, in screen coordinates, of the * content area, or `NULL`. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_PLATFORM_ERROR. * * @thread_safety This function must only be called from the main thread. * * @sa @ref window_size * @sa @ref glfwSetWindowSize * * @since Added in version 1.0. * @glfw3 Added window handle parameter. * * @ingroup window */ GLFWAPI void glfwGetWindowSize(GLFWwindow* window, int* width, int* height); /*! @brief Sets the size limits of the specified window. * * This function sets the size limits of the content area of the specified * window. If the window is full screen, the size limits only take effect * once it is made windowed. If the window is not resizable, this function * does nothing. * * The size limits are applied immediately to a windowed mode window and may * cause it to be resized. * * The maximum dimensions must be greater than or equal to the minimum * dimensions and all must be greater than or equal to zero. * * @param[in] window The window to set limits for. * @param[in] minwidth The minimum width, in screen coordinates, of the content * area, or `GLFW_DONT_CARE`. * @param[in] minheight The minimum height, in screen coordinates, of the * content area, or `GLFW_DONT_CARE`. * @param[in] maxwidth The maximum width, in screen coordinates, of the content * area, or `GLFW_DONT_CARE`. * @param[in] maxheight The maximum height, in screen coordinates, of the * content area, or `GLFW_DONT_CARE`. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref * GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR. * * @remark If you set size limits and an aspect ratio that conflict, the * results are undefined. * * @remark @wayland The size limits will not be applied until the window is * actually resized, either by the user or by the compositor. * * @thread_safety This function must only be called from the main thread. * * @sa @ref window_sizelimits * @sa @ref glfwSetWindowAspectRatio * * @since Added in version 3.2. * * @ingroup window */ GLFWAPI void glfwSetWindowSizeLimits(GLFWwindow* window, int minwidth, int minheight, int maxwidth, int maxheight); /*! @brief Sets the aspect ratio of the specified window. * * This function sets the required aspect ratio of the content area of the * specified window. If the window is full screen, the aspect ratio only takes * effect once it is made windowed. If the window is not resizable, this * function does nothing. * * The aspect ratio is specified as a numerator and a denominator and both * values must be greater than zero. For example, the common 16:9 aspect ratio * is specified as 16 and 9, respectively. * * If the numerator and denominator is set to `GLFW_DONT_CARE` then the aspect * ratio limit is disabled. * * The aspect ratio is applied immediately to a windowed mode window and may * cause it to be resized. * * @param[in] window The window to set limits for. * @param[in] numer The numerator of the desired aspect ratio, or * `GLFW_DONT_CARE`. * @param[in] denom The denominator of the desired aspect ratio, or * `GLFW_DONT_CARE`. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref * GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR. * * @remark If you set size limits and an aspect ratio that conflict, the * results are undefined. * * @remark @wayland The aspect ratio will not be applied until the window is * actually resized, either by the user or by the compositor. * * @thread_safety This function must only be called from the main thread. * * @sa @ref window_sizelimits * @sa @ref glfwSetWindowSizeLimits * * @since Added in version 3.2. * * @ingroup window */ GLFWAPI void glfwSetWindowAspectRatio(GLFWwindow* window, int numer, int denom); /*! @brief Sets the size of the content area of the specified window. * * This function sets the size, in screen coordinates, of the content area of * the specified window. * * For full screen windows, this function updates the resolution of its desired * video mode and switches to the video mode closest to it, without affecting * the window's context. As the context is unaffected, the bit depths of the * framebuffer remain unchanged. * * If you wish to update the refresh rate of the desired video mode in addition * to its resolution, see @ref glfwSetWindowMonitor. * * The window manager may put limits on what sizes are allowed. GLFW cannot * and should not override these limits. * * @param[in] window The window to resize. * @param[in] width The desired width, in screen coordinates, of the window * content area. * @param[in] height The desired height, in screen coordinates, of the window * content area. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_PLATFORM_ERROR. * * @remark @wayland A full screen window will not attempt to change the mode, * no matter what the requested size. * * @thread_safety This function must only be called from the main thread. * * @sa @ref window_size * @sa @ref glfwGetWindowSize * @sa @ref glfwSetWindowMonitor * * @since Added in version 1.0. * @glfw3 Added window handle parameter. * * @ingroup window */ GLFWAPI void glfwSetWindowSize(GLFWwindow* window, int width, int height); /*! @brief Retrieves the size of the framebuffer of the specified window. * * This function retrieves the size, in pixels, of the framebuffer of the * specified window. If you wish to retrieve the size of the window in screen * coordinates, see @ref glfwGetWindowSize. * * Any or all of the size arguments may be `NULL`. If an error occurs, all * non-`NULL` size arguments will be set to zero. * * @param[in] window The window whose framebuffer to query. * @param[out] width Where to store the width, in pixels, of the framebuffer, * or `NULL`. * @param[out] height Where to store the height, in pixels, of the framebuffer, * or `NULL`. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_PLATFORM_ERROR. * * @thread_safety This function must only be called from the main thread. * * @sa @ref window_fbsize * @sa @ref glfwSetFramebufferSizeCallback * * @since Added in version 3.0. * * @ingroup window */ GLFWAPI void glfwGetFramebufferSize(GLFWwindow* window, int* width, int* height); /*! @brief Retrieves the size of the frame of the window. * * This function retrieves the size, in screen coordinates, of each edge of the * frame of the specified window. This size includes the title bar, if the * window has one. The size of the frame may vary depending on the * [window-related hints](@ref window_hints_wnd) used to create it. * * Because this function retrieves the size of each window frame edge and not * the offset along a particular coordinate axis, the retrieved values will * always be zero or positive. * * Any or all of the size arguments may be `NULL`. If an error occurs, all * non-`NULL` size arguments will be set to zero. * * @param[in] window The window whose frame size to query. * @param[out] left Where to store the size, in screen coordinates, of the left * edge of the window frame, or `NULL`. * @param[out] top Where to store the size, in screen coordinates, of the top * edge of the window frame, or `NULL`. * @param[out] right Where to store the size, in screen coordinates, of the * right edge of the window frame, or `NULL`. * @param[out] bottom Where to store the size, in screen coordinates, of the * bottom edge of the window frame, or `NULL`. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_PLATFORM_ERROR. * * @thread_safety This function must only be called from the main thread. * * @sa @ref window_size * * @since Added in version 3.1. * * @ingroup window */ GLFWAPI void glfwGetWindowFrameSize(GLFWwindow* window, int* left, int* top, int* right, int* bottom); /*! @brief Retrieves the content scale for the specified window. * * This function retrieves the content scale for the specified window. The * content scale is the ratio between the current DPI and the platform's * default DPI. This is especially important for text and any UI elements. If * the pixel dimensions of your UI scaled by this look appropriate on your * machine then it should appear at a reasonable size on other machines * regardless of their DPI and scaling settings. This relies on the system DPI * and scaling settings being somewhat correct. * * On systems where each monitors can have its own content scale, the window * content scale will depend on which monitor the system considers the window * to be on. * * @param[in] window The window to query. * @param[out] xscale Where to store the x-axis content scale, or `NULL`. * @param[out] yscale Where to store the y-axis content scale, or `NULL`. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_PLATFORM_ERROR. * * @thread_safety This function must only be called from the main thread. * * @sa @ref window_scale * @sa @ref glfwSetWindowContentScaleCallback * @sa @ref glfwGetMonitorContentScale * * @since Added in version 3.3. * * @ingroup window */ GLFWAPI void glfwGetWindowContentScale(GLFWwindow* window, float* xscale, float* yscale); /*! @brief Returns the opacity of the whole window. * * This function returns the opacity of the window, including any decorations. * * The opacity (or alpha) value is a positive finite number between zero and * one, where zero is fully transparent and one is fully opaque. If the system * does not support whole window transparency, this function always returns one. * * The initial opacity value for newly created windows is one. * * @param[in] window The window to query. * @return The opacity value of the specified window. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_PLATFORM_ERROR. * * @thread_safety This function must only be called from the main thread. * * @sa @ref window_transparency * @sa @ref glfwSetWindowOpacity * * @since Added in version 3.3. * * @ingroup window */ GLFWAPI float glfwGetWindowOpacity(GLFWwindow* window); /*! @brief Sets the opacity of the whole window. * * This function sets the opacity of the window, including any decorations. * * The opacity (or alpha) value is a positive finite number between zero and * one, where zero is fully transparent and one is fully opaque. * * The initial opacity value for newly created windows is one. * * A window created with framebuffer transparency may not use whole window * transparency. The results of doing this are undefined. * * @param[in] window The window to set the opacity for. * @param[in] opacity The desired opacity of the specified window. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_PLATFORM_ERROR. * * @thread_safety This function must only be called from the main thread. * * @sa @ref window_transparency * @sa @ref glfwGetWindowOpacity * * @since Added in version 3.3. * * @ingroup window */ GLFWAPI void glfwSetWindowOpacity(GLFWwindow* window, float opacity); /*! @brief Iconifies the specified window. * * This function iconifies (minimizes) the specified window if it was * 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. * * @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 * @sa @ref glfwRestoreWindow * @sa @ref glfwMaximizeWindow * * @since Added in version 2.1. * @glfw3 Added window handle parameter. * * @ingroup window */ GLFWAPI void glfwIconifyWindow(GLFWwindow* window); /*! @brief Restores the specified window. * * This function restores the specified window if it was previously iconified * (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. * * @param[in] window The window to restore. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_PLATFORM_ERROR. * * @thread_safety This function must only be called from the main thread. * * @sa @ref window_iconify * @sa @ref glfwIconifyWindow * @sa @ref glfwMaximizeWindow * * @since Added in version 2.1. * @glfw3 Added window handle parameter. * * @ingroup window */ GLFWAPI void glfwRestoreWindow(GLFWwindow* window); /*! @brief Maximizes the specified window. * * This function maximizes the specified window if it was previously not * maximized. If the window is already maximized, this function does nothing. * * If the specified window is a full screen window, this function does nothing. * * @param[in] window The window to maximize. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_PLATFORM_ERROR. * * @par Thread Safety * This function may only be called from the main thread. * * @sa @ref window_iconify * @sa @ref glfwIconifyWindow * @sa @ref glfwRestoreWindow * * @since Added in GLFW 3.2. * * @ingroup window */ GLFWAPI void glfwMaximizeWindow(GLFWwindow* window); /*! @brief Makes the specified window visible. * * This function makes the specified window visible if it was previously * hidden. If the window is already visible or is in full screen mode, this * function does nothing. * * By default, windowed mode windows are focused when shown * Set the [GLFW_FOCUS_ON_SHOW](@ref GLFW_FOCUS_ON_SHOW_hint) window hint * to change this behavior for all newly created windows, or change the * behavior for an existing window with @ref glfwSetWindowAttrib. * * @param[in] window The window to make visible. * * @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 * @sa @ref glfwHideWindow * * @since Added in version 3.0. * * @ingroup window */ GLFWAPI void glfwShowWindow(GLFWwindow* window); /*! @brief Hides the specified window. * * This function hides the specified window if it was previously visible. If * the window is already hidden or is in full screen mode, this function does * nothing. * * @param[in] window The window to hide. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_PLATFORM_ERROR. * * @thread_safety This function must only be called from the main thread. * * @sa @ref window_hide * @sa @ref glfwShowWindow * * @since Added in version 3.0. * * @ingroup window */ GLFWAPI void glfwHideWindow(GLFWwindow* window); /*! @brief Brings the specified window to front and sets input focus. * * This function brings the specified window to front and sets input focus. * The window should already be visible and not iconified. * * By default, both windowed and full screen mode windows are focused when * initially created. Set the [GLFW_FOCUSED](@ref GLFW_FOCUSED_hint) to * disable this behavior. * * Also by default, windowed mode windows are focused when shown * with @ref glfwShowWindow. Set the * [GLFW_FOCUS_ON_SHOW](@ref GLFW_FOCUS_ON_SHOW_hint) to disable this behavior. * * __Do not use this function__ to steal focus from other applications unless * you are certain that is what the user wants. Focus stealing can be * extremely disruptive. * * For a less disruptive way of getting the user's attention, see * [attention requests](@ref window_attention). * * @param[in] window The window to give input focus. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_PLATFORM_ERROR. * * @remark @wayland It is not possible for an application to bring its windows * to front, this function will always emit @ref GLFW_PLATFORM_ERROR. * * @thread_safety This function must only be called from the main thread. * * @sa @ref window_focus * @sa @ref window_attention * * @since Added in version 3.2. * * @ingroup window */ GLFWAPI void glfwFocusWindow(GLFWwindow* window); /*! @brief Requests user attention to the specified window. * * This function requests user attention to the specified window. On * platforms where this is not supported, attention is requested to the * application as a whole. * * Once the user has given attention, usually by focusing the window or * application, the system will end the request automatically. * * @param[in] window The window to request attention to. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_PLATFORM_ERROR. * * @remark @macos Attention is requested to the application as a whole, not the * specific window. * * @thread_safety This function must only be called from the main thread. * * @sa @ref window_attention * * @since Added in version 3.3. * * @ingroup window */ GLFWAPI void glfwRequestWindowAttention(GLFWwindow* window); /*! @brief Returns the monitor that the window uses for full screen mode. * * This function returns the handle of the monitor that the specified window is * in full screen on. * * @param[in] window The window to query. * @return The monitor, or `NULL` if the window is in windowed mode or an * [error](@ref error_handling) occurred. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function must only be called from the main thread. * * @sa @ref window_monitor * @sa @ref glfwSetWindowMonitor * * @since Added in version 3.0. * * @ingroup window */ GLFWAPI GLFWmonitor* glfwGetWindowMonitor(GLFWwindow* window); /*! @brief Sets the mode, monitor, video mode and placement of a window. * * This function sets the monitor that the window uses for full screen mode or, * if the monitor is `NULL`, makes it windowed mode. * * When setting a monitor, this function updates the width, height and refresh * rate of the desired video mode and switches to the video mode closest to it. * The window position is ignored when setting a monitor. * * When the monitor is `NULL`, the position, width and height are used to * place the window content area. The refresh rate is ignored when no monitor * is specified. * * If you only wish to update the resolution of a full screen window or the * size of a windowed mode window, see @ref glfwSetWindowSize. * * When a window transitions from full screen to windowed mode, this function * restores any previous window settings such as whether it is decorated, * floating, resizable, has size or aspect ratio limits, etc. * * @param[in] window The window whose monitor, size or video mode to set. * @param[in] monitor The desired monitor, or `NULL` to set windowed mode. * @param[in] xpos The desired x-coordinate of the upper-left corner of the * content area. * @param[in] ypos The desired y-coordinate of the upper-left corner of the * content area. * @param[in] width The desired with, in screen coordinates, of the content * area or video mode. * @param[in] height The desired height, in screen coordinates, of the content * area or video mode. * @param[in] refreshRate The desired refresh rate, in Hz, of the video mode, * or `GLFW_DONT_CARE`. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_PLATFORM_ERROR. * * @remark The OpenGL or OpenGL ES context will not be destroyed or otherwise * affected by any resizing or mode switching, although you may need to update * your viewport if the framebuffer size has changed. * * @remark @wayland The desired window position is ignored, as there is no way * for an application to set this property. * * @remark @wayland Setting the window to full screen will not attempt to * change the mode, no matter what the requested size or refresh rate. * * @thread_safety This function must only be called from the main thread. * * @sa @ref window_monitor * @sa @ref window_full_screen * @sa @ref glfwGetWindowMonitor * @sa @ref glfwSetWindowSize * * @since Added in version 3.2. * * @ingroup window */ GLFWAPI void glfwSetWindowMonitor(GLFWwindow* window, GLFWmonitor* monitor, int xpos, int ypos, int width, int height, int refreshRate); /*! @brief Returns an attribute of the specified window. * * This function returns the value of an attribute of the specified window or * its OpenGL or OpenGL ES context. * * @param[in] window The window to query. * @param[in] attrib The [window attribute](@ref window_attribs) whose value to * return. * @return The value of the attribute, or zero if an * [error](@ref error_handling) occurred. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. * * @remark Framebuffer related hints are not window attributes. See @ref * window_attribs_fb for more information. * * @remark Zero is a valid value for many window and context related * attributes so you cannot use a return value of zero as an indication of * errors. However, this function should not fail as long as it is passed * valid arguments and the library has been [initialized](@ref intro_init). * * @thread_safety This function must only be called from the main thread. * * @sa @ref window_attribs * @sa @ref glfwSetWindowAttrib * * @since Added in version 3.0. Replaces `glfwGetWindowParam` and * `glfwGetGLVersion`. * * @ingroup window */ GLFWAPI int glfwGetWindowAttrib(GLFWwindow* window, int attrib); /*! @brief Sets an attribute of the specified window. * * This function sets the value of an attribute of the specified window. * * The supported attributes are [GLFW_DECORATED](@ref GLFW_DECORATED_attrib), * [GLFW_RESIZABLE](@ref GLFW_RESIZABLE_attrib), * [GLFW_FLOATING](@ref GLFW_FLOATING_attrib), * [GLFW_AUTO_ICONIFY](@ref GLFW_AUTO_ICONIFY_attrib) and * [GLFW_FOCUS_ON_SHOW](@ref GLFW_FOCUS_ON_SHOW_attrib). * * Some of these attributes are ignored for full screen windows. The new * value will take effect if the window is later made windowed. * * Some of these attributes are ignored for windowed mode windows. The new * value will take effect if the window is later made full screen. * * @param[in] window The window to set the attribute for. * @param[in] attrib A supported window attribute. * @param[in] value `GLFW_TRUE` or `GLFW_FALSE`. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref * GLFW_INVALID_ENUM, @ref GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR. * * @remark Calling @ref glfwGetWindowAttrib will always return the latest * value, even if that value is ignored by the current mode of the window. * * @thread_safety This function must only be called from the main thread. * * @sa @ref window_attribs * @sa @ref glfwGetWindowAttrib * * @since Added in version 3.3. * * @ingroup window */ GLFWAPI void glfwSetWindowAttrib(GLFWwindow* window, int attrib, int value); /*! @brief Sets the user pointer of the specified window. * * This function sets the user-defined pointer of the specified window. The * current value is retained until the window is destroyed. The initial value * is `NULL`. * * @param[in] window The window whose pointer to set. * @param[in] pointer The new value. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function may be called from any thread. Access is not * synchronized. * * @sa @ref window_userptr * @sa @ref glfwGetWindowUserPointer * * @since Added in version 3.0. * * @ingroup window */ GLFWAPI void glfwSetWindowUserPointer(GLFWwindow* window, void* pointer); /*! @brief Returns the user pointer of the specified window. * * This function returns the current value of the user-defined pointer of the * specified window. The initial value is `NULL`. * * @param[in] window The window whose pointer to return. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function may be called from any thread. Access is not * synchronized. * * @sa @ref window_userptr * @sa @ref glfwSetWindowUserPointer * * @since Added in version 3.0. * * @ingroup window */ GLFWAPI void* glfwGetWindowUserPointer(GLFWwindow* window); /*! @brief Sets the position callback for the specified window. * * This function sets the position callback of the specified window, which is * called when the window is moved. The callback is provided with the * position, in screen coordinates, of the upper-left corner of the content * area of the window. * * @param[in] window The window whose callback to set. * @param[in] callback The new callback, or `NULL` to remove the currently set * callback. * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * * @callback_signature * @code * void function_name(GLFWwindow* window, int xpos, int ypos) * @endcode * For more information about the callback parameters, see the * [function pointer type](@ref GLFWwindowposfun). * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @remark @wayland This callback will never be called, as there is no way for * an application to know its global position. * * @thread_safety This function must only be called from the main thread. * * @sa @ref window_pos * * @since Added in version 3.0. * * @ingroup window */ GLFWAPI GLFWwindowposfun glfwSetWindowPosCallback(GLFWwindow* window, GLFWwindowposfun callback); /*! @brief Sets the size callback for the specified window. * * This function sets the size callback of the specified window, which is * called when the window is resized. The callback is provided with the size, * in screen coordinates, of the content area of the window. * * @param[in] window The window whose callback to set. * @param[in] callback The new callback, or `NULL` to remove the currently set * callback. * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * * @callback_signature * @code * void function_name(GLFWwindow* window, int width, int height) * @endcode * For more information about the callback parameters, see the * [function pointer type](@ref GLFWwindowsizefun). * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function must only be called from the main thread. * * @sa @ref window_size * * @since Added in version 1.0. * @glfw3 Added window handle parameter and return value. * * @ingroup window */ GLFWAPI GLFWwindowsizefun glfwSetWindowSizeCallback(GLFWwindow* window, GLFWwindowsizefun callback); /*! @brief Sets the close callback for the specified window. * * This function sets the close callback of the specified window, which is * called when the user attempts to close the window, for example by clicking * the close widget in the title bar. * * The close flag is set before this callback is called, but you can modify it * at any time with @ref glfwSetWindowShouldClose. * * The close callback is not triggered by @ref glfwDestroyWindow. * * @param[in] window The window whose callback to set. * @param[in] callback The new callback, or `NULL` to remove the currently set * callback. * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * * @callback_signature * @code * void function_name(GLFWwindow* window) * @endcode * For more information about the callback parameters, see the * [function pointer type](@ref GLFWwindowclosefun). * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @remark @macos Selecting Quit from the application menu will trigger the * close callback for all windows. * * @thread_safety This function must only be called from the main thread. * * @sa @ref window_close * * @since Added in version 2.5. * @glfw3 Added window handle parameter and return value. * * @ingroup window */ GLFWAPI GLFWwindowclosefun glfwSetWindowCloseCallback(GLFWwindow* window, GLFWwindowclosefun callback); /*! @brief Sets the refresh callback for the specified window. * * This function sets the refresh callback of the specified window, which is * called when the content area of the window needs to be redrawn, for example * if the window has been exposed after having been covered by another window. * * On compositing window systems such as Aero, Compiz, Aqua or Wayland, where * the window contents are saved off-screen, this callback may be called only * very infrequently or never at all. * * @param[in] window The window whose callback to set. * @param[in] callback The new callback, or `NULL` to remove the currently set * callback. * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * * @callback_signature * @code * void function_name(GLFWwindow* window); * @endcode * For more information about the callback parameters, see the * [function pointer type](@ref GLFWwindowrefreshfun). * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function must only be called from the main thread. * * @sa @ref window_refresh * * @since Added in version 2.5. * @glfw3 Added window handle parameter and return value. * * @ingroup window */ GLFWAPI GLFWwindowrefreshfun glfwSetWindowRefreshCallback(GLFWwindow* window, GLFWwindowrefreshfun callback); /*! @brief Sets the focus callback for the specified window. * * This function sets the focus callback of the specified window, which is * called when the window gains or loses input focus. * * After the focus callback is called for a window that lost input focus, * synthetic key and mouse button release events will be generated for all such * that had been pressed. For more information, see @ref glfwSetKeyCallback * and @ref glfwSetMouseButtonCallback. * * @param[in] window The window whose callback to set. * @param[in] callback The new callback, or `NULL` to remove the currently set * callback. * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * * @callback_signature * @code * void function_name(GLFWwindow* window, int focused) * @endcode * For more information about the callback parameters, see the * [function pointer type](@ref GLFWwindowfocusfun). * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function must only be called from the main thread. * * @sa @ref window_focus * * @since Added in version 3.0. * * @ingroup window */ GLFWAPI GLFWwindowfocusfun glfwSetWindowFocusCallback(GLFWwindow* window, GLFWwindowfocusfun callback); /*! @brief Sets the iconify callback for the specified window. * * This function sets the iconification callback of the specified window, which * is called when the window is iconified or restored. * * @param[in] window The window whose callback to set. * @param[in] callback The new callback, or `NULL` to remove the currently set * callback. * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * * @callback_signature * @code * void function_name(GLFWwindow* window, int iconified) * @endcode * For more information about the callback parameters, see the * [function pointer type](@ref GLFWwindowiconifyfun). * * @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. * * @thread_safety This function must only be called from the main thread. * * @sa @ref window_iconify * * @since Added in version 3.0. * * @ingroup window */ GLFWAPI GLFWwindowiconifyfun glfwSetWindowIconifyCallback(GLFWwindow* window, GLFWwindowiconifyfun callback); /*! @brief Sets the maximize callback for the specified window. * * This function sets the maximization callback of the specified window, which * is called when the window is maximized or restored. * * @param[in] window The window whose callback to set. * @param[in] callback The new callback, or `NULL` to remove the currently set * callback. * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * * @callback_signature * @code * void function_name(GLFWwindow* window, int maximized) * @endcode * For more information about the callback parameters, see the * [function pointer type](@ref GLFWwindowmaximizefun). * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function must only be called from the main thread. * * @sa @ref window_maximize * * @since Added in version 3.3. * * @ingroup window */ GLFWAPI GLFWwindowmaximizefun glfwSetWindowMaximizeCallback(GLFWwindow* window, GLFWwindowmaximizefun callback); /*! @brief Sets the framebuffer resize callback for the specified window. * * This function sets the framebuffer resize callback of the specified window, * which is called when the framebuffer of the specified window is resized. * * @param[in] window The window whose callback to set. * @param[in] callback The new callback, or `NULL` to remove the currently set * callback. * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * * @callback_signature * @code * void function_name(GLFWwindow* window, int width, int height) * @endcode * For more information about the callback parameters, see the * [function pointer type](@ref GLFWframebuffersizefun). * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function must only be called from the main thread. * * @sa @ref window_fbsize * * @since Added in version 3.0. * * @ingroup window */ GLFWAPI GLFWframebuffersizefun glfwSetFramebufferSizeCallback(GLFWwindow* window, GLFWframebuffersizefun callback); /*! @brief Sets the window content scale callback for the specified window. * * This function sets the window content scale callback of the specified window, * which is called when the content scale of the specified window changes. * * @param[in] window The window whose callback to set. * @param[in] callback The new callback, or `NULL` to remove the currently set * callback. * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * * @callback_signature * @code * void function_name(GLFWwindow* window, float xscale, float yscale) * @endcode * For more information about the callback parameters, see the * [function pointer type](@ref GLFWwindowcontentscalefun). * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function must only be called from the main thread. * * @sa @ref window_scale * @sa @ref glfwGetWindowContentScale * * @since Added in version 3.3. * * @ingroup window */ GLFWAPI GLFWwindowcontentscalefun glfwSetWindowContentScaleCallback(GLFWwindow* window, GLFWwindowcontentscalefun callback); /*! @brief Processes all pending events. * * This function processes only those events that are already in the event * queue and then returns immediately. Processing events will cause the window * and input callbacks associated with those events to be called. * * On some platforms, a window move, resize or menu operation will cause event * processing to block. This is due to how event processing is designed on * those platforms. You can use the * [window refresh callback](@ref window_refresh) to redraw the contents of * your window when necessary during such operations. * * Do not assume that callbacks you set will _only_ be called in response to * event processing functions like this one. While it is necessary to poll for * events, window systems that require GLFW to register callbacks of its own * can pass events to GLFW in response to many window system function calls. * GLFW will pass those events on to the application callbacks before * returning. * * Event processing is not required for joystick input to work. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_PLATFORM_ERROR. * * @reentrancy This function must not be called from a callback. * * @thread_safety This function must only be called from the main thread. * * @sa @ref events * @sa @ref glfwWaitEvents * @sa @ref glfwWaitEventsTimeout * * @since Added in version 1.0. * * @ingroup window */ GLFWAPI void glfwPollEvents(void); /*! @brief Waits until events are queued and processes them. * * This function puts the calling thread to sleep until at least one event is * available in the event queue. Once one or more events are available, * it behaves exactly like @ref glfwPollEvents, i.e. the events in the queue * are processed and the function then returns immediately. Processing events * will cause the window and input callbacks associated with those events to be * called. * * Since not all events are associated with callbacks, this function may return * without a callback having been called even if you are monitoring all * callbacks. * * On some platforms, a window move, resize or menu operation will cause event * processing to block. This is due to how event processing is designed on * those platforms. You can use the * [window refresh callback](@ref window_refresh) to redraw the contents of * your window when necessary during such operations. * * Do not assume that callbacks you set will _only_ be called in response to * event processing functions like this one. While it is necessary to poll for * events, window systems that require GLFW to register callbacks of its own * can pass events to GLFW in response to many window system function calls. * GLFW will pass those events on to the application callbacks before * returning. * * Event processing is not required for joystick input to work. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_PLATFORM_ERROR. * * @reentrancy This function must not be called from a callback. * * @thread_safety This function must only be called from the main thread. * * @sa @ref events * @sa @ref glfwPollEvents * @sa @ref glfwWaitEventsTimeout * * @since Added in version 2.5. * * @ingroup window */ GLFWAPI void glfwWaitEvents(void); /*! @brief Waits with timeout until events are queued and processes them. * * This function puts the calling thread to sleep until at least one event is * available in the event queue, or until the specified timeout is reached. If * one or more events are available, it behaves exactly like @ref * glfwPollEvents, i.e. the events in the queue are processed and the function * then returns immediately. Processing events will cause the window and input * callbacks associated with those events to be called. * * The timeout value must be a positive finite number. * * Since not all events are associated with callbacks, this function may return * without a callback having been called even if you are monitoring all * callbacks. * * On some platforms, a window move, resize or menu operation will cause event * processing to block. This is due to how event processing is designed on * those platforms. You can use the * [window refresh callback](@ref window_refresh) to redraw the contents of * your window when necessary during such operations. * * Do not assume that callbacks you set will _only_ be called in response to * event processing functions like this one. While it is necessary to poll for * events, window systems that require GLFW to register callbacks of its own * can pass events to GLFW in response to many window system function calls. * GLFW will pass those events on to the application callbacks before * returning. * * Event processing is not required for joystick input to work. * * @param[in] timeout The maximum amount of time, in seconds, to wait. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref * GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR. * * @reentrancy This function must not be called from a callback. * * @thread_safety This function must only be called from the main thread. * * @sa @ref events * @sa @ref glfwPollEvents * @sa @ref glfwWaitEvents * * @since Added in version 3.2. * * @ingroup window */ GLFWAPI void glfwWaitEventsTimeout(double timeout); /*! @brief Posts an empty event to the event queue. * * This function posts an empty event from the current thread to the event * queue, causing @ref glfwWaitEvents or @ref glfwWaitEventsTimeout to return. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_PLATFORM_ERROR. * * @thread_safety This function may be called from any thread. * * @sa @ref events * @sa @ref glfwWaitEvents * @sa @ref glfwWaitEventsTimeout * * @since Added in version 3.1. * * @ingroup window */ GLFWAPI void glfwPostEmptyEvent(void); /*! @brief Returns the value of an input option for the specified window. * * This function returns the value of an input option for the specified window. * The mode must be one of @ref GLFW_CURSOR, @ref GLFW_STICKY_KEYS, * @ref GLFW_STICKY_MOUSE_BUTTONS, @ref GLFW_LOCK_KEY_MODS or * @ref GLFW_RAW_MOUSE_MOTION. * * @param[in] window The window to query. * @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS`, * `GLFW_STICKY_MOUSE_BUTTONS`, `GLFW_LOCK_KEY_MODS` or * `GLFW_RAW_MOUSE_MOTION`. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_INVALID_ENUM. * * @thread_safety This function must only be called from the main thread. * * @sa @ref glfwSetInputMode * * @since Added in version 3.0. * * @ingroup input */ GLFWAPI int glfwGetInputMode(GLFWwindow* window, int mode); /*! @brief Sets an input option for the specified window. * * This function sets an input mode option for the specified window. The mode * must be one of @ref GLFW_CURSOR, @ref GLFW_STICKY_KEYS, * @ref GLFW_STICKY_MOUSE_BUTTONS, @ref GLFW_LOCK_KEY_MODS or * @ref GLFW_RAW_MOUSE_MOTION. * * If the mode is `GLFW_CURSOR`, the value must be one of the following cursor * modes: * - `GLFW_CURSOR_NORMAL` makes the cursor visible and behaving normally. * - `GLFW_CURSOR_HIDDEN` makes the cursor invisible when it is over the * content area of the window but does not restrict the cursor from leaving. * - `GLFW_CURSOR_DISABLED` hides and grabs the cursor, providing virtual * and unlimited cursor movement. This is useful for implementing for * example 3D camera controls. * * If the mode is `GLFW_STICKY_KEYS`, the value must be either `GLFW_TRUE` to * enable sticky keys, or `GLFW_FALSE` to disable it. If sticky keys are * enabled, a key press will ensure that @ref glfwGetKey returns `GLFW_PRESS` * the next time it is called even if the key had been released before the * call. This is useful when you are only interested in whether keys have been * pressed but not when or in which order. * * If the mode is `GLFW_STICKY_MOUSE_BUTTONS`, the value must be either * `GLFW_TRUE` to enable sticky mouse buttons, or `GLFW_FALSE` to disable it. * If sticky mouse buttons are enabled, a mouse button press will ensure that * @ref glfwGetMouseButton returns `GLFW_PRESS` the next time it is called even * if the mouse button had been released before the call. This is useful when * you are only interested in whether mouse buttons have been pressed but not * when or in which order. * * If the mode is `GLFW_LOCK_KEY_MODS`, the value must be either `GLFW_TRUE` to * enable lock key modifier bits, or `GLFW_FALSE` to disable them. If enabled, * callbacks that receive modifier bits will also have the @ref * GLFW_MOD_CAPS_LOCK bit set when the event was generated with Caps Lock on, * and the @ref GLFW_MOD_NUM_LOCK bit when Num Lock was on. * * If the mode is `GLFW_RAW_MOUSE_MOTION`, the value must be either `GLFW_TRUE` * to enable raw (unscaled and unaccelerated) mouse motion when the cursor is * disabled, or `GLFW_FALSE` to disable it. If raw motion is not supported, * attempting to set this will emit @ref GLFW_PLATFORM_ERROR. Call @ref * glfwRawMouseMotionSupported to check for support. * * @param[in] window The window whose input mode to set. * @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS`, * `GLFW_STICKY_MOUSE_BUTTONS`, `GLFW_LOCK_KEY_MODS` or * `GLFW_RAW_MOUSE_MOTION`. * @param[in] value The new value of the specified input mode. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. * * @thread_safety This function must only be called from the main thread. * * @sa @ref glfwGetInputMode * * @since Added in version 3.0. Replaces `glfwEnable` and `glfwDisable`. * * @ingroup input */ GLFWAPI void glfwSetInputMode(GLFWwindow* window, int mode, int value); /*! @brief Returns whether raw mouse motion is supported. * * This function returns whether raw mouse motion is supported on the current * system. This status does not change after GLFW has been initialized so you * only need to check this once. If you attempt to enable raw motion on * a system that does not support it, @ref GLFW_PLATFORM_ERROR will be emitted. * * Raw mouse motion is closer to the actual motion of the mouse across * a surface. It is not affected by the scaling and acceleration applied to * the motion of the desktop cursor. That processing is suitable for a cursor * while raw motion is better for controlling for example a 3D camera. Because * of this, raw mouse motion is only provided when the cursor is disabled. * * @return `GLFW_TRUE` if raw mouse motion is supported on the current machine, * or `GLFW_FALSE` otherwise. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function must only be called from the main thread. * * @sa @ref raw_mouse_motion * @sa @ref glfwSetInputMode * * @since Added in version 3.3. * * @ingroup input */ GLFWAPI int glfwRawMouseMotionSupported(void); /*! @brief Returns the layout-specific name of the specified printable key. * * This function returns the name of the specified printable key, encoded as * UTF-8. This is typically the character that key would produce without any * modifier keys, intended for displaying key bindings to the user. For dead * keys, it is typically the diacritic it would add to a character. * * __Do not use this function__ for [text input](@ref input_char). You will * break text input for many languages even if it happens to work for yours. * * If the key is `GLFW_KEY_UNKNOWN`, the scancode is used to identify the key, * otherwise the scancode is ignored. If you specify a non-printable key, or * `GLFW_KEY_UNKNOWN` and a scancode that maps to a non-printable key, this * function returns `NULL` but does not emit an error. * * This behavior allows you to always pass in the arguments in the * [key callback](@ref input_key) without modification. * * The printable keys are: * - `GLFW_KEY_APOSTROPHE` * - `GLFW_KEY_COMMA` * - `GLFW_KEY_MINUS` * - `GLFW_KEY_PERIOD` * - `GLFW_KEY_SLASH` * - `GLFW_KEY_SEMICOLON` * - `GLFW_KEY_EQUAL` * - `GLFW_KEY_LEFT_BRACKET` * - `GLFW_KEY_RIGHT_BRACKET` * - `GLFW_KEY_BACKSLASH` * - `GLFW_KEY_WORLD_1` * - `GLFW_KEY_WORLD_2` * - `GLFW_KEY_0` to `GLFW_KEY_9` * - `GLFW_KEY_A` to `GLFW_KEY_Z` * - `GLFW_KEY_KP_0` to `GLFW_KEY_KP_9` * - `GLFW_KEY_KP_DECIMAL` * - `GLFW_KEY_KP_DIVIDE` * - `GLFW_KEY_KP_MULTIPLY` * - `GLFW_KEY_KP_SUBTRACT` * - `GLFW_KEY_KP_ADD` * - `GLFW_KEY_KP_EQUAL` * * Names for printable keys depend on keyboard layout, while names for * non-printable keys are the same across layouts but depend on the application * language and should be localized along with other user interface text. * * @param[in] key The key to query, or `GLFW_KEY_UNKNOWN`. * @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. * * @remark The contents of the returned string may change when a keyboard * layout change event is received. * * @pointer_lifetime The returned string is allocated and freed by GLFW. You * should not free it yourself. It is valid until the library is terminated. * * @thread_safety This function must only be called from the main thread. * * @sa @ref input_key_name * * @since Added in version 3.2. * * @ingroup input */ GLFWAPI const char* glfwGetKeyName(int key, int scancode); GLFWAPI const char* glfwGetKeys(GLFWwindow* handle); //<< @r-lyeh added /*! @brief Returns the platform-specific scancode of the specified key. * * 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`. * * @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. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. * * @thread_safety This function may be called from any thread. * * @sa @ref input_key * * @since Added in version 3.3. * * @ingroup input */ GLFWAPI int glfwGetKeyScancode(int key); /*! @brief Returns the last reported state of a keyboard key for the specified * window. * * 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. * * 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 * that key has already been released. * * The key functions deal with physical keys, with [key tokens](@ref keys) * named after their use on the standard US keyboard layout. If you want to * input text, use the Unicode character callback instead. * * The [modifier key bit masks](@ref mods) are not key tokens and cannot be * used with this function. * * __Do not use this function__ to implement [text input](@ref input_char). * * @param[in] window The desired window. * @param[in] key The desired [keyboard key](@ref keys). `GLFW_KEY_UNKNOWN` is * not a valid key for this function. * @return One of `GLFW_PRESS` or `GLFW_RELEASE`. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_INVALID_ENUM. * * @thread_safety This function must only be called from the main thread. * * @sa @ref input_key * * @since Added in version 1.0. * @glfw3 Added window handle parameter. * * @ingroup input */ GLFWAPI int glfwGetKey(GLFWwindow* window, int key); /*! @brief Returns the last reported state of a mouse button for the specified * window. * * This function returns the last state reported for the specified mouse button * to the specified window. The returned state is one of `GLFW_PRESS` or * `GLFW_RELEASE`. * * If the @ref GLFW_STICKY_MOUSE_BUTTONS input mode is enabled, this function * returns `GLFW_PRESS` the first time you call it for a mouse button that was * pressed, even if that mouse button has already been released. * * @param[in] window The desired window. * @param[in] button The desired [mouse button](@ref buttons). * @return One of `GLFW_PRESS` or `GLFW_RELEASE`. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_INVALID_ENUM. * * @thread_safety This function must only be called from the main thread. * * @sa @ref input_mouse_button * * @since Added in version 1.0. * @glfw3 Added window handle parameter. * * @ingroup input */ GLFWAPI int glfwGetMouseButton(GLFWwindow* window, int button); /*! @brief Retrieves the position of the cursor relative to the content area of * the window. * * This function returns the position of the cursor, in screen coordinates, * relative to the upper-left corner of the content area of the specified * window. * * If the cursor is disabled (with `GLFW_CURSOR_DISABLED`) then the cursor * position is unbounded and limited only by the minimum and maximum values of * a `double`. * * The coordinate can be converted to their integer equivalents with the * `floor` function. Casting directly to an integer type works for positive * coordinates, but fails for negative ones. * * Any or all of the position arguments may be `NULL`. If an error occurs, all * non-`NULL` position arguments will be set to zero. * * @param[in] window The desired window. * @param[out] xpos Where to store the cursor x-coordinate, relative to the * left edge of the content area, or `NULL`. * @param[out] ypos Where to store the cursor y-coordinate, relative to the to * top edge of the content area, or `NULL`. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_PLATFORM_ERROR. * * @thread_safety This function must only be called from the main thread. * * @sa @ref cursor_pos * @sa @ref glfwSetCursorPos * * @since Added in version 3.0. Replaces `glfwGetMousePos`. * * @ingroup input */ GLFWAPI void glfwGetCursorPos(GLFWwindow* window, double* xpos, double* ypos); /*! @brief Sets the position of the cursor, relative to the content area of the * window. * * This function sets the position, in screen coordinates, of the cursor * relative to the upper-left corner of the content area of the specified * window. The window must have input focus. If the window does not have * input focus when this function is called, it fails silently. * * __Do not use this function__ to implement things like camera controls. GLFW * already provides the `GLFW_CURSOR_DISABLED` cursor mode that hides the * cursor, transparently re-centers it and provides unconstrained cursor * motion. See @ref glfwSetInputMode for more information. * * If the cursor mode is `GLFW_CURSOR_DISABLED` then the cursor position is * unconstrained and limited only by the minimum and maximum values of * a `double`. * * @param[in] window The desired window. * @param[in] xpos The desired x-coordinate, relative to the left edge of the * content area. * @param[in] ypos The desired y-coordinate, relative to the top edge of the * content area. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_PLATFORM_ERROR. * * @remark @wayland This function will only work when the cursor mode is * `GLFW_CURSOR_DISABLED`, otherwise it will do nothing. * * @thread_safety This function must only be called from the main thread. * * @sa @ref cursor_pos * @sa @ref glfwGetCursorPos * * @since Added in version 3.0. Replaces `glfwSetMousePos`. * * @ingroup input */ GLFWAPI void glfwSetCursorPos(GLFWwindow* window, double xpos, double ypos); /*! @brief Creates a custom cursor. * * Creates a new custom cursor image that can be set for a window with @ref * glfwSetCursor. The cursor can be destroyed with @ref glfwDestroyCursor. * Any remaining cursors are destroyed by @ref glfwTerminate. * * The pixels are 32-bit, little-endian, non-premultiplied RGBA, i.e. eight * bits per channel with the red channel first. They are arranged canonically * as packed sequential rows, starting from the top-left corner. * * The cursor hotspot is specified in pixels, relative to the upper-left corner * of the cursor image. Like all other coordinate systems in GLFW, the X-axis * points to the right and the Y-axis points down. * * @param[in] image The desired cursor image. * @param[in] xhot The desired x-coordinate, in pixels, of the cursor hotspot. * @param[in] yhot The desired y-coordinate, in pixels, of the cursor hotspot. * @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. * * @pointer_lifetime The specified image data is copied before this function * returns. * * @thread_safety This function must only be called from the main thread. * * @sa @ref cursor_object * @sa @ref glfwDestroyCursor * @sa @ref glfwCreateStandardCursor * * @since Added in version 3.1. * * @ingroup input */ GLFWAPI GLFWcursor* glfwCreateCursor(const GLFWimage* image, int xhot, int yhot); /*! @brief Creates a cursor with a standard shape. * * Returns a cursor with a [standard shape](@ref shapes), that can be set for * a window with @ref glfwSetCursor. * * @param[in] shape One of the [standard shapes](@ref shapes). * @return A new cursor ready to use or `NULL` if an * [error](@ref error_handling) occurred. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. * * @thread_safety This function must only be called from the main thread. * * @sa @ref cursor_object * @sa @ref glfwCreateCursor * * @since Added in version 3.1. * * @ingroup input */ GLFWAPI GLFWcursor* glfwCreateStandardCursor(int shape); /*! @brief Destroys a cursor. * * This function destroys a cursor previously created with @ref * glfwCreateCursor. Any remaining cursors will be destroyed by @ref * glfwTerminate. * * If the specified cursor is current for any window, that window will be * reverted to the default cursor. This does not affect the cursor mode. * * @param[in] cursor The cursor object to destroy. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_PLATFORM_ERROR. * * @reentrancy This function must not be called from a callback. * * @thread_safety This function must only be called from the main thread. * * @sa @ref cursor_object * @sa @ref glfwCreateCursor * * @since Added in version 3.1. * * @ingroup input */ GLFWAPI void glfwDestroyCursor(GLFWcursor* cursor); /*! @brief Sets the cursor for the window. * * This function sets the cursor image to be used when the cursor is over the * content area of the specified window. The set cursor will only be visible * when the [cursor mode](@ref cursor_mode) of the window is * `GLFW_CURSOR_NORMAL`. * * On some platforms, the set cursor may not be visible unless the window also * has input focus. * * @param[in] window The window to set the cursor for. * @param[in] cursor The cursor to set, or `NULL` to switch back to the default * arrow cursor. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_PLATFORM_ERROR. * * @thread_safety This function must only be called from the main thread. * * @sa @ref cursor_object * * @since Added in version 3.1. * * @ingroup input */ GLFWAPI void glfwSetCursor(GLFWwindow* window, GLFWcursor* cursor); /*! @brief Sets the key callback. * * This function sets the key callback of the specified window, which is called * when a key is pressed, repeated or released. * * The key functions deal with physical keys, with layout independent * [key tokens](@ref keys) named after their values in the standard US keyboard * layout. If you want to input text, use the * [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 * [window focus callback](@ref glfwSetWindowFocusCallback) has been called. * * The scancode of a key is specific to that platform or sometimes even to that * machine. Scancodes are intended to allow users to bind keys that don't have * a GLFW key token. Such keys have `key` set to `GLFW_KEY_UNKNOWN`, their * state is not saved and so it cannot be queried with @ref glfwGetKey. * * Sometimes GLFW needs to generate synthetic key events, in which case the * scancode may be zero. * * @param[in] window The window whose callback to set. * @param[in] callback The new key callback, or `NULL` to remove the currently * set callback. * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * * @callback_signature * @code * void function_name(GLFWwindow* window, int key, int scancode, int action, int mods) * @endcode * For more information about the callback parameters, see the * [function pointer type](@ref GLFWkeyfun). * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function must only be called from the main thread. * * @sa @ref input_key * * @since Added in version 1.0. * @glfw3 Added window handle parameter and return value. * * @ingroup input */ GLFWAPI GLFWkeyfun glfwSetKeyCallback(GLFWwindow* window, GLFWkeyfun callback); /*! @brief Sets the Unicode character callback. * * This function sets the character callback of the specified window, which is * called when a Unicode character is input. * * The character callback is intended for Unicode text input. As it deals with * characters, it is keyboard layout dependent, whereas the * [key callback](@ref glfwSetKeyCallback) is not. Characters do not map 1:1 * to physical keys, as a key may produce zero, one or more characters. If you * want to know whether a specific physical key was pressed or released, see * the key callback instead. * * The character callback behaves as system text input normally does and will * not be called if modifier keys are held down that would prevent normal text * input on that platform, for example a Super (Command) key on macOS or Alt key * on Windows. * * @param[in] window The window whose callback to set. * @param[in] callback The new callback, or `NULL` to remove the currently set * callback. * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * * @callback_signature * @code * void function_name(GLFWwindow* window, unsigned int codepoint) * @endcode * For more information about the callback parameters, see the * [function pointer type](@ref GLFWcharfun). * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function must only be called from the main thread. * * @sa @ref input_char * * @since Added in version 2.4. * @glfw3 Added window handle parameter and return value. * * @ingroup input */ GLFWAPI GLFWcharfun glfwSetCharCallback(GLFWwindow* window, GLFWcharfun callback); /*! @brief Sets the Unicode character with modifiers callback. * * This function sets the character with modifiers callback of the specified * window, which is called when a Unicode character is input regardless of what * modifier keys are used. * * The character with modifiers callback is intended for implementing custom * Unicode character input. For regular Unicode text input, see the * [character callback](@ref glfwSetCharCallback). Like the character * callback, the character with modifiers callback deals with characters and is * keyboard layout dependent. Characters do not map 1:1 to physical keys, as * a key may produce zero, one or more characters. If you want to know whether * a specific physical key was pressed or released, see the * [key callback](@ref glfwSetKeyCallback) instead. * * @param[in] window The window whose callback to set. * @param[in] callback The new callback, or `NULL` to remove the currently set * callback. * @return The previously set callback, or `NULL` if no callback was set or an * [error](@ref error_handling) occurred. * * @callback_signature * @code * void function_name(GLFWwindow* window, unsigned int codepoint, int mods) * @endcode * For more information about the callback parameters, see the * [function pointer type](@ref GLFWcharmodsfun). * * @deprecated Scheduled for removal in version 4.0. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function must only be called from the main thread. * * @sa @ref input_char * * @since Added in version 3.1. * * @ingroup input */ GLFWAPI GLFWcharmodsfun glfwSetCharModsCallback(GLFWwindow* window, GLFWcharmodsfun callback); /*! @brief Sets the mouse button callback. * * This function sets the mouse button callback of the specified window, which * is called when a mouse button is pressed or released. * * When a window loses input focus, it will generate synthetic mouse button * release events for all pressed mouse buttons. 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. * * @param[in] window The window whose callback to set. * @param[in] callback The new callback, or `NULL` to remove the currently set * callback. * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * * @callback_signature * @code * void function_name(GLFWwindow* window, int button, int action, int mods) * @endcode * For more information about the callback parameters, see the * [function pointer type](@ref GLFWmousebuttonfun). * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function must only be called from the main thread. * * @sa @ref input_mouse_button * * @since Added in version 1.0. * @glfw3 Added window handle parameter and return value. * * @ingroup input */ GLFWAPI GLFWmousebuttonfun glfwSetMouseButtonCallback(GLFWwindow* window, GLFWmousebuttonfun callback); /*! @brief Sets the cursor position callback. * * This function sets the cursor position callback of the specified window, * which is called when the cursor is moved. The callback is provided with the * position, in screen coordinates, relative to the upper-left corner of the * content area of the window. * * @param[in] window The window whose callback to set. * @param[in] callback The new callback, or `NULL` to remove the currently set * callback. * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * * @callback_signature * @code * void function_name(GLFWwindow* window, double xpos, double ypos); * @endcode * For more information about the callback parameters, see the * [function pointer type](@ref GLFWcursorposfun). * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function must only be called from the main thread. * * @sa @ref cursor_pos * * @since Added in version 3.0. Replaces `glfwSetMousePosCallback`. * * @ingroup input */ GLFWAPI GLFWcursorposfun glfwSetCursorPosCallback(GLFWwindow* window, GLFWcursorposfun callback); /*! @brief Sets the cursor enter/leave callback. * * This function sets the cursor boundary crossing callback of the specified * window, which is called when the cursor enters or leaves the content area of * the window. * * @param[in] window The window whose callback to set. * @param[in] callback The new callback, or `NULL` to remove the currently set * callback. * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * * @callback_signature * @code * void function_name(GLFWwindow* window, int entered) * @endcode * For more information about the callback parameters, see the * [function pointer type](@ref GLFWcursorenterfun). * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function must only be called from the main thread. * * @sa @ref cursor_enter * * @since Added in version 3.0. * * @ingroup input */ GLFWAPI GLFWcursorenterfun glfwSetCursorEnterCallback(GLFWwindow* window, GLFWcursorenterfun callback); /*! @brief Sets the scroll callback. * * This function sets the scroll callback of the specified window, which is * called when a scrolling device is used, such as a mouse wheel or scrolling * area of a touchpad. * * The scroll callback receives all scrolling input, like that from a mouse * wheel or a touchpad scrolling area. * * @param[in] window The window whose callback to set. * @param[in] callback The new scroll callback, or `NULL` to remove the * currently set callback. * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * * @callback_signature * @code * void function_name(GLFWwindow* window, double xoffset, double yoffset) * @endcode * For more information about the callback parameters, see the * [function pointer type](@ref GLFWscrollfun). * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function must only be called from the main thread. * * @sa @ref scrolling * * @since Added in version 3.0. Replaces `glfwSetMouseWheelCallback`. * * @ingroup input */ GLFWAPI GLFWscrollfun glfwSetScrollCallback(GLFWwindow* window, GLFWscrollfun callback); /*! @brief Sets the path drop callback. * * This function sets the path drop callback of the specified window, which is * called when one or more dragged paths are dropped on the window. * * Because the path array and its strings may have been generated specifically * for that event, they are not guaranteed to be valid after the callback has * returned. If you wish to use them after the callback returns, you need to * make a deep copy. * * @param[in] window The window whose callback to set. * @param[in] callback The new file drop callback, or `NULL` to remove the * currently set callback. * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * * @callback_signature * @code * void function_name(GLFWwindow* window, int path_count, const char* paths[]) * @endcode * For more information about the callback parameters, see the * [function pointer type](@ref GLFWdropfun). * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @remark @wayland File drop is currently unimplemented. * * @thread_safety This function must only be called from the main thread. * * @sa @ref path_drop * * @since Added in version 3.1. * * @ingroup input */ GLFWAPI GLFWdropfun glfwSetDropCallback(GLFWwindow* window, GLFWdropfun callback); /*! @brief Returns whether the specified joystick is present. * * This function returns whether the specified joystick is present. * * There is no need to call this function before other functions that accept * a joystick ID, as they all check for presence before performing any other * work. * * @param[in] jid The [joystick](@ref joysticks) to query. * @return `GLFW_TRUE` if the joystick is present, or `GLFW_FALSE` otherwise. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. * * @thread_safety This function must only be called from the main thread. * * @sa @ref joystick * * @since Added in version 3.0. Replaces `glfwGetJoystickParam`. * * @ingroup input */ GLFWAPI int glfwJoystickPresent(int jid); /*! @brief Returns the values of all axes of the specified joystick. * * This function returns the values of all axes of the specified joystick. * Each element in the array is a value between -1.0 and 1.0. * * If the specified joystick is not present this function will return `NULL` * but will not generate an error. This can be used instead of first calling * @ref glfwJoystickPresent. * * @param[in] jid The [joystick](@ref joysticks) to query. * @param[out] count Where to store the number of axis values in the returned * array. This is set to zero if the joystick is not present or an error * occurred. * @return An array of axis values, or `NULL` if the joystick is not present or * an [error](@ref error_handling) occurred. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. * * @pointer_lifetime The returned array is allocated and freed by GLFW. You * should not free it yourself. It is valid until the specified joystick is * disconnected or the library is terminated. * * @thread_safety This function must only be called from the main thread. * * @sa @ref joystick_axis * * @since Added in version 3.0. Replaces `glfwGetJoystickPos`. * * @ingroup input */ GLFWAPI const float* glfwGetJoystickAxes(int jid, int* count); /*! @brief Returns the state of all buttons of the specified joystick. * * This function returns the state of all buttons of the specified joystick. * Each element in the array is either `GLFW_PRESS` or `GLFW_RELEASE`. * * For backward compatibility with earlier versions that did not have @ref * glfwGetJoystickHats, the button array also includes all hats, each * represented as four buttons. The hats are in the same order as returned by * __glfwGetJoystickHats__ and are in the order _up_, _right_, _down_ and * _left_. To disable these extra buttons, set the @ref * GLFW_JOYSTICK_HAT_BUTTONS init hint before initialization. * * If the specified joystick is not present this function will return `NULL` * but will not generate an error. This can be used instead of first calling * @ref glfwJoystickPresent. * * @param[in] jid The [joystick](@ref joysticks) to query. * @param[out] count Where to store the number of button states in the returned * array. This is set to zero if the joystick is not present or an error * occurred. * @return An array of button states, or `NULL` if the joystick is not present * or an [error](@ref error_handling) occurred. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. * * @pointer_lifetime The returned array is allocated and freed by GLFW. You * should not free it yourself. It is valid until the specified joystick is * disconnected or the library is terminated. * * @thread_safety This function must only be called from the main thread. * * @sa @ref joystick_button * * @since Added in version 2.2. * @glfw3 Changed to return a dynamic array. * * @ingroup input */ GLFWAPI const unsigned char* glfwGetJoystickButtons(int jid, int* count); /*! @brief Returns the state of all hats of the specified joystick. * * This function returns the state of all hats of the specified joystick. * Each element in the array is one of the following values: * * Name | Value * ---- | ----- * `GLFW_HAT_CENTERED` | 0 * `GLFW_HAT_UP` | 1 * `GLFW_HAT_RIGHT` | 2 * `GLFW_HAT_DOWN` | 4 * `GLFW_HAT_LEFT` | 8 * `GLFW_HAT_RIGHT_UP` | `GLFW_HAT_RIGHT` \| `GLFW_HAT_UP` * `GLFW_HAT_RIGHT_DOWN` | `GLFW_HAT_RIGHT` \| `GLFW_HAT_DOWN` * `GLFW_HAT_LEFT_UP` | `GLFW_HAT_LEFT` \| `GLFW_HAT_UP` * `GLFW_HAT_LEFT_DOWN` | `GLFW_HAT_LEFT` \| `GLFW_HAT_DOWN` * * The diagonal directions are bitwise combinations of the primary (up, right, * down and left) directions and you can test for these individually by ANDing * it with the corresponding direction. * * @code * if (hats[2] & GLFW_HAT_RIGHT) * { * // State of hat 2 could be right-up, right or right-down * } * @endcode * * If the specified joystick is not present this function will return `NULL` * but will not generate an error. This can be used instead of first calling * @ref glfwJoystickPresent. * * @param[in] jid The [joystick](@ref joysticks) to query. * @param[out] count Where to store the number of hat states in the returned * array. This is set to zero if the joystick is not present or an error * occurred. * @return An array of hat states, or `NULL` if the joystick is not present * or an [error](@ref error_handling) occurred. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. * * @pointer_lifetime The returned array is allocated and freed by GLFW. You * should not free it yourself. It is valid until the specified joystick is * disconnected, this function is called again for that joystick or the library * is terminated. * * @thread_safety This function must only be called from the main thread. * * @sa @ref joystick_hat * * @since Added in version 3.3. * * @ingroup input */ GLFWAPI const unsigned char* glfwGetJoystickHats(int jid, int* count); /*! @brief Returns the name of the specified joystick. * * This function returns the name, encoded as UTF-8, of the specified joystick. * The returned string is allocated and freed by GLFW. You should not free it * yourself. * * If the specified joystick is not present this function will return `NULL` * but will not generate an error. This can be used instead of first calling * @ref glfwJoystickPresent. * * @param[in] jid The [joystick](@ref joysticks) to query. * @return The UTF-8 encoded name of the joystick, or `NULL` if the joystick * is not present or an [error](@ref error_handling) occurred. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref * GLFW_INVALID_ENUM 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 specified joystick is * disconnected or the library is terminated. * * @thread_safety This function must only be called from the main thread. * * @sa @ref joystick_name * * @since Added in version 3.0. * * @ingroup input */ GLFWAPI const char* glfwGetJoystickName(int jid); /*! @brief Returns the SDL compatible GUID of the specified joystick. * * This function returns the SDL compatible GUID, as a UTF-8 encoded * hexadecimal string, of the specified joystick. The returned string is * allocated and freed by GLFW. You should not free it yourself. * * The GUID is what connects a joystick to a gamepad mapping. A connected * joystick will always have a GUID even if there is no gamepad mapping * assigned to it. * * If the specified joystick is not present this function will return `NULL` * but will not generate an error. This can be used instead of first calling * @ref glfwJoystickPresent. * * The GUID uses the format introduced in SDL 2.0.5. This GUID tries to * uniquely identify the make and model of a joystick but does not identify * a specific unit, e.g. all wired Xbox 360 controllers will have the same * GUID on that platform. The GUID for a unit may vary between platforms * depending on what hardware information the platform specific APIs provide. * * @param[in] jid The [joystick](@ref joysticks) to query. * @return The UTF-8 encoded GUID of the joystick, or `NULL` if the joystick * is not present or an [error](@ref error_handling) occurred. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref * GLFW_INVALID_ENUM 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 specified joystick is * disconnected or the library is terminated. * * @thread_safety This function must only be called from the main thread. * * @sa @ref gamepad * * @since Added in version 3.3. * * @ingroup input */ GLFWAPI const char* glfwGetJoystickGUID(int jid); /*! @brief Sets the user pointer of the specified joystick. * * This function sets the user-defined pointer of the specified joystick. The * current value is retained until the joystick is disconnected. The initial * value is `NULL`. * * This function may be called from the joystick callback, even for a joystick * that is being disconnected. * * @param[in] jid The joystick whose pointer to set. * @param[in] pointer The new value. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function may be called from any thread. Access is not * synchronized. * * @sa @ref joystick_userptr * @sa @ref glfwGetJoystickUserPointer * * @since Added in version 3.3. * * @ingroup input */ GLFWAPI void glfwSetJoystickUserPointer(int jid, void* pointer); /*! @brief Returns the user pointer of the specified joystick. * * This function returns the current value of the user-defined pointer of the * specified joystick. The initial value is `NULL`. * * This function may be called from the joystick callback, even for a joystick * that is being disconnected. * * @param[in] jid The joystick whose pointer to return. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function may be called from any thread. Access is not * synchronized. * * @sa @ref joystick_userptr * @sa @ref glfwSetJoystickUserPointer * * @since Added in version 3.3. * * @ingroup input */ GLFWAPI void* glfwGetJoystickUserPointer(int jid); /*! @brief Returns whether the specified joystick has a gamepad mapping. * * This function returns whether the specified joystick is both present and has * a gamepad mapping. * * If the specified joystick is present but does not have a gamepad mapping * this function will return `GLFW_FALSE` but will not generate an error. Call * @ref glfwJoystickPresent to check if a joystick is present regardless of * whether it has a mapping. * * @param[in] jid The [joystick](@ref joysticks) to query. * @return `GLFW_TRUE` if a joystick is both present and has a gamepad mapping, * or `GLFW_FALSE` otherwise. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_INVALID_ENUM. * * @thread_safety This function must only be called from the main thread. * * @sa @ref gamepad * @sa @ref glfwGetGamepadState * * @since Added in version 3.3. * * @ingroup input */ GLFWAPI int glfwJoystickIsGamepad(int jid); /*! @brief Sets the joystick configuration callback. * * This function sets the joystick configuration callback, or removes the * currently set callback. This is called when a joystick is connected to or * disconnected from the system. * * For joystick connection and disconnection events to be delivered on all * platforms, you need to call one of the [event processing](@ref events) * functions. Joystick disconnection may also be detected and the callback * called by joystick functions. The function will then return whatever it * returns if the joystick is not present. * * @param[in] callback The new callback, or `NULL` to remove the currently set * callback. * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * * @callback_signature * @code * void function_name(int jid, int event) * @endcode * For more information about the callback parameters, see the * [function pointer type](@ref GLFWjoystickfun). * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function must only be called from the main thread. * * @sa @ref joystick_event * * @since Added in version 3.2. * * @ingroup input */ GLFWAPI GLFWjoystickfun glfwSetJoystickCallback(GLFWjoystickfun callback); /*! @brief Adds the specified SDL_GameControllerDB gamepad mappings. * * This function parses the specified ASCII encoded string and updates the * internal list with any gamepad mappings it finds. This string may * contain either a single gamepad mapping or many mappings separated by * newlines. The parser supports the full format of the `gamecontrollerdb.txt` * source file including empty lines and comments. * * See @ref gamepad_mapping for a description of the format. * * If there is already a gamepad mapping for a given GUID in the internal list, * it will be replaced by the one passed to this function. If the library is * terminated and re-initialized the internal list will revert to the built-in * default. * * @param[in] string The string containing the gamepad mappings. * @return `GLFW_TRUE` if successful, or `GLFW_FALSE` if an * [error](@ref error_handling) occurred. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_INVALID_VALUE. * * @thread_safety This function must only be called from the main thread. * * @sa @ref gamepad * @sa @ref glfwJoystickIsGamepad * @sa @ref glfwGetGamepadName * * @since Added in version 3.3. * * @ingroup input */ GLFWAPI int glfwUpdateGamepadMappings(const char* string); /*! @brief Returns the human-readable gamepad name for the specified joystick. * * This function returns the human-readable name of the gamepad from the * gamepad mapping assigned to the specified joystick. * * If the specified joystick is not present or does not have a gamepad mapping * this function will return `NULL` but will not generate an error. Call * @ref glfwJoystickPresent to check whether it is present regardless of * whether it has a mapping. * * @param[in] jid The [joystick](@ref joysticks) to query. * @return The UTF-8 encoded name of the gamepad, or `NULL` if the * 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. * * @thread_safety This function must only be called from the main thread. * * @sa @ref gamepad * @sa @ref glfwJoystickIsGamepad * * @since Added in version 3.3. * * @ingroup input */ GLFWAPI const char* glfwGetGamepadName(int jid); /*! @brief Retrieves the state of the specified joystick remapped as a gamepad. * * This function retrieves the state of the specified joystick remapped to * an Xbox-like gamepad. * * If the specified joystick is not present or does not have a gamepad mapping * this function will return `GLFW_FALSE` but will not generate an error. Call * @ref glfwJoystickPresent to check whether it is present regardless of * whether it has a mapping. * * The Guide button may not be available for input as it is often hooked by the * system or the Steam client. * * Not all devices have all the buttons or axes provided by @ref * GLFWgamepadstate. Unavailable buttons and axes will always report * `GLFW_RELEASE` and 0.0 respectively. * * @param[in] jid The [joystick](@ref joysticks) to query. * @param[out] state The gamepad input state of the joystick. * @return `GLFW_TRUE` if successful, or `GLFW_FALSE` if no joystick is * connected, it has no gamepad mapping or an [error](@ref error_handling) * occurred. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_INVALID_ENUM. * * @thread_safety This function must only be called from the main thread. * * @sa @ref gamepad * @sa @ref glfwUpdateGamepadMappings * @sa @ref glfwJoystickIsGamepad * * @since Added in version 3.3. * * @ingroup input */ GLFWAPI int glfwGetGamepadState(int jid, GLFWgamepadstate* state); /*! @brief Sets the clipboard to the specified string. * * This function sets the system clipboard to the specified, UTF-8 encoded * string. * * @param[in] window Deprecated. Any valid window or `NULL`. * @param[in] string A UTF-8 encoded string. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_PLATFORM_ERROR. * * @pointer_lifetime The specified string is copied before this function * returns. * * @thread_safety This function must only be called from the main thread. * * @sa @ref clipboard * @sa @ref glfwGetClipboardString * * @since Added in version 3.0. * * @ingroup input */ GLFWAPI void glfwSetClipboardString(GLFWwindow* window, const char* string); /*! @brief Returns the contents of the clipboard as a string. * * This function returns the contents of the system clipboard, if it contains * or is convertible to a UTF-8 encoded string. If the clipboard is empty or * if its contents cannot be converted, `NULL` is returned and a @ref * GLFW_FORMAT_UNAVAILABLE error is generated. * * @param[in] window Deprecated. Any valid window or `NULL`. * @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, @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 * glfwGetClipboardString or @ref glfwSetClipboardString, or until the library * is terminated. * * @thread_safety This function must only be called from the main thread. * * @sa @ref clipboard * @sa @ref glfwSetClipboardString * * @since Added in version 3.0. * * @ingroup input */ GLFWAPI const char* glfwGetClipboardString(GLFWwindow* window); /*! @brief Returns the GLFW time. * * This function returns the current GLFW time, in seconds. Unless the time * has been set using @ref glfwSetTime it measures time elapsed since GLFW was * initialized. * * This function and @ref glfwSetTime are helper functions on top of @ref * glfwGetTimerFrequency and @ref glfwGetTimerValue. * * The resolution of the timer is system dependent, but is usually on the order * of a few micro- or nanoseconds. It uses the highest-resolution monotonic * time source on each supported platform. * * @return The current time, in seconds, or zero if an * [error](@ref error_handling) occurred. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function may be called from any thread. Reading and * writing of the internal base time is not atomic, so it needs to be * externally synchronized with calls to @ref glfwSetTime. * * @sa @ref time * * @since Added in version 1.0. * * @ingroup input */ GLFWAPI double glfwGetTime(void); /*! @brief Sets the GLFW time. * * This function sets the current GLFW time, in seconds. The value must be * a positive finite number less than or equal to 18446744073.0, which is * approximately 584.5 years. * * This function and @ref glfwGetTime are helper functions on top of @ref * glfwGetTimerFrequency and @ref glfwGetTimerValue. * * @param[in] time The new value, in seconds. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_INVALID_VALUE. * * @remark The upper limit of GLFW time is calculated as * floor((264 - 1) / 109) and is due to implementations * storing nanoseconds in 64 bits. The limit may be increased in the future. * * @thread_safety This function may be called from any thread. Reading and * writing of the internal base time is not atomic, so it needs to be * externally synchronized with calls to @ref glfwGetTime. * * @sa @ref time * * @since Added in version 2.2. * * @ingroup input */ GLFWAPI void glfwSetTime(double time); /*! @brief Returns the current value of the raw timer. * * This function returns the current value of the raw timer, measured in * 1 / frequency seconds. To get the frequency, call @ref * glfwGetTimerFrequency. * * @return The value of the timer, or zero if an * [error](@ref error_handling) occurred. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function may be called from any thread. * * @sa @ref time * @sa @ref glfwGetTimerFrequency * * @since Added in version 3.2. * * @ingroup input */ GLFWAPI uint64_t glfwGetTimerValue(void); /*! @brief Returns the frequency, in Hz, of the raw timer. * * This function returns the frequency, in Hz, of the raw timer. * * @return The frequency of the timer, in Hz, or zero if an * [error](@ref error_handling) occurred. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function may be called from any thread. * * @sa @ref time * @sa @ref glfwGetTimerValue * * @since Added in version 3.2. * * @ingroup input */ GLFWAPI uint64_t glfwGetTimerFrequency(void); /*! @brief Makes the context of the specified window current for the calling * 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. * * When moving a context between threads, you must 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 * [GLFW_CONTEXT_RELEASE_BEHAVIOR](@ref GLFW_CONTEXT_RELEASE_BEHAVIOR_hint) * hint. * * The specified window must have an OpenGL or OpenGL ES context. Specifying * a window without a context will generate a @ref GLFW_NO_WINDOW_CONTEXT * error. * * @param[in] window The window whose context to make current, or `NULL` to * detach the current context. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref * GLFW_NO_WINDOW_CONTEXT and @ref GLFW_PLATFORM_ERROR. * * @thread_safety This function may be called from any thread. * * @sa @ref context_current * @sa @ref glfwGetCurrentContext * * @since Added in version 3.0. * * @ingroup context */ GLFWAPI void glfwMakeContextCurrent(GLFWwindow* window); /*! @brief Returns the window whose context is current on the calling thread. * * This function returns the window whose OpenGL or OpenGL ES context is * current on the calling thread. * * @return The window whose context is current, or `NULL` if no window's * context is current. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function may be called from any thread. * * @sa @ref context_current * @sa @ref glfwMakeContextCurrent * * @since Added in version 3.0. * * @ingroup context */ GLFWAPI GLFWwindow* glfwGetCurrentContext(void); /*! @brief Swaps the front and back buffers of the specified window. * * This function swaps the front and back buffers of the specified window when * rendering with OpenGL or OpenGL ES. If the swap interval is greater than * zero, the GPU driver waits the specified number of screen updates before * swapping the buffers. * * The specified window must have an OpenGL or OpenGL ES context. Specifying * a window without a context will generate a @ref GLFW_NO_WINDOW_CONTEXT * error. * * This function does not apply to Vulkan. If you are rendering with Vulkan, * see `vkQueuePresentKHR` instead. * * @param[in] window The window whose buffers to swap. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref * GLFW_NO_WINDOW_CONTEXT and @ref GLFW_PLATFORM_ERROR. * * @remark __EGL:__ The context of the specified window must be current on the * calling thread. * * @thread_safety This function may be called from any thread. * * @sa @ref buffer_swap * @sa @ref glfwSwapInterval * * @since Added in version 1.0. * @glfw3 Added window handle parameter. * * @ingroup window */ GLFWAPI void glfwSwapBuffers(GLFWwindow* window); /*! @brief Sets the swap interval for the current context. * * This function sets the swap interval for the current OpenGL or OpenGL ES * context, i.e. the number of screen updates to wait from the time @ref * glfwSwapBuffers was called before swapping the buffers and returning. This * is sometimes called _vertical synchronization_, _vertical retrace * synchronization_ or just _vsync_. * * A context that supports either of the `WGL_EXT_swap_control_tear` and * `GLX_EXT_swap_control_tear` extensions also accepts _negative_ swap * intervals, which allows the driver to swap immediately even if a frame * arrives a little bit late. You can check for these extensions with @ref * glfwExtensionSupported. * * A context must be current on the calling thread. Calling this function * without a current context will cause a @ref GLFW_NO_CURRENT_CONTEXT error. * * This function does not apply to Vulkan. If you are rendering with Vulkan, * see the present mode of your swapchain instead. * * @param[in] interval The minimum number of screen updates to wait for * until the buffers are swapped by @ref glfwSwapBuffers. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref * GLFW_NO_CURRENT_CONTEXT and @ref GLFW_PLATFORM_ERROR. * * @remark This function is not called during context creation, leaving the * swap interval set to whatever is the default on that platform. This is done * because some swap interval extensions used by GLFW do not allow the swap * interval to be reset to zero once it has been set to a non-zero value. * * @remark Some GPU drivers do not honor the requested swap interval, either * because of a user setting that overrides the application's request or due to * bugs in the driver. * * @thread_safety This function may be called from any thread. * * @sa @ref buffer_swap * @sa @ref glfwSwapBuffers * * @since Added in version 1.0. * * @ingroup context */ GLFWAPI void glfwSwapInterval(int interval); /*! @brief Returns whether the specified extension is available. * * This function returns whether the specified * [API extension](@ref context_glext) is supported by the current OpenGL or * OpenGL ES context. It searches both for client API extension and context * creation API extensions. * * A context must be current on the calling thread. Calling this function * without a current context will cause a @ref GLFW_NO_CURRENT_CONTEXT error. * * As this functions retrieves and searches one or more extension strings each * call, it is recommended that you cache its results if it is going to be used * frequently. The extension strings will not change during the lifetime of * a context, so there is no danger in doing this. * * This function does not apply to Vulkan. If you are using Vulkan, see @ref * glfwGetRequiredInstanceExtensions, `vkEnumerateInstanceExtensionProperties` * and `vkEnumerateDeviceExtensionProperties` instead. * * @param[in] extension The ASCII encoded name of the extension. * @return `GLFW_TRUE` if the extension is available, or `GLFW_FALSE` * otherwise. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref * GLFW_NO_CURRENT_CONTEXT, @ref GLFW_INVALID_VALUE and @ref * GLFW_PLATFORM_ERROR. * * @thread_safety This function may be called from any thread. * * @sa @ref context_glext * @sa @ref glfwGetProcAddress * * @since Added in version 1.0. * * @ingroup context */ GLFWAPI int glfwExtensionSupported(const char* extension); /*! @brief Returns the address of the specified function for the current * context. * * This function returns the address of the specified OpenGL or OpenGL ES * [core or extension function](@ref context_glext), if it is supported * by the current context. * * A context must be current on the calling thread. Calling this function * without a current context will cause a @ref GLFW_NO_CURRENT_CONTEXT error. * * This function does not apply to Vulkan. If you are rendering with Vulkan, * see @ref glfwGetInstanceProcAddress, `vkGetInstanceProcAddr` and * `vkGetDeviceProcAddr` instead. * * @param[in] procname The ASCII encoded name of the function. * @return The address of the function, or `NULL` if an * [error](@ref error_handling) occurred. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref * GLFW_NO_CURRENT_CONTEXT and @ref GLFW_PLATFORM_ERROR. * * @remark The address of a given function is not guaranteed to be the same * between contexts. * * @remark This function may return a non-`NULL` address despite the * associated version or extension not being available. Always check the * context version or extension string first. * * @pointer_lifetime The returned function pointer is valid until the context * is destroyed or the library is terminated. * * @thread_safety This function may be called from any thread. * * @sa @ref context_glext * @sa @ref glfwExtensionSupported * * @since Added in version 1.0. * * @ingroup context */ GLFWAPI GLFWglproc glfwGetProcAddress(const char* procname); /*! @brief Returns whether the Vulkan loader and an ICD have been found. * * 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. 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. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function may be called from any thread. * * @sa @ref vulkan_support * * @since Added in version 3.2. * * @ingroup vulkan */ GLFWAPI int glfwVulkanSupported(void); /*! @brief Returns the Vulkan instance extensions required by GLFW. * * This function returns an array of names of Vulkan instance extensions required * by GLFW for creating Vulkan surfaces for GLFW windows. If successful, the * list will always contain `VK_KHR_surface`, so if you don't require any * additional extensions you can pass this list directly to the * `VkInstanceCreateInfo` struct. * * If Vulkan is not available on the machine, this function returns `NULL` and * generates a @ref GLFW_API_UNAVAILABLE error. Call @ref glfwVulkanSupported * to check whether Vulkan is at least minimally available. * * If Vulkan is available but no set of extensions allowing window surface * creation was found, this function returns `NULL`. You may still use Vulkan * for off-screen rendering and compute work. * * @param[out] count Where to store the number of extensions in the returned * array. This is set to zero if an error occurred. * @return An array of ASCII encoded extension names, or `NULL` if an * [error](@ref error_handling) occurred. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_API_UNAVAILABLE. * * @remark Additional extensions may be required by future versions of GLFW. * You should check if any extensions you wish to enable are already in the * returned array, as it is an error to specify an extension more than once in * the `VkInstanceCreateInfo` struct. * * @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. * * @thread_safety This function may be called from any thread. * * @sa @ref vulkan_ext * @sa @ref glfwCreateWindowSurface * * @since Added in version 3.2. * * @ingroup vulkan */ GLFWAPI const char** glfwGetRequiredInstanceExtensions(uint32_t* count); #if defined(VK_VERSION_1_0) /*! @brief Returns the address of the specified Vulkan instance function. * * This function returns the address of the specified Vulkan core or extension * function for the specified instance. If instance is set to `NULL` it can * return any function exported from the Vulkan loader, including at least the * following functions: * * - `vkEnumerateInstanceExtensionProperties` * - `vkEnumerateInstanceLayerProperties` * - `vkCreateInstance` * - `vkGetInstanceProcAddr` * * If Vulkan is not available on the machine, this function returns `NULL` and * generates a @ref GLFW_API_UNAVAILABLE error. Call @ref glfwVulkanSupported * to check whether Vulkan is at least minimally available. * * This function is equivalent to calling `vkGetInstanceProcAddr` with * a platform-specific query of the Vulkan loader as a fallback. * * @param[in] instance The Vulkan instance to query, or `NULL` to retrieve * functions related to instance creation. * @param[in] procname The ASCII encoded name of the function. * @return The address of the function, or `NULL` if an * [error](@ref error_handling) occurred. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_API_UNAVAILABLE. * * @pointer_lifetime The returned function pointer is valid until the library * is terminated. * * @thread_safety This function may be called from any thread. * * @sa @ref vulkan_proc * * @since Added in version 3.2. * * @ingroup vulkan */ GLFWAPI GLFWvkproc glfwGetInstanceProcAddress(VkInstance instance, const char* procname); /*! @brief Returns whether the specified queue family can present images. * * This function returns whether the specified queue family of the specified * physical device supports presentation to the platform GLFW was built for. * * If Vulkan or the required window surface creation instance extensions are * not available on the machine, or if the specified instance was not created * with the required extensions, this function returns `GLFW_FALSE` and * generates a @ref GLFW_API_UNAVAILABLE error. Call @ref glfwVulkanSupported * to check whether Vulkan is at least minimally available and @ref * glfwGetRequiredInstanceExtensions to check what instance extensions are * required. * * @param[in] instance The instance that the physical device belongs to. * @param[in] device The physical device that the queue family belongs to. * @param[in] queuefamily The index of the queue family to query. * @return `GLFW_TRUE` if the queue family supports presentation, or * `GLFW_FALSE` otherwise. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref * GLFW_API_UNAVAILABLE and @ref GLFW_PLATFORM_ERROR. * * @remark @macos This function currently always returns `GLFW_TRUE`, as the * `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 * synchronization details of Vulkan objects, see the Vulkan specification. * * @sa @ref vulkan_present * * @since Added in version 3.2. * * @ingroup vulkan */ GLFWAPI int glfwGetPhysicalDevicePresentationSupport(VkInstance instance, VkPhysicalDevice device, uint32_t queuefamily); /*! @brief Creates a Vulkan surface for the specified window. * * This function creates a Vulkan surface for the specified window. * * If the Vulkan loader or at least one minimally functional ICD were not found, * this function returns `VK_ERROR_INITIALIZATION_FAILED` and generates a @ref * GLFW_API_UNAVAILABLE error. Call @ref glfwVulkanSupported to check whether * Vulkan is at least minimally available. * * If the required window surface creation instance extensions are not * available or if the specified instance was not created with these extensions * enabled, this function returns `VK_ERROR_EXTENSION_NOT_PRESENT` and * generates a @ref GLFW_API_UNAVAILABLE error. Call @ref * glfwGetRequiredInstanceExtensions to check what instance extensions are * required. * * The window surface cannot be shared with another API so the window must * have been created with the [client api hint](@ref GLFW_CLIENT_API_attrib) * set to `GLFW_NO_API` otherwise it generates a @ref GLFW_INVALID_VALUE error * and returns `VK_ERROR_NATIVE_WINDOW_IN_USE_KHR`. * * The window surface must be destroyed before the specified Vulkan instance. * It is the responsibility of the caller to destroy the window surface. GLFW * does not destroy it for you. Call `vkDestroySurfaceKHR` to destroy the * surface. * * @param[in] instance The Vulkan instance to create the surface in. * @param[in] window The window to create the surface for. * @param[in] allocator The allocator to use, or `NULL` to use the default * allocator. * @param[out] surface Where to store the handle of the surface. This is set * to `VK_NULL_HANDLE` if an error occurred. * @return `VK_SUCCESS` if successful, or a Vulkan error code if an * [error](@ref error_handling) occurred. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref * GLFW_API_UNAVAILABLE, @ref GLFW_PLATFORM_ERROR and @ref GLFW_INVALID_VALUE * * @remark If an error occurs before the creation call is made, GLFW returns * the Vulkan error code most appropriate for the error. Appropriate use of * @ref glfwVulkanSupported and @ref glfwGetRequiredInstanceExtensions should * eliminate almost all occurrences of these errors. * * @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. * * @thread_safety This function may be called from any thread. For * synchronization details of Vulkan objects, see the Vulkan specification. * * @sa @ref vulkan_surface * @sa @ref glfwGetRequiredInstanceExtensions * * @since Added in version 3.2. * * @ingroup vulkan */ GLFWAPI VkResult glfwCreateWindowSurface(VkInstance instance, GLFWwindow* window, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface); #endif /*VK_VERSION_1_0*/ /************************************************************************* * Global definition cleanup *************************************************************************/ /* ------------------- BEGIN SYSTEM/COMPILER SPECIFIC -------------------- */ #ifdef GLFW_WINGDIAPI_DEFINED #undef WINGDIAPI #undef GLFW_WINGDIAPI_DEFINED #endif #ifdef GLFW_CALLBACK_DEFINED #undef CALLBACK #undef GLFW_CALLBACK_DEFINED #endif /* Some OpenGL related headers need GLAPIENTRY, but it is unconditionally * defined by some gl.h variants (OpenBSD) so define it after if needed. */ #ifndef GLAPIENTRY #define GLAPIENTRY APIENTRY #endif /* -------------------- END SYSTEM/COMPILER SPECIFIC --------------------- */ #ifdef __cplusplus } #endif #endif /* _glfw3_h_ */ /************************************************************************* * GLFW 3.3.7 - www.glfw.org * A library for OpenGL, window and input *------------------------------------------------------------------------ * Copyright (c) 2002-2006 Marcus Geelnard * Copyright (c) 2006-2018 Camilla Löwy * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would * be appreciated but is not required. * * 2. Altered source versions must be plainly marked as such, and must not * be misrepresented as being the original software. * * 3. This notice may not be removed or altered from any source * distribution. * *************************************************************************/ #ifndef _glfw3_native_h_ #define _glfw3_native_h_ #ifdef __cplusplus extern "C" { #endif /************************************************************************* * Doxygen documentation *************************************************************************/ /*! @file glfw3native.h * @brief The header of the native access functions. * * This is the header file of the native access functions. See @ref native for * more information. */ /*! @defgroup native Native access * @brief Functions related to accessing native handles. * * **By using the native access functions you assert that you know what you're * doing and how to fix problems caused by using them. If you don't, you * shouldn't be using them.** * * Before the inclusion of @ref glfw3native.h, you may define zero or more * window system API macro and zero or more context creation API macros. * * The chosen backends must match those the library was compiled for. Failure * to do this will cause a link-time error. * * The available window API macros are: * * `GLFW_EXPOSE_NATIVE_WIN32` * * `GLFW_EXPOSE_NATIVE_COCOA` * * `GLFW_EXPOSE_NATIVE_X11` * * `GLFW_EXPOSE_NATIVE_WAYLAND` * * The available context API macros are: * * `GLFW_EXPOSE_NATIVE_WGL` * * `GLFW_EXPOSE_NATIVE_NSGL` * * `GLFW_EXPOSE_NATIVE_GLX` * * `GLFW_EXPOSE_NATIVE_EGL` * * `GLFW_EXPOSE_NATIVE_OSMESA` * * These macros select which of the native access functions that are declared * and which platform-specific headers to include. It is then up your (by * definition platform-specific) code to handle which of these should be * defined. */ /************************************************************************* * System headers and types *************************************************************************/ #if defined(GLFW_EXPOSE_NATIVE_WIN32) || defined(GLFW_EXPOSE_NATIVE_WGL) // This is a workaround for the fact that glfw3.h needs to export APIENTRY (for // example to allow applications to correctly declare a GL_KHR_debug callback) // but windows.h assumes no one will define APIENTRY before it does #if defined(GLFW_APIENTRY_DEFINED) #undef APIENTRY #undef GLFW_APIENTRY_DEFINED #endif #include #elif defined(GLFW_EXPOSE_NATIVE_COCOA) || defined(GLFW_EXPOSE_NATIVE_NSGL) #if defined(__OBJC__) #import #else #include typedef void* id; #endif #elif defined(GLFW_EXPOSE_NATIVE_X11) || defined(GLFW_EXPOSE_NATIVE_GLX) #include #include #elif defined(GLFW_EXPOSE_NATIVE_WAYLAND) #include #endif #if defined(GLFW_EXPOSE_NATIVE_WGL) /* WGL is declared by windows.h */ #endif #if defined(GLFW_EXPOSE_NATIVE_NSGL) /* NSGL is declared by Cocoa.h */ #endif #if defined(GLFW_EXPOSE_NATIVE_GLX) #include #endif #if defined(GLFW_EXPOSE_NATIVE_EGL) #include #endif #if defined(GLFW_EXPOSE_NATIVE_OSMESA) #include #endif /************************************************************************* * Functions *************************************************************************/ #if defined(GLFW_EXPOSE_NATIVE_WIN32) /*! @brief Returns the adapter device name of the specified monitor. * * @return The UTF-8 encoded adapter device name (for example `\\.\DISPLAY1`) * of the specified monitor, or `NULL` if an [error](@ref error_handling) * occurred. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function may be called from any thread. Access is not * synchronized. * * @since Added in version 3.1. * * @ingroup native */ GLFWAPI const char* glfwGetWin32Adapter(GLFWmonitor* monitor); /*! @brief Returns the display device name of the specified monitor. * * @return The UTF-8 encoded display device name (for example * `\\.\DISPLAY1\Monitor0`) of the specified monitor, or `NULL` if an * [error](@ref error_handling) occurred. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function may be called from any thread. Access is not * synchronized. * * @since Added in version 3.1. * * @ingroup native */ GLFWAPI const char* glfwGetWin32Monitor(GLFWmonitor* monitor); /*! @brief Returns the `HWND` of the specified window. * * @return The `HWND` of the specified window, or `NULL` if an * [error](@ref error_handling) occurred. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @remark The `HDC` associated with the window can be queried with the * [GetDC](https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getdc) * function. * @code * HDC dc = GetDC(glfwGetWin32Window(window)); * @endcode * This DC is private and does not need to be released. * * @thread_safety This function may be called from any thread. Access is not * synchronized. * * @since Added in version 3.0. * * @ingroup native */ GLFWAPI HWND glfwGetWin32Window(GLFWwindow* window); #endif #if defined(GLFW_EXPOSE_NATIVE_WGL) /*! @brief Returns the `HGLRC` of the specified window. * * @return The `HGLRC` of the specified window, or `NULL` if an * [error](@ref error_handling) occurred. * * @errors Possible errors include @ref GLFW_NO_WINDOW_CONTEXT and @ref * GLFW_NOT_INITIALIZED. * * @remark The `HDC` associated with the window can be queried with the * [GetDC](https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getdc) * function. * @code * HDC dc = GetDC(glfwGetWin32Window(window)); * @endcode * This DC is private and does not need to be released. * * @thread_safety This function may be called from any thread. Access is not * synchronized. * * @since Added in version 3.0. * * @ingroup native */ GLFWAPI HGLRC glfwGetWGLContext(GLFWwindow* window); #endif #if defined(GLFW_EXPOSE_NATIVE_COCOA) /*! @brief Returns the `CGDirectDisplayID` of the specified monitor. * * @return The `CGDirectDisplayID` of the specified monitor, or * `kCGNullDirectDisplay` if an [error](@ref error_handling) occurred. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function may be called from any thread. Access is not * synchronized. * * @since Added in version 3.1. * * @ingroup native */ GLFWAPI CGDirectDisplayID glfwGetCocoaMonitor(GLFWmonitor* monitor); /*! @brief Returns the `NSWindow` of the specified window. * * @return The `NSWindow` of the specified window, or `nil` if an * [error](@ref error_handling) occurred. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function may be called from any thread. Access is not * synchronized. * * @since Added in version 3.0. * * @ingroup native */ GLFWAPI id glfwGetCocoaWindow(GLFWwindow* window); #endif #if defined(GLFW_EXPOSE_NATIVE_NSGL) /*! @brief Returns the `NSOpenGLContext` of the specified window. * * @return The `NSOpenGLContext` of the specified window, or `nil` if an * [error](@ref error_handling) occurred. * * @errors Possible errors include @ref GLFW_NO_WINDOW_CONTEXT and @ref * GLFW_NOT_INITIALIZED. * * @thread_safety This function may be called from any thread. Access is not * synchronized. * * @since Added in version 3.0. * * @ingroup native */ GLFWAPI id glfwGetNSGLContext(GLFWwindow* window); #endif #if defined(GLFW_EXPOSE_NATIVE_X11) /*! @brief Returns the `Display` used by GLFW. * * @return The `Display` used by GLFW, or `NULL` if an * [error](@ref error_handling) occurred. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function may be called from any thread. Access is not * synchronized. * * @since Added in version 3.0. * * @ingroup native */ GLFWAPI Display* glfwGetX11Display(void); /*! @brief Returns the `RRCrtc` of the specified monitor. * * @return The `RRCrtc` of the specified monitor, or `None` if an * [error](@ref error_handling) occurred. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function may be called from any thread. Access is not * synchronized. * * @since Added in version 3.1. * * @ingroup native */ GLFWAPI RRCrtc glfwGetX11Adapter(GLFWmonitor* monitor); /*! @brief Returns the `RROutput` of the specified monitor. * * @return The `RROutput` of the specified monitor, or `None` if an * [error](@ref error_handling) occurred. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function may be called from any thread. Access is not * synchronized. * * @since Added in version 3.1. * * @ingroup native */ GLFWAPI RROutput glfwGetX11Monitor(GLFWmonitor* monitor); /*! @brief Returns the `Window` of the specified window. * * @return The `Window` of the specified window, or `None` if an * [error](@ref error_handling) occurred. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function may be called from any thread. Access is not * synchronized. * * @since Added in version 3.0. * * @ingroup native */ GLFWAPI Window glfwGetX11Window(GLFWwindow* window); /*! @brief Sets the current primary selection to the specified string. * * @param[in] string A UTF-8 encoded string. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_PLATFORM_ERROR. * * @pointer_lifetime The specified string is copied before this function * returns. * * @thread_safety This function must only be called from the main thread. * * @sa @ref clipboard * @sa glfwGetX11SelectionString * @sa glfwSetClipboardString * * @since Added in version 3.3. * * @ingroup native */ GLFWAPI void glfwSetX11SelectionString(const char* string); /*! @brief Returns the contents of the current primary selection as a string. * * If the selection is empty or if its contents cannot be converted, `NULL` * is returned and a @ref GLFW_FORMAT_UNAVAILABLE error is generated. * * @return The contents of the selection 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. * * @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 * glfwGetX11SelectionString or @ref glfwSetX11SelectionString, or until the * library is terminated. * * @thread_safety This function must only be called from the main thread. * * @sa @ref clipboard * @sa glfwSetX11SelectionString * @sa glfwGetClipboardString * * @since Added in version 3.3. * * @ingroup native */ GLFWAPI const char* glfwGetX11SelectionString(void); #endif #if defined(GLFW_EXPOSE_NATIVE_GLX) /*! @brief Returns the `GLXContext` of the specified window. * * @return The `GLXContext` of the specified window, or `NULL` if an * [error](@ref error_handling) occurred. * * @errors Possible errors include @ref GLFW_NO_WINDOW_CONTEXT and @ref * GLFW_NOT_INITIALIZED. * * @thread_safety This function may be called from any thread. Access is not * synchronized. * * @since Added in version 3.0. * * @ingroup native */ GLFWAPI GLXContext glfwGetGLXContext(GLFWwindow* window); /*! @brief Returns the `GLXWindow` of the specified window. * * @return The `GLXWindow` of the specified window, or `None` if an * [error](@ref error_handling) occurred. * * @errors Possible errors include @ref GLFW_NO_WINDOW_CONTEXT and @ref * GLFW_NOT_INITIALIZED. * * @thread_safety This function may be called from any thread. Access is not * synchronized. * * @since Added in version 3.2. * * @ingroup native */ GLFWAPI GLXWindow glfwGetGLXWindow(GLFWwindow* window); #endif #if defined(GLFW_EXPOSE_NATIVE_WAYLAND) /*! @brief Returns the `struct wl_display*` used by GLFW. * * @return The `struct wl_display*` used by GLFW, or `NULL` if an * [error](@ref error_handling) occurred. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function may be called from any thread. Access is not * synchronized. * * @since Added in version 3.2. * * @ingroup native */ GLFWAPI struct wl_display* glfwGetWaylandDisplay(void); /*! @brief Returns the `struct wl_output*` of the specified monitor. * * @return The `struct wl_output*` of the specified monitor, or `NULL` if an * [error](@ref error_handling) occurred. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function may be called from any thread. Access is not * synchronized. * * @since Added in version 3.2. * * @ingroup native */ GLFWAPI struct wl_output* glfwGetWaylandMonitor(GLFWmonitor* monitor); /*! @brief Returns the main `struct wl_surface*` of the specified window. * * @return The main `struct wl_surface*` of the specified window, or `NULL` if * an [error](@ref error_handling) occurred. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function may be called from any thread. Access is not * synchronized. * * @since Added in version 3.2. * * @ingroup native */ GLFWAPI struct wl_surface* glfwGetWaylandWindow(GLFWwindow* window); #endif #if defined(GLFW_EXPOSE_NATIVE_EGL) /*! @brief Returns the `EGLDisplay` used by GLFW. * * @return The `EGLDisplay` used by GLFW, or `EGL_NO_DISPLAY` if an * [error](@ref error_handling) occurred. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function may be called from any thread. Access is not * synchronized. * * @since Added in version 3.0. * * @ingroup native */ GLFWAPI EGLDisplay glfwGetEGLDisplay(void); /*! @brief Returns the `EGLContext` of the specified window. * * @return The `EGLContext` of the specified window, or `EGL_NO_CONTEXT` if an * [error](@ref error_handling) occurred. * * @errors Possible errors include @ref GLFW_NO_WINDOW_CONTEXT and @ref * GLFW_NOT_INITIALIZED. * * @thread_safety This function may be called from any thread. Access is not * synchronized. * * @since Added in version 3.0. * * @ingroup native */ GLFWAPI EGLContext glfwGetEGLContext(GLFWwindow* window); /*! @brief Returns the `EGLSurface` of the specified window. * * @return The `EGLSurface` of the specified window, or `EGL_NO_SURFACE` if an * [error](@ref error_handling) occurred. * * @errors Possible errors include @ref GLFW_NO_WINDOW_CONTEXT and @ref * GLFW_NOT_INITIALIZED. * * @thread_safety This function may be called from any thread. Access is not * synchronized. * * @since Added in version 3.0. * * @ingroup native */ GLFWAPI EGLSurface glfwGetEGLSurface(GLFWwindow* window); #endif #if defined(GLFW_EXPOSE_NATIVE_OSMESA) /*! @brief Retrieves the color buffer associated with the specified window. * * @param[in] window The window whose color buffer to retrieve. * @param[out] width Where to store the width of the color buffer, or `NULL`. * @param[out] height Where to store the height of the color buffer, or `NULL`. * @param[out] format Where to store the OSMesa pixel format of the color * buffer, or `NULL`. * @param[out] buffer Where to store the address of the color buffer, or * `NULL`. * @return `GLFW_TRUE` if successful, or `GLFW_FALSE` if an * [error](@ref error_handling) occurred. * * @errors Possible errors include @ref GLFW_NO_WINDOW_CONTEXT and @ref * GLFW_NOT_INITIALIZED. * * @thread_safety This function may be called from any thread. Access is not * synchronized. * * @since Added in version 3.3. * * @ingroup native */ GLFWAPI int glfwGetOSMesaColorBuffer(GLFWwindow* window, int* width, int* height, int* format, void** buffer); /*! @brief Retrieves the depth buffer associated with the specified window. * * @param[in] window The window whose depth buffer to retrieve. * @param[out] width Where to store the width of the depth buffer, or `NULL`. * @param[out] height Where to store the height of the depth buffer, or `NULL`. * @param[out] bytesPerValue Where to store the number of bytes per depth * buffer element, or `NULL`. * @param[out] buffer Where to store the address of the depth buffer, or * `NULL`. * @return `GLFW_TRUE` if successful, or `GLFW_FALSE` if an * [error](@ref error_handling) occurred. * * @errors Possible errors include @ref GLFW_NO_WINDOW_CONTEXT and @ref * GLFW_NOT_INITIALIZED. * * @thread_safety This function may be called from any thread. Access is not * synchronized. * * @since Added in version 3.3. * * @ingroup native */ GLFWAPI int glfwGetOSMesaDepthBuffer(GLFWwindow* window, int* width, int* height, int* bytesPerValue, void** buffer); /*! @brief Returns the `OSMesaContext` of the specified window. * * @return The `OSMesaContext` of the specified window, or `NULL` if an * [error](@ref error_handling) occurred. * * @errors Possible errors include @ref GLFW_NO_WINDOW_CONTEXT and @ref * GLFW_NOT_INITIALIZED. * * @thread_safety This function may be called from any thread. Access is not * synchronized. * * @since Added in version 3.3. * * @ingroup native */ GLFWAPI OSMesaContext glfwGetOSMesaContext(GLFWwindow* window); #endif #ifdef __cplusplus } #endif #endif /* _glfw3_native_h_ */ #ifdef _GLFW_IMPLEMENTATION #ifndef HEADER_GUARD_INTERNAL_H #define HEADER_GUARD_INTERNAL_H //======================================================================== // GLFW 3.3.7 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2019 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== #pragma once #if defined(_GLFW_USE_CONFIG_H) #include "glfw_config.h" #endif #if defined(GLFW_INCLUDE_GLCOREARB) || \ defined(GLFW_INCLUDE_ES1) || \ defined(GLFW_INCLUDE_ES2) || \ defined(GLFW_INCLUDE_ES3) || \ defined(GLFW_INCLUDE_ES31) || \ defined(GLFW_INCLUDE_ES32) || \ defined(GLFW_INCLUDE_NONE) || \ defined(GLFW_INCLUDE_GLEXT) || \ defined(GLFW_INCLUDE_GLU) || \ defined(GLFW_INCLUDE_VULKAN) || \ defined(GLFW_DLL) //#error "You must not define any header option macros when compiling GLFW" #endif #define GLFW_INCLUDE_NONE //#include "../include/GLFW/glfw3.h" #define _GLFW_INSERT_FIRST 0 #define _GLFW_INSERT_LAST 1 #define _GLFW_POLL_PRESENCE 0 #define _GLFW_POLL_AXES 1 #define _GLFW_POLL_BUTTONS 2 #define _GLFW_POLL_ALL (_GLFW_POLL_AXES | _GLFW_POLL_BUTTONS) #define _GLFW_MESSAGE_SIZE 1024 typedef int GLFWbool; typedef struct _GLFWerror _GLFWerror; typedef struct _GLFWinitconfig _GLFWinitconfig; typedef struct _GLFWwndconfig _GLFWwndconfig; typedef struct _GLFWctxconfig _GLFWctxconfig; typedef struct _GLFWfbconfig _GLFWfbconfig; typedef struct _GLFWcontext _GLFWcontext; typedef struct _GLFWwindow _GLFWwindow; typedef struct _GLFWlibrary _GLFWlibrary; typedef struct _GLFWmonitor _GLFWmonitor; typedef struct _GLFWcursor _GLFWcursor; typedef struct _GLFWmapelement _GLFWmapelement; typedef struct _GLFWmapping _GLFWmapping; typedef struct _GLFWjoystick _GLFWjoystick; typedef struct _GLFWtls _GLFWtls; typedef struct _GLFWmutex _GLFWmutex; typedef void (* _GLFWmakecontextcurrentfun)(_GLFWwindow*); typedef void (* _GLFWswapbuffersfun)(_GLFWwindow*); typedef void (* _GLFWswapintervalfun)(int); typedef int (* _GLFWextensionsupportedfun)(const char*); typedef GLFWglproc (* _GLFWgetprocaddressfun)(const char*); typedef void (* _GLFWdestroycontextfun)(_GLFWwindow*); //#define GL_VERSION 0x1f02 #define GL_NONE 0 #define GL_COLOR_BUFFER_BIT 0x00004000 #define GL_UNSIGNED_BYTE 0x1401 //#define GL_EXTENSIONS 0x1f03 //#define GL_NUM_EXTENSIONS 0x821d //#define GL_CONTEXT_FLAGS 0x821e #define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x00000001 #define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002 #define GL_CONTEXT_PROFILE_MASK 0x9126 #define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002 #define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001 #define GL_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 #define GL_LOSE_CONTEXT_ON_RESET_ARB 0x8252 #define GL_NO_RESET_NOTIFICATION_ARB 0x8261 //#define GL_CONTEXT_RELEASE_BEHAVIOR 0x82fb ////#define GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH 0x82fc #define GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR 0x00000008 typedef int GLint; typedef unsigned int GLuint; typedef unsigned int GLenum; typedef unsigned int GLbitfield; typedef unsigned char GLubyte; typedef void (APIENTRY * PFNGLCLEARPROC)(GLbitfield); typedef const GLubyte* (APIENTRY * PFNGLGETSTRINGPROC)(GLenum); typedef void (APIENTRY * PFNGLGETINTEGERVPROC)(GLenum,GLint*); typedef const GLubyte* (APIENTRY * PFNGLGETSTRINGIPROC)(GLenum,GLuint); #define VK_NULL_HANDLE 0 typedef void* VkInstance; typedef void* VkPhysicalDevice; typedef uint64_t VkSurfaceKHR; typedef uint32_t VkFlags; typedef uint32_t VkBool32; typedef enum VkStructureType { VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR = 1000004000, VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR = 1000005000, VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR = 1000006000, VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR = 1000009000, VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK = 1000123000, VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT = 1000217000, VK_STRUCTURE_TYPE_MAX_ENUM = 0x7FFFFFFF } VkStructureType; typedef enum VkResult { VK_SUCCESS = 0, VK_NOT_READY = 1, VK_TIMEOUT = 2, VK_EVENT_SET = 3, VK_EVENT_RESET = 4, VK_INCOMPLETE = 5, VK_ERROR_OUT_OF_HOST_MEMORY = -1, VK_ERROR_OUT_OF_DEVICE_MEMORY = -2, VK_ERROR_INITIALIZATION_FAILED = -3, VK_ERROR_DEVICE_LOST = -4, VK_ERROR_MEMORY_MAP_FAILED = -5, VK_ERROR_LAYER_NOT_PRESENT = -6, VK_ERROR_EXTENSION_NOT_PRESENT = -7, VK_ERROR_FEATURE_NOT_PRESENT = -8, VK_ERROR_INCOMPATIBLE_DRIVER = -9, VK_ERROR_TOO_MANY_OBJECTS = -10, VK_ERROR_FORMAT_NOT_SUPPORTED = -11, VK_ERROR_SURFACE_LOST_KHR = -1000000000, VK_SUBOPTIMAL_KHR = 1000001003, VK_ERROR_OUT_OF_DATE_KHR = -1000001004, VK_ERROR_INCOMPATIBLE_DISPLAY_KHR = -1000003001, VK_ERROR_NATIVE_WINDOW_IN_USE_KHR = -1000000001, VK_ERROR_VALIDATION_FAILED_EXT = -1000011001, VK_RESULT_MAX_ENUM = 0x7FFFFFFF } VkResult; typedef struct VkAllocationCallbacks VkAllocationCallbacks; typedef struct VkExtensionProperties { char extensionName[256]; uint32_t specVersion; } VkExtensionProperties; typedef void (APIENTRY * PFN_vkVoidFunction)(void); #if defined(_GLFW_VULKAN_STATIC) PFN_vkVoidFunction vkGetInstanceProcAddr(VkInstance,const char*); VkResult vkEnumerateInstanceExtensionProperties(const char*,uint32_t*,VkExtensionProperties*); #else typedef PFN_vkVoidFunction (APIENTRY * PFN_vkGetInstanceProcAddr)(VkInstance,const char*); typedef VkResult (APIENTRY * PFN_vkEnumerateInstanceExtensionProperties)(const char*,uint32_t*,VkExtensionProperties*); #define vkEnumerateInstanceExtensionProperties _glfw.vk.EnumerateInstanceExtensionProperties #define vkGetInstanceProcAddr _glfw.vk.GetInstanceProcAddr #endif #if defined(_GLFW_COCOA) #ifndef HEADER_GUARD_COCOA_PLATFORM_H #define HEADER_GUARD_COCOA_PLATFORM_H //======================================================================== // GLFW 3.3.7 macOS - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2009-2019 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== #include #include #include // 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 #else typedef void* id; #endif // NOTE: Many Cocoa enum values 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 base SDK does not provide the newer names. #if MAC_OS_X_VERSION_MAX_ALLOWED < 101200 #define NSBitmapFormatAlphaNonpremultiplied NSAlphaNonpremultipliedBitmapFormat #define NSEventMaskAny NSAnyEventMask #define NSEventMaskKeyUp NSKeyUpMask #define NSEventModifierFlagCapsLock NSAlphaShiftKeyMask #define NSEventModifierFlagCommand NSCommandKeyMask #define NSEventModifierFlagControl NSControlKeyMask #define NSEventModifierFlagDeviceIndependentFlagsMask NSDeviceIndependentModifierFlagsMask #define NSEventModifierFlagOption NSAlternateKeyMask #define NSEventModifierFlagShift NSShiftKeyMask #define NSEventTypeApplicationDefined NSApplicationDefined #define NSWindowStyleMaskBorderless NSBorderlessWindowMask #define NSWindowStyleMaskClosable NSClosableWindowMask #define NSWindowStyleMaskMiniaturizable NSMiniaturizableWindowMask #define NSWindowStyleMaskResizable NSResizableWindowMask #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; typedef struct VkMacOSSurfaceCreateInfoMVK { VkStructureType sType; const void* pNext; VkMacOSSurfaceCreateFlagsMVK flags; const void* pView; } VkMacOSSurfaceCreateInfoMVK; typedef struct VkMetalSurfaceCreateInfoEXT { VkStructureType sType; const void* pNext; VkMetalSurfaceCreateFlagsEXT flags; const void* pLayer; } VkMetalSurfaceCreateInfoEXT; typedef VkResult (APIENTRY *PFN_vkCreateMacOSSurfaceMVK)(VkInstance,const VkMacOSSurfaceCreateInfoMVK*,const VkAllocationCallbacks*,VkSurfaceKHR*); typedef VkResult (APIENTRY *PFN_vkCreateMetalSurfaceEXT)(VkInstance,const VkMetalSurfaceCreateInfoEXT*,const VkAllocationCallbacks*,VkSurfaceKHR*); #ifndef HEADER_GUARD_POSIX_THREAD_H #define HEADER_GUARD_POSIX_THREAD_H //======================================================================== // GLFW 3.3.7 POSIX - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2017 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== #include #define _GLFW_PLATFORM_TLS_STATE _GLFWtlsPOSIX posix #define _GLFW_PLATFORM_MUTEX_STATE _GLFWmutexPOSIX posix // POSIX-specific thread local storage data // typedef struct _GLFWtlsPOSIX { GLFWbool allocated; pthread_key_t key; } _GLFWtlsPOSIX; // POSIX-specific mutex data // typedef struct _GLFWmutexPOSIX { GLFWbool allocated; pthread_mutex_t handle; } _GLFWmutexPOSIX; #endif #ifndef HEADER_GUARD_COCOA_JOYSTICK_H #define HEADER_GUARD_COCOA_JOYSTICK_H //======================================================================== // GLFW 3.3.7 Cocoa - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2006-2017 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== #include #include #include #include #define _GLFW_PLATFORM_JOYSTICK_STATE _GLFWjoystickNS ns #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 // typedef struct _GLFWjoystickNS { IOHIDDeviceRef device; CFMutableArrayRef axes; CFMutableArrayRef buttons; CFMutableArrayRef hats; } _GLFWjoystickNS; void _glfwInitJoysticksNS(void); void _glfwTerminateJoysticksNS(void); #endif #ifndef HEADER_GUARD_NSGL_CONTEXT_H #define HEADER_GUARD_NSGL_CONTEXT_H //======================================================================== // GLFW 3.3.7 macOS - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2009-2019 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== // NOTE: Many Cocoa enum values 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 base SDK does not provide the newer names. #if MAC_OS_X_VERSION_MAX_ALLOWED < 101400 #define NSOpenGLContextParameterSwapInterval NSOpenGLCPSwapInterval #define NSOpenGLContextParameterSurfaceOpacity NSOpenGLCPSurfaceOpacity #endif #define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextNSGL nsgl #define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE _GLFWlibraryNSGL nsgl #include // NSGL-specific per-context data // typedef struct _GLFWcontextNSGL { id pixelFormat; id object; } _GLFWcontextNSGL; // NSGL-specific global data // typedef struct _GLFWlibraryNSGL { // dlopen handle for OpenGL.framework (for glfwGetProcAddress) CFBundleRef framework; } _GLFWlibraryNSGL; GLFWbool _glfwInitNSGL(void); void _glfwTerminateNSGL(void); GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig); void _glfwDestroyContextNSGL(_GLFWwindow* window); #endif #ifndef HEADER_GUARD_EGL_CONTEXT_H #define HEADER_GUARD_EGL_CONTEXT_H //======================================================================== // GLFW 3.3.7 EGL - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2017 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== #if defined(_GLFW_USE_EGLPLATFORM_H) #include #elif defined(_GLFW_WIN32) #define EGLAPIENTRY __stdcall typedef HDC EGLNativeDisplayType; typedef HWND EGLNativeWindowType; #elif defined(_GLFW_COCOA) #define EGLAPIENTRY typedef void* EGLNativeDisplayType; typedef id EGLNativeWindowType; #elif defined(_GLFW_X11) #define EGLAPIENTRY typedef Display* EGLNativeDisplayType; typedef Window EGLNativeWindowType; #elif defined(_GLFW_WAYLAND) #define EGLAPIENTRY typedef struct wl_display* EGLNativeDisplayType; typedef struct wl_egl_window* EGLNativeWindowType; #else #error "No supported EGL platform selected" #endif #define EGL_SUCCESS 0x3000 #define EGL_NOT_INITIALIZED 0x3001 #define EGL_BAD_ACCESS 0x3002 #define EGL_BAD_ALLOC 0x3003 #define EGL_BAD_ATTRIBUTE 0x3004 #define EGL_BAD_CONFIG 0x3005 #define EGL_BAD_CONTEXT 0x3006 #define EGL_BAD_CURRENT_SURFACE 0x3007 #define EGL_BAD_DISPLAY 0x3008 #define EGL_BAD_MATCH 0x3009 #define EGL_BAD_NATIVE_PIXMAP 0x300a #define EGL_BAD_NATIVE_WINDOW 0x300b #define EGL_BAD_PARAMETER 0x300c #define EGL_BAD_SURFACE 0x300d #define EGL_CONTEXT_LOST 0x300e #define EGL_COLOR_BUFFER_TYPE 0x303f #define EGL_RGB_BUFFER 0x308e #define EGL_SURFACE_TYPE 0x3033 #define EGL_WINDOW_BIT 0x0004 #define EGL_RENDERABLE_TYPE 0x3040 #define EGL_OPENGL_ES_BIT 0x0001 #define EGL_OPENGL_ES2_BIT 0x0004 #define EGL_OPENGL_BIT 0x0008 #define EGL_ALPHA_SIZE 0x3021 #define EGL_BLUE_SIZE 0x3022 #define EGL_GREEN_SIZE 0x3023 #define EGL_RED_SIZE 0x3024 #define EGL_DEPTH_SIZE 0x3025 #define EGL_STENCIL_SIZE 0x3026 #define EGL_SAMPLES 0x3031 #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 #define EGL_NO_SURFACE ((EGLSurface) 0) #define EGL_NO_DISPLAY ((EGLDisplay) 0) #define EGL_NO_CONTEXT ((EGLContext) 0) #define EGL_DEFAULT_DISPLAY ((EGLNativeDisplayType) 0) #define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR 0x00000002 #define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR 0x00000001 #define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR 0x00000002 #define EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR 0x00000001 #define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR 0x31bd #define EGL_NO_RESET_NOTIFICATION_KHR 0x31be #define EGL_LOSE_CONTEXT_ON_RESET_KHR 0x31bf #define EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR 0x00000004 #define EGL_CONTEXT_MAJOR_VERSION_KHR 0x3098 #define EGL_CONTEXT_MINOR_VERSION_KHR 0x30fb #define EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR 0x30fd #define EGL_CONTEXT_FLAGS_KHR 0x30fc #define EGL_CONTEXT_OPENGL_NO_ERROR_KHR 0x31b3 #define EGL_GL_COLORSPACE_KHR 0x309d #define EGL_GL_COLORSPACE_SRGB_KHR 0x3089 #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; typedef unsigned int EGLenum; typedef void* EGLConfig; typedef void* EGLContext; typedef void* EGLDisplay; typedef void* EGLSurface; // EGL function pointer typedefs typedef EGLBoolean (EGLAPIENTRY * PFN_eglGetConfigAttrib)(EGLDisplay,EGLConfig,EGLint,EGLint*); typedef EGLBoolean (EGLAPIENTRY * PFN_eglGetConfigs)(EGLDisplay,EGLConfig*,EGLint,EGLint*); typedef EGLDisplay (EGLAPIENTRY * PFN_eglGetDisplay)(EGLNativeDisplayType); typedef EGLint (EGLAPIENTRY * PFN_eglGetError)(void); typedef EGLBoolean (EGLAPIENTRY * PFN_eglInitialize)(EGLDisplay,EGLint*,EGLint*); typedef EGLBoolean (EGLAPIENTRY * PFN_eglTerminate)(EGLDisplay); typedef EGLBoolean (EGLAPIENTRY * PFN_eglBindAPI)(EGLenum); typedef EGLContext (EGLAPIENTRY * PFN_eglCreateContext)(EGLDisplay,EGLConfig,EGLContext,const EGLint*); typedef EGLBoolean (EGLAPIENTRY * PFN_eglDestroySurface)(EGLDisplay,EGLSurface); typedef EGLBoolean (EGLAPIENTRY * PFN_eglDestroyContext)(EGLDisplay,EGLContext); typedef EGLSurface (EGLAPIENTRY * PFN_eglCreateWindowSurface)(EGLDisplay,EGLConfig,EGLNativeWindowType,const EGLint*); typedef EGLBoolean (EGLAPIENTRY * PFN_eglMakeCurrent)(EGLDisplay,EGLSurface,EGLSurface,EGLContext); typedef EGLBoolean (EGLAPIENTRY * PFN_eglSwapBuffers)(EGLDisplay,EGLSurface); typedef EGLBoolean (EGLAPIENTRY * PFN_eglSwapInterval)(EGLDisplay,EGLint); typedef const char* (EGLAPIENTRY * PFN_eglQueryString)(EGLDisplay,EGLint); typedef GLFWglproc (EGLAPIENTRY * PFN_eglGetProcAddress)(const char*); #define eglGetConfigAttrib _glfw.egl.GetConfigAttrib #define eglGetConfigs _glfw.egl.GetConfigs #define eglGetDisplay _glfw.egl.GetDisplay #define eglGetError _glfw.egl.GetError #define eglInitialize _glfw.egl.Initialize #define eglTerminate _glfw.egl.Terminate #define eglBindAPI _glfw.egl.BindAPI #define eglCreateContext _glfw.egl.CreateContext #define eglDestroySurface _glfw.egl.DestroySurface #define eglDestroyContext _glfw.egl.DestroyContext #define eglCreateWindowSurface _glfw.egl.CreateWindowSurface #define eglMakeCurrent _glfw.egl.MakeCurrent #define eglSwapBuffers _glfw.egl.SwapBuffers #define eglSwapInterval _glfw.egl.SwapInterval #define eglQueryString _glfw.egl.QueryString #define eglGetProcAddress _glfw.egl.GetProcAddress #define _GLFW_EGL_CONTEXT_STATE _GLFWcontextEGL egl #define _GLFW_EGL_LIBRARY_CONTEXT_STATE _GLFWlibraryEGL egl // EGL-specific per-context data // typedef struct _GLFWcontextEGL { EGLConfig config; EGLContext handle; EGLSurface surface; void* client; } _GLFWcontextEGL; // EGL-specific global data // typedef struct _GLFWlibraryEGL { EGLDisplay display; EGLint major, minor; GLFWbool prefix; GLFWbool KHR_create_context; GLFWbool KHR_create_context_no_error; GLFWbool KHR_gl_colorspace; GLFWbool KHR_get_all_proc_addresses; GLFWbool KHR_context_flush_control; GLFWbool EXT_present_opaque; void* handle; PFN_eglGetConfigAttrib GetConfigAttrib; PFN_eglGetConfigs GetConfigs; PFN_eglGetDisplay GetDisplay; PFN_eglGetError GetError; PFN_eglInitialize Initialize; PFN_eglTerminate Terminate; PFN_eglBindAPI BindAPI; PFN_eglCreateContext CreateContext; PFN_eglDestroySurface DestroySurface; PFN_eglDestroyContext DestroyContext; PFN_eglCreateWindowSurface CreateWindowSurface; PFN_eglMakeCurrent MakeCurrent; PFN_eglSwapBuffers SwapBuffers; PFN_eglSwapInterval SwapInterval; PFN_eglQueryString QueryString; PFN_eglGetProcAddress GetProcAddress; } _GLFWlibraryEGL; GLFWbool _glfwInitEGL(void); void _glfwTerminateEGL(void); GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig); #if defined(_GLFW_X11) GLFWbool _glfwChooseVisualEGL(const _GLFWwndconfig* wndconfig, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig, Visual** visual, int* depth); #endif /*_GLFW_X11*/ #endif #ifndef HEADER_GUARD_OSMESA_CONTEXT_H #define HEADER_GUARD_OSMESA_CONTEXT_H //======================================================================== // GLFW 3.3.7 OSMesa - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2016 Google Inc. // Copyright (c) 2016-2017 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== #define OSMESA_RGBA 0x1908 #define OSMESA_FORMAT 0x22 #define OSMESA_DEPTH_BITS 0x30 #define OSMESA_STENCIL_BITS 0x31 #define OSMESA_ACCUM_BITS 0x32 #define OSMESA_PROFILE 0x33 #define OSMESA_CORE_PROFILE 0x34 #define OSMESA_COMPAT_PROFILE 0x35 #define OSMESA_CONTEXT_MAJOR_VERSION 0x36 #define OSMESA_CONTEXT_MINOR_VERSION 0x37 typedef void* OSMesaContext; typedef void (*OSMESAproc)(void); typedef OSMesaContext (GLAPIENTRY * PFN_OSMesaCreateContextExt)(GLenum,GLint,GLint,GLint,OSMesaContext); typedef OSMesaContext (GLAPIENTRY * PFN_OSMesaCreateContextAttribs)(const int*,OSMesaContext); typedef void (GLAPIENTRY * PFN_OSMesaDestroyContext)(OSMesaContext); typedef int (GLAPIENTRY * PFN_OSMesaMakeCurrent)(OSMesaContext,void*,int,int,int); typedef int (GLAPIENTRY * PFN_OSMesaGetColorBuffer)(OSMesaContext,int*,int*,int*,void**); typedef int (GLAPIENTRY * PFN_OSMesaGetDepthBuffer)(OSMesaContext,int*,int*,int*,void**); typedef GLFWglproc (GLAPIENTRY * PFN_OSMesaGetProcAddress)(const char*); #define OSMesaCreateContextExt _glfw.osmesa.CreateContextExt #define OSMesaCreateContextAttribs _glfw.osmesa.CreateContextAttribs #define OSMesaDestroyContext _glfw.osmesa.DestroyContext #define OSMesaMakeCurrent _glfw.osmesa.MakeCurrent #define OSMesaGetColorBuffer _glfw.osmesa.GetColorBuffer #define OSMesaGetDepthBuffer _glfw.osmesa.GetDepthBuffer #define OSMesaGetProcAddress _glfw.osmesa.GetProcAddress #define _GLFW_OSMESA_CONTEXT_STATE _GLFWcontextOSMesa osmesa #define _GLFW_OSMESA_LIBRARY_CONTEXT_STATE _GLFWlibraryOSMesa osmesa // OSMesa-specific per-context data // typedef struct _GLFWcontextOSMesa { OSMesaContext handle; int width; int height; void* buffer; } _GLFWcontextOSMesa; // OSMesa-specific global data // typedef struct _GLFWlibraryOSMesa { void* handle; PFN_OSMesaCreateContextExt CreateContextExt; PFN_OSMesaCreateContextAttribs CreateContextAttribs; PFN_OSMesaDestroyContext DestroyContext; PFN_OSMesaMakeCurrent MakeCurrent; PFN_OSMesaGetColorBuffer GetColorBuffer; PFN_OSMesaGetDepthBuffer GetDepthBuffer; PFN_OSMesaGetProcAddress GetProcAddress; } _GLFWlibraryOSMesa; GLFWbool _glfwInitOSMesa(void); void _glfwTerminateOSMesa(void); GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig); #endif #define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL) #define _glfw_dlclose(handle) dlclose(handle) #define _glfw_dlsym(handle, name) dlsym(handle, name) #define _GLFW_EGL_NATIVE_WINDOW ((EGLNativeWindowType) window->ns.layer) #define _GLFW_EGL_NATIVE_DISPLAY EGL_DEFAULT_DISPLAY #define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowNS ns #define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryNS ns #define _GLFW_PLATFORM_LIBRARY_TIMER_STATE _GLFWtimerNS ns #define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorNS ns #define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorNS ns // HIToolbox.framework pointer typedefs #define kTISPropertyUnicodeKeyLayoutData _glfw.ns.tis.kPropertyUnicodeKeyLayoutData typedef TISInputSourceRef (*PFN_TISCopyCurrentKeyboardLayoutInputSource)(void); #define TISCopyCurrentKeyboardLayoutInputSource _glfw.ns.tis.CopyCurrentKeyboardLayoutInputSource typedef void* (*PFN_TISGetInputSourceProperty)(TISInputSourceRef,CFStringRef); #define TISGetInputSourceProperty _glfw.ns.tis.GetInputSourceProperty typedef UInt8 (*PFN_LMGetKbdType)(void); #define LMGetKbdType _glfw.ns.tis.GetKbdType // Cocoa-specific per-window data // typedef struct _GLFWwindowNS { id object; id delegate; id view; id layer; GLFWbool maximized; GLFWbool occluded; GLFWbool retina; // Cached window properties to filter out duplicate events int width, height; int fbWidth, fbHeight; float xscale, yscale; // The total sum of the distances the cursor has been warped // 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 // typedef struct _GLFWlibraryNS { CGEventSourceRef eventSource; id delegate; GLFWbool finishedLaunching; GLFWbool cursorHidden; TISInputSourceRef inputSource; IOHIDManagerRef hidManager; id unicodeData; id helper; id keyUpMonitor; id nibObjects; char keynames[GLFW_KEY_LAST + 1][17]; short int keycodes[256]; short int scancodes[GLFW_KEY_LAST + 1]; char* clipboardString; CGPoint cascadePoint; // Where to place the cursor when re-enabled double restoreCursorPosX, restoreCursorPosY; // The window whose disabled cursor mode is active _GLFWwindow* disabledCursorWindow; struct { CFBundleRef bundle; PFN_TISCopyCurrentKeyboardLayoutInputSource CopyCurrentKeyboardLayoutInputSource; PFN_TISGetInputSourceProperty GetInputSourceProperty; PFN_LMGetKbdType GetKbdType; CFStringRef kPropertyUnicodeKeyLayoutData; } tis; } _GLFWlibraryNS; // Cocoa-specific per-monitor data // typedef struct _GLFWmonitorNS { CGDirectDisplayID displayID; CGDisplayModeRef previousMode; uint32_t unitNumber; id screen; double fallbackRefreshRate; } _GLFWmonitorNS; // Cocoa-specific per-cursor data // typedef struct _GLFWcursorNS { id object; } _GLFWcursorNS; // Cocoa-specific global timer data // typedef struct _GLFWtimerNS { uint64_t frequency; } _GLFWtimerNS; void _glfwInitTimerNS(void); void _glfwPollMonitorsNS(void); void _glfwSetVideoModeNS(_GLFWmonitor* monitor, const GLFWvidmode* desired); void _glfwRestoreVideoModeNS(_GLFWmonitor* monitor); float _glfwTransformYNS(float y); void* _glfwLoadLocalVulkanLoaderNS(void); #endif #elif defined(_GLFW_WIN32) #ifndef HEADER_GUARD_WIN32_PLATFORM_H #define HEADER_GUARD_WIN32_PLATFORM_H //======================================================================== // GLFW 3.3.7 Win32 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2019 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== // We don't need all the fancy stuff #ifndef NOMINMAX #define NOMINMAX #endif #ifndef VC_EXTRALEAN #define VC_EXTRALEAN #endif #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #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_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 #ifndef UNICODE #define UNICODE #endif // GLFW requires Windows XP or later #if WINVER < 0x0501 #undef WINVER #define WINVER 0x0501 #endif #if _WIN32_WINNT < 0x0501 #undef _WIN32_WINNT #define _WIN32_WINNT 0x0501 #endif // GLFW uses DirectInput8 interfaces #define DIRECTINPUT_VERSION 0x0800 // GLFW uses OEM cursor resources #define OEMRESOURCE #include #include #include #include #include // HACK: Define macros that some windows.h variants don't #ifndef WM_MOUSEHWHEEL #define WM_MOUSEHWHEEL 0x020E #endif #ifndef WM_DWMCOMPOSITIONCHANGED #define WM_DWMCOMPOSITIONCHANGED 0x031E #endif #ifndef WM_DWMCOLORIZATIONCOLORCHANGED #define WM_DWMCOLORIZATIONCOLORCHANGED 0x0320 #endif #ifndef WM_COPYGLOBALDATA #define WM_COPYGLOBALDATA 0x0049 #endif #ifndef WM_UNICHAR #define WM_UNICHAR 0x0109 #endif #ifndef UNICODE_NOCHAR #define UNICODE_NOCHAR 0xFFFF #endif #ifndef WM_DPICHANGED #define WM_DPICHANGED 0x02E0 #endif #ifndef GET_XBUTTON_WPARAM #define GET_XBUTTON_WPARAM(w) (HIWORD(w)) #endif #ifndef EDS_ROTATEDMODE #define EDS_ROTATEDMODE 0x00000004 #endif #ifndef DISPLAY_DEVICE_ACTIVE #define DISPLAY_DEVICE_ACTIVE 0x00000001 #endif #ifndef _WIN32_WINNT_WINBLUE #define _WIN32_WINNT_WINBLUE 0x0603 #endif #ifndef _WIN32_WINNT_WIN8 #define _WIN32_WINNT_WIN8 0x0602 #endif #ifndef WM_GETDPISCALEDSIZE #define WM_GETDPISCALEDSIZE 0x02e4 #endif #ifndef USER_DEFAULT_SCREEN_DPI #define USER_DEFAULT_SCREEN_DPI 96 #endif #ifndef OCR_HAND #define OCR_HAND 32649 #endif #if WINVER < 0x0601 typedef struct { DWORD cbSize; DWORD ExtStatus; } CHANGEFILTERSTRUCT; #ifndef MSGFLT_ALLOW #define MSGFLT_ALLOW 1 #endif #endif /*Windows 7*/ #if WINVER < 0x0600 #define DWM_BB_ENABLE 0x00000001 #define DWM_BB_BLURREGION 0x00000002 typedef struct { DWORD dwFlags; BOOL fEnable; HRGN hRgnBlur; BOOL fTransitionOnMaximized; } DWM_BLURBEHIND; #else #include #endif /*Windows Vista*/ #ifndef DPI_ENUMS_DECLARED typedef enum { PROCESS_DPI_UNAWARE = 0, PROCESS_SYSTEM_DPI_AWARE = 1, PROCESS_PER_MONITOR_DPI_AWARE = 2 } PROCESS_DPI_AWARENESS; typedef enum { MDT_EFFECTIVE_DPI = 0, MDT_ANGULAR_DPI = 1, MDT_RAW_DPI = 2, MDT_DEFAULT = MDT_EFFECTIVE_DPI } MONITOR_DPI_TYPE; #endif /*DPI_ENUMS_DECLARED*/ #ifndef DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 #define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((HANDLE) -4) #endif /*DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2*/ // 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) #define IsWindowsVistaOrGreater() \ _glfwIsWindowsVersionOrGreaterWin32(HIBYTE(_WIN32_WINNT_VISTA), \ LOBYTE(_WIN32_WINNT_VISTA), 0) #define IsWindows7OrGreater() \ _glfwIsWindowsVersionOrGreaterWin32(HIBYTE(_WIN32_WINNT_WIN7), \ LOBYTE(_WIN32_WINNT_WIN7), 0) #define IsWindows8OrGreater() \ _glfwIsWindowsVersionOrGreaterWin32(HIBYTE(_WIN32_WINNT_WIN8), \ LOBYTE(_WIN32_WINNT_WIN8), 0) #define IsWindows8Point1OrGreater() \ _glfwIsWindowsVersionOrGreaterWin32(HIBYTE(_WIN32_WINNT_WINBLUE), \ LOBYTE(_WIN32_WINNT_WINBLUE), 0) #define _glfwIsWindows10AnniversaryUpdateOrGreaterWin32() \ _glfwIsWindows10BuildOrGreaterWin32(14393) #define _glfwIsWindows10CreatorsUpdateOrGreaterWin32() \ _glfwIsWindows10BuildOrGreaterWin32(15063) // HACK: Define macros that some xinput.h variants don't #ifndef XINPUT_CAPS_WIRELESS #define XINPUT_CAPS_WIRELESS 0x0002 #endif #ifndef XINPUT_DEVSUBTYPE_WHEEL #define XINPUT_DEVSUBTYPE_WHEEL 0x02 #endif #ifndef XINPUT_DEVSUBTYPE_ARCADE_STICK #define XINPUT_DEVSUBTYPE_ARCADE_STICK 0x03 #endif #ifndef XINPUT_DEVSUBTYPE_FLIGHT_STICK #define XINPUT_DEVSUBTYPE_FLIGHT_STICK 0x04 #endif #ifndef XINPUT_DEVSUBTYPE_DANCE_PAD #define XINPUT_DEVSUBTYPE_DANCE_PAD 0x05 #endif #ifndef XINPUT_DEVSUBTYPE_GUITAR #define XINPUT_DEVSUBTYPE_GUITAR 0x06 #endif #ifndef XINPUT_DEVSUBTYPE_DRUM_KIT #define XINPUT_DEVSUBTYPE_DRUM_KIT 0x08 #endif #ifndef XINPUT_DEVSUBTYPE_ARCADE_PAD #define XINPUT_DEVSUBTYPE_ARCADE_PAD 0x13 #endif #ifndef XUSER_MAX_COUNT #define XUSER_MAX_COUNT 4 #endif // HACK: Define macros that some dinput.h variants don't #ifndef DIDFT_OPTIONAL #define DIDFT_OPTIONAL 0x80000000 #endif // xinput.dll function pointer typedefs typedef DWORD (WINAPI * PFN_XInputGetCapabilities)(DWORD,DWORD,XINPUT_CAPABILITIES*); typedef DWORD (WINAPI * PFN_XInputGetState)(DWORD,XINPUT_STATE*); #define XInputGetCapabilities _glfw.win32.xinput.GetCapabilities #define XInputGetState _glfw.win32.xinput.GetState // dinput8.dll function pointer typedefs typedef HRESULT (WINAPI * PFN_DirectInput8Create)(HINSTANCE,DWORD,REFIID,LPVOID*,LPUNKNOWN); #define DirectInput8Create _glfw.win32.dinput8.Create // user32.dll function pointer typedefs typedef BOOL (WINAPI * PFN_SetProcessDPIAware)(void); typedef BOOL (WINAPI * PFN_ChangeWindowMessageFilterEx)(HWND,UINT,DWORD,CHANGEFILTERSTRUCT*); typedef BOOL (WINAPI * PFN_EnableNonClientDpiScaling)(HWND); 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); typedef HRESULT (WINAPI * PFN_GetDpiForMonitor)(HMONITOR,MONITOR_DPI_TYPE,UINT*,UINT*); #define SetProcessDpiAwareness _glfw.win32.shcore.SetProcessDpiAwareness_ #define GetDpiForMonitor _glfw.win32.shcore.GetDpiForMonitor_ // ntdll.dll function pointer typedefs typedef LONG (WINAPI * PFN_RtlVerifyVersionInfo)(OSVERSIONINFOEXW*,ULONG,ULONGLONG); #define RtlVerifyVersionInfo _glfw.win32.ntdll.RtlVerifyVersionInfo_ typedef VkFlags VkWin32SurfaceCreateFlagsKHR; typedef struct VkWin32SurfaceCreateInfoKHR { VkStructureType sType; const void* pNext; VkWin32SurfaceCreateFlagsKHR flags; HINSTANCE hinstance; HWND hwnd; } VkWin32SurfaceCreateInfoKHR; typedef VkResult (APIENTRY *PFN_vkCreateWin32SurfaceKHR)(VkInstance,const VkWin32SurfaceCreateInfoKHR*,const VkAllocationCallbacks*,VkSurfaceKHR*); typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR)(VkPhysicalDevice,uint32_t); #ifndef HEADER_GUARD_WIN32_JOYSTICK_H #define HEADER_GUARD_WIN32_JOYSTICK_H //======================================================================== // GLFW 3.3.7 Win32 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2006-2017 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== #define _GLFW_PLATFORM_JOYSTICK_STATE _GLFWjoystickWin32 win32 #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) // typedef struct _GLFWjoyobjectWin32 { int offset; int type; } _GLFWjoyobjectWin32; // Win32-specific per-joystick data // typedef struct _GLFWjoystickWin32 { _GLFWjoyobjectWin32* objects; int objectCount; IDirectInputDevice8W* device; DWORD index; GUID guid; } _GLFWjoystickWin32; void _glfwInitJoysticksWin32(void); void _glfwTerminateJoysticksWin32(void); void _glfwDetectJoystickConnectionWin32(void); void _glfwDetectJoystickDisconnectionWin32(void); #endif #ifndef HEADER_GUARD_WGL_CONTEXT_H #define HEADER_GUARD_WGL_CONTEXT_H //======================================================================== // GLFW 3.3.7 WGL - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2018 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== #define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000 #define WGL_SUPPORT_OPENGL_ARB 0x2010 #define WGL_DRAW_TO_WINDOW_ARB 0x2001 #define WGL_PIXEL_TYPE_ARB 0x2013 #define WGL_TYPE_RGBA_ARB 0x202b #define WGL_ACCELERATION_ARB 0x2003 #define WGL_NO_ACCELERATION_ARB 0x2025 #define WGL_RED_BITS_ARB 0x2015 #define WGL_RED_SHIFT_ARB 0x2016 #define WGL_GREEN_BITS_ARB 0x2017 #define WGL_GREEN_SHIFT_ARB 0x2018 #define WGL_BLUE_BITS_ARB 0x2019 #define WGL_BLUE_SHIFT_ARB 0x201a #define WGL_ALPHA_BITS_ARB 0x201b #define WGL_ALPHA_SHIFT_ARB 0x201c #define WGL_ACCUM_BITS_ARB 0x201d #define WGL_ACCUM_RED_BITS_ARB 0x201e #define WGL_ACCUM_GREEN_BITS_ARB 0x201f #define WGL_ACCUM_BLUE_BITS_ARB 0x2020 #define WGL_ACCUM_ALPHA_BITS_ARB 0x2021 #define WGL_DEPTH_BITS_ARB 0x2022 #define WGL_STENCIL_BITS_ARB 0x2023 #define WGL_AUX_BUFFERS_ARB 0x2024 #define WGL_STEREO_ARB 0x2012 #define WGL_DOUBLE_BUFFER_ARB 0x2011 #define WGL_SAMPLES_ARB 0x2042 #define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20a9 #define WGL_CONTEXT_DEBUG_BIT_ARB 0x00000001 #define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002 #define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 #define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 #define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 #define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 #define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 #define WGL_CONTEXT_FLAGS_ARB 0x2094 #define WGL_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004 #define WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004 #define WGL_LOSE_CONTEXT_ON_RESET_ARB 0x8252 #define WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 #define WGL_NO_RESET_NOTIFICATION_ARB 0x8261 #define WGL_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097 #define WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0 #define WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098 #define WGL_CONTEXT_OPENGL_NO_ERROR_ARB 0x31b3 #define WGL_COLORSPACE_EXT 0x309d #define WGL_COLORSPACE_SRGB_EXT 0x3089 #define ERROR_INVALID_VERSION_ARB 0x2095 #define ERROR_INVALID_PROFILE_ARB 0x2096 #define ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB 0x2054 // WGL extension pointer typedefs typedef BOOL (WINAPI * PFNWGLSWAPINTERVALEXTPROC)(int); typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVARBPROC)(HDC,int,int,UINT,const int*,int*); typedef const char* (WINAPI * PFNWGLGETEXTENSIONSSTRINGEXTPROC)(void); typedef const char* (WINAPI * PFNWGLGETEXTENSIONSSTRINGARBPROC)(HDC); typedef HGLRC (WINAPI * PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC,HGLRC,const int*); #define wglSwapIntervalEXT _glfw.wgl.SwapIntervalEXT #define wglGetPixelFormatAttribivARB _glfw.wgl.GetPixelFormatAttribivARB #define wglGetExtensionsStringEXT _glfw.wgl.GetExtensionsStringEXT #define wglGetExtensionsStringARB _glfw.wgl.GetExtensionsStringARB #define wglCreateContextAttribsARB _glfw.wgl.CreateContextAttribsARB // opengl32.dll function pointer typedefs typedef HGLRC (WINAPI * PFN_wglCreateContext)(HDC); typedef BOOL (WINAPI * PFN_wglDeleteContext)(HGLRC); typedef PROC (WINAPI * PFN_wglGetProcAddress)(LPCSTR); typedef HDC (WINAPI * PFN_wglGetCurrentDC)(void); typedef HGLRC (WINAPI * PFN_wglGetCurrentContext)(void); typedef BOOL (WINAPI * PFN_wglMakeCurrent)(HDC,HGLRC); typedef BOOL (WINAPI * PFN_wglShareLists)(HGLRC,HGLRC); #define wglCreateContext _glfw.wgl.CreateContext #define wglDeleteContext _glfw.wgl.DeleteContext #define wglGetProcAddress _glfw.wgl.GetProcAddress #define wglGetCurrentDC _glfw.wgl.GetCurrentDC #define wglGetCurrentContext _glfw.wgl.GetCurrentContext #define wglMakeCurrent _glfw.wgl.MakeCurrent #define wglShareLists _glfw.wgl.ShareLists #define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextWGL wgl #define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE _GLFWlibraryWGL wgl // WGL-specific per-context data // typedef struct _GLFWcontextWGL { HDC dc; HGLRC handle; int interval; } _GLFWcontextWGL; // WGL-specific global data // typedef struct _GLFWlibraryWGL { HINSTANCE instance; PFN_wglCreateContext CreateContext; PFN_wglDeleteContext DeleteContext; PFN_wglGetProcAddress GetProcAddress; PFN_wglGetCurrentDC GetCurrentDC; PFN_wglGetCurrentContext GetCurrentContext; PFN_wglMakeCurrent MakeCurrent; PFN_wglShareLists ShareLists; PFNWGLSWAPINTERVALEXTPROC SwapIntervalEXT; PFNWGLGETPIXELFORMATATTRIBIVARBPROC GetPixelFormatAttribivARB; PFNWGLGETEXTENSIONSSTRINGEXTPROC GetExtensionsStringEXT; PFNWGLGETEXTENSIONSSTRINGARBPROC GetExtensionsStringARB; PFNWGLCREATECONTEXTATTRIBSARBPROC CreateContextAttribsARB; GLFWbool EXT_swap_control; GLFWbool EXT_colorspace; GLFWbool ARB_multisample; GLFWbool ARB_framebuffer_sRGB; GLFWbool EXT_framebuffer_sRGB; GLFWbool ARB_pixel_format; GLFWbool ARB_create_context; GLFWbool ARB_create_context_profile; GLFWbool EXT_create_context_es2_profile; GLFWbool ARB_create_context_robustness; GLFWbool ARB_create_context_no_error; GLFWbool ARB_context_flush_control; } _GLFWlibraryWGL; GLFWbool _glfwInitWGL(void); void _glfwTerminateWGL(void); GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig); #endif #ifndef HEADER_GUARD_EGL_CONTEXT_H #define HEADER_GUARD_EGL_CONTEXT_H //======================================================================== // GLFW 3.3.7 EGL - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2017 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== #if defined(_GLFW_USE_EGLPLATFORM_H) #include #elif defined(_GLFW_WIN32) #define EGLAPIENTRY __stdcall typedef HDC EGLNativeDisplayType; typedef HWND EGLNativeWindowType; #elif defined(_GLFW_COCOA) #define EGLAPIENTRY typedef void* EGLNativeDisplayType; typedef id EGLNativeWindowType; #elif defined(_GLFW_X11) #define EGLAPIENTRY typedef Display* EGLNativeDisplayType; typedef Window EGLNativeWindowType; #elif defined(_GLFW_WAYLAND) #define EGLAPIENTRY typedef struct wl_display* EGLNativeDisplayType; typedef struct wl_egl_window* EGLNativeWindowType; #else #error "No supported EGL platform selected" #endif #define EGL_SUCCESS 0x3000 #define EGL_NOT_INITIALIZED 0x3001 #define EGL_BAD_ACCESS 0x3002 #define EGL_BAD_ALLOC 0x3003 #define EGL_BAD_ATTRIBUTE 0x3004 #define EGL_BAD_CONFIG 0x3005 #define EGL_BAD_CONTEXT 0x3006 #define EGL_BAD_CURRENT_SURFACE 0x3007 #define EGL_BAD_DISPLAY 0x3008 #define EGL_BAD_MATCH 0x3009 #define EGL_BAD_NATIVE_PIXMAP 0x300a #define EGL_BAD_NATIVE_WINDOW 0x300b #define EGL_BAD_PARAMETER 0x300c #define EGL_BAD_SURFACE 0x300d #define EGL_CONTEXT_LOST 0x300e #define EGL_COLOR_BUFFER_TYPE 0x303f #define EGL_RGB_BUFFER 0x308e #define EGL_SURFACE_TYPE 0x3033 #define EGL_WINDOW_BIT 0x0004 #define EGL_RENDERABLE_TYPE 0x3040 #define EGL_OPENGL_ES_BIT 0x0001 #define EGL_OPENGL_ES2_BIT 0x0004 #define EGL_OPENGL_BIT 0x0008 #define EGL_ALPHA_SIZE 0x3021 #define EGL_BLUE_SIZE 0x3022 #define EGL_GREEN_SIZE 0x3023 #define EGL_RED_SIZE 0x3024 #define EGL_DEPTH_SIZE 0x3025 #define EGL_STENCIL_SIZE 0x3026 #define EGL_SAMPLES 0x3031 #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 #define EGL_NO_SURFACE ((EGLSurface) 0) #define EGL_NO_DISPLAY ((EGLDisplay) 0) #define EGL_NO_CONTEXT ((EGLContext) 0) #define EGL_DEFAULT_DISPLAY ((EGLNativeDisplayType) 0) #define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR 0x00000002 #define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR 0x00000001 #define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR 0x00000002 #define EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR 0x00000001 #define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR 0x31bd #define EGL_NO_RESET_NOTIFICATION_KHR 0x31be #define EGL_LOSE_CONTEXT_ON_RESET_KHR 0x31bf #define EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR 0x00000004 #define EGL_CONTEXT_MAJOR_VERSION_KHR 0x3098 #define EGL_CONTEXT_MINOR_VERSION_KHR 0x30fb #define EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR 0x30fd #define EGL_CONTEXT_FLAGS_KHR 0x30fc #define EGL_CONTEXT_OPENGL_NO_ERROR_KHR 0x31b3 #define EGL_GL_COLORSPACE_KHR 0x309d #define EGL_GL_COLORSPACE_SRGB_KHR 0x3089 #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; typedef unsigned int EGLenum; typedef void* EGLConfig; typedef void* EGLContext; typedef void* EGLDisplay; typedef void* EGLSurface; // EGL function pointer typedefs typedef EGLBoolean (EGLAPIENTRY * PFN_eglGetConfigAttrib)(EGLDisplay,EGLConfig,EGLint,EGLint*); typedef EGLBoolean (EGLAPIENTRY * PFN_eglGetConfigs)(EGLDisplay,EGLConfig*,EGLint,EGLint*); typedef EGLDisplay (EGLAPIENTRY * PFN_eglGetDisplay)(EGLNativeDisplayType); typedef EGLint (EGLAPIENTRY * PFN_eglGetError)(void); typedef EGLBoolean (EGLAPIENTRY * PFN_eglInitialize)(EGLDisplay,EGLint*,EGLint*); typedef EGLBoolean (EGLAPIENTRY * PFN_eglTerminate)(EGLDisplay); typedef EGLBoolean (EGLAPIENTRY * PFN_eglBindAPI)(EGLenum); typedef EGLContext (EGLAPIENTRY * PFN_eglCreateContext)(EGLDisplay,EGLConfig,EGLContext,const EGLint*); typedef EGLBoolean (EGLAPIENTRY * PFN_eglDestroySurface)(EGLDisplay,EGLSurface); typedef EGLBoolean (EGLAPIENTRY * PFN_eglDestroyContext)(EGLDisplay,EGLContext); typedef EGLSurface (EGLAPIENTRY * PFN_eglCreateWindowSurface)(EGLDisplay,EGLConfig,EGLNativeWindowType,const EGLint*); typedef EGLBoolean (EGLAPIENTRY * PFN_eglMakeCurrent)(EGLDisplay,EGLSurface,EGLSurface,EGLContext); typedef EGLBoolean (EGLAPIENTRY * PFN_eglSwapBuffers)(EGLDisplay,EGLSurface); typedef EGLBoolean (EGLAPIENTRY * PFN_eglSwapInterval)(EGLDisplay,EGLint); typedef const char* (EGLAPIENTRY * PFN_eglQueryString)(EGLDisplay,EGLint); typedef GLFWglproc (EGLAPIENTRY * PFN_eglGetProcAddress)(const char*); #define eglGetConfigAttrib _glfw.egl.GetConfigAttrib #define eglGetConfigs _glfw.egl.GetConfigs #define eglGetDisplay _glfw.egl.GetDisplay #define eglGetError _glfw.egl.GetError #define eglInitialize _glfw.egl.Initialize #define eglTerminate _glfw.egl.Terminate #define eglBindAPI _glfw.egl.BindAPI #define eglCreateContext _glfw.egl.CreateContext #define eglDestroySurface _glfw.egl.DestroySurface #define eglDestroyContext _glfw.egl.DestroyContext #define eglCreateWindowSurface _glfw.egl.CreateWindowSurface #define eglMakeCurrent _glfw.egl.MakeCurrent #define eglSwapBuffers _glfw.egl.SwapBuffers #define eglSwapInterval _glfw.egl.SwapInterval #define eglQueryString _glfw.egl.QueryString #define eglGetProcAddress _glfw.egl.GetProcAddress #define _GLFW_EGL_CONTEXT_STATE _GLFWcontextEGL egl #define _GLFW_EGL_LIBRARY_CONTEXT_STATE _GLFWlibraryEGL egl // EGL-specific per-context data // typedef struct _GLFWcontextEGL { EGLConfig config; EGLContext handle; EGLSurface surface; void* client; } _GLFWcontextEGL; // EGL-specific global data // typedef struct _GLFWlibraryEGL { EGLDisplay display; EGLint major, minor; GLFWbool prefix; GLFWbool KHR_create_context; GLFWbool KHR_create_context_no_error; GLFWbool KHR_gl_colorspace; GLFWbool KHR_get_all_proc_addresses; GLFWbool KHR_context_flush_control; GLFWbool EXT_present_opaque; void* handle; PFN_eglGetConfigAttrib GetConfigAttrib; PFN_eglGetConfigs GetConfigs; PFN_eglGetDisplay GetDisplay; PFN_eglGetError GetError; PFN_eglInitialize Initialize; PFN_eglTerminate Terminate; PFN_eglBindAPI BindAPI; PFN_eglCreateContext CreateContext; PFN_eglDestroySurface DestroySurface; PFN_eglDestroyContext DestroyContext; PFN_eglCreateWindowSurface CreateWindowSurface; PFN_eglMakeCurrent MakeCurrent; PFN_eglSwapBuffers SwapBuffers; PFN_eglSwapInterval SwapInterval; PFN_eglQueryString QueryString; PFN_eglGetProcAddress GetProcAddress; } _GLFWlibraryEGL; GLFWbool _glfwInitEGL(void); void _glfwTerminateEGL(void); GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig); #if defined(_GLFW_X11) GLFWbool _glfwChooseVisualEGL(const _GLFWwndconfig* wndconfig, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig, Visual** visual, int* depth); #endif /*_GLFW_X11*/ #endif #ifndef HEADER_GUARD_OSMESA_CONTEXT_H #define HEADER_GUARD_OSMESA_CONTEXT_H //======================================================================== // GLFW 3.3.7 OSMesa - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2016 Google Inc. // Copyright (c) 2016-2017 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== #define OSMESA_RGBA 0x1908 #define OSMESA_FORMAT 0x22 #define OSMESA_DEPTH_BITS 0x30 #define OSMESA_STENCIL_BITS 0x31 #define OSMESA_ACCUM_BITS 0x32 #define OSMESA_PROFILE 0x33 #define OSMESA_CORE_PROFILE 0x34 #define OSMESA_COMPAT_PROFILE 0x35 #define OSMESA_CONTEXT_MAJOR_VERSION 0x36 #define OSMESA_CONTEXT_MINOR_VERSION 0x37 typedef void* OSMesaContext; typedef void (*OSMESAproc)(void); typedef OSMesaContext (GLAPIENTRY * PFN_OSMesaCreateContextExt)(GLenum,GLint,GLint,GLint,OSMesaContext); typedef OSMesaContext (GLAPIENTRY * PFN_OSMesaCreateContextAttribs)(const int*,OSMesaContext); typedef void (GLAPIENTRY * PFN_OSMesaDestroyContext)(OSMesaContext); typedef int (GLAPIENTRY * PFN_OSMesaMakeCurrent)(OSMesaContext,void*,int,int,int); typedef int (GLAPIENTRY * PFN_OSMesaGetColorBuffer)(OSMesaContext,int*,int*,int*,void**); typedef int (GLAPIENTRY * PFN_OSMesaGetDepthBuffer)(OSMesaContext,int*,int*,int*,void**); typedef GLFWglproc (GLAPIENTRY * PFN_OSMesaGetProcAddress)(const char*); #define OSMesaCreateContextExt _glfw.osmesa.CreateContextExt #define OSMesaCreateContextAttribs _glfw.osmesa.CreateContextAttribs #define OSMesaDestroyContext _glfw.osmesa.DestroyContext #define OSMesaMakeCurrent _glfw.osmesa.MakeCurrent #define OSMesaGetColorBuffer _glfw.osmesa.GetColorBuffer #define OSMesaGetDepthBuffer _glfw.osmesa.GetDepthBuffer #define OSMesaGetProcAddress _glfw.osmesa.GetProcAddress #define _GLFW_OSMESA_CONTEXT_STATE _GLFWcontextOSMesa osmesa #define _GLFW_OSMESA_LIBRARY_CONTEXT_STATE _GLFWlibraryOSMesa osmesa // OSMesa-specific per-context data // typedef struct _GLFWcontextOSMesa { OSMesaContext handle; int width; int height; void* buffer; } _GLFWcontextOSMesa; // OSMesa-specific global data // typedef struct _GLFWlibraryOSMesa { void* handle; PFN_OSMesaCreateContextExt CreateContextExt; PFN_OSMesaCreateContextAttribs CreateContextAttribs; PFN_OSMesaDestroyContext DestroyContext; PFN_OSMesaMakeCurrent MakeCurrent; PFN_OSMesaGetColorBuffer GetColorBuffer; PFN_OSMesaGetDepthBuffer GetDepthBuffer; PFN_OSMesaGetProcAddress GetProcAddress; } _GLFWlibraryOSMesa; GLFWbool _glfwInitOSMesa(void); void _glfwTerminateOSMesa(void); GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig); #endif #if !defined(_GLFW_WNDCLASSNAME) #define _GLFW_WNDCLASSNAME L"GLFW30" #endif #define _glfw_dlopen(name) LoadLibraryA(name) #define _glfw_dlclose(handle) FreeLibrary((HMODULE) handle) #define _glfw_dlsym(handle, name) GetProcAddress((HMODULE) handle, name) #define _GLFW_EGL_NATIVE_WINDOW ((EGLNativeWindowType) window->win32.handle) #define _GLFW_EGL_NATIVE_DISPLAY EGL_DEFAULT_DISPLAY #define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowWin32 win32 #define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryWin32 win32 #define _GLFW_PLATFORM_LIBRARY_TIMER_STATE _GLFWtimerWin32 win32 #define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorWin32 win32 #define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorWin32 win32 #define _GLFW_PLATFORM_TLS_STATE _GLFWtlsWin32 win32 #define _GLFW_PLATFORM_MUTEX_STATE _GLFWmutexWin32 win32 // Win32-specific per-window data // typedef struct _GLFWwindowWin32 { HWND handle; HICON bigIcon; HICON smallIcon; GLFWbool cursorTracked; GLFWbool frameAction; GLFWbool iconified; GLFWbool maximized; // Whether to enable framebuffer transparency on DWM 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 { HWND helperWindowHandle; HDEVNOTIFY deviceNotificationHandle; DWORD foregroundLockTimeout; int acquiredMonitorCount; char* clipboardString; short int keycodes[512]; short int scancodes[GLFW_KEY_LAST + 1]; char keynames[GLFW_KEY_LAST + 1][5]; // Where to place the cursor when re-enabled double restoreCursorPosX, restoreCursorPosY; // The window whose disabled cursor mode is active _GLFWwindow* disabledCursorWindow; RAWINPUT* rawInput; int rawInputSize; UINT mouseTrailSize; struct { HINSTANCE instance; PFN_DirectInput8Create Create; IDirectInput8W* api; } dinput8; struct { HINSTANCE instance; PFN_XInputGetCapabilities GetCapabilities; PFN_XInputGetState GetState; } xinput; struct { HINSTANCE instance; PFN_SetProcessDPIAware SetProcessDPIAware_; PFN_ChangeWindowMessageFilterEx ChangeWindowMessageFilterEx_; PFN_EnableNonClientDpiScaling EnableNonClientDpiScaling_; PFN_SetProcessDpiAwarenessContext SetProcessDpiAwarenessContext_; PFN_GetDpiForWindow GetDpiForWindow_; PFN_AdjustWindowRectExForDpi AdjustWindowRectExForDpi_; PFN_GetSystemMetricsForDpi GetSystemMetricsForDpi_; } user32; struct { HINSTANCE instance; PFN_DwmIsCompositionEnabled IsCompositionEnabled; PFN_DwmFlush Flush; PFN_DwmEnableBlurBehindWindow EnableBlurBehindWindow; PFN_DwmGetColorizationColor GetColorizationColor; } dwmapi; struct { HINSTANCE instance; PFN_SetProcessDpiAwareness SetProcessDpiAwareness_; PFN_GetDpiForMonitor GetDpiForMonitor_; } shcore; struct { HINSTANCE instance; PFN_RtlVerifyVersionInfo RtlVerifyVersionInfo_; } ntdll; } _GLFWlibraryWin32; // Win32-specific per-monitor data // typedef struct _GLFWmonitorWin32 { HMONITOR handle; // This size matches the static size of DISPLAY_DEVICE.DeviceName WCHAR adapterName[32]; WCHAR displayName[32]; char publicAdapterName[32]; char publicDisplayName[32]; GLFWbool modesPruned; GLFWbool modeChanged; } _GLFWmonitorWin32; // Win32-specific per-cursor data // typedef struct _GLFWcursorWin32 { HCURSOR handle; } _GLFWcursorWin32; // Win32-specific global timer data // typedef struct _GLFWtimerWin32 { uint64_t frequency; } _GLFWtimerWin32; // Win32-specific thread local storage data // typedef struct _GLFWtlsWin32 { GLFWbool allocated; DWORD index; } _GLFWtlsWin32; // Win32-specific mutex data // typedef struct _GLFWmutexWin32 { GLFWbool allocated; CRITICAL_SECTION section; } _GLFWmutexWin32; GLFWbool _glfwRegisterWindowClassWin32(void); void _glfwUnregisterWindowClassWin32(void); WCHAR* _glfwCreateWideStringFromUTF8Win32(const char* source); char* _glfwCreateUTF8FromWideStringWin32(const WCHAR* source); BOOL _glfwIsWindowsVersionOrGreaterWin32(WORD major, WORD minor, WORD sp); BOOL _glfwIsWindows10BuildOrGreaterWin32(WORD build); void _glfwInputErrorWin32(int error, const char* description); void _glfwUpdateKeyNamesWin32(void); void _glfwInitTimerWin32(void); void _glfwPollMonitorsWin32(void); void _glfwSetVideoModeWin32(_GLFWmonitor* monitor, const GLFWvidmode* desired); void _glfwRestoreVideoModeWin32(_GLFWmonitor* monitor); void _glfwGetMonitorContentScaleWin32(HMONITOR handle, float* xscale, float* yscale); #endif #elif defined(_GLFW_X11) #ifndef HEADER_GUARD_X11_PLATFORM_H #define HEADER_GUARD_X11_PLATFORM_H //======================================================================== // GLFW 3.3.7 X11 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2019 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== #include #include #include #include #include #include #include #include // The XRandR extension provides mode setting and gamma control #include // The Xkb extension provides improved keyboard support #include // The Xinerama extension provides legacy monitor indices #include // The XInput extension provides raw mouse motion input #include typedef XRRCrtcGamma* (* PFN_XRRAllocGamma)(int); typedef void (* PFN_XRRFreeCrtcInfo)(XRRCrtcInfo*); typedef void (* PFN_XRRFreeGamma)(XRRCrtcGamma*); typedef void (* PFN_XRRFreeOutputInfo)(XRROutputInfo*); typedef void (* PFN_XRRFreeScreenResources)(XRRScreenResources*); typedef XRRCrtcGamma* (* PFN_XRRGetCrtcGamma)(Display*,RRCrtc); typedef int (* PFN_XRRGetCrtcGammaSize)(Display*,RRCrtc); typedef XRRCrtcInfo* (* PFN_XRRGetCrtcInfo) (Display*,XRRScreenResources*,RRCrtc); typedef XRROutputInfo* (* PFN_XRRGetOutputInfo)(Display*,XRRScreenResources*,RROutput); typedef RROutput (* PFN_XRRGetOutputPrimary)(Display*,Window); typedef XRRScreenResources* (* PFN_XRRGetScreenResourcesCurrent)(Display*,Window); typedef Bool (* PFN_XRRQueryExtension)(Display*,int*,int*); typedef Status (* PFN_XRRQueryVersion)(Display*,int*,int*); typedef void (* PFN_XRRSelectInput)(Display*,Window,int); typedef Status (* PFN_XRRSetCrtcConfig)(Display*,XRRScreenResources*,RRCrtc,Time,int,int,RRMode,Rotation,RROutput*,int); typedef void (* PFN_XRRSetCrtcGamma)(Display*,RRCrtc,XRRCrtcGamma*); typedef int (* PFN_XRRUpdateConfiguration)(XEvent*); #define XRRAllocGamma _glfw.x11.randr.AllocGamma #define XRRFreeCrtcInfo _glfw.x11.randr.FreeCrtcInfo #define XRRFreeGamma _glfw.x11.randr.FreeGamma #define XRRFreeOutputInfo _glfw.x11.randr.FreeOutputInfo #define XRRFreeScreenResources _glfw.x11.randr.FreeScreenResources #define XRRGetCrtcGamma _glfw.x11.randr.GetCrtcGamma #define XRRGetCrtcGammaSize _glfw.x11.randr.GetCrtcGammaSize #define XRRGetCrtcInfo _glfw.x11.randr.GetCrtcInfo #define XRRGetOutputInfo _glfw.x11.randr.GetOutputInfo #define XRRGetOutputPrimary _glfw.x11.randr.GetOutputPrimary #define XRRGetScreenResourcesCurrent _glfw.x11.randr.GetScreenResourcesCurrent #define XRRQueryExtension _glfw.x11.randr.QueryExtension #define XRRQueryVersion _glfw.x11.randr.QueryVersion #define XRRSelectInput _glfw.x11.randr.SelectInput #define XRRSetCrtcConfig _glfw.x11.randr.SetCrtcConfig #define XRRSetCrtcGamma _glfw.x11.randr.SetCrtcGamma #define XRRUpdateConfiguration _glfw.x11.randr.UpdateConfiguration typedef XcursorImage* (* PFN_XcursorImageCreate)(int,int); typedef void (* PFN_XcursorImageDestroy)(XcursorImage*); typedef Cursor (* PFN_XcursorImageLoadCursor)(Display*,const XcursorImage*); #define XcursorImageCreate _glfw.x11.xcursor.ImageCreate #define XcursorImageDestroy _glfw.x11.xcursor.ImageDestroy #define XcursorImageLoadCursor _glfw.x11.xcursor.ImageLoadCursor typedef Bool (* PFN_XineramaIsActive)(Display*); typedef Bool (* PFN_XineramaQueryExtension)(Display*,int*,int*); typedef XineramaScreenInfo* (* PFN_XineramaQueryScreens)(Display*,int*); #define XineramaIsActive _glfw.x11.xinerama.IsActive #define XineramaQueryExtension _glfw.x11.xinerama.QueryExtension #define XineramaQueryScreens _glfw.x11.xinerama.QueryScreens typedef XID xcb_window_t; typedef XID xcb_visualid_t; typedef struct xcb_connection_t xcb_connection_t; typedef xcb_connection_t* (* PFN_XGetXCBConnection)(Display*); #define XGetXCBConnection _glfw.x11.x11xcb.GetXCBConnection typedef Bool (* PFN_XF86VidModeQueryExtension)(Display*,int*,int*); typedef Bool (* PFN_XF86VidModeGetGammaRamp)(Display*,int,int,unsigned short*,unsigned short*,unsigned short*); typedef Bool (* PFN_XF86VidModeSetGammaRamp)(Display*,int,int,unsigned short*,unsigned short*,unsigned short*); typedef Bool (* PFN_XF86VidModeGetGammaRampSize)(Display*,int,int*); #define XF86VidModeQueryExtension _glfw.x11.vidmode.QueryExtension #define XF86VidModeGetGammaRamp _glfw.x11.vidmode.GetGammaRamp #define XF86VidModeSetGammaRamp _glfw.x11.vidmode.SetGammaRamp #define XF86VidModeGetGammaRampSize _glfw.x11.vidmode.GetGammaRampSize typedef Status (* PFN_XIQueryVersion)(Display*,int*,int*); typedef int (* PFN_XISelectEvents)(Display*,Window,XIEventMask*,int); #define XIQueryVersion _glfw.x11.xi.QueryVersion #define XISelectEvents _glfw.x11.xi.SelectEvents typedef Bool (* PFN_XRenderQueryExtension)(Display*,int*,int*); typedef Status (* PFN_XRenderQueryVersion)(Display*dpy,int*,int*); typedef XRenderPictFormat* (* PFN_XRenderFindVisualFormat)(Display*,Visual const*); #define XRenderQueryExtension _glfw.x11.xrender.QueryExtension #define XRenderQueryVersion _glfw.x11.xrender.QueryVersion #define XRenderFindVisualFormat _glfw.x11.xrender.FindVisualFormat typedef VkFlags VkXlibSurfaceCreateFlagsKHR; typedef VkFlags VkXcbSurfaceCreateFlagsKHR; typedef struct VkXlibSurfaceCreateInfoKHR { VkStructureType sType; const void* pNext; VkXlibSurfaceCreateFlagsKHR flags; Display* dpy; Window window; } VkXlibSurfaceCreateInfoKHR; typedef struct VkXcbSurfaceCreateInfoKHR { VkStructureType sType; const void* pNext; VkXcbSurfaceCreateFlagsKHR flags; xcb_connection_t* connection; xcb_window_t window; } VkXcbSurfaceCreateInfoKHR; typedef VkResult (APIENTRY *PFN_vkCreateXlibSurfaceKHR)(VkInstance,const VkXlibSurfaceCreateInfoKHR*,const VkAllocationCallbacks*,VkSurfaceKHR*); typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR)(VkPhysicalDevice,uint32_t,Display*,VisualID); typedef VkResult (APIENTRY *PFN_vkCreateXcbSurfaceKHR)(VkInstance,const VkXcbSurfaceCreateInfoKHR*,const VkAllocationCallbacks*,VkSurfaceKHR*); typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)(VkPhysicalDevice,uint32_t,xcb_connection_t*,xcb_visualid_t); #ifndef HEADER_GUARD_POSIX_THREAD_H #define HEADER_GUARD_POSIX_THREAD_H //======================================================================== // GLFW 3.3.7 POSIX - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2017 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== #include #define _GLFW_PLATFORM_TLS_STATE _GLFWtlsPOSIX posix #define _GLFW_PLATFORM_MUTEX_STATE _GLFWmutexPOSIX posix // POSIX-specific thread local storage data // typedef struct _GLFWtlsPOSIX { GLFWbool allocated; pthread_key_t key; } _GLFWtlsPOSIX; // POSIX-specific mutex data // typedef struct _GLFWmutexPOSIX { GLFWbool allocated; pthread_mutex_t handle; } _GLFWmutexPOSIX; #endif #ifndef HEADER_GUARD_POSIX_TIME_H #define HEADER_GUARD_POSIX_TIME_H //======================================================================== // GLFW 3.3.7 POSIX - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2017 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== #define _GLFW_PLATFORM_LIBRARY_TIMER_STATE _GLFWtimerPOSIX posix #include // POSIX-specific global timer data // typedef struct _GLFWtimerPOSIX { GLFWbool monotonic; uint64_t frequency; } _GLFWtimerPOSIX; void _glfwInitTimerPOSIX(void); #endif #ifndef HEADER_GUARD_XKB_UNICODE_H #define HEADER_GUARD_XKB_UNICODE_H //======================================================================== // GLFW 3.3.7 Linux - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2014 Jonas Ådahl // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== #define GLFW_INVALID_CODEPOINT 0xffffffffu uint32_t _glfwKeySym2Unicode(unsigned int keysym); #endif #ifndef HEADER_GUARD_GLX_CONTEXT_H #define HEADER_GUARD_GLX_CONTEXT_H //======================================================================== // GLFW 3.3.7 GLX - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2017 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== #define GLX_VENDOR 1 #define GLX_RGBA_BIT 0x00000001 #define GLX_WINDOW_BIT 0x00000001 #define GLX_DRAWABLE_TYPE 0x8010 #define GLX_RENDER_TYPE 0x8011 #define GLX_RGBA_TYPE 0x8014 #define GLX_DOUBLEBUFFER 5 #define GLX_STEREO 6 #define GLX_AUX_BUFFERS 7 #define GLX_RED_SIZE 8 #define GLX_GREEN_SIZE 9 #define GLX_BLUE_SIZE 10 #define GLX_ALPHA_SIZE 11 #define GLX_DEPTH_SIZE 12 #define GLX_STENCIL_SIZE 13 #define GLX_ACCUM_RED_SIZE 14 #define GLX_ACCUM_GREEN_SIZE 15 #define GLX_ACCUM_BLUE_SIZE 16 #define GLX_ACCUM_ALPHA_SIZE 17 #define GLX_SAMPLES 0x186a1 #define GLX_VISUAL_ID 0x800b #define GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20b2 #define GLX_CONTEXT_DEBUG_BIT_ARB 0x00000001 #define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 #define GLX_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 #define GLX_CONTEXT_PROFILE_MASK_ARB 0x9126 #define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002 #define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091 #define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092 #define GLX_CONTEXT_FLAGS_ARB 0x2094 #define GLX_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004 #define GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004 #define GLX_LOSE_CONTEXT_ON_RESET_ARB 0x8252 #define GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 #define GLX_NO_RESET_NOTIFICATION_ARB 0x8261 #define GLX_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097 #define GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0 #define GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098 #define GLX_CONTEXT_OPENGL_NO_ERROR_ARB 0x31b3 typedef XID GLXWindow; typedef XID GLXDrawable; typedef struct __GLXFBConfig* GLXFBConfig; typedef struct __GLXcontext* GLXContext; typedef void (*__GLXextproc)(void); typedef int (*PFNGLXGETFBCONFIGATTRIBPROC)(Display*,GLXFBConfig,int,int*); typedef const char* (*PFNGLXGETCLIENTSTRINGPROC)(Display*,int); typedef Bool (*PFNGLXQUERYEXTENSIONPROC)(Display*,int*,int*); typedef Bool (*PFNGLXQUERYVERSIONPROC)(Display*,int*,int*); typedef void (*PFNGLXDESTROYCONTEXTPROC)(Display*,GLXContext); typedef Bool (*PFNGLXMAKECURRENTPROC)(Display*,GLXDrawable,GLXContext); typedef void (*PFNGLXSWAPBUFFERSPROC)(Display*,GLXDrawable); typedef const char* (*PFNGLXQUERYEXTENSIONSSTRINGPROC)(Display*,int); typedef GLXFBConfig* (*PFNGLXGETFBCONFIGSPROC)(Display*,int,int*); typedef GLXContext (*PFNGLXCREATENEWCONTEXTPROC)(Display*,GLXFBConfig,int,GLXContext,Bool); typedef __GLXextproc (* PFNGLXGETPROCADDRESSPROC)(const GLubyte *procName); typedef void (*PFNGLXSWAPINTERVALEXTPROC)(Display*,GLXDrawable,int); typedef XVisualInfo* (*PFNGLXGETVISUALFROMFBCONFIGPROC)(Display*,GLXFBConfig); typedef GLXWindow (*PFNGLXCREATEWINDOWPROC)(Display*,GLXFBConfig,Window,const int*); typedef void (*PFNGLXDESTROYWINDOWPROC)(Display*,GLXWindow); typedef int (*PFNGLXSWAPINTERVALMESAPROC)(int); typedef int (*PFNGLXSWAPINTERVALSGIPROC)(int); typedef GLXContext (*PFNGLXCREATECONTEXTATTRIBSARBPROC)(Display*,GLXFBConfig,GLXContext,Bool,const int*); // libGL.so function pointer typedefs #define glXGetFBConfigs _glfw.glx.GetFBConfigs #define glXGetFBConfigAttrib _glfw.glx.GetFBConfigAttrib #define glXGetClientString _glfw.glx.GetClientString #define glXQueryExtension _glfw.glx.QueryExtension #define glXQueryVersion _glfw.glx.QueryVersion #define glXDestroyContext _glfw.glx.DestroyContext #define glXMakeCurrent _glfw.glx.MakeCurrent #define glXSwapBuffers _glfw.glx.SwapBuffers #define glXQueryExtensionsString _glfw.glx.QueryExtensionsString #define glXCreateNewContext _glfw.glx.CreateNewContext #define glXGetVisualFromFBConfig _glfw.glx.GetVisualFromFBConfig #define glXCreateWindow _glfw.glx.CreateWindow #define glXDestroyWindow _glfw.glx.DestroyWindow #define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextGLX glx #define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE _GLFWlibraryGLX glx // GLX-specific per-context data // typedef struct _GLFWcontextGLX { GLXContext handle; GLXWindow window; } _GLFWcontextGLX; // GLX-specific global data // typedef struct _GLFWlibraryGLX { int major, minor; int eventBase; int errorBase; // dlopen handle for libGL.so.1 void* handle; // GLX 1.3 functions PFNGLXGETFBCONFIGSPROC GetFBConfigs; PFNGLXGETFBCONFIGATTRIBPROC GetFBConfigAttrib; PFNGLXGETCLIENTSTRINGPROC GetClientString; PFNGLXQUERYEXTENSIONPROC QueryExtension; PFNGLXQUERYVERSIONPROC QueryVersion; PFNGLXDESTROYCONTEXTPROC DestroyContext; PFNGLXMAKECURRENTPROC MakeCurrent; PFNGLXSWAPBUFFERSPROC SwapBuffers; PFNGLXQUERYEXTENSIONSSTRINGPROC QueryExtensionsString; PFNGLXCREATENEWCONTEXTPROC CreateNewContext; PFNGLXGETVISUALFROMFBCONFIGPROC GetVisualFromFBConfig; PFNGLXCREATEWINDOWPROC CreateWindow; PFNGLXDESTROYWINDOWPROC DestroyWindow; // GLX 1.4 and extension functions PFNGLXGETPROCADDRESSPROC GetProcAddress; PFNGLXGETPROCADDRESSPROC GetProcAddressARB; PFNGLXSWAPINTERVALSGIPROC SwapIntervalSGI; PFNGLXSWAPINTERVALEXTPROC SwapIntervalEXT; PFNGLXSWAPINTERVALMESAPROC SwapIntervalMESA; PFNGLXCREATECONTEXTATTRIBSARBPROC CreateContextAttribsARB; GLFWbool SGI_swap_control; GLFWbool EXT_swap_control; GLFWbool MESA_swap_control; GLFWbool ARB_multisample; GLFWbool ARB_framebuffer_sRGB; GLFWbool EXT_framebuffer_sRGB; GLFWbool ARB_create_context; GLFWbool ARB_create_context_profile; GLFWbool ARB_create_context_robustness; GLFWbool EXT_create_context_es2_profile; GLFWbool ARB_create_context_no_error; GLFWbool ARB_context_flush_control; } _GLFWlibraryGLX; GLFWbool _glfwInitGLX(void); void _glfwTerminateGLX(void); GLFWbool _glfwCreateContextGLX(_GLFWwindow* window, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig); void _glfwDestroyContextGLX(_GLFWwindow* window); GLFWbool _glfwChooseVisualGLX(const _GLFWwndconfig* wndconfig, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig, Visual** visual, int* depth); #endif #ifndef HEADER_GUARD_EGL_CONTEXT_H #define HEADER_GUARD_EGL_CONTEXT_H //======================================================================== // GLFW 3.3.7 EGL - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2017 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== #if defined(_GLFW_USE_EGLPLATFORM_H) #include #elif defined(_GLFW_WIN32) #define EGLAPIENTRY __stdcall typedef HDC EGLNativeDisplayType; typedef HWND EGLNativeWindowType; #elif defined(_GLFW_COCOA) #define EGLAPIENTRY typedef void* EGLNativeDisplayType; typedef id EGLNativeWindowType; #elif defined(_GLFW_X11) #define EGLAPIENTRY typedef Display* EGLNativeDisplayType; typedef Window EGLNativeWindowType; #elif defined(_GLFW_WAYLAND) #define EGLAPIENTRY typedef struct wl_display* EGLNativeDisplayType; typedef struct wl_egl_window* EGLNativeWindowType; #else #error "No supported EGL platform selected" #endif #define EGL_SUCCESS 0x3000 #define EGL_NOT_INITIALIZED 0x3001 #define EGL_BAD_ACCESS 0x3002 #define EGL_BAD_ALLOC 0x3003 #define EGL_BAD_ATTRIBUTE 0x3004 #define EGL_BAD_CONFIG 0x3005 #define EGL_BAD_CONTEXT 0x3006 #define EGL_BAD_CURRENT_SURFACE 0x3007 #define EGL_BAD_DISPLAY 0x3008 #define EGL_BAD_MATCH 0x3009 #define EGL_BAD_NATIVE_PIXMAP 0x300a #define EGL_BAD_NATIVE_WINDOW 0x300b #define EGL_BAD_PARAMETER 0x300c #define EGL_BAD_SURFACE 0x300d #define EGL_CONTEXT_LOST 0x300e #define EGL_COLOR_BUFFER_TYPE 0x303f #define EGL_RGB_BUFFER 0x308e #define EGL_SURFACE_TYPE 0x3033 #define EGL_WINDOW_BIT 0x0004 #define EGL_RENDERABLE_TYPE 0x3040 #define EGL_OPENGL_ES_BIT 0x0001 #define EGL_OPENGL_ES2_BIT 0x0004 #define EGL_OPENGL_BIT 0x0008 #define EGL_ALPHA_SIZE 0x3021 #define EGL_BLUE_SIZE 0x3022 #define EGL_GREEN_SIZE 0x3023 #define EGL_RED_SIZE 0x3024 #define EGL_DEPTH_SIZE 0x3025 #define EGL_STENCIL_SIZE 0x3026 #define EGL_SAMPLES 0x3031 #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 #define EGL_NO_SURFACE ((EGLSurface) 0) #define EGL_NO_DISPLAY ((EGLDisplay) 0) #define EGL_NO_CONTEXT ((EGLContext) 0) #define EGL_DEFAULT_DISPLAY ((EGLNativeDisplayType) 0) #define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR 0x00000002 #define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR 0x00000001 #define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR 0x00000002 #define EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR 0x00000001 #define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR 0x31bd #define EGL_NO_RESET_NOTIFICATION_KHR 0x31be #define EGL_LOSE_CONTEXT_ON_RESET_KHR 0x31bf #define EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR 0x00000004 #define EGL_CONTEXT_MAJOR_VERSION_KHR 0x3098 #define EGL_CONTEXT_MINOR_VERSION_KHR 0x30fb #define EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR 0x30fd #define EGL_CONTEXT_FLAGS_KHR 0x30fc #define EGL_CONTEXT_OPENGL_NO_ERROR_KHR 0x31b3 #define EGL_GL_COLORSPACE_KHR 0x309d #define EGL_GL_COLORSPACE_SRGB_KHR 0x3089 #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; typedef unsigned int EGLenum; typedef void* EGLConfig; typedef void* EGLContext; typedef void* EGLDisplay; typedef void* EGLSurface; // EGL function pointer typedefs typedef EGLBoolean (EGLAPIENTRY * PFN_eglGetConfigAttrib)(EGLDisplay,EGLConfig,EGLint,EGLint*); typedef EGLBoolean (EGLAPIENTRY * PFN_eglGetConfigs)(EGLDisplay,EGLConfig*,EGLint,EGLint*); typedef EGLDisplay (EGLAPIENTRY * PFN_eglGetDisplay)(EGLNativeDisplayType); typedef EGLint (EGLAPIENTRY * PFN_eglGetError)(void); typedef EGLBoolean (EGLAPIENTRY * PFN_eglInitialize)(EGLDisplay,EGLint*,EGLint*); typedef EGLBoolean (EGLAPIENTRY * PFN_eglTerminate)(EGLDisplay); typedef EGLBoolean (EGLAPIENTRY * PFN_eglBindAPI)(EGLenum); typedef EGLContext (EGLAPIENTRY * PFN_eglCreateContext)(EGLDisplay,EGLConfig,EGLContext,const EGLint*); typedef EGLBoolean (EGLAPIENTRY * PFN_eglDestroySurface)(EGLDisplay,EGLSurface); typedef EGLBoolean (EGLAPIENTRY * PFN_eglDestroyContext)(EGLDisplay,EGLContext); typedef EGLSurface (EGLAPIENTRY * PFN_eglCreateWindowSurface)(EGLDisplay,EGLConfig,EGLNativeWindowType,const EGLint*); typedef EGLBoolean (EGLAPIENTRY * PFN_eglMakeCurrent)(EGLDisplay,EGLSurface,EGLSurface,EGLContext); typedef EGLBoolean (EGLAPIENTRY * PFN_eglSwapBuffers)(EGLDisplay,EGLSurface); typedef EGLBoolean (EGLAPIENTRY * PFN_eglSwapInterval)(EGLDisplay,EGLint); typedef const char* (EGLAPIENTRY * PFN_eglQueryString)(EGLDisplay,EGLint); typedef GLFWglproc (EGLAPIENTRY * PFN_eglGetProcAddress)(const char*); #define eglGetConfigAttrib _glfw.egl.GetConfigAttrib #define eglGetConfigs _glfw.egl.GetConfigs #define eglGetDisplay _glfw.egl.GetDisplay #define eglGetError _glfw.egl.GetError #define eglInitialize _glfw.egl.Initialize #define eglTerminate _glfw.egl.Terminate #define eglBindAPI _glfw.egl.BindAPI #define eglCreateContext _glfw.egl.CreateContext #define eglDestroySurface _glfw.egl.DestroySurface #define eglDestroyContext _glfw.egl.DestroyContext #define eglCreateWindowSurface _glfw.egl.CreateWindowSurface #define eglMakeCurrent _glfw.egl.MakeCurrent #define eglSwapBuffers _glfw.egl.SwapBuffers #define eglSwapInterval _glfw.egl.SwapInterval #define eglQueryString _glfw.egl.QueryString #define eglGetProcAddress _glfw.egl.GetProcAddress #define _GLFW_EGL_CONTEXT_STATE _GLFWcontextEGL egl #define _GLFW_EGL_LIBRARY_CONTEXT_STATE _GLFWlibraryEGL egl // EGL-specific per-context data // typedef struct _GLFWcontextEGL { EGLConfig config; EGLContext handle; EGLSurface surface; void* client; } _GLFWcontextEGL; // EGL-specific global data // typedef struct _GLFWlibraryEGL { EGLDisplay display; EGLint major, minor; GLFWbool prefix; GLFWbool KHR_create_context; GLFWbool KHR_create_context_no_error; GLFWbool KHR_gl_colorspace; GLFWbool KHR_get_all_proc_addresses; GLFWbool KHR_context_flush_control; GLFWbool EXT_present_opaque; void* handle; PFN_eglGetConfigAttrib GetConfigAttrib; PFN_eglGetConfigs GetConfigs; PFN_eglGetDisplay GetDisplay; PFN_eglGetError GetError; PFN_eglInitialize Initialize; PFN_eglTerminate Terminate; PFN_eglBindAPI BindAPI; PFN_eglCreateContext CreateContext; PFN_eglDestroySurface DestroySurface; PFN_eglDestroyContext DestroyContext; PFN_eglCreateWindowSurface CreateWindowSurface; PFN_eglMakeCurrent MakeCurrent; PFN_eglSwapBuffers SwapBuffers; PFN_eglSwapInterval SwapInterval; PFN_eglQueryString QueryString; PFN_eglGetProcAddress GetProcAddress; } _GLFWlibraryEGL; GLFWbool _glfwInitEGL(void); void _glfwTerminateEGL(void); GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig); #if defined(_GLFW_X11) GLFWbool _glfwChooseVisualEGL(const _GLFWwndconfig* wndconfig, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig, Visual** visual, int* depth); #endif /*_GLFW_X11*/ #endif #ifndef HEADER_GUARD_OSMESA_CONTEXT_H #define HEADER_GUARD_OSMESA_CONTEXT_H //======================================================================== // GLFW 3.3.7 OSMesa - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2016 Google Inc. // Copyright (c) 2016-2017 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== #define OSMESA_RGBA 0x1908 #define OSMESA_FORMAT 0x22 #define OSMESA_DEPTH_BITS 0x30 #define OSMESA_STENCIL_BITS 0x31 #define OSMESA_ACCUM_BITS 0x32 #define OSMESA_PROFILE 0x33 #define OSMESA_CORE_PROFILE 0x34 #define OSMESA_COMPAT_PROFILE 0x35 #define OSMESA_CONTEXT_MAJOR_VERSION 0x36 #define OSMESA_CONTEXT_MINOR_VERSION 0x37 typedef void* OSMesaContext; typedef void (*OSMESAproc)(void); typedef OSMesaContext (GLAPIENTRY * PFN_OSMesaCreateContextExt)(GLenum,GLint,GLint,GLint,OSMesaContext); typedef OSMesaContext (GLAPIENTRY * PFN_OSMesaCreateContextAttribs)(const int*,OSMesaContext); typedef void (GLAPIENTRY * PFN_OSMesaDestroyContext)(OSMesaContext); typedef int (GLAPIENTRY * PFN_OSMesaMakeCurrent)(OSMesaContext,void*,int,int,int); typedef int (GLAPIENTRY * PFN_OSMesaGetColorBuffer)(OSMesaContext,int*,int*,int*,void**); typedef int (GLAPIENTRY * PFN_OSMesaGetDepthBuffer)(OSMesaContext,int*,int*,int*,void**); typedef GLFWglproc (GLAPIENTRY * PFN_OSMesaGetProcAddress)(const char*); #define OSMesaCreateContextExt _glfw.osmesa.CreateContextExt #define OSMesaCreateContextAttribs _glfw.osmesa.CreateContextAttribs #define OSMesaDestroyContext _glfw.osmesa.DestroyContext #define OSMesaMakeCurrent _glfw.osmesa.MakeCurrent #define OSMesaGetColorBuffer _glfw.osmesa.GetColorBuffer #define OSMesaGetDepthBuffer _glfw.osmesa.GetDepthBuffer #define OSMesaGetProcAddress _glfw.osmesa.GetProcAddress #define _GLFW_OSMESA_CONTEXT_STATE _GLFWcontextOSMesa osmesa #define _GLFW_OSMESA_LIBRARY_CONTEXT_STATE _GLFWlibraryOSMesa osmesa // OSMesa-specific per-context data // typedef struct _GLFWcontextOSMesa { OSMesaContext handle; int width; int height; void* buffer; } _GLFWcontextOSMesa; // OSMesa-specific global data // typedef struct _GLFWlibraryOSMesa { void* handle; PFN_OSMesaCreateContextExt CreateContextExt; PFN_OSMesaCreateContextAttribs CreateContextAttribs; PFN_OSMesaDestroyContext DestroyContext; PFN_OSMesaMakeCurrent MakeCurrent; PFN_OSMesaGetColorBuffer GetColorBuffer; PFN_OSMesaGetDepthBuffer GetDepthBuffer; PFN_OSMesaGetProcAddress GetProcAddress; } _GLFWlibraryOSMesa; GLFWbool _glfwInitOSMesa(void); void _glfwTerminateOSMesa(void); GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig); #endif #if defined(__linux__) #ifndef HEADER_GUARD_LINUX_JOYSTICK_H #define HEADER_GUARD_LINUX_JOYSTICK_H //======================================================================== // GLFW 3.3.7 Linux - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2014 Jonas Ådahl // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== #include #include #include #define _GLFW_PLATFORM_JOYSTICK_STATE _GLFWjoystickLinux linjs #define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE _GLFWlibraryLinux linjs #define _GLFW_PLATFORM_MAPPING_NAME "Linux" #define GLFW_BUILD_LINUX_MAPPINGS // Linux-specific joystick data // typedef struct _GLFWjoystickLinux { int fd; char path[PATH_MAX]; int keyMap[KEY_CNT - BTN_MISC]; int absMap[ABS_CNT]; struct input_absinfo absInfo[ABS_CNT]; int hats[4][2]; } _GLFWjoystickLinux; // Linux-specific joystick API data // typedef struct _GLFWlibraryLinux { int inotify; int watch; regex_t regex; GLFWbool dropped; } _GLFWlibraryLinux; GLFWbool _glfwInitJoysticksLinux(void); void _glfwTerminateJoysticksLinux(void); void _glfwDetectJoystickConnectionLinux(void); #endif #else #ifndef HEADER_GUARD_NULL_JOYSTICK_H #define HEADER_GUARD_NULL_JOYSTICK_H //======================================================================== // GLFW 3.3.7 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2006-2017 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== #define _GLFW_PLATFORM_JOYSTICK_STATE struct { int dummyJoystick; } #define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE struct { int dummyLibraryJoystick; } #define _GLFW_PLATFORM_MAPPING_NAME "" #endif #endif #define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL) #define _glfw_dlclose(handle) dlclose(handle) #define _glfw_dlsym(handle, name) dlsym(handle, name) #define _GLFW_EGL_NATIVE_WINDOW ((EGLNativeWindowType) window->x11.handle) #define _GLFW_EGL_NATIVE_DISPLAY ((EGLNativeDisplayType) _glfw.x11.display) #define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowX11 x11 #define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryX11 x11 #define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorX11 x11 #define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorX11 x11 // X11-specific per-window data // typedef struct _GLFWwindowX11 { Colormap colormap; Window handle; Window parent; XIC ic; GLFWbool overrideRedirect; GLFWbool iconified; GLFWbool maximized; // Whether the visual supports framebuffer transparency GLFWbool transparent; // Cached position and size used to filter out duplicate events int width, height; int xpos, ypos; // The last received cursor position, regardless of source int lastCursorPosX, lastCursorPosY; // The last position the cursor was warped to by GLFW int warpCursorPosX, warpCursorPosY; // 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 // typedef struct _GLFWlibraryX11 { Display* display; int screen; Window root; // System content scale float contentScaleX, contentScaleY; // Helper window for IPC Window helperWindowHandle; // Invisible cursor for hidden cursor mode Cursor hiddenCursorHandle; // Context for mapping window XIDs to _GLFWwindow pointers XContext context; // XIM input method XIM im; // Most recent error code received by X error handler int errorCode; // Primary selection string (while the primary selection is owned) char* primarySelectionString; // Clipboard string (while the selection is owned) char* clipboardString; // Key name string char keynames[GLFW_KEY_LAST + 1][5]; // X11 keycode to GLFW key LUT short int keycodes[256]; // GLFW key to X11 keycode LUT short int scancodes[GLFW_KEY_LAST + 1]; // Where to place the cursor when re-enabled double restoreCursorPosX, restoreCursorPosY; // The window whose disabled cursor mode is active _GLFWwindow* disabledCursorWindow; int emptyEventPipe[2]; // Window manager atoms Atom NET_SUPPORTED; Atom NET_SUPPORTING_WM_CHECK; Atom WM_PROTOCOLS; Atom WM_STATE; Atom WM_DELETE_WINDOW; Atom NET_WM_NAME; Atom NET_WM_ICON_NAME; Atom NET_WM_ICON; Atom NET_WM_PID; Atom NET_WM_PING; Atom NET_WM_WINDOW_TYPE; Atom NET_WM_WINDOW_TYPE_NORMAL; Atom NET_WM_STATE; Atom NET_WM_STATE_ABOVE; Atom NET_WM_STATE_FULLSCREEN; Atom NET_WM_STATE_MAXIMIZED_VERT; Atom NET_WM_STATE_MAXIMIZED_HORZ; Atom NET_WM_STATE_DEMANDS_ATTENTION; Atom NET_WM_BYPASS_COMPOSITOR; Atom NET_WM_FULLSCREEN_MONITORS; Atom NET_WM_WINDOW_OPACITY; Atom NET_WM_CM_Sx; Atom NET_WORKAREA; Atom NET_CURRENT_DESKTOP; Atom NET_ACTIVE_WINDOW; Atom NET_FRAME_EXTENTS; Atom NET_REQUEST_FRAME_EXTENTS; Atom MOTIF_WM_HINTS; // Xdnd (drag and drop) atoms Atom XdndAware; Atom XdndEnter; Atom XdndPosition; Atom XdndStatus; Atom XdndActionCopy; Atom XdndDrop; Atom XdndFinished; Atom XdndSelection; Atom XdndTypeList; Atom text_uri_list; // Selection (clipboard) atoms Atom TARGETS; Atom MULTIPLE; Atom INCR; Atom CLIPBOARD; Atom PRIMARY; Atom CLIPBOARD_MANAGER; Atom SAVE_TARGETS; Atom NULL_; Atom UTF8_STRING; Atom COMPOUND_STRING; Atom ATOM_PAIR; Atom GLFW_SELECTION; struct { GLFWbool available; void* handle; int eventBase; int errorBase; int major; int minor; GLFWbool gammaBroken; GLFWbool monitorBroken; PFN_XRRAllocGamma AllocGamma; PFN_XRRFreeCrtcInfo FreeCrtcInfo; PFN_XRRFreeGamma FreeGamma; PFN_XRRFreeOutputInfo FreeOutputInfo; PFN_XRRFreeScreenResources FreeScreenResources; PFN_XRRGetCrtcGamma GetCrtcGamma; PFN_XRRGetCrtcGammaSize GetCrtcGammaSize; PFN_XRRGetCrtcInfo GetCrtcInfo; PFN_XRRGetOutputInfo GetOutputInfo; PFN_XRRGetOutputPrimary GetOutputPrimary; PFN_XRRGetScreenResourcesCurrent GetScreenResourcesCurrent; PFN_XRRQueryExtension QueryExtension; PFN_XRRQueryVersion QueryVersion; PFN_XRRSelectInput SelectInput; PFN_XRRSetCrtcConfig SetCrtcConfig; PFN_XRRSetCrtcGamma SetCrtcGamma; PFN_XRRUpdateConfiguration UpdateConfiguration; } randr; struct { GLFWbool available; GLFWbool detectable; int majorOpcode; int eventBase; int errorBase; int major; int minor; unsigned int group; } xkb; struct { int count; int timeout; int interval; int blanking; int exposure; } saver; struct { int version; Window source; Atom format; } xdnd; struct { void* handle; PFN_XcursorImageCreate ImageCreate; PFN_XcursorImageDestroy ImageDestroy; PFN_XcursorImageLoadCursor ImageLoadCursor; } xcursor; struct { GLFWbool available; void* handle; int major; int minor; PFN_XineramaIsActive IsActive; PFN_XineramaQueryExtension QueryExtension; PFN_XineramaQueryScreens QueryScreens; } xinerama; struct { void* handle; PFN_XGetXCBConnection GetXCBConnection; } x11xcb; struct { GLFWbool available; void* handle; int eventBase; int errorBase; PFN_XF86VidModeQueryExtension QueryExtension; PFN_XF86VidModeGetGammaRamp GetGammaRamp; PFN_XF86VidModeSetGammaRamp SetGammaRamp; PFN_XF86VidModeGetGammaRampSize GetGammaRampSize; } vidmode; struct { GLFWbool available; void* handle; int majorOpcode; int eventBase; int errorBase; int major; int minor; PFN_XIQueryVersion QueryVersion; PFN_XISelectEvents SelectEvents; } xi; struct { GLFWbool available; void* handle; int major; int minor; int eventBase; int errorBase; PFN_XRenderQueryExtension QueryExtension; PFN_XRenderQueryVersion QueryVersion; PFN_XRenderFindVisualFormat FindVisualFormat; } xrender; } _GLFWlibraryX11; // X11-specific per-monitor data // typedef struct _GLFWmonitorX11 { RROutput output; RRCrtc crtc; RRMode oldMode; // Index of corresponding Xinerama screen, // for EWMH full screen window placement int index; } _GLFWmonitorX11; // X11-specific per-cursor data // typedef struct _GLFWcursorX11 { Cursor handle; } _GLFWcursorX11; void _glfwPollMonitorsX11(void); void _glfwSetVideoModeX11(_GLFWmonitor* monitor, const GLFWvidmode* desired); void _glfwRestoreVideoModeX11(_GLFWmonitor* monitor); Cursor _glfwCreateCursorX11(const GLFWimage* image, int xhot, int yhot); unsigned long _glfwGetWindowPropertyX11(Window window, Atom property, Atom type, unsigned char** value); GLFWbool _glfwIsVisualTransparentX11(Visual* visual); void _glfwGrabErrorHandlerX11(void); void _glfwReleaseErrorHandlerX11(void); void _glfwInputErrorX11(int error, const char* message); void _glfwPushSelectionToManagerX11(void); #endif #elif defined(_GLFW_WAYLAND) #ifndef HEADER_GUARD_WL_PLATFORM_H #define HEADER_GUARD_WL_PLATFORM_H //======================================================================== // GLFW 3.3.7 Wayland - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2014 Jonas Ådahl // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== #include #include #include #include typedef VkFlags VkWaylandSurfaceCreateFlagsKHR; typedef struct VkWaylandSurfaceCreateInfoKHR { VkStructureType sType; const void* pNext; VkWaylandSurfaceCreateFlagsKHR flags; struct wl_display* display; struct wl_surface* surface; } VkWaylandSurfaceCreateInfoKHR; typedef VkResult (APIENTRY *PFN_vkCreateWaylandSurfaceKHR)(VkInstance,const VkWaylandSurfaceCreateInfoKHR*,const VkAllocationCallbacks*,VkSurfaceKHR*); typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR)(VkPhysicalDevice,uint32_t,struct wl_display*); #ifndef HEADER_GUARD_POSIX_THREAD_H #define HEADER_GUARD_POSIX_THREAD_H //======================================================================== // GLFW 3.3.7 POSIX - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2017 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== #include #define _GLFW_PLATFORM_TLS_STATE _GLFWtlsPOSIX posix #define _GLFW_PLATFORM_MUTEX_STATE _GLFWmutexPOSIX posix // POSIX-specific thread local storage data // typedef struct _GLFWtlsPOSIX { GLFWbool allocated; pthread_key_t key; } _GLFWtlsPOSIX; // POSIX-specific mutex data // typedef struct _GLFWmutexPOSIX { GLFWbool allocated; pthread_mutex_t handle; } _GLFWmutexPOSIX; #endif #ifndef HEADER_GUARD_POSIX_TIME_H #define HEADER_GUARD_POSIX_TIME_H //======================================================================== // GLFW 3.3.7 POSIX - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2017 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== #define _GLFW_PLATFORM_LIBRARY_TIMER_STATE _GLFWtimerPOSIX posix #include // POSIX-specific global timer data // typedef struct _GLFWtimerPOSIX { GLFWbool monotonic; uint64_t frequency; } _GLFWtimerPOSIX; void _glfwInitTimerPOSIX(void); #endif #ifdef __linux__ #ifndef HEADER_GUARD_LINUX_JOYSTICK_H #define HEADER_GUARD_LINUX_JOYSTICK_H //======================================================================== // GLFW 3.3.7 Linux - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2014 Jonas Ådahl // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== #include #include #include #define _GLFW_PLATFORM_JOYSTICK_STATE _GLFWjoystickLinux linjs #define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE _GLFWlibraryLinux linjs #define _GLFW_PLATFORM_MAPPING_NAME "Linux" #define GLFW_BUILD_LINUX_MAPPINGS // Linux-specific joystick data // typedef struct _GLFWjoystickLinux { int fd; char path[PATH_MAX]; int keyMap[KEY_CNT - BTN_MISC]; int absMap[ABS_CNT]; struct input_absinfo absInfo[ABS_CNT]; int hats[4][2]; } _GLFWjoystickLinux; // Linux-specific joystick API data // typedef struct _GLFWlibraryLinux { int inotify; int watch; regex_t regex; GLFWbool dropped; } _GLFWlibraryLinux; GLFWbool _glfwInitJoysticksLinux(void); void _glfwTerminateJoysticksLinux(void); void _glfwDetectJoystickConnectionLinux(void); #endif #else #ifndef HEADER_GUARD_NULL_JOYSTICK_H #define HEADER_GUARD_NULL_JOYSTICK_H //======================================================================== // GLFW 3.3.7 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2006-2017 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== #define _GLFW_PLATFORM_JOYSTICK_STATE struct { int dummyJoystick; } #define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE struct { int dummyLibraryJoystick; } #define _GLFW_PLATFORM_MAPPING_NAME "" #endif #endif #ifndef HEADER_GUARD_XKB_UNICODE_H #define HEADER_GUARD_XKB_UNICODE_H //======================================================================== // GLFW 3.3.7 Linux - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2014 Jonas Ådahl // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== #define GLFW_INVALID_CODEPOINT 0xffffffffu uint32_t _glfwKeySym2Unicode(unsigned int keysym); #endif #ifndef HEADER_GUARD_EGL_CONTEXT_H #define HEADER_GUARD_EGL_CONTEXT_H //======================================================================== // GLFW 3.3.7 EGL - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2017 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== #if defined(_GLFW_USE_EGLPLATFORM_H) #include #elif defined(_GLFW_WIN32) #define EGLAPIENTRY __stdcall typedef HDC EGLNativeDisplayType; typedef HWND EGLNativeWindowType; #elif defined(_GLFW_COCOA) #define EGLAPIENTRY typedef void* EGLNativeDisplayType; typedef id EGLNativeWindowType; #elif defined(_GLFW_X11) #define EGLAPIENTRY typedef Display* EGLNativeDisplayType; typedef Window EGLNativeWindowType; #elif defined(_GLFW_WAYLAND) #define EGLAPIENTRY typedef struct wl_display* EGLNativeDisplayType; typedef struct wl_egl_window* EGLNativeWindowType; #else #error "No supported EGL platform selected" #endif #define EGL_SUCCESS 0x3000 #define EGL_NOT_INITIALIZED 0x3001 #define EGL_BAD_ACCESS 0x3002 #define EGL_BAD_ALLOC 0x3003 #define EGL_BAD_ATTRIBUTE 0x3004 #define EGL_BAD_CONFIG 0x3005 #define EGL_BAD_CONTEXT 0x3006 #define EGL_BAD_CURRENT_SURFACE 0x3007 #define EGL_BAD_DISPLAY 0x3008 #define EGL_BAD_MATCH 0x3009 #define EGL_BAD_NATIVE_PIXMAP 0x300a #define EGL_BAD_NATIVE_WINDOW 0x300b #define EGL_BAD_PARAMETER 0x300c #define EGL_BAD_SURFACE 0x300d #define EGL_CONTEXT_LOST 0x300e #define EGL_COLOR_BUFFER_TYPE 0x303f #define EGL_RGB_BUFFER 0x308e #define EGL_SURFACE_TYPE 0x3033 #define EGL_WINDOW_BIT 0x0004 #define EGL_RENDERABLE_TYPE 0x3040 #define EGL_OPENGL_ES_BIT 0x0001 #define EGL_OPENGL_ES2_BIT 0x0004 #define EGL_OPENGL_BIT 0x0008 #define EGL_ALPHA_SIZE 0x3021 #define EGL_BLUE_SIZE 0x3022 #define EGL_GREEN_SIZE 0x3023 #define EGL_RED_SIZE 0x3024 #define EGL_DEPTH_SIZE 0x3025 #define EGL_STENCIL_SIZE 0x3026 #define EGL_SAMPLES 0x3031 #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 #define EGL_NO_SURFACE ((EGLSurface) 0) #define EGL_NO_DISPLAY ((EGLDisplay) 0) #define EGL_NO_CONTEXT ((EGLContext) 0) #define EGL_DEFAULT_DISPLAY ((EGLNativeDisplayType) 0) #define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR 0x00000002 #define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR 0x00000001 #define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR 0x00000002 #define EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR 0x00000001 #define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR 0x31bd #define EGL_NO_RESET_NOTIFICATION_KHR 0x31be #define EGL_LOSE_CONTEXT_ON_RESET_KHR 0x31bf #define EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR 0x00000004 #define EGL_CONTEXT_MAJOR_VERSION_KHR 0x3098 #define EGL_CONTEXT_MINOR_VERSION_KHR 0x30fb #define EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR 0x30fd #define EGL_CONTEXT_FLAGS_KHR 0x30fc #define EGL_CONTEXT_OPENGL_NO_ERROR_KHR 0x31b3 #define EGL_GL_COLORSPACE_KHR 0x309d #define EGL_GL_COLORSPACE_SRGB_KHR 0x3089 #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; typedef unsigned int EGLenum; typedef void* EGLConfig; typedef void* EGLContext; typedef void* EGLDisplay; typedef void* EGLSurface; // EGL function pointer typedefs typedef EGLBoolean (EGLAPIENTRY * PFN_eglGetConfigAttrib)(EGLDisplay,EGLConfig,EGLint,EGLint*); typedef EGLBoolean (EGLAPIENTRY * PFN_eglGetConfigs)(EGLDisplay,EGLConfig*,EGLint,EGLint*); typedef EGLDisplay (EGLAPIENTRY * PFN_eglGetDisplay)(EGLNativeDisplayType); typedef EGLint (EGLAPIENTRY * PFN_eglGetError)(void); typedef EGLBoolean (EGLAPIENTRY * PFN_eglInitialize)(EGLDisplay,EGLint*,EGLint*); typedef EGLBoolean (EGLAPIENTRY * PFN_eglTerminate)(EGLDisplay); typedef EGLBoolean (EGLAPIENTRY * PFN_eglBindAPI)(EGLenum); typedef EGLContext (EGLAPIENTRY * PFN_eglCreateContext)(EGLDisplay,EGLConfig,EGLContext,const EGLint*); typedef EGLBoolean (EGLAPIENTRY * PFN_eglDestroySurface)(EGLDisplay,EGLSurface); typedef EGLBoolean (EGLAPIENTRY * PFN_eglDestroyContext)(EGLDisplay,EGLContext); typedef EGLSurface (EGLAPIENTRY * PFN_eglCreateWindowSurface)(EGLDisplay,EGLConfig,EGLNativeWindowType,const EGLint*); typedef EGLBoolean (EGLAPIENTRY * PFN_eglMakeCurrent)(EGLDisplay,EGLSurface,EGLSurface,EGLContext); typedef EGLBoolean (EGLAPIENTRY * PFN_eglSwapBuffers)(EGLDisplay,EGLSurface); typedef EGLBoolean (EGLAPIENTRY * PFN_eglSwapInterval)(EGLDisplay,EGLint); typedef const char* (EGLAPIENTRY * PFN_eglQueryString)(EGLDisplay,EGLint); typedef GLFWglproc (EGLAPIENTRY * PFN_eglGetProcAddress)(const char*); #define eglGetConfigAttrib _glfw.egl.GetConfigAttrib #define eglGetConfigs _glfw.egl.GetConfigs #define eglGetDisplay _glfw.egl.GetDisplay #define eglGetError _glfw.egl.GetError #define eglInitialize _glfw.egl.Initialize #define eglTerminate _glfw.egl.Terminate #define eglBindAPI _glfw.egl.BindAPI #define eglCreateContext _glfw.egl.CreateContext #define eglDestroySurface _glfw.egl.DestroySurface #define eglDestroyContext _glfw.egl.DestroyContext #define eglCreateWindowSurface _glfw.egl.CreateWindowSurface #define eglMakeCurrent _glfw.egl.MakeCurrent #define eglSwapBuffers _glfw.egl.SwapBuffers #define eglSwapInterval _glfw.egl.SwapInterval #define eglQueryString _glfw.egl.QueryString #define eglGetProcAddress _glfw.egl.GetProcAddress #define _GLFW_EGL_CONTEXT_STATE _GLFWcontextEGL egl #define _GLFW_EGL_LIBRARY_CONTEXT_STATE _GLFWlibraryEGL egl // EGL-specific per-context data // typedef struct _GLFWcontextEGL { EGLConfig config; EGLContext handle; EGLSurface surface; void* client; } _GLFWcontextEGL; // EGL-specific global data // typedef struct _GLFWlibraryEGL { EGLDisplay display; EGLint major, minor; GLFWbool prefix; GLFWbool KHR_create_context; GLFWbool KHR_create_context_no_error; GLFWbool KHR_gl_colorspace; GLFWbool KHR_get_all_proc_addresses; GLFWbool KHR_context_flush_control; GLFWbool EXT_present_opaque; void* handle; PFN_eglGetConfigAttrib GetConfigAttrib; PFN_eglGetConfigs GetConfigs; PFN_eglGetDisplay GetDisplay; PFN_eglGetError GetError; PFN_eglInitialize Initialize; PFN_eglTerminate Terminate; PFN_eglBindAPI BindAPI; PFN_eglCreateContext CreateContext; PFN_eglDestroySurface DestroySurface; PFN_eglDestroyContext DestroyContext; PFN_eglCreateWindowSurface CreateWindowSurface; PFN_eglMakeCurrent MakeCurrent; PFN_eglSwapBuffers SwapBuffers; PFN_eglSwapInterval SwapInterval; PFN_eglQueryString QueryString; PFN_eglGetProcAddress GetProcAddress; } _GLFWlibraryEGL; GLFWbool _glfwInitEGL(void); void _glfwTerminateEGL(void); GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig); #if defined(_GLFW_X11) GLFWbool _glfwChooseVisualEGL(const _GLFWwndconfig* wndconfig, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig, Visual** visual, int* depth); #endif /*_GLFW_X11*/ #endif #ifndef HEADER_GUARD_OSMESA_CONTEXT_H #define HEADER_GUARD_OSMESA_CONTEXT_H //======================================================================== // GLFW 3.3.7 OSMesa - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2016 Google Inc. // Copyright (c) 2016-2017 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== #define OSMESA_RGBA 0x1908 #define OSMESA_FORMAT 0x22 #define OSMESA_DEPTH_BITS 0x30 #define OSMESA_STENCIL_BITS 0x31 #define OSMESA_ACCUM_BITS 0x32 #define OSMESA_PROFILE 0x33 #define OSMESA_CORE_PROFILE 0x34 #define OSMESA_COMPAT_PROFILE 0x35 #define OSMESA_CONTEXT_MAJOR_VERSION 0x36 #define OSMESA_CONTEXT_MINOR_VERSION 0x37 typedef void* OSMesaContext; typedef void (*OSMESAproc)(void); typedef OSMesaContext (GLAPIENTRY * PFN_OSMesaCreateContextExt)(GLenum,GLint,GLint,GLint,OSMesaContext); typedef OSMesaContext (GLAPIENTRY * PFN_OSMesaCreateContextAttribs)(const int*,OSMesaContext); typedef void (GLAPIENTRY * PFN_OSMesaDestroyContext)(OSMesaContext); typedef int (GLAPIENTRY * PFN_OSMesaMakeCurrent)(OSMesaContext,void*,int,int,int); typedef int (GLAPIENTRY * PFN_OSMesaGetColorBuffer)(OSMesaContext,int*,int*,int*,void**); typedef int (GLAPIENTRY * PFN_OSMesaGetDepthBuffer)(OSMesaContext,int*,int*,int*,void**); typedef GLFWglproc (GLAPIENTRY * PFN_OSMesaGetProcAddress)(const char*); #define OSMesaCreateContextExt _glfw.osmesa.CreateContextExt #define OSMesaCreateContextAttribs _glfw.osmesa.CreateContextAttribs #define OSMesaDestroyContext _glfw.osmesa.DestroyContext #define OSMesaMakeCurrent _glfw.osmesa.MakeCurrent #define OSMesaGetColorBuffer _glfw.osmesa.GetColorBuffer #define OSMesaGetDepthBuffer _glfw.osmesa.GetDepthBuffer #define OSMesaGetProcAddress _glfw.osmesa.GetProcAddress #define _GLFW_OSMESA_CONTEXT_STATE _GLFWcontextOSMesa osmesa #define _GLFW_OSMESA_LIBRARY_CONTEXT_STATE _GLFWlibraryOSMesa osmesa // OSMesa-specific per-context data // typedef struct _GLFWcontextOSMesa { OSMesaContext handle; int width; int height; void* buffer; } _GLFWcontextOSMesa; // OSMesa-specific global data // typedef struct _GLFWlibraryOSMesa { void* handle; PFN_OSMesaCreateContextExt CreateContextExt; PFN_OSMesaCreateContextAttribs CreateContextAttribs; PFN_OSMesaDestroyContext DestroyContext; PFN_OSMesaMakeCurrent MakeCurrent; PFN_OSMesaGetColorBuffer GetColorBuffer; PFN_OSMesaGetDepthBuffer GetDepthBuffer; PFN_OSMesaGetProcAddress GetProcAddress; } _GLFWlibraryOSMesa; GLFWbool _glfwInitOSMesa(void); void _glfwTerminateOSMesa(void); GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig); #endif #include "wayland-xdg-shell-client-protocol.h" #include "wayland-xdg-decoration-client-protocol.h" #include "wayland-viewporter-client-protocol.h" #include "wayland-relative-pointer-unstable-v1-client-protocol.h" #include "wayland-pointer-constraints-unstable-v1-client-protocol.h" #include "wayland-idle-inhibit-unstable-v1-client-protocol.h" #define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL) #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_DISPLAY ((EGLNativeDisplayType) _glfw.wl.display) #define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowWayland wl #define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryWayland wl #define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorWayland wl #define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorWayland wl #define _GLFW_PLATFORM_CONTEXT_STATE struct { int dummyContext; } #define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE struct { int dummyLibraryContext; } struct wl_cursor_image { uint32_t width; uint32_t height; uint32_t hotspot_x; uint32_t hotspot_y; uint32_t delay; }; struct wl_cursor { unsigned int image_count; struct wl_cursor_image** images; char* name; }; typedef struct wl_cursor_theme* (* PFN_wl_cursor_theme_load)(const char*, int, struct wl_shm*); typedef void (* PFN_wl_cursor_theme_destroy)(struct wl_cursor_theme*); typedef struct wl_cursor* (* PFN_wl_cursor_theme_get_cursor)(struct wl_cursor_theme*, const char*); typedef struct wl_buffer* (* PFN_wl_cursor_image_get_buffer)(struct wl_cursor_image*); #define wl_cursor_theme_load _glfw.wl.cursor.theme_load #define wl_cursor_theme_destroy _glfw.wl.cursor.theme_destroy #define wl_cursor_theme_get_cursor _glfw.wl.cursor.theme_get_cursor #define wl_cursor_image_get_buffer _glfw.wl.cursor.image_get_buffer typedef struct wl_egl_window* (* PFN_wl_egl_window_create)(struct wl_surface*, int, int); typedef void (* PFN_wl_egl_window_destroy)(struct wl_egl_window*); typedef void (* PFN_wl_egl_window_resize)(struct wl_egl_window*, int, int, int, int); #define wl_egl_window_create _glfw.wl.egl.window_create #define wl_egl_window_destroy _glfw.wl.egl.window_destroy #define wl_egl_window_resize _glfw.wl.egl.window_resize typedef struct xkb_context* (* PFN_xkb_context_new)(enum xkb_context_flags); typedef void (* PFN_xkb_context_unref)(struct xkb_context*); typedef struct xkb_keymap* (* PFN_xkb_keymap_new_from_string)(struct xkb_context*, const char*, enum xkb_keymap_format, enum xkb_keymap_compile_flags); 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); #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 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); typedef void (* PFN_xkb_compose_state_unref)(struct xkb_compose_state*); typedef enum xkb_compose_feed_result (* PFN_xkb_compose_state_feed)(struct xkb_compose_state*, xkb_keysym_t); typedef enum xkb_compose_status (* PFN_xkb_compose_state_get_status)(struct xkb_compose_state*); typedef xkb_keysym_t (* PFN_xkb_compose_state_get_one_sym)(struct xkb_compose_state*); #define xkb_compose_table_new_from_locale _glfw.wl.xkb.compose_table_new_from_locale #define xkb_compose_table_unref _glfw.wl.xkb.compose_table_unref #define xkb_compose_state_new _glfw.wl.xkb.compose_state_new #define xkb_compose_state_unref _glfw.wl.xkb.compose_state_unref #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 #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) typedef enum _GLFWdecorationSideWayland { mainWindow, topDecoration, leftDecoration, rightDecoration, bottomDecoration, } _GLFWdecorationSideWayland; typedef struct _GLFWdecorationWayland { struct wl_surface* surface; struct wl_subsurface* subsurface; struct wp_viewport* viewport; } _GLFWdecorationWayland; // Wayland-specific per-window data // typedef struct _GLFWwindowWayland { int width, height; GLFWbool visible; GLFWbool maximized; GLFWbool hovered; GLFWbool transparent; struct wl_surface* surface; struct wl_egl_window* native; struct wl_shell_surface* shellSurface; struct wl_callback* callback; struct { struct xdg_surface* surface; struct xdg_toplevel* toplevel; struct zxdg_toplevel_decoration_v1* decoration; } xdg; _GLFWcursor* currentCursor; double cursorPosX, cursorPosY; char* title; // We need to track the monitors the window spans on to calculate the // optimal scaling factor. int scale; _GLFWmonitor** monitors; int monitorsCount; int monitorsSize; struct { struct zwp_relative_pointer_v1* relativePointer; struct zwp_locked_pointer_v1* lockedPointer; } pointerLock; struct zwp_idle_inhibitor_v1* idleInhibitor; GLFWbool wasFullscreen; struct { GLFWbool serverSide; struct wl_buffer* buffer; _GLFWdecorationWayland top, left, right, bottom; int focus; } decorations; } _GLFWwindowWayland; // Wayland-specific global data // typedef struct _GLFWlibraryWayland { struct wl_display* display; 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; struct zwp_relative_pointer_manager_v1* relativePointerManager; struct zwp_pointer_constraints_v1* pointerConstraints; struct zwp_idle_inhibit_manager_v1* idleInhibitManager; int compositorVersion; int seatVersion; 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; 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; struct xkb_compose_state* composeState; 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; unsigned int modifiers; PFN_xkb_context_new context_new; PFN_xkb_context_unref context_unref; PFN_xkb_keymap_new_from_string keymap_new_from_string; 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_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; PFN_xkb_compose_state_unref compose_state_unref; 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; } xkb; _GLFWwindow* pointerFocus; _GLFWwindow* keyboardFocus; struct { void* handle; PFN_wl_cursor_theme_load theme_load; PFN_wl_cursor_theme_destroy theme_destroy; PFN_wl_cursor_theme_get_cursor theme_get_cursor; PFN_wl_cursor_image_get_buffer image_get_buffer; } cursor; struct { void* handle; PFN_wl_egl_window_create window_create; PFN_wl_egl_window_destroy window_destroy; PFN_wl_egl_window_resize window_resize; } egl; } _GLFWlibraryWayland; // Wayland-specific per-monitor data // typedef struct _GLFWmonitorWayland { struct wl_output* output; uint32_t name; int currentMode; int x; int y; int scale; } _GLFWmonitorWayland; // Wayland-specific per-cursor data // typedef struct _GLFWcursorWayland { struct wl_cursor* cursor; struct wl_cursor* cursorHiDPI; struct wl_buffer* buffer; int width, height; int xhot, yhot; int currentImage; } _GLFWcursorWayland; void _glfwAddOutputWayland(uint32_t name, uint32_t version); GLFWbool _glfwInputTextWayland(_GLFWwindow* window, uint32_t scancode); #endif #elif defined(_GLFW_OSMESA) #ifndef HEADER_GUARD_NULL_PLATFORM_H #define HEADER_GUARD_NULL_PLATFORM_H //======================================================================== // GLFW 3.3.7 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2016 Google Inc. // Copyright (c) 2016-2017 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== #include #define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowNull null #define _GLFW_PLATFORM_CONTEXT_STATE struct { int dummyContext; } #define _GLFW_PLATFORM_MONITOR_STATE struct { int dummyMonitor; } #define _GLFW_PLATFORM_CURSOR_STATE struct { int dummyCursor; } #define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE struct { int dummyLibraryWindow; } #define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE struct { int dummyLibraryContext; } #define _GLFW_EGL_CONTEXT_STATE struct { int dummyEGLContext; } #define _GLFW_EGL_LIBRARY_CONTEXT_STATE struct { int dummyEGLLibraryContext; } #ifndef HEADER_GUARD_OSMESA_CONTEXT_H #define HEADER_GUARD_OSMESA_CONTEXT_H //======================================================================== // GLFW 3.3.7 OSMesa - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2016 Google Inc. // Copyright (c) 2016-2017 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== #define OSMESA_RGBA 0x1908 #define OSMESA_FORMAT 0x22 #define OSMESA_DEPTH_BITS 0x30 #define OSMESA_STENCIL_BITS 0x31 #define OSMESA_ACCUM_BITS 0x32 #define OSMESA_PROFILE 0x33 #define OSMESA_CORE_PROFILE 0x34 #define OSMESA_COMPAT_PROFILE 0x35 #define OSMESA_CONTEXT_MAJOR_VERSION 0x36 #define OSMESA_CONTEXT_MINOR_VERSION 0x37 typedef void* OSMesaContext; typedef void (*OSMESAproc)(void); typedef OSMesaContext (GLAPIENTRY * PFN_OSMesaCreateContextExt)(GLenum,GLint,GLint,GLint,OSMesaContext); typedef OSMesaContext (GLAPIENTRY * PFN_OSMesaCreateContextAttribs)(const int*,OSMesaContext); typedef void (GLAPIENTRY * PFN_OSMesaDestroyContext)(OSMesaContext); typedef int (GLAPIENTRY * PFN_OSMesaMakeCurrent)(OSMesaContext,void*,int,int,int); typedef int (GLAPIENTRY * PFN_OSMesaGetColorBuffer)(OSMesaContext,int*,int*,int*,void**); typedef int (GLAPIENTRY * PFN_OSMesaGetDepthBuffer)(OSMesaContext,int*,int*,int*,void**); typedef GLFWglproc (GLAPIENTRY * PFN_OSMesaGetProcAddress)(const char*); #define OSMesaCreateContextExt _glfw.osmesa.CreateContextExt #define OSMesaCreateContextAttribs _glfw.osmesa.CreateContextAttribs #define OSMesaDestroyContext _glfw.osmesa.DestroyContext #define OSMesaMakeCurrent _glfw.osmesa.MakeCurrent #define OSMesaGetColorBuffer _glfw.osmesa.GetColorBuffer #define OSMesaGetDepthBuffer _glfw.osmesa.GetDepthBuffer #define OSMesaGetProcAddress _glfw.osmesa.GetProcAddress #define _GLFW_OSMESA_CONTEXT_STATE _GLFWcontextOSMesa osmesa #define _GLFW_OSMESA_LIBRARY_CONTEXT_STATE _GLFWlibraryOSMesa osmesa // OSMesa-specific per-context data // typedef struct _GLFWcontextOSMesa { OSMesaContext handle; int width; int height; void* buffer; } _GLFWcontextOSMesa; // OSMesa-specific global data // typedef struct _GLFWlibraryOSMesa { void* handle; PFN_OSMesaCreateContextExt CreateContextExt; PFN_OSMesaCreateContextAttribs CreateContextAttribs; PFN_OSMesaDestroyContext DestroyContext; PFN_OSMesaMakeCurrent MakeCurrent; PFN_OSMesaGetColorBuffer GetColorBuffer; PFN_OSMesaGetDepthBuffer GetDepthBuffer; PFN_OSMesaGetProcAddress GetProcAddress; } _GLFWlibraryOSMesa; GLFWbool _glfwInitOSMesa(void); void _glfwTerminateOSMesa(void); GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig); #endif #ifndef HEADER_GUARD_POSIX_TIME_H #define HEADER_GUARD_POSIX_TIME_H //======================================================================== // GLFW 3.3.7 POSIX - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2017 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== #define _GLFW_PLATFORM_LIBRARY_TIMER_STATE _GLFWtimerPOSIX posix #include // POSIX-specific global timer data // typedef struct _GLFWtimerPOSIX { GLFWbool monotonic; uint64_t frequency; } _GLFWtimerPOSIX; void _glfwInitTimerPOSIX(void); #endif #ifndef HEADER_GUARD_POSIX_THREAD_H #define HEADER_GUARD_POSIX_THREAD_H //======================================================================== // GLFW 3.3.7 POSIX - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2017 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== #include #define _GLFW_PLATFORM_TLS_STATE _GLFWtlsPOSIX posix #define _GLFW_PLATFORM_MUTEX_STATE _GLFWmutexPOSIX posix // POSIX-specific thread local storage data // typedef struct _GLFWtlsPOSIX { GLFWbool allocated; pthread_key_t key; } _GLFWtlsPOSIX; // POSIX-specific mutex data // typedef struct _GLFWmutexPOSIX { GLFWbool allocated; pthread_mutex_t handle; } _GLFWmutexPOSIX; #endif #ifndef HEADER_GUARD_NULL_JOYSTICK_H #define HEADER_GUARD_NULL_JOYSTICK_H //======================================================================== // GLFW 3.3.7 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2006-2017 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== #define _GLFW_PLATFORM_JOYSTICK_STATE struct { int dummyJoystick; } #define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE struct { int dummyLibraryJoystick; } #define _GLFW_PLATFORM_MAPPING_NAME "" #endif #if defined(_GLFW_WIN32) #define _glfw_dlopen(name) LoadLibraryA(name) #define _glfw_dlclose(handle) FreeLibrary((HMODULE) handle) #define _glfw_dlsym(handle, name) GetProcAddress((HMODULE) handle, name) #else #define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL) #define _glfw_dlclose(handle) dlclose(handle) #define _glfw_dlsym(handle, name) dlsym(handle, name) #endif // Null-specific per-window data // typedef struct _GLFWwindowNull { int width; int height; } _GLFWwindowNull; #endif #else #error "No supported window creation API selected" #endif // Constructs a version number string from the public header macros #define _GLFW_CONCAT_VERSION(m, n, r) #m "." #n "." #r #define _GLFW_MAKE_VERSION(m, n, r) _GLFW_CONCAT_VERSION(m, n, r) #define _GLFW_VERSION_NUMBER _GLFW_MAKE_VERSION(GLFW_VERSION_MAJOR, \ GLFW_VERSION_MINOR, \ GLFW_VERSION_REVISION) // Checks for whether the library has been initialized #define _GLFW_REQUIRE_INIT() \ if (!_glfw.initialized) \ { \ _glfwInputError(GLFW_NOT_INITIALIZED, NULL); \ return; \ } #define _GLFW_REQUIRE_INIT_OR_RETURN(x) \ if (!_glfw.initialized) \ { \ _glfwInputError(GLFW_NOT_INITIALIZED, NULL); \ return x; \ } // Swaps the provided pointers #define _GLFW_SWAP_POINTERS(x, y) \ { \ void* t; \ t = x; \ x = y; \ y = t; \ } // Per-thread error structure // struct _GLFWerror { _GLFWerror* next; int code; char description[_GLFW_MESSAGE_SIZE]; }; // Initialization configuration // // Parameters relating to the initialization of the library // struct _GLFWinitconfig { GLFWbool hatButtons; struct { GLFWbool menubar; GLFWbool chdir; } ns; }; // Window configuration // // Parameters relating to the creation of the window but not directly related // to the framebuffer. This is used to pass window creation parameters from // shared code to the platform API. // struct _GLFWwndconfig { int width; int height; const char* title; GLFWbool resizable; GLFWbool visible; GLFWbool decorated; GLFWbool focused; GLFWbool autoIconify; GLFWbool floating; GLFWbool maximized; GLFWbool centerCursor; GLFWbool focusOnShow; GLFWbool scaleToMonitor; struct { GLFWbool retina; char frameName[256]; } ns; struct { char className[256]; char instanceName[256]; } x11; }; // Context configuration // // Parameters relating to the creation of the context but not directly related // to the framebuffer. This is used to pass context creation parameters from // shared code to the platform API. // struct _GLFWctxconfig { int client; int source; int major; int minor; GLFWbool forward; GLFWbool debug; GLFWbool noerror; int profile; int robustness; int release; _GLFWwindow* share; struct { GLFWbool offline; } nsgl; }; // Framebuffer configuration // // This describes buffers and their sizes. It also contains // a platform-specific ID used to map back to the backend API object. // // It is used to pass framebuffer parameters from shared code to the platform // API and also to enumerate and select available framebuffer configs. // struct _GLFWfbconfig { int redBits; int greenBits; int blueBits; int alphaBits; int depthBits; int stencilBits; int accumRedBits; int accumGreenBits; int accumBlueBits; int accumAlphaBits; int auxBuffers; GLFWbool stereo; int samples; GLFWbool sRGB; GLFWbool doublebuffer; GLFWbool transparent; uintptr_t handle; }; // Context structure // struct _GLFWcontext { int client; int source; int major, minor, revision; GLFWbool forward, debug, noerror; int profile; int robustness; int release; PFNGLGETSTRINGIPROC GetStringi; PFNGLGETINTEGERVPROC GetIntegerv; PFNGLGETSTRINGPROC GetString; _GLFWmakecontextcurrentfun makeCurrent; _GLFWswapbuffersfun swapBuffers; _GLFWswapintervalfun swapInterval; _GLFWextensionsupportedfun extensionSupported; _GLFWgetprocaddressfun getProcAddress; _GLFWdestroycontextfun destroy; // This is defined in the context API's context.h _GLFW_PLATFORM_CONTEXT_STATE; // This is defined in egl_context.h _GLFW_EGL_CONTEXT_STATE; // This is defined in osmesa_context.h _GLFW_OSMESA_CONTEXT_STATE; }; // Window and context structure // struct _GLFWwindow { struct _GLFWwindow* next; // Window settings and state GLFWbool resizable; GLFWbool decorated; GLFWbool autoIconify; GLFWbool floating; GLFWbool focusOnShow; GLFWbool shouldClose; void* userPointer; GLFWbool doublebuffer; GLFWvidmode videoMode; _GLFWmonitor* monitor; _GLFWcursor* cursor; int minwidth, minheight; int maxwidth, maxheight; int numer, denom; GLFWbool stickyKeys; GLFWbool stickyMouseButtons; GLFWbool lockKeyMods; int cursorMode; char mouseButtons[GLFW_MOUSE_BUTTON_LAST + 1]; char keys[GLFW_KEY_LAST + 1]; // Virtual cursor position when cursor is disabled double virtualCursorPosX, virtualCursorPosY; GLFWbool rawMouseMotion; _GLFWcontext context; struct { 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; } callbacks; // This is defined in the window API's platform.h _GLFW_PLATFORM_WINDOW_STATE; }; // Monitor structure // struct _GLFWmonitor { char name[128]; void* userPointer; // Physical dimensions in millimeters. int widthMM, heightMM; // The window whose video mode is current on this monitor _GLFWwindow* window; GLFWvidmode* modes; int modeCount; GLFWvidmode currentMode; GLFWgammaramp originalRamp; GLFWgammaramp currentRamp; // This is defined in the window API's platform.h _GLFW_PLATFORM_MONITOR_STATE; }; // Cursor structure // struct _GLFWcursor { _GLFWcursor* next; // This is defined in the window API's platform.h _GLFW_PLATFORM_CURSOR_STATE; }; // Gamepad mapping element structure // struct _GLFWmapelement { uint8_t type; uint8_t index; int8_t axisScale; int8_t axisOffset; }; // Gamepad mapping structure // struct _GLFWmapping { char name[128]; char guid[33]; _GLFWmapelement buttons[15]; _GLFWmapelement axes[6]; }; // Joystick structure // struct _GLFWjoystick { GLFWbool present; float* axes; int axisCount; unsigned char* buttons; int buttonCount; unsigned char* hats; int hatCount; char name[128]; void* userPointer; char guid[33]; _GLFWmapping* mapping; // This is defined in the joystick API's joystick.h _GLFW_PLATFORM_JOYSTICK_STATE; }; // Thread local storage structure // struct _GLFWtls { // This is defined in the platform's thread.h _GLFW_PLATFORM_TLS_STATE; }; // Mutex structure // struct _GLFWmutex { // This is defined in the platform's thread.h _GLFW_PLATFORM_MUTEX_STATE; }; // Library global data // struct _GLFWlibrary { GLFWbool initialized; struct { _GLFWinitconfig init; _GLFWfbconfig framebuffer; _GLFWwndconfig window; _GLFWctxconfig context; int refreshRate; } hints; _GLFWerror* errorListHead; _GLFWcursor* cursorListHead; _GLFWwindow* windowListHead; _GLFWmonitor** monitors; int monitorCount; _GLFWjoystick joysticks[GLFW_JOYSTICK_LAST + 1]; _GLFWmapping* mappings; int mappingCount; _GLFWtls errorSlot; _GLFWtls contextSlot; _GLFWmutex errorLock; struct { uint64_t offset; // This is defined in the platform's time.h _GLFW_PLATFORM_LIBRARY_TIMER_STATE; } timer; struct { GLFWbool available; void* handle; char* extensions[2]; #if !defined(_GLFW_VULKAN_STATIC) PFN_vkEnumerateInstanceExtensionProperties EnumerateInstanceExtensionProperties; PFN_vkGetInstanceProcAddr GetInstanceProcAddr; #endif GLFWbool KHR_surface; #if defined(_GLFW_WIN32) GLFWbool KHR_win32_surface; #elif defined(_GLFW_COCOA) GLFWbool MVK_macos_surface; GLFWbool EXT_metal_surface; #elif defined(_GLFW_X11) GLFWbool KHR_xlib_surface; GLFWbool KHR_xcb_surface; #elif defined(_GLFW_WAYLAND) GLFWbool KHR_wayland_surface; #endif } vk; struct { GLFWmonitorfun monitor; GLFWjoystickfun joystick; } callbacks; // This is defined in the window API's platform.h _GLFW_PLATFORM_LIBRARY_WINDOW_STATE; // This is defined in the context API's context.h _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE; // This is defined in the platform's joystick.h _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE; // This is defined in egl_context.h _GLFW_EGL_LIBRARY_CONTEXT_STATE; // This is defined in osmesa_context.h _GLFW_OSMESA_LIBRARY_CONTEXT_STATE; }; // Global state shared between compilation units of GLFW // extern _GLFWlibrary _glfw; ////////////////////////////////////////////////////////////////////////// ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// int _glfwPlatformInit(void); void _glfwPlatformTerminate(void); const char* _glfwPlatformGetVersionString(void); void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos); void _glfwPlatformSetCursorPos(_GLFWwindow* window, double xpos, double ypos); void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode); void _glfwPlatformSetRawMouseMotion(_GLFWwindow *window, GLFWbool enabled); GLFWbool _glfwPlatformRawMouseMotionSupported(void); int _glfwPlatformCreateCursor(_GLFWcursor* cursor, const GLFWimage* image, int xhot, int yhot); int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape); void _glfwPlatformDestroyCursor(_GLFWcursor* cursor); void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor); const char* _glfwPlatformGetScancodeName(int scancode); int _glfwPlatformGetKeyScancode(int key); void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor); void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos); void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor, float* xscale, float* yscale); void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor, int* xpos, int* ypos, int *width, int *height); GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count); void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode); GLFWbool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp); void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp); void _glfwPlatformSetClipboardString(const char* string); const char* _glfwPlatformGetClipboardString(void); int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode); void _glfwPlatformUpdateGamepadGUID(char* guid); uint64_t _glfwPlatformGetTimerValue(void); uint64_t _glfwPlatformGetTimerFrequency(void); int _glfwPlatformCreateWindow(_GLFWwindow* window, const _GLFWwndconfig* wndconfig, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig); void _glfwPlatformDestroyWindow(_GLFWwindow* window); void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title); void _glfwPlatformSetWindowIcon(_GLFWwindow* window, int count, const GLFWimage* images); void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos); void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos); void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height); void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height); void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window, int minwidth, int minheight, int maxwidth, int maxheight); void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom); void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height); void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, int* left, int* top, int* right, int* bottom); void _glfwPlatformGetWindowContentScale(_GLFWwindow* window, float* xscale, float* yscale); void _glfwPlatformIconifyWindow(_GLFWwindow* window); void _glfwPlatformRestoreWindow(_GLFWwindow* window); void _glfwPlatformMaximizeWindow(_GLFWwindow* window); void _glfwPlatformShowWindow(_GLFWwindow* window); void _glfwPlatformHideWindow(_GLFWwindow* window); void _glfwPlatformRequestWindowAttention(_GLFWwindow* window); void _glfwPlatformFocusWindow(_GLFWwindow* window); void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor, int xpos, int ypos, int width, int height, int refreshRate); int _glfwPlatformWindowFocused(_GLFWwindow* window); int _glfwPlatformWindowIconified(_GLFWwindow* window); int _glfwPlatformWindowVisible(_GLFWwindow* window); int _glfwPlatformWindowMaximized(_GLFWwindow* window); int _glfwPlatformWindowHovered(_GLFWwindow* window); int _glfwPlatformFramebufferTransparent(_GLFWwindow* window); float _glfwPlatformGetWindowOpacity(_GLFWwindow* window); void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled); void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled); void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled); void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity); void _glfwPlatformPollEvents(void); void _glfwPlatformWaitEvents(void); void _glfwPlatformWaitEventsTimeout(double timeout); void _glfwPlatformPostEmptyEvent(void); void _glfwPlatformGetRequiredInstanceExtensions(char** extensions); int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, VkPhysicalDevice device, uint32_t queuefamily); VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, _GLFWwindow* window, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface); GLFWbool _glfwPlatformCreateTls(_GLFWtls* tls); void _glfwPlatformDestroyTls(_GLFWtls* tls); void* _glfwPlatformGetTls(_GLFWtls* tls); void _glfwPlatformSetTls(_GLFWtls* tls, void* value); GLFWbool _glfwPlatformCreateMutex(_GLFWmutex* mutex); void _glfwPlatformDestroyMutex(_GLFWmutex* mutex); void _glfwPlatformLockMutex(_GLFWmutex* mutex); void _glfwPlatformUnlockMutex(_GLFWmutex* mutex); ////////////////////////////////////////////////////////////////////////// ////// GLFW event API ////// ////////////////////////////////////////////////////////////////////////// void _glfwInputWindowFocus(_GLFWwindow* window, GLFWbool focused); void _glfwInputWindowPos(_GLFWwindow* window, int xpos, int ypos); void _glfwInputWindowSize(_GLFWwindow* window, int width, int height); void _glfwInputFramebufferSize(_GLFWwindow* window, int width, int height); void _glfwInputWindowContentScale(_GLFWwindow* window, float xscale, float yscale); void _glfwInputWindowIconify(_GLFWwindow* window, GLFWbool iconified); void _glfwInputWindowMaximize(_GLFWwindow* window, GLFWbool maximized); void _glfwInputWindowDamage(_GLFWwindow* window); void _glfwInputWindowCloseRequest(_GLFWwindow* window); void _glfwInputWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor); void _glfwInputKey(_GLFWwindow* window, int key, int scancode, int action, int mods); void _glfwInputChar(_GLFWwindow* window, 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); void _glfwInputCursorEnter(_GLFWwindow* window, GLFWbool entered); void _glfwInputDrop(_GLFWwindow* window, int count, const char** names); void _glfwInputJoystick(_GLFWjoystick* js, int event); void _glfwInputJoystickAxis(_GLFWjoystick* js, int axis, float value); void _glfwInputJoystickButton(_GLFWjoystick* js, int button, char value); void _glfwInputJoystickHat(_GLFWjoystick* js, int hat, char value); void _glfwInputMonitor(_GLFWmonitor* monitor, int action, int placement); void _glfwInputMonitorWindow(_GLFWmonitor* monitor, _GLFWwindow* window); #if defined(__GNUC__) void _glfwInputError(int code, const char* format, ...) __attribute__((format(printf, 2, 3))); #else void _glfwInputError(int code, const char* format, ...); #endif ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// GLFWbool _glfwStringInExtensionString(const char* string, const char* extensions); const _GLFWfbconfig* _glfwChooseFBConfig(const _GLFWfbconfig* desired, const _GLFWfbconfig* alternatives, unsigned int count); GLFWbool _glfwRefreshContextAttribs(_GLFWwindow* window, const _GLFWctxconfig* ctxconfig); GLFWbool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig); const GLFWvidmode* _glfwChooseVideoMode(_GLFWmonitor* monitor, const GLFWvidmode* desired); int _glfwCompareVideoModes(const GLFWvidmode* first, const GLFWvidmode* second); _GLFWmonitor* _glfwAllocMonitor(const char* name, int widthMM, int heightMM); void _glfwFreeMonitor(_GLFWmonitor* monitor); void _glfwAllocGammaArrays(GLFWgammaramp* ramp, unsigned int size); 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, int buttonCount, int hatCount); void _glfwFreeJoystick(_GLFWjoystick* js); void _glfwCenterCursorInContentArea(_GLFWwindow* window); GLFWbool _glfwInitVulkan(int mode); void _glfwTerminateVulkan(void); const char* _glfwGetVulkanResultString(VkResult result); size_t _glfwEncodeUTF8(char* s, uint32_t codepoint); char* _glfw_strdup(const char* source); float _glfw_fminf(float a, float b); float _glfw_fmaxf(float a, float b); #endif #ifndef HEADER_GUARD_OSMESA_CONTEXT_C #define HEADER_GUARD_OSMESA_CONTEXT_C //======================================================================== // GLFW 3.3.7 OSMesa - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2016 Google Inc. // Copyright (c) 2016-2017 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== // Please use C89 style variable declarations in this file because VS 2010 //======================================================================== #include #include #include static void makeContextCurrentOSMesa(_GLFWwindow* window) { if (window) { int width, height; _glfwPlatformGetFramebufferSize(window, &width, &height); // Check to see if we need to allocate a new buffer if ((window->context.osmesa.buffer == NULL) || (width != window->context.osmesa.width) || (height != window->context.osmesa.height)) { free(window->context.osmesa.buffer); // Allocate the new buffer (width * height * 8-bit RGBA) window->context.osmesa.buffer = calloc(4, (size_t) width * height); window->context.osmesa.width = width; window->context.osmesa.height = height; } if (!OSMesaMakeCurrent(window->context.osmesa.handle, window->context.osmesa.buffer, GL_UNSIGNED_BYTE, width, height)) { _glfwInputError(GLFW_PLATFORM_ERROR, "OSMesa: Failed to make context current"); return; } } _glfwPlatformSetTls(&_glfw.contextSlot, window); } static GLFWglproc getProcAddressOSMesa(const char* procname) { return (GLFWglproc) OSMesaGetProcAddress(procname); } static void destroyContextOSMesa(_GLFWwindow* window) { if (window->context.osmesa.handle) { OSMesaDestroyContext(window->context.osmesa.handle); window->context.osmesa.handle = NULL; } if (window->context.osmesa.buffer) { free(window->context.osmesa.buffer); window->context.osmesa.width = 0; window->context.osmesa.height = 0; } } static void swapBuffersOSMesa(_GLFWwindow* window) { // No double buffering on OSMesa } static void swapIntervalOSMesa(int interval) { // No swap interval on OSMesa } static int extensionSupportedOSMesa(const char* extension) { // OSMesa does not have extensions return GLFW_FALSE; } ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// GLFWbool _glfwInitOSMesa(void) { int i; const char* sonames[] = { #if defined(_GLFW_OSMESA_LIBRARY) _GLFW_OSMESA_LIBRARY, #elif defined(_WIN32) "libOSMesa.dll", "OSMesa.dll", #elif defined(__APPLE__) "libOSMesa.8.dylib", #elif defined(__CYGWIN__) "libOSMesa-8.so", #elif defined(__OpenBSD__) || defined(__NetBSD__) "libOSMesa.so", #else "libOSMesa.so.8", "libOSMesa.so.6", #endif NULL }; if (_glfw.osmesa.handle) return GLFW_TRUE; for (i = 0; sonames[i]; i++) { _glfw.osmesa.handle = _glfw_dlopen(sonames[i]); if (_glfw.osmesa.handle) break; } if (!_glfw.osmesa.handle) { _glfwInputError(GLFW_API_UNAVAILABLE, "OSMesa: Library not found"); return GLFW_FALSE; } _glfw.osmesa.CreateContextExt = (PFN_OSMesaCreateContextExt) _glfw_dlsym(_glfw.osmesa.handle, "OSMesaCreateContextExt"); _glfw.osmesa.CreateContextAttribs = (PFN_OSMesaCreateContextAttribs) _glfw_dlsym(_glfw.osmesa.handle, "OSMesaCreateContextAttribs"); _glfw.osmesa.DestroyContext = (PFN_OSMesaDestroyContext) _glfw_dlsym(_glfw.osmesa.handle, "OSMesaDestroyContext"); _glfw.osmesa.MakeCurrent = (PFN_OSMesaMakeCurrent) _glfw_dlsym(_glfw.osmesa.handle, "OSMesaMakeCurrent"); _glfw.osmesa.GetColorBuffer = (PFN_OSMesaGetColorBuffer) _glfw_dlsym(_glfw.osmesa.handle, "OSMesaGetColorBuffer"); _glfw.osmesa.GetDepthBuffer = (PFN_OSMesaGetDepthBuffer) _glfw_dlsym(_glfw.osmesa.handle, "OSMesaGetDepthBuffer"); _glfw.osmesa.GetProcAddress = (PFN_OSMesaGetProcAddress) _glfw_dlsym(_glfw.osmesa.handle, "OSMesaGetProcAddress"); if (!_glfw.osmesa.CreateContextExt || !_glfw.osmesa.DestroyContext || !_glfw.osmesa.MakeCurrent || !_glfw.osmesa.GetColorBuffer || !_glfw.osmesa.GetDepthBuffer || !_glfw.osmesa.GetProcAddress) { _glfwInputError(GLFW_PLATFORM_ERROR, "OSMesa: Failed to load required entry points"); _glfwTerminateOSMesa(); return GLFW_FALSE; } return GLFW_TRUE; } void _glfwTerminateOSMesa(void) { if (_glfw.osmesa.handle) { _glfw_dlclose(_glfw.osmesa.handle); _glfw.osmesa.handle = NULL; } } #define setAttrib(a, v) \ { \ assert(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \ attribs[index++] = a; \ attribs[index++] = v; \ } GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig) { OSMesaContext share = NULL; const int accumBits = fbconfig->accumRedBits + fbconfig->accumGreenBits + fbconfig->accumBlueBits + fbconfig->accumAlphaBits; if (ctxconfig->client == GLFW_OPENGL_ES_API) { _glfwInputError(GLFW_API_UNAVAILABLE, "OSMesa: OpenGL ES is not available on OSMesa"); return GLFW_FALSE; } if (ctxconfig->share) share = ctxconfig->share->context.osmesa.handle; if (OSMesaCreateContextAttribs) { int index = 0, attribs[40]; setAttrib(OSMESA_FORMAT, OSMESA_RGBA); setAttrib(OSMESA_DEPTH_BITS, fbconfig->depthBits); setAttrib(OSMESA_STENCIL_BITS, fbconfig->stencilBits); setAttrib(OSMESA_ACCUM_BITS, accumBits); if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE) { setAttrib(OSMESA_PROFILE, OSMESA_CORE_PROFILE); } else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE) { setAttrib(OSMESA_PROFILE, OSMESA_COMPAT_PROFILE); } if (ctxconfig->major != 1 || ctxconfig->minor != 0) { setAttrib(OSMESA_CONTEXT_MAJOR_VERSION, ctxconfig->major); setAttrib(OSMESA_CONTEXT_MINOR_VERSION, ctxconfig->minor); } if (ctxconfig->forward) { _glfwInputError(GLFW_VERSION_UNAVAILABLE, "OSMesa: Forward-compatible contexts not supported"); return GLFW_FALSE; } setAttrib(0, 0); window->context.osmesa.handle = OSMesaCreateContextAttribs(attribs, share); } else { if (ctxconfig->profile) { _glfwInputError(GLFW_VERSION_UNAVAILABLE, "OSMesa: OpenGL profiles unavailable"); return GLFW_FALSE; } window->context.osmesa.handle = OSMesaCreateContextExt(OSMESA_RGBA, fbconfig->depthBits, fbconfig->stencilBits, accumBits, share); } if (window->context.osmesa.handle == NULL) { _glfwInputError(GLFW_VERSION_UNAVAILABLE, "OSMesa: Failed to create context"); return GLFW_FALSE; } window->context.makeCurrent = makeContextCurrentOSMesa; window->context.swapBuffers = swapBuffersOSMesa; window->context.swapInterval = swapIntervalOSMesa; window->context.extensionSupported = extensionSupportedOSMesa; window->context.getProcAddress = getProcAddressOSMesa; window->context.destroy = destroyContextOSMesa; return GLFW_TRUE; } #undef setAttrib ////////////////////////////////////////////////////////////////////////// ////// GLFW native API ////// ////////////////////////////////////////////////////////////////////////// GLFWAPI int glfwGetOSMesaColorBuffer(GLFWwindow* handle, int* width, int* height, int* format, void** buffer) { void* mesaBuffer; GLint mesaWidth, mesaHeight, mesaFormat; _GLFWwindow* window = (_GLFWwindow*) handle; assert(window != NULL); _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)) { _glfwInputError(GLFW_PLATFORM_ERROR, "OSMesa: Failed to retrieve color buffer"); return GLFW_FALSE; } if (width) *width = mesaWidth; if (height) *height = mesaHeight; if (format) *format = mesaFormat; if (buffer) *buffer = mesaBuffer; return GLFW_TRUE; } GLFWAPI int glfwGetOSMesaDepthBuffer(GLFWwindow* handle, int* width, int* height, int* bytesPerValue, void** buffer) { void* mesaBuffer; GLint mesaWidth, mesaHeight, mesaBytes; _GLFWwindow* window = (_GLFWwindow*) handle; assert(window != NULL); _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)) { _glfwInputError(GLFW_PLATFORM_ERROR, "OSMesa: Failed to retrieve depth buffer"); return GLFW_FALSE; } if (width) *width = mesaWidth; if (height) *height = mesaHeight; if (bytesPerValue) *bytesPerValue = mesaBytes; if (buffer) *buffer = mesaBuffer; return GLFW_TRUE; } GLFWAPI OSMesaContext glfwGetOSMesaContext(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(NULL); if (window->context.source != GLFW_OSMESA_CONTEXT_API) { _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); return NULL; } return window->context.osmesa.handle; } #endif #ifndef HEADER_GUARD_EGL_CONTEXT_C #define HEADER_GUARD_EGL_CONTEXT_C //======================================================================== // GLFW 3.3.7 EGL - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2019 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== // Please use C89 style variable declarations in this file because VS 2010 //======================================================================== #include #include #include #include // Return a description of the specified EGL error // static const char* getEGLErrorString(EGLint error) { switch (error) { case EGL_SUCCESS: return "Success"; case EGL_NOT_INITIALIZED: return "EGL is not or could not be initialized"; case EGL_BAD_ACCESS: return "EGL cannot access a requested resource"; case EGL_BAD_ALLOC: return "EGL failed to allocate resources for the requested operation"; case EGL_BAD_ATTRIBUTE: return "An unrecognized attribute or attribute value was passed in the attribute list"; case EGL_BAD_CONTEXT: return "An EGLContext argument does not name a valid EGL rendering context"; case EGL_BAD_CONFIG: return "An EGLConfig argument does not name a valid EGL frame buffer configuration"; case EGL_BAD_CURRENT_SURFACE: return "The current surface of the calling thread is a window, pixel buffer or pixmap that is no longer valid"; case EGL_BAD_DISPLAY: return "An EGLDisplay argument does not name a valid EGL display connection"; case EGL_BAD_SURFACE: return "An EGLSurface argument does not name a valid surface configured for GL rendering"; case EGL_BAD_MATCH: return "Arguments are inconsistent"; case EGL_BAD_PARAMETER: return "One or more argument values are invalid"; case EGL_BAD_NATIVE_PIXMAP: return "A NativePixmapType argument does not refer to a valid native pixmap"; case EGL_BAD_NATIVE_WINDOW: return "A NativeWindowType argument does not refer to a valid native window"; case EGL_CONTEXT_LOST: return "The application must destroy all contexts and reinitialise"; default: return "ERROR: UNKNOWN EGL ERROR"; } } // Returns the specified attribute of the specified EGLConfig // static int getEGLConfigAttrib(EGLConfig config, int attrib) { int value; eglGetConfigAttrib(_glfw.egl.display, config, attrib, &value); return value; } // Return the EGLConfig most closely matching the specified hints // static GLFWbool chooseEGLConfig(const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* desired, EGLConfig* result) { EGLConfig* nativeConfigs; _GLFWfbconfig* usableConfigs; const _GLFWfbconfig* closest; int i, nativeCount, usableCount; eglGetConfigs(_glfw.egl.display, NULL, 0, &nativeCount); if (!nativeCount) { _glfwInputError(GLFW_API_UNAVAILABLE, "EGL: No EGLConfigs returned"); return GLFW_FALSE; } nativeConfigs = calloc(nativeCount, sizeof(EGLConfig)); eglGetConfigs(_glfw.egl.display, nativeConfigs, nativeCount, &nativeCount); usableConfigs = calloc(nativeCount, sizeof(_GLFWfbconfig)); usableCount = 0; for (i = 0; i < nativeCount; i++) { const EGLConfig n = nativeConfigs[i]; _GLFWfbconfig* u = usableConfigs + usableCount; // Only consider RGB(A) EGLConfigs if (getEGLConfigAttrib(n, EGL_COLOR_BUFFER_TYPE) != EGL_RGB_BUFFER) continue; // Only consider window EGLConfigs if (!(getEGLConfigAttrib(n, EGL_SURFACE_TYPE) & EGL_WINDOW_BIT)) continue; #if defined(_GLFW_X11) { XVisualInfo vi = {0}; // Only consider EGLConfigs with associated Visuals vi.visualid = getEGLConfigAttrib(n, EGL_NATIVE_VISUAL_ID); if (!vi.visualid) continue; if (desired->transparent) { int count; XVisualInfo* vis = XGetVisualInfo(_glfw.x11.display, VisualIDMask, &vi, &count); if (vis) { u->transparent = _glfwIsVisualTransparentX11(vis[0].visual); XFree(vis); } } } #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) & EGL_OPENGL_BIT)) continue; } u->redBits = getEGLConfigAttrib(n, EGL_RED_SIZE); u->greenBits = getEGLConfigAttrib(n, EGL_GREEN_SIZE); u->blueBits = getEGLConfigAttrib(n, EGL_BLUE_SIZE); u->alphaBits = getEGLConfigAttrib(n, EGL_ALPHA_SIZE); u->depthBits = getEGLConfigAttrib(n, EGL_DEPTH_SIZE); u->stencilBits = getEGLConfigAttrib(n, EGL_STENCIL_SIZE); u->samples = getEGLConfigAttrib(n, EGL_SAMPLES); u->doublebuffer = desired->doublebuffer; u->handle = (uintptr_t) n; usableCount++; } closest = _glfwChooseFBConfig(desired, usableConfigs, usableCount); if (closest) *result = (EGLConfig) closest->handle; free(nativeConfigs); free(usableConfigs); return closest != NULL; } static void makeContextCurrentEGL(_GLFWwindow* window) { if (window) { if (!eglMakeCurrent(_glfw.egl.display, window->context.egl.surface, window->context.egl.surface, window->context.egl.handle)) { _glfwInputError(GLFW_PLATFORM_ERROR, "EGL: Failed to make context current: %s", getEGLErrorString(eglGetError())); return; } } else { if (!eglMakeCurrent(_glfw.egl.display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) { _glfwInputError(GLFW_PLATFORM_ERROR, "EGL: Failed to clear current context: %s", getEGLErrorString(eglGetError())); return; } } _glfwPlatformSetTls(&_glfw.contextSlot, window); } static void swapBuffersEGL(_GLFWwindow* window) { if (window != _glfwPlatformGetTls(&_glfw.contextSlot)) { _glfwInputError(GLFW_PLATFORM_ERROR, "EGL: The context must be current on the calling thread when swapping buffers"); 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); } static void swapIntervalEGL(int interval) { eglSwapInterval(_glfw.egl.display, interval); } static int extensionSupportedEGL(const char* extension) { const char* extensions = eglQueryString(_glfw.egl.display, EGL_EXTENSIONS); if (extensions) { if (_glfwStringInExtensionString(extension, extensions)) return GLFW_TRUE; } return GLFW_FALSE; } static GLFWglproc getProcAddressEGL(const char* procname) { _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot); if (window->context.egl.client) { GLFWglproc proc = (GLFWglproc) _glfw_dlsym(window->context.egl.client, procname); if (proc) return proc; } return eglGetProcAddress(procname); } static void destroyContextEGL(_GLFWwindow* window) { #if defined(_GLFW_X11) // NOTE: Do not unload libGL.so.1 while the X11 display is still open, // as it will make XCloseDisplay segfault if (window->context.client != GLFW_OPENGL_API) #endif // _GLFW_X11 { if (window->context.egl.client) { _glfw_dlclose(window->context.egl.client); window->context.egl.client = NULL; } } if (window->context.egl.surface) { eglDestroySurface(_glfw.egl.display, window->context.egl.surface); window->context.egl.surface = EGL_NO_SURFACE; } if (window->context.egl.handle) { eglDestroyContext(_glfw.egl.display, window->context.egl.handle); window->context.egl.handle = EGL_NO_CONTEXT; } } ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// // Initialize EGL // GLFWbool _glfwInitEGL(void) { int i; const char* sonames[] = { #if defined(_GLFW_EGL_LIBRARY) _GLFW_EGL_LIBRARY, #elif defined(_GLFW_WIN32) "libEGL.dll", "EGL.dll", #elif defined(_GLFW_COCOA) "libEGL.dylib", #elif defined(__CYGWIN__) "libEGL-1.so", #elif defined(__OpenBSD__) || defined(__NetBSD__) "libEGL.so", #else "libEGL.so.1", #endif NULL }; if (_glfw.egl.handle) return GLFW_TRUE; for (i = 0; sonames[i]; i++) { _glfw.egl.handle = _glfw_dlopen(sonames[i]); if (_glfw.egl.handle) break; } if (!_glfw.egl.handle) { _glfwInputError(GLFW_API_UNAVAILABLE, "EGL: Library not found"); return GLFW_FALSE; } _glfw.egl.prefix = (strncmp(sonames[i], "lib", 3) == 0); _glfw.egl.GetConfigAttrib = (PFN_eglGetConfigAttrib) _glfw_dlsym(_glfw.egl.handle, "eglGetConfigAttrib"); _glfw.egl.GetConfigs = (PFN_eglGetConfigs) _glfw_dlsym(_glfw.egl.handle, "eglGetConfigs"); _glfw.egl.GetDisplay = (PFN_eglGetDisplay) _glfw_dlsym(_glfw.egl.handle, "eglGetDisplay"); _glfw.egl.GetError = (PFN_eglGetError) _glfw_dlsym(_glfw.egl.handle, "eglGetError"); _glfw.egl.Initialize = (PFN_eglInitialize) _glfw_dlsym(_glfw.egl.handle, "eglInitialize"); _glfw.egl.Terminate = (PFN_eglTerminate) _glfw_dlsym(_glfw.egl.handle, "eglTerminate"); _glfw.egl.BindAPI = (PFN_eglBindAPI) _glfw_dlsym(_glfw.egl.handle, "eglBindAPI"); _glfw.egl.CreateContext = (PFN_eglCreateContext) _glfw_dlsym(_glfw.egl.handle, "eglCreateContext"); _glfw.egl.DestroySurface = (PFN_eglDestroySurface) _glfw_dlsym(_glfw.egl.handle, "eglDestroySurface"); _glfw.egl.DestroyContext = (PFN_eglDestroyContext) _glfw_dlsym(_glfw.egl.handle, "eglDestroyContext"); _glfw.egl.CreateWindowSurface = (PFN_eglCreateWindowSurface) _glfw_dlsym(_glfw.egl.handle, "eglCreateWindowSurface"); _glfw.egl.MakeCurrent = (PFN_eglMakeCurrent) _glfw_dlsym(_glfw.egl.handle, "eglMakeCurrent"); _glfw.egl.SwapBuffers = (PFN_eglSwapBuffers) _glfw_dlsym(_glfw.egl.handle, "eglSwapBuffers"); _glfw.egl.SwapInterval = (PFN_eglSwapInterval) _glfw_dlsym(_glfw.egl.handle, "eglSwapInterval"); _glfw.egl.QueryString = (PFN_eglQueryString) _glfw_dlsym(_glfw.egl.handle, "eglQueryString"); _glfw.egl.GetProcAddress = (PFN_eglGetProcAddress) _glfw_dlsym(_glfw.egl.handle, "eglGetProcAddress"); if (!_glfw.egl.GetConfigAttrib || !_glfw.egl.GetConfigs || !_glfw.egl.GetDisplay || !_glfw.egl.GetError || !_glfw.egl.Initialize || !_glfw.egl.Terminate || !_glfw.egl.BindAPI || !_glfw.egl.CreateContext || !_glfw.egl.DestroySurface || !_glfw.egl.DestroyContext || !_glfw.egl.CreateWindowSurface || !_glfw.egl.MakeCurrent || !_glfw.egl.SwapBuffers || !_glfw.egl.SwapInterval || !_glfw.egl.QueryString || !_glfw.egl.GetProcAddress) { _glfwInputError(GLFW_PLATFORM_ERROR, "EGL: Failed to load required entry points"); _glfwTerminateEGL(); return GLFW_FALSE; } _glfw.egl.display = eglGetDisplay(_GLFW_EGL_NATIVE_DISPLAY); if (_glfw.egl.display == EGL_NO_DISPLAY) { _glfwInputError(GLFW_API_UNAVAILABLE, "EGL: Failed to get EGL display: %s", getEGLErrorString(eglGetError())); _glfwTerminateEGL(); return GLFW_FALSE; } if (!eglInitialize(_glfw.egl.display, &_glfw.egl.major, &_glfw.egl.minor)) { _glfwInputError(GLFW_API_UNAVAILABLE, "EGL: Failed to initialize EGL: %s", getEGLErrorString(eglGetError())); _glfwTerminateEGL(); return GLFW_FALSE; } _glfw.egl.KHR_create_context = extensionSupportedEGL("EGL_KHR_create_context"); _glfw.egl.KHR_create_context_no_error = extensionSupportedEGL("EGL_KHR_create_context_no_error"); _glfw.egl.KHR_gl_colorspace = extensionSupportedEGL("EGL_KHR_gl_colorspace"); _glfw.egl.KHR_get_all_proc_addresses = 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; } // Terminate EGL // void _glfwTerminateEGL(void) { if (_glfw.egl.display) { eglTerminate(_glfw.egl.display); _glfw.egl.display = EGL_NO_DISPLAY; } if (_glfw.egl.handle) { _glfw_dlclose(_glfw.egl.handle); _glfw.egl.handle = NULL; } } #define setAttrib(a, v) \ { \ assert(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \ attribs[index++] = a; \ attribs[index++] = v; \ } // Create the OpenGL or OpenGL ES context // GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig) { EGLint attribs[40]; EGLConfig config; EGLContext share = NULL; int index = 0; if (!_glfw.egl.display) { _glfwInputError(GLFW_API_UNAVAILABLE, "EGL: API not available"); return GLFW_FALSE; } if (ctxconfig->share) 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) { if (!eglBindAPI(EGL_OPENGL_ES_API)) { _glfwInputError(GLFW_API_UNAVAILABLE, "EGL: Failed to bind OpenGL ES: %s", getEGLErrorString(eglGetError())); return GLFW_FALSE; } } else { if (!eglBindAPI(EGL_OPENGL_API)) { _glfwInputError(GLFW_API_UNAVAILABLE, "EGL: Failed to bind OpenGL: %s", getEGLErrorString(eglGetError())); return GLFW_FALSE; } } if (_glfw.egl.KHR_create_context) { int mask = 0, flags = 0; if (ctxconfig->client == GLFW_OPENGL_API) { if (ctxconfig->forward) flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR; if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE) mask |= EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR; else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE) mask |= EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR; } if (ctxconfig->debug) flags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR; if (ctxconfig->robustness) { if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION) { setAttrib(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR, EGL_NO_RESET_NOTIFICATION_KHR); } else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET) { setAttrib(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR, EGL_LOSE_CONTEXT_ON_RESET_KHR); } 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 (mask) setAttrib(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, mask); if (flags) setAttrib(EGL_CONTEXT_FLAGS_KHR, flags); } else { if (ctxconfig->client == GLFW_OPENGL_ES_API) setAttrib(EGL_CONTEXT_CLIENT_VERSION, ctxconfig->major); } if (_glfw.egl.KHR_context_flush_control) { if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE) { setAttrib(EGL_CONTEXT_RELEASE_BEHAVIOR_KHR, EGL_CONTEXT_RELEASE_BEHAVIOR_NONE_KHR); } else if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_FLUSH) { setAttrib(EGL_CONTEXT_RELEASE_BEHAVIOR_KHR, EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR); } } setAttrib(EGL_NONE, EGL_NONE); window->context.egl.handle = eglCreateContext(_glfw.egl.display, config, share, attribs); if (window->context.egl.handle == EGL_NO_CONTEXT) { _glfwInputError(GLFW_VERSION_UNAVAILABLE, "EGL: Failed to create context: %s", getEGLErrorString(eglGetError())); return GLFW_FALSE; } // Set up attributes for surface creation index = 0; 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); if (_glfw.egl.EXT_present_opaque) setAttrib(EGL_PRESENT_OPAQUE_EXT, !fbconfig->transparent); setAttrib(EGL_NONE, EGL_NONE); window->context.egl.surface = eglCreateWindowSurface(_glfw.egl.display, config, _GLFW_EGL_NATIVE_WINDOW, attribs); if (window->context.egl.surface == EGL_NO_SURFACE) { _glfwInputError(GLFW_PLATFORM_ERROR, "EGL: Failed to create window surface: %s", getEGLErrorString(eglGetError())); return GLFW_FALSE; } window->context.egl.config = config; // Load the appropriate client library if (!_glfw.egl.KHR_get_all_proc_addresses) { int i; const char** sonames; const char* es1sonames[] = { #if defined(_GLFW_GLESV1_LIBRARY) _GLFW_GLESV1_LIBRARY, #elif defined(_GLFW_WIN32) "GLESv1_CM.dll", "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", #endif NULL }; const char* es2sonames[] = { #if defined(_GLFW_GLESV2_LIBRARY) _GLFW_GLESV2_LIBRARY, #elif defined(_GLFW_WIN32) "GLESv2.dll", "libGLESv2.dll", #elif defined(_GLFW_COCOA) "libGLESv2.dylib", #elif defined(__CYGWIN__) "libGLESv2-2.so", #elif defined(__OpenBSD__) || defined(__NetBSD__) "libGLESv2.so", #else "libGLESv2.so.2", #endif NULL }; const char* glsonames[] = { #if defined(_GLFW_OPENGL_LIBRARY) _GLFW_OPENGL_LIBRARY, #elif defined(_GLFW_WIN32) #elif defined(_GLFW_COCOA) #elif defined(__OpenBSD__) || defined(__NetBSD__) "libGL.so", #else "libGL.so.1", #endif NULL }; if (ctxconfig->client == GLFW_OPENGL_ES_API) { if (ctxconfig->major == 1) sonames = es1sonames; else sonames = es2sonames; } else sonames = glsonames; for (i = 0; sonames[i]; i++) { // HACK: Match presence of lib prefix to increase chance of finding // a matching pair in the jungle that is Win32 EGL/GLES if (_glfw.egl.prefix != (strncmp(sonames[i], "lib", 3) == 0)) continue; window->context.egl.client = _glfw_dlopen(sonames[i]); if (window->context.egl.client) break; } if (!window->context.egl.client) { _glfwInputError(GLFW_API_UNAVAILABLE, "EGL: Failed to load client library"); return GLFW_FALSE; } } window->context.makeCurrent = makeContextCurrentEGL; window->context.swapBuffers = swapBuffersEGL; window->context.swapInterval = swapIntervalEGL; window->context.extensionSupported = extensionSupportedEGL; window->context.getProcAddress = getProcAddressEGL; window->context.destroy = destroyContextEGL; return GLFW_TRUE; } #undef setAttrib // Returns the Visual and depth of the chosen EGLConfig // #if defined(_GLFW_X11) GLFWbool _glfwChooseVisualEGL(const _GLFWwndconfig* wndconfig, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig, Visual** visual, int* depth) { XVisualInfo* result; XVisualInfo desired; EGLConfig native; EGLint visualID = 0, count = 0; 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); desired.screen = _glfw.x11.screen; desired.visualid = visualID; result = XGetVisualInfo(_glfw.x11.display, vimask, &desired, &count); if (!result) { _glfwInputError(GLFW_PLATFORM_ERROR, "EGL: Failed to retrieve Visual for EGLConfig"); return GLFW_FALSE; } *visual = result->visual; *depth = result->depth; XFree(result); return GLFW_TRUE; } #endif // _GLFW_X11 ////////////////////////////////////////////////////////////////////////// ////// GLFW native API ////// ////////////////////////////////////////////////////////////////////////// GLFWAPI EGLDisplay glfwGetEGLDisplay(void) { _GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_DISPLAY); return _glfw.egl.display; } GLFWAPI EGLContext glfwGetEGLContext(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_CONTEXT); if (window->context.source != GLFW_EGL_CONTEXT_API) { _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); return EGL_NO_CONTEXT; } return window->context.egl.handle; } GLFWAPI EGLSurface glfwGetEGLSurface(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_SURFACE); if (window->context.source != GLFW_EGL_CONTEXT_API) { _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); return EGL_NO_SURFACE; } return window->context.egl.surface; } #endif #ifndef HEADER_GUARD_CONTEXT_C #define HEADER_GUARD_CONTEXT_C //======================================================================== // GLFW 3.3.7 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2016 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== // Please use C89 style variable declarations in this file because VS 2010 //======================================================================== #include #include #include #include #include ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// // Checks whether the desired context attributes are valid // // This function checks things like whether the specified client API version // exists and whether all relevant options have supported and non-conflicting // values // 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) { _glfwInputError(GLFW_INVALID_ENUM, "Invalid context creation API 0x%08X", ctxconfig->source); return GLFW_FALSE; } if (ctxconfig->client != GLFW_NO_API && ctxconfig->client != GLFW_OPENGL_API && ctxconfig->client != GLFW_OPENGL_ES_API) { _glfwInputError(GLFW_INVALID_ENUM, "Invalid client API 0x%08X", ctxconfig->client); return GLFW_FALSE; } if (ctxconfig->client == GLFW_OPENGL_API) { if ((ctxconfig->major < 1 || ctxconfig->minor < 0) || (ctxconfig->major == 1 && ctxconfig->minor > 5) || (ctxconfig->major == 2 && ctxconfig->minor > 1) || (ctxconfig->major == 3 && ctxconfig->minor > 3)) { // OpenGL 1.0 is the smallest valid version // OpenGL 1.x series ended with version 1.5 // OpenGL 2.x series ended with version 2.1 // OpenGL 3.x series ended with version 3.3 // For now, let everything else through _glfwInputError(GLFW_INVALID_VALUE, "Invalid OpenGL version %i.%i", ctxconfig->major, ctxconfig->minor); return GLFW_FALSE; } if (ctxconfig->profile) { if (ctxconfig->profile != GLFW_OPENGL_CORE_PROFILE && ctxconfig->profile != GLFW_OPENGL_COMPAT_PROFILE) { _glfwInputError(GLFW_INVALID_ENUM, "Invalid OpenGL profile 0x%08X", ctxconfig->profile); return GLFW_FALSE; } if (ctxconfig->major <= 2 || (ctxconfig->major == 3 && ctxconfig->minor < 2)) { // Desktop OpenGL context profiles are only defined for version 3.2 // and above _glfwInputError(GLFW_INVALID_VALUE, "Context profiles are only defined for OpenGL version 3.2 and above"); return GLFW_FALSE; } } if (ctxconfig->forward && ctxconfig->major <= 2) { // Forward-compatible contexts are only defined for OpenGL version 3.0 and above _glfwInputError(GLFW_INVALID_VALUE, "Forward-compatibility is only defined for OpenGL version 3.0 and above"); return GLFW_FALSE; } } else if (ctxconfig->client == GLFW_OPENGL_ES_API) { if (ctxconfig->major < 1 || ctxconfig->minor < 0 || (ctxconfig->major == 1 && ctxconfig->minor > 1) || (ctxconfig->major == 2 && ctxconfig->minor > 0)) { // OpenGL ES 1.0 is the smallest valid version // OpenGL ES 1.x series ended with version 1.1 // OpenGL ES 2.x series ended with version 2.0 // For now, let everything else through _glfwInputError(GLFW_INVALID_VALUE, "Invalid OpenGL ES version %i.%i", ctxconfig->major, ctxconfig->minor); return GLFW_FALSE; } } if (ctxconfig->robustness) { if (ctxconfig->robustness != GLFW_NO_RESET_NOTIFICATION && ctxconfig->robustness != GLFW_LOSE_CONTEXT_ON_RESET) { _glfwInputError(GLFW_INVALID_ENUM, "Invalid context robustness mode 0x%08X", ctxconfig->robustness); return GLFW_FALSE; } } if (ctxconfig->release) { if (ctxconfig->release != GLFW_RELEASE_BEHAVIOR_NONE && ctxconfig->release != GLFW_RELEASE_BEHAVIOR_FLUSH) { _glfwInputError(GLFW_INVALID_ENUM, "Invalid context release behavior 0x%08X", ctxconfig->release); return GLFW_FALSE; } } return GLFW_TRUE; } // Chooses the framebuffer config that best matches the desired one // const _GLFWfbconfig* _glfwChooseFBConfig(const _GLFWfbconfig* desired, const _GLFWfbconfig* alternatives, unsigned int count) { unsigned int i; unsigned int missing, leastMissing = UINT_MAX; unsigned int colorDiff, leastColorDiff = UINT_MAX; unsigned int extraDiff, leastExtraDiff = UINT_MAX; const _GLFWfbconfig* current; const _GLFWfbconfig* closest = NULL; for (i = 0; i < count; i++) { current = alternatives + i; if (desired->stereo > 0 && current->stereo == 0) { // Stereo is a hard constraint continue; } // Count number of missing buffers { missing = 0; if (desired->alphaBits > 0 && current->alphaBits == 0) missing++; if (desired->depthBits > 0 && current->depthBits == 0) missing++; if (desired->stencilBits > 0 && current->stencilBits == 0) missing++; if (desired->auxBuffers > 0 && current->auxBuffers < desired->auxBuffers) { missing += desired->auxBuffers - current->auxBuffers; } if (desired->samples > 0 && current->samples == 0) { // Technically, several multisampling buffers could be // involved, but that's a lower level implementation detail and // not important to us here, so we count them as one missing++; } if (desired->transparent != current->transparent) missing++; } // These polynomials make many small channel size differences matter // less than one large channel size difference // Calculate color channel size difference value { colorDiff = 0; if (desired->redBits != GLFW_DONT_CARE) { colorDiff += (desired->redBits - current->redBits) * (desired->redBits - current->redBits); } if (desired->greenBits != GLFW_DONT_CARE) { colorDiff += (desired->greenBits - current->greenBits) * (desired->greenBits - current->greenBits); } if (desired->blueBits != GLFW_DONT_CARE) { colorDiff += (desired->blueBits - current->blueBits) * (desired->blueBits - current->blueBits); } } // Calculate non-color channel size difference value { extraDiff = 0; if (desired->alphaBits != GLFW_DONT_CARE) { extraDiff += (desired->alphaBits - current->alphaBits) * (desired->alphaBits - current->alphaBits); } if (desired->depthBits != GLFW_DONT_CARE) { extraDiff += (desired->depthBits - current->depthBits) * (desired->depthBits - current->depthBits); } if (desired->stencilBits != GLFW_DONT_CARE) { extraDiff += (desired->stencilBits - current->stencilBits) * (desired->stencilBits - current->stencilBits); } if (desired->accumRedBits != GLFW_DONT_CARE) { extraDiff += (desired->accumRedBits - current->accumRedBits) * (desired->accumRedBits - current->accumRedBits); } if (desired->accumGreenBits != GLFW_DONT_CARE) { extraDiff += (desired->accumGreenBits - current->accumGreenBits) * (desired->accumGreenBits - current->accumGreenBits); } if (desired->accumBlueBits != GLFW_DONT_CARE) { extraDiff += (desired->accumBlueBits - current->accumBlueBits) * (desired->accumBlueBits - current->accumBlueBits); } if (desired->accumAlphaBits != GLFW_DONT_CARE) { extraDiff += (desired->accumAlphaBits - current->accumAlphaBits) * (desired->accumAlphaBits - current->accumAlphaBits); } if (desired->samples != GLFW_DONT_CARE) { extraDiff += (desired->samples - current->samples) * (desired->samples - current->samples); } if (desired->sRGB && !current->sRGB) extraDiff++; } // Figure out if the current one is better than the best one found so far // Least number of missing buffers is the most important heuristic, // then color buffer size match and lastly size match for other buffers if (missing < leastMissing) closest = current; else if (missing == leastMissing) { if ((colorDiff < leastColorDiff) || (colorDiff == leastColorDiff && extraDiff < leastExtraDiff)) { closest = current; } } if (current == closest) { leastMissing = missing; leastColorDiff = colorDiff; leastExtraDiff = extraDiff; } } return closest; } // Retrieves the attributes of the current context // GLFWbool _glfwRefreshContextAttribs(_GLFWwindow* window, const _GLFWctxconfig* ctxconfig) { int i; _GLFWwindow* previous; const char* version; const char* prefixes[] = { "OpenGL ES-CM ", "OpenGL ES-CL ", "OpenGL ES ", NULL }; window->context.source = ctxconfig->source; window->context.client = GLFW_OPENGL_API; previous = _glfwPlatformGetTls(&_glfw.contextSlot); glfwMakeContextCurrent((GLFWwindow*) window); window->context.GetIntegerv = (PFNGLGETINTEGERVPROC) window->context.getProcAddress("glGetIntegerv"); window->context.GetString = (PFNGLGETSTRINGPROC) window->context.getProcAddress("glGetString"); if (!window->context.GetIntegerv || !window->context.GetString) { _glfwInputError(GLFW_PLATFORM_ERROR, "Entry point retrieval is broken"); glfwMakeContextCurrent((GLFWwindow*) previous); return GLFW_FALSE; } version = (const char*) window->context.GetString(GL_VERSION); if (!version) { if (ctxconfig->client == GLFW_OPENGL_API) { _glfwInputError(GLFW_PLATFORM_ERROR, "OpenGL version string retrieval is broken"); } else { _glfwInputError(GLFW_PLATFORM_ERROR, "OpenGL ES version string retrieval is broken"); } glfwMakeContextCurrent((GLFWwindow*) previous); return GLFW_FALSE; } for (i = 0; prefixes[i]; i++) { const size_t length = strlen(prefixes[i]); if (strncmp(version, prefixes[i], length) == 0) { version += length; window->context.client = GLFW_OPENGL_ES_API; break; } } if (!sscanf(version, "%d.%d.%d", &window->context.major, &window->context.minor, &window->context.revision)) { if (window->context.client == GLFW_OPENGL_API) { _glfwInputError(GLFW_PLATFORM_ERROR, "No version found in OpenGL version string"); } else { _glfwInputError(GLFW_PLATFORM_ERROR, "No version found in OpenGL ES version string"); } glfwMakeContextCurrent((GLFWwindow*) previous); return GLFW_FALSE; } if (window->context.major < ctxconfig->major || (window->context.major == ctxconfig->major && window->context.minor < ctxconfig->minor)) { // The desired OpenGL version is greater than the actual version // This only happens if the machine lacks {GLX|WGL}_ARB_create_context // /and/ the user has requested an OpenGL version greater than 1.0 // For API consistency, we emulate the behavior of the // {GLX|WGL}_ARB_create_context extension and fail here if (window->context.client == GLFW_OPENGL_API) { _glfwInputError(GLFW_VERSION_UNAVAILABLE, "Requested OpenGL version %i.%i, got version %i.%i", ctxconfig->major, ctxconfig->minor, window->context.major, window->context.minor); } else { _glfwInputError(GLFW_VERSION_UNAVAILABLE, "Requested OpenGL ES version %i.%i, got version %i.%i", ctxconfig->major, ctxconfig->minor, window->context.major, window->context.minor); } glfwMakeContextCurrent((GLFWwindow*) previous); return GLFW_FALSE; } if (window->context.major >= 3) { // OpenGL 3.0+ uses a different function for extension string retrieval // We cache it here instead of in glfwExtensionSupported mostly to alert // users as early as possible that their build may be broken window->context.GetStringi = (PFNGLGETSTRINGIPROC) window->context.getProcAddress("glGetStringi"); if (!window->context.GetStringi) { _glfwInputError(GLFW_PLATFORM_ERROR, "Entry point retrieval is broken"); glfwMakeContextCurrent((GLFWwindow*) previous); return GLFW_FALSE; } } if (window->context.client == GLFW_OPENGL_API) { // Read back context flags (OpenGL 3.0 and above) if (window->context.major >= 3) { GLint flags; window->context.GetIntegerv(GL_CONTEXT_FLAGS, &flags); if (flags & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT) window->context.forward = GLFW_TRUE; if (flags & GL_CONTEXT_FLAG_DEBUG_BIT) window->context.debug = GLFW_TRUE; else if (glfwExtensionSupported("GL_ARB_debug_output") && ctxconfig->debug) { // HACK: This is a workaround for older drivers (pre KHR_debug) // not setting the debug bit in the context flags for // debug contexts window->context.debug = GLFW_TRUE; } if (flags & GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR) window->context.noerror = GLFW_TRUE; } // Read back OpenGL context profile (OpenGL 3.2 and above) if (window->context.major >= 4 || (window->context.major == 3 && window->context.minor >= 2)) { GLint mask; window->context.GetIntegerv(GL_CONTEXT_PROFILE_MASK, &mask); if (mask & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT) window->context.profile = GLFW_OPENGL_COMPAT_PROFILE; else if (mask & GL_CONTEXT_CORE_PROFILE_BIT) window->context.profile = GLFW_OPENGL_CORE_PROFILE; else if (glfwExtensionSupported("GL_ARB_compatibility")) { // HACK: This is a workaround for the compatibility profile bit // not being set in the context flags if an OpenGL 3.2+ // context was created without having requested a specific // version window->context.profile = GLFW_OPENGL_COMPAT_PROFILE; } } // Read back robustness strategy if (glfwExtensionSupported("GL_ARB_robustness")) { // NOTE: We avoid using the context flags for detection, as they are // only present from 3.0 while the extension applies from 1.1 GLint strategy; window->context.GetIntegerv(GL_RESET_NOTIFICATION_STRATEGY_ARB, &strategy); if (strategy == GL_LOSE_CONTEXT_ON_RESET_ARB) window->context.robustness = GLFW_LOSE_CONTEXT_ON_RESET; else if (strategy == GL_NO_RESET_NOTIFICATION_ARB) window->context.robustness = GLFW_NO_RESET_NOTIFICATION; } } else { // Read back robustness strategy if (glfwExtensionSupported("GL_EXT_robustness")) { // NOTE: The values of these constants match those of the OpenGL ARB // one, so we can reuse them here GLint strategy; window->context.GetIntegerv(GL_RESET_NOTIFICATION_STRATEGY_ARB, &strategy); if (strategy == GL_LOSE_CONTEXT_ON_RESET_ARB) window->context.robustness = GLFW_LOSE_CONTEXT_ON_RESET; else if (strategy == GL_NO_RESET_NOTIFICATION_ARB) window->context.robustness = GLFW_NO_RESET_NOTIFICATION; } } if (glfwExtensionSupported("GL_KHR_context_flush_control")) { GLint behavior; window->context.GetIntegerv(GL_CONTEXT_RELEASE_BEHAVIOR, &behavior); if (behavior == GL_NONE) window->context.release = GLFW_RELEASE_BEHAVIOR_NONE; else if (behavior == GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH) window->context.release = GLFW_RELEASE_BEHAVIOR_FLUSH; } // Clearing the front buffer to black to avoid garbage pixels left over from // previous uses of our bit of VRAM { PFNGLCLEARPROC glClear = (PFNGLCLEARPROC) window->context.getProcAddress("glClear"); glClear(GL_COLOR_BUFFER_BIT); if (window->doublebuffer) window->context.swapBuffers(window); } glfwMakeContextCurrent((GLFWwindow*) previous); return GLFW_TRUE; } // Searches an extension string for the specified extension // GLFWbool _glfwStringInExtensionString(const char* string, const char* extensions) { const char* start = extensions; for (;;) { const char* where; const char* terminator; where = strstr(start, string); if (!where) return GLFW_FALSE; terminator = where + strlen(string); if (where == start || *(where - 1) == ' ') { if (*terminator == ' ' || *terminator == '\0') break; } start = terminator; } return GLFW_TRUE; } ////////////////////////////////////////////////////////////////////////// ////// GLFW public API ////// ////////////////////////////////////////////////////////////////////////// GLFWAPI void glfwMakeContextCurrent(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; _GLFWwindow* previous = _glfwPlatformGetTls(&_glfw.contextSlot); _GLFW_REQUIRE_INIT(); if (window && window->context.client == GLFW_NO_API) { _glfwInputError(GLFW_NO_WINDOW_CONTEXT, "Cannot make current with a window that has no OpenGL or OpenGL ES context"); return; } if (previous) { if (!window || window->context.source != previous->context.source) previous->context.makeCurrent(NULL); } if (window) window->context.makeCurrent(window); } GLFWAPI GLFWwindow* glfwGetCurrentContext(void) { _GLFW_REQUIRE_INIT_OR_RETURN(NULL); return _glfwPlatformGetTls(&_glfw.contextSlot); } GLFWAPI void glfwSwapBuffers(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; assert(window != NULL); _GLFW_REQUIRE_INIT(); if (window->context.client == GLFW_NO_API) { _glfwInputError(GLFW_NO_WINDOW_CONTEXT, "Cannot swap buffers of a window that has no OpenGL or OpenGL ES context"); return; } window->context.swapBuffers(window); } GLFWAPI void glfwSwapInterval(int interval) { _GLFWwindow* window; _GLFW_REQUIRE_INIT(); window = _glfwPlatformGetTls(&_glfw.contextSlot); if (!window) { _glfwInputError(GLFW_NO_CURRENT_CONTEXT, "Cannot set swap interval without a current OpenGL or OpenGL ES context"); return; } window->context.swapInterval(interval); } GLFWAPI int glfwExtensionSupported(const char* extension) { _GLFWwindow* window; assert(extension != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE); window = _glfwPlatformGetTls(&_glfw.contextSlot); if (!window) { _glfwInputError(GLFW_NO_CURRENT_CONTEXT, "Cannot query extension without a current OpenGL or OpenGL ES context"); return GLFW_FALSE; } if (*extension == '\0') { _glfwInputError(GLFW_INVALID_VALUE, "Extension name cannot be an empty string"); return GLFW_FALSE; } if (window->context.major >= 3) { int i; GLint count; // Check if extension is in the modern OpenGL extensions string list window->context.GetIntegerv(GL_NUM_EXTENSIONS, &count); for (i = 0; i < count; i++) { const char* en = (const char*) window->context.GetStringi(GL_EXTENSIONS, i); if (!en) { _glfwInputError(GLFW_PLATFORM_ERROR, "Extension string retrieval is broken"); return GLFW_FALSE; } if (strcmp(en, extension) == 0) return GLFW_TRUE; } } else { // Check if extension is in the old style OpenGL extensions string const char* extensions = (const char*) window->context.GetString(GL_EXTENSIONS); if (!extensions) { _glfwInputError(GLFW_PLATFORM_ERROR, "Extension string retrieval is broken"); return GLFW_FALSE; } if (_glfwStringInExtensionString(extension, extensions)) return GLFW_TRUE; } // Check if extension is in the platform-specific string return window->context.extensionSupported(extension); } GLFWAPI GLFWglproc glfwGetProcAddress(const char* procname) { _GLFWwindow* window; assert(procname != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); window = _glfwPlatformGetTls(&_glfw.contextSlot); if (!window) { _glfwInputError(GLFW_NO_CURRENT_CONTEXT, "Cannot query entry point without a current OpenGL or OpenGL ES context"); return NULL; } return window->context.getProcAddress(procname); } #endif #ifndef HEADER_GUARD_INIT_C #define HEADER_GUARD_INIT_C //======================================================================== // GLFW 3.3.7 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2018 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== // Please use C89 style variable declarations in this file because VS 2010 //======================================================================== #include #include #include #include #include // NOTE: The global variables below comprise all mutable global data in GLFW // Any other mutable global variable is a bug // 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 without special handling when _glfw is cleared to zero // static _GLFWerror _glfwMainThreadError; static GLFWerrorfun _glfwErrorCallback; static _GLFWinitconfig _glfwInitHints = { GLFW_TRUE, // hat buttons { GLFW_TRUE, // macOS menu bar GLFW_TRUE // macOS bundle chdir } }; // Terminate the library // static void terminate(void) { int i; memset(&_glfw.callbacks, 0, sizeof(_glfw.callbacks)); while (_glfw.windowListHead) glfwDestroyWindow((GLFWwindow*) _glfw.windowListHead); while (_glfw.cursorListHead) glfwDestroyCursor((GLFWcursor*) _glfw.cursorListHead); for (i = 0; i < _glfw.monitorCount; i++) { _GLFWmonitor* monitor = _glfw.monitors[i]; if (monitor->originalRamp.size) _glfwPlatformSetGammaRamp(monitor, &monitor->originalRamp); _glfwFreeMonitor(monitor); } free(_glfw.monitors); _glfw.monitors = NULL; _glfw.monitorCount = 0; free(_glfw.mappings); _glfw.mappings = NULL; _glfw.mappingCount = 0; _glfwTerminateVulkan(); _glfwPlatformTerminate(); _glfw.initialized = GLFW_FALSE; while (_glfw.errorListHead) { _GLFWerror* error = _glfw.errorListHead; _glfw.errorListHead = error->next; free(error); } _glfwPlatformDestroyTls(&_glfw.contextSlot); _glfwPlatformDestroyTls(&_glfw.errorSlot); _glfwPlatformDestroyMutex(&_glfw.errorLock); memset(&_glfw, 0, sizeof(_glfw)); } ////////////////////////////////////////////////////////////////////////// ////// 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; } char* _glfw_strdup(const char* source) { const size_t length = strlen(source); char* result = calloc(length + 1, 1); strcpy(result, source); return result; } float _glfw_fminf(float a, float b) { if (a != a) return b; else if (b != b) return a; else if (a < b) return a; else return b; } float _glfw_fmaxf(float a, float b) { if (a != a) return b; else if (b != b) return a; else if (a > b) return a; else return b; } ////////////////////////////////////////////////////////////////////////// ////// GLFW event API ////// ////////////////////////////////////////////////////////////////////////// // Notifies shared code of an error // void _glfwInputError(int code, const char* format, ...) { _GLFWerror* error; char description[_GLFW_MESSAGE_SIZE]; if (format) { va_list vl; va_start(vl, format); vsnprintf(description, sizeof(description), format, vl); va_end(vl); description[sizeof(description) - 1] = '\0'; } else { if (code == GLFW_NOT_INITIALIZED) strcpy(description, "The GLFW library is not initialized"); else if (code == GLFW_NO_CURRENT_CONTEXT) strcpy(description, "There is no current context"); else if (code == GLFW_INVALID_ENUM) strcpy(description, "Invalid argument for enum parameter"); else if (code == GLFW_INVALID_VALUE) strcpy(description, "Invalid value for parameter"); else if (code == GLFW_OUT_OF_MEMORY) strcpy(description, "Out of memory"); else if (code == GLFW_API_UNAVAILABLE) strcpy(description, "The requested API is unavailable"); else if (code == GLFW_VERSION_UNAVAILABLE) strcpy(description, "The requested API version is unavailable"); else if (code == GLFW_PLATFORM_ERROR) strcpy(description, "A platform-specific error occurred"); else if (code == GLFW_FORMAT_UNAVAILABLE) strcpy(description, "The requested format is unavailable"); else if (code == GLFW_NO_WINDOW_CONTEXT) strcpy(description, "The specified window has no context"); else strcpy(description, "ERROR: UNKNOWN GLFW ERROR"); } if (_glfw.initialized) { error = _glfwPlatformGetTls(&_glfw.errorSlot); if (!error) { error = calloc(1, sizeof(_GLFWerror)); _glfwPlatformSetTls(&_glfw.errorSlot, error); _glfwPlatformLockMutex(&_glfw.errorLock); error->next = _glfw.errorListHead; _glfw.errorListHead = error; _glfwPlatformUnlockMutex(&_glfw.errorLock); } } else error = &_glfwMainThreadError; error->code = code; strcpy(error->description, description); if (_glfwErrorCallback) _glfwErrorCallback(code, description); } ////////////////////////////////////////////////////////////////////////// ////// GLFW public API ////// ////////////////////////////////////////////////////////////////////////// GLFWAPI int glfwInit(void) { if (_glfw.initialized) return GLFW_TRUE; memset(&_glfw, 0, sizeof(_glfw)); _glfw.hints.init = _glfwInitHints; if (!_glfwPlatformInit()) { terminate(); return GLFW_FALSE; } if (!_glfwPlatformCreateMutex(&_glfw.errorLock) || !_glfwPlatformCreateTls(&_glfw.errorSlot) || !_glfwPlatformCreateTls(&_glfw.contextSlot)) { terminate(); return GLFW_FALSE; } _glfwPlatformSetTls(&_glfw.errorSlot, &_glfwMainThreadError); _glfwInitGamepadMappings(); _glfw.initialized = GLFW_TRUE; _glfw.timer.offset = _glfwPlatformGetTimerValue(); glfwDefaultWindowHints(); return GLFW_TRUE; } GLFWAPI void glfwTerminate(void) { if (!_glfw.initialized) return; terminate(); } GLFWAPI void glfwInitHint(int hint, int value) { switch (hint) { case GLFW_JOYSTICK_HAT_BUTTONS: _glfwInitHints.hatButtons = value; return; case GLFW_COCOA_CHDIR_RESOURCES: _glfwInitHints.ns.chdir = value; return; case GLFW_COCOA_MENUBAR: _glfwInitHints.ns.menubar = value; return; } _glfwInputError(GLFW_INVALID_ENUM, "Invalid init hint 0x%08X", hint); } GLFWAPI void glfwGetVersion(int* major, int* minor, int* rev) { if (major != NULL) *major = GLFW_VERSION_MAJOR; if (minor != NULL) *minor = GLFW_VERSION_MINOR; if (rev != NULL) *rev = GLFW_VERSION_REVISION; } GLFWAPI const char* glfwGetVersionString(void) { return _glfwPlatformGetVersionString(); } GLFWAPI int glfwGetError(const char** description) { _GLFWerror* error; int code = GLFW_NO_ERROR; if (description) *description = NULL; if (_glfw.initialized) error = _glfwPlatformGetTls(&_glfw.errorSlot); else error = &_glfwMainThreadError; if (error) { code = error->code; error->code = GLFW_NO_ERROR; if (description && code) *description = error->description; } return code; } GLFWAPI GLFWerrorfun glfwSetErrorCallback(GLFWerrorfun cbfun) { _GLFW_SWAP_POINTERS(_glfwErrorCallback, cbfun); return cbfun; } #endif #ifndef HEADER_GUARD_INPUT_C #define HEADER_GUARD_INPUT_C //======================================================================== // GLFW 3.3.7 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2019 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== // Please use C89 style variable declarations in this file because VS 2010 //======================================================================== #ifndef HEADER_GUARD_MAPPINGS_H #define HEADER_GUARD_MAPPINGS_H //======================================================================== // GLFW 3.3.7 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2006-2018 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== // As mappings.h.in, this file is used by CMake to produce the mappings.h // header file. If you are adding a GLFW specific gamepad mapping, this is // where to put it. //======================================================================== // As mappings.h, this provides all pre-defined gamepad mappings, including // 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 'update_mappings' CMake target. //======================================================================== // All gamepad mappings not labeled GLFW are copied from the // SDL_GameControllerDB project under the following license: // // Simple DirectMedia Layer // Copyright (C) 1997-2013 Sam Lantinga // // This software is provided 'as-is', without any express or implied warranty. // In no event will the authors be held liable for any damages arising from the // use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source distribution. 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,", "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,", "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,", "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,", "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,", "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,", "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,", "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 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,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,", "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,", "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,", "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,", "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 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,", "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,", "03000000300f00001210000000000000,QanBa Joystick Plus,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Windows,", "03000000341a00000104000000000000,QanBa Joystick Q4RAF,a:b5,b:b6,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b0,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b7,start:b9,x:b1,y:b2,platform:Windows,", "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,", "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,", "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,", "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,", "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,", "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,", "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 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,", "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,", "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,", "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,", "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,", "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,", "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,", "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,", "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,", "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,", "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,", "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,", "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,", "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,", "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,", "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,", "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,", "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,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,", "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,", "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,", "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,", "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,", "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,", "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,", "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,", "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,", "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 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,", "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,", "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,", "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,", "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,", "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,", "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,", "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,", "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 }; #endif #include #include #include #include #include // Internal key state used for sticky keys #define _GLFW_STICK 3 // Internal constants for gamepad mapping source types #define _GLFW_JOYSTICK_AXIS 1 #define _GLFW_JOYSTICK_BUTTON 2 #define _GLFW_JOYSTICK_HATBIT 3 // Finds a mapping based on joystick GUID // static _GLFWmapping* findMapping(const char* guid) { int i; for (i = 0; i < _glfw.mappingCount; i++) { if (strcmp(_glfw.mappings[i].guid, guid) == 0) return _glfw.mappings + i; } return NULL; } // Checks whether a gamepad mapping element is present in the hardware // static GLFWbool isValidElementForJoystick(const _GLFWmapelement* e, const _GLFWjoystick* js) { if (e->type == _GLFW_JOYSTICK_HATBIT && (e->index >> 4) >= js->hatCount) return GLFW_FALSE; else if (e->type == _GLFW_JOYSTICK_BUTTON && e->index >= js->buttonCount) return GLFW_FALSE; else if (e->type == _GLFW_JOYSTICK_AXIS && e->index >= js->axisCount) return GLFW_FALSE; return GLFW_TRUE; } // Finds a mapping based on joystick GUID and verifies element indices // static _GLFWmapping* findValidMapping(const _GLFWjoystick* js) { _GLFWmapping* mapping = findMapping(js->guid); if (mapping) { int i; for (i = 0; i <= GLFW_GAMEPAD_BUTTON_LAST; i++) { if (!isValidElementForJoystick(mapping->buttons + i, js)) return NULL; } for (i = 0; i <= GLFW_GAMEPAD_AXIS_LAST; i++) { if (!isValidElementForJoystick(mapping->axes + i, js)) return NULL; } } return mapping; } // Parses an SDL_GameControllerDB line and adds it to the mapping list // static GLFWbool parseMapping(_GLFWmapping* mapping, const char* string) { const char* c = string; size_t i, length; struct { const char* name; _GLFWmapelement* element; } fields[] = { { "platform", NULL }, { "a", mapping->buttons + GLFW_GAMEPAD_BUTTON_A }, { "b", mapping->buttons + GLFW_GAMEPAD_BUTTON_B }, { "x", mapping->buttons + GLFW_GAMEPAD_BUTTON_X }, { "y", mapping->buttons + GLFW_GAMEPAD_BUTTON_Y }, { "back", mapping->buttons + GLFW_GAMEPAD_BUTTON_BACK }, { "start", mapping->buttons + GLFW_GAMEPAD_BUTTON_START }, { "guide", mapping->buttons + GLFW_GAMEPAD_BUTTON_GUIDE }, { "leftshoulder", mapping->buttons + GLFW_GAMEPAD_BUTTON_LEFT_BUMPER }, { "rightshoulder", mapping->buttons + GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER }, { "leftstick", mapping->buttons + GLFW_GAMEPAD_BUTTON_LEFT_THUMB }, { "rightstick", mapping->buttons + GLFW_GAMEPAD_BUTTON_RIGHT_THUMB }, { "dpup", mapping->buttons + GLFW_GAMEPAD_BUTTON_DPAD_UP }, { "dpright", mapping->buttons + GLFW_GAMEPAD_BUTTON_DPAD_RIGHT }, { "dpdown", mapping->buttons + GLFW_GAMEPAD_BUTTON_DPAD_DOWN }, { "dpleft", mapping->buttons + GLFW_GAMEPAD_BUTTON_DPAD_LEFT }, { "lefttrigger", mapping->axes + GLFW_GAMEPAD_AXIS_LEFT_TRIGGER }, { "righttrigger", mapping->axes + GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER }, { "leftx", mapping->axes + GLFW_GAMEPAD_AXIS_LEFT_X }, { "lefty", mapping->axes + GLFW_GAMEPAD_AXIS_LEFT_Y }, { "rightx", mapping->axes + GLFW_GAMEPAD_AXIS_RIGHT_X }, { "righty", mapping->axes + GLFW_GAMEPAD_AXIS_RIGHT_Y } }; length = strcspn(c, ","); if (length != 32 || c[length] != ',') { _glfwInputError(GLFW_INVALID_VALUE, NULL); return GLFW_FALSE; } memcpy(mapping->guid, c, length); c += length + 1; length = strcspn(c, ","); if (length >= sizeof(mapping->name) || c[length] != ',') { _glfwInputError(GLFW_INVALID_VALUE, NULL); return GLFW_FALSE; } memcpy(mapping->name, c, length); c += length + 1; while (*c) { // TODO: Implement output modifiers if (*c == '+' || *c == '-') return GLFW_FALSE; for (i = 0; i < sizeof(fields) / sizeof(fields[0]); i++) { length = strlen(fields[i].name); if (strncmp(c, fields[i].name, length) != 0 || c[length] != ':') continue; c += length + 1; if (fields[i].element) { _GLFWmapelement* e = fields[i].element; int8_t minimum = -1; int8_t maximum = 1; if (*c == '+') { minimum = 0; c += 1; } else if (*c == '-') { maximum = 0; c += 1; } if (*c == 'a') e->type = _GLFW_JOYSTICK_AXIS; else if (*c == 'b') e->type = _GLFW_JOYSTICK_BUTTON; else if (*c == 'h') e->type = _GLFW_JOYSTICK_HATBIT; else break; if (e->type == _GLFW_JOYSTICK_HATBIT) { const unsigned long hat = strtoul(c + 1, (char**) &c, 10); const unsigned long bit = strtoul(c + 1, (char**) &c, 10); e->index = (uint8_t) ((hat << 4) | bit); } else e->index = (uint8_t) strtoul(c + 1, (char**) &c, 10); if (e->type == _GLFW_JOYSTICK_AXIS) { e->axisScale = 2 / (maximum - minimum); e->axisOffset = -(maximum + minimum); if (*c == '~') { e->axisScale = -e->axisScale; e->axisOffset = -e->axisOffset; } } } else { length = strlen(_GLFW_PLATFORM_MAPPING_NAME); if (strncmp(c, _GLFW_PLATFORM_MAPPING_NAME, length) != 0) return GLFW_FALSE; } break; } c += strcspn(c, ","); c += strspn(c, ","); } for (i = 0; i < 32; i++) { if (mapping->guid[i] >= 'A' && mapping->guid[i] <= 'F') mapping->guid[i] += 'a' - 'A'; } _glfwPlatformUpdateGamepadGUID(mapping->guid); return GLFW_TRUE; } ////////////////////////////////////////////////////////////////////////// ////// GLFW event API ////// ////////////////////////////////////////////////////////////////////////// // Notifies shared code of a physical key event // void _glfwInputKey(_GLFWwindow* window, int key, int scancode, int action, int mods) { if (key >= 0 && key <= GLFW_KEY_LAST) { GLFWbool repeated = GLFW_FALSE; if (action == GLFW_RELEASE && window->keys[key] == GLFW_RELEASE) return; if (action == GLFW_PRESS && window->keys[key] == GLFW_PRESS) repeated = GLFW_TRUE; if (action == GLFW_RELEASE && window->stickyKeys) window->keys[key] = _GLFW_STICK; else window->keys[key] = (char) action; if (repeated) action = GLFW_REPEAT; } if (!window->lockKeyMods) mods &= ~(GLFW_MOD_CAPS_LOCK | GLFW_MOD_NUM_LOCK); if (window->callbacks.key) window->callbacks.key((GLFWwindow*) window, key, scancode, action, mods); } // Notifies shared code of a Unicode codepoint input event // The 'plain' parameter determines whether to emit a regular character event // void _glfwInputChar(_GLFWwindow* window, uint32_t codepoint, int mods, GLFWbool plain) { if (codepoint < 32 || (codepoint > 126 && codepoint < 160)) return; if (!window->lockKeyMods) mods &= ~(GLFW_MOD_CAPS_LOCK | GLFW_MOD_NUM_LOCK); if (window->callbacks.charmods) window->callbacks.charmods((GLFWwindow*) window, codepoint, mods); if (plain) { if (window->callbacks.character) window->callbacks.character((GLFWwindow*) window, codepoint); } } // Notifies shared code of a scroll event // void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset) { if (window->callbacks.scroll) window->callbacks.scroll((GLFWwindow*) window, xoffset, yoffset); } // Notifies shared code of a mouse button click event // void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods) { if (button < 0 || button > GLFW_MOUSE_BUTTON_LAST) return; if (!window->lockKeyMods) mods &= ~(GLFW_MOD_CAPS_LOCK | GLFW_MOD_NUM_LOCK); if (action == GLFW_RELEASE && window->stickyMouseButtons) window->mouseButtons[button] = _GLFW_STICK; else window->mouseButtons[button] = (char) action; if (window->callbacks.mouseButton) window->callbacks.mouseButton((GLFWwindow*) window, button, action, mods); } // Notifies shared code of a cursor motion event // The position is specified in content area relative screen coordinates // void _glfwInputCursorPos(_GLFWwindow* window, double xpos, double ypos) { if (window->virtualCursorPosX == xpos && window->virtualCursorPosY == ypos) return; window->virtualCursorPosX = xpos; window->virtualCursorPosY = ypos; if (window->callbacks.cursorPos) window->callbacks.cursorPos((GLFWwindow*) window, xpos, ypos); } // Notifies shared code of a cursor enter/leave event // void _glfwInputCursorEnter(_GLFWwindow* window, GLFWbool entered) { if (window->callbacks.cursorEnter) window->callbacks.cursorEnter((GLFWwindow*) window, entered); } // Notifies shared code of files or directories dropped on a window // void _glfwInputDrop(_GLFWwindow* window, int count, const char** paths) { if (window->callbacks.drop) window->callbacks.drop((GLFWwindow*) window, count, paths); } // Notifies shared code of a joystick connection or disconnection // void _glfwInputJoystick(_GLFWjoystick* js, int event) { const int jid = (int) (js - _glfw.joysticks); if (_glfw.callbacks.joystick) _glfw.callbacks.joystick(jid, event); } // Notifies shared code of the new value of a joystick axis // void _glfwInputJoystickAxis(_GLFWjoystick* js, int axis, float value) { js->axes[axis] = value; } // Notifies shared code of the new value of a joystick button // void _glfwInputJoystickButton(_GLFWjoystick* js, int button, char value) { js->buttons[button] = value; } // Notifies shared code of the new value of a joystick hat // void _glfwInputJoystickHat(_GLFWjoystick* js, int hat, char value) { const int base = js->buttonCount + hat * 4; js->buttons[base + 0] = (value & 0x01) ? GLFW_PRESS : GLFW_RELEASE; js->buttons[base + 1] = (value & 0x02) ? GLFW_PRESS : GLFW_RELEASE; js->buttons[base + 2] = (value & 0x04) ? GLFW_PRESS : GLFW_RELEASE; js->buttons[base + 3] = (value & 0x08) ? GLFW_PRESS : GLFW_RELEASE; js->hats[hat] = value; } ////////////////////////////////////////////////////////////////////////// ////// 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->present) js->mapping = findValidMapping(js); } } // Returns an available joystick object with arrays and name allocated // _GLFWjoystick* _glfwAllocJoystick(const char* name, const char* guid, int axisCount, int buttonCount, int hatCount) { int jid; _GLFWjoystick* js; for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) { if (!_glfw.joysticks[jid].present) break; } if (jid > GLFW_JOYSTICK_LAST) return NULL; js = _glfw.joysticks + jid; js->present = GLFW_TRUE; js->axes = calloc(axisCount, sizeof(float)); js->buttons = calloc(buttonCount + (size_t) hatCount * 4, 1); js->hats = calloc(hatCount, 1); js->axisCount = axisCount; 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); return js; } // Frees arrays and name and flags the joystick object as unused // void _glfwFreeJoystick(_GLFWjoystick* js) { free(js->axes); free(js->buttons); free(js->hats); memset(js, 0, sizeof(_GLFWjoystick)); } // Center the cursor in the content area of the specified window // void _glfwCenterCursorInContentArea(_GLFWwindow* window) { int width, height; _glfwPlatformGetWindowSize(window, &width, &height); _glfwPlatformSetCursorPos(window, width / 2.0, height / 2.0); } ////////////////////////////////////////////////////////////////////////// ////// GLFW public API ////// ////////////////////////////////////////////////////////////////////////// GLFWAPI int glfwGetInputMode(GLFWwindow* handle, int mode) { _GLFWwindow* window = (_GLFWwindow*) handle; assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(0); switch (mode) { case GLFW_CURSOR: return window->cursorMode; case GLFW_STICKY_KEYS: return window->stickyKeys; case GLFW_STICKY_MOUSE_BUTTONS: return window->stickyMouseButtons; case GLFW_LOCK_KEY_MODS: return window->lockKeyMods; case GLFW_RAW_MOUSE_MOTION: return window->rawMouseMotion; } _glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode); return 0; } GLFWAPI void glfwSetInputMode(GLFWwindow* handle, int mode, int value) { _GLFWwindow* window = (_GLFWwindow*) handle; assert(window != NULL); _GLFW_REQUIRE_INIT(); if (mode == GLFW_CURSOR) { if (value != GLFW_CURSOR_NORMAL && value != GLFW_CURSOR_HIDDEN && value != GLFW_CURSOR_DISABLED) { _glfwInputError(GLFW_INVALID_ENUM, "Invalid cursor mode 0x%08X", value); return; } if (window->cursorMode == value) return; window->cursorMode = value; _glfwPlatformGetCursorPos(window, &window->virtualCursorPosX, &window->virtualCursorPosY); _glfwPlatformSetCursorMode(window, value); } else if (mode == GLFW_STICKY_KEYS) { value = value ? GLFW_TRUE : GLFW_FALSE; if (window->stickyKeys == value) return; if (!value) { int i; // Release all sticky keys for (i = 0; i <= GLFW_KEY_LAST; i++) { if (window->keys[i] == _GLFW_STICK) window->keys[i] = GLFW_RELEASE; } } window->stickyKeys = value; } else if (mode == GLFW_STICKY_MOUSE_BUTTONS) { value = value ? GLFW_TRUE : GLFW_FALSE; if (window->stickyMouseButtons == value) return; if (!value) { int i; // Release all sticky mouse buttons for (i = 0; i <= GLFW_MOUSE_BUTTON_LAST; i++) { if (window->mouseButtons[i] == _GLFW_STICK) window->mouseButtons[i] = GLFW_RELEASE; } } window->stickyMouseButtons = value; } else if (mode == GLFW_LOCK_KEY_MODS) { window->lockKeyMods = value ? GLFW_TRUE : GLFW_FALSE; } else if (mode == GLFW_RAW_MOUSE_MOTION) { if (!_glfwPlatformRawMouseMotionSupported()) { _glfwInputError(GLFW_PLATFORM_ERROR, "Raw mouse motion is not supported on this system"); return; } value = value ? GLFW_TRUE : GLFW_FALSE; if (window->rawMouseMotion == value) return; window->rawMouseMotion = value; _glfwPlatformSetRawMouseMotion(window, value); } else _glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode); } GLFWAPI int glfwRawMouseMotionSupported(void) { _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE); return _glfwPlatformRawMouseMotionSupported(); } GLFWAPI const char * glfwGetKeys(GLFWwindow* handle) //< @r-lyeh { _GLFWwindow* window = (_GLFWwindow*) handle; assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); return window->keys; } GLFWAPI const char* glfwGetKeyName(int key, int scancode) { _GLFW_REQUIRE_INIT_OR_RETURN(NULL); if (key != GLFW_KEY_UNKNOWN) { 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)) { return NULL; } scancode = _glfwPlatformGetKeyScancode(key); } return _glfwPlatformGetScancodeName(scancode); } GLFWAPI int glfwGetKeyScancode(int key) { _GLFW_REQUIRE_INIT_OR_RETURN(-1); if (key < GLFW_KEY_SPACE || key > GLFW_KEY_LAST) { _glfwInputError(GLFW_INVALID_ENUM, "Invalid key %i", key); return GLFW_RELEASE; } return _glfwPlatformGetKeyScancode(key); } GLFWAPI int glfwGetKey(GLFWwindow* handle, int key) { _GLFWwindow* window = (_GLFWwindow*) handle; assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_RELEASE); if (key < GLFW_KEY_SPACE || key > GLFW_KEY_LAST) { _glfwInputError(GLFW_INVALID_ENUM, "Invalid key %i", key); return GLFW_RELEASE; } if (window->keys[key] == _GLFW_STICK) { // Sticky mode: release key now window->keys[key] = GLFW_RELEASE; return GLFW_PRESS; } return (int) window->keys[key]; } GLFWAPI int glfwGetMouseButton(GLFWwindow* handle, int button) { _GLFWwindow* window = (_GLFWwindow*) handle; assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_RELEASE); if (button < GLFW_MOUSE_BUTTON_1 || button > GLFW_MOUSE_BUTTON_LAST) { _glfwInputError(GLFW_INVALID_ENUM, "Invalid mouse button %i", button); return GLFW_RELEASE; } if (window->mouseButtons[button] == _GLFW_STICK) { // Sticky mode: release mouse button now window->mouseButtons[button] = GLFW_RELEASE; return GLFW_PRESS; } return (int) window->mouseButtons[button]; } GLFWAPI void glfwGetCursorPos(GLFWwindow* handle, double* xpos, double* ypos) { _GLFWwindow* window = (_GLFWwindow*) handle; assert(window != NULL); if (xpos) *xpos = 0; if (ypos) *ypos = 0; _GLFW_REQUIRE_INIT(); if (window->cursorMode == GLFW_CURSOR_DISABLED) { if (xpos) *xpos = window->virtualCursorPosX; if (ypos) *ypos = window->virtualCursorPosY; } else _glfwPlatformGetCursorPos(window, xpos, ypos); } GLFWAPI void glfwSetCursorPos(GLFWwindow* handle, double xpos, double ypos) { _GLFWwindow* window = (_GLFWwindow*) handle; assert(window != NULL); _GLFW_REQUIRE_INIT(); if (xpos != xpos || xpos < -DBL_MAX || xpos > DBL_MAX || ypos != ypos || ypos < -DBL_MAX || ypos > DBL_MAX) { _glfwInputError(GLFW_INVALID_VALUE, "Invalid cursor position %f %f", xpos, ypos); return; } if (!_glfwPlatformWindowFocused(window)) return; if (window->cursorMode == GLFW_CURSOR_DISABLED) { // Only update the accumulated position if the cursor is disabled window->virtualCursorPosX = xpos; window->virtualCursorPosY = ypos; } else { // Update system cursor position _glfwPlatformSetCursorPos(window, xpos, ypos); } } GLFWAPI GLFWcursor* glfwCreateCursor(const GLFWimage* image, int xhot, int yhot) { _GLFWcursor* cursor; assert(image != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); cursor = calloc(1, sizeof(_GLFWcursor)); cursor->next = _glfw.cursorListHead; _glfw.cursorListHead = cursor; if (!_glfwPlatformCreateCursor(cursor, image, xhot, yhot)) { glfwDestroyCursor((GLFWcursor*) cursor); return NULL; } return (GLFWcursor*) cursor; } GLFWAPI GLFWcursor* glfwCreateStandardCursor(int shape) { _GLFWcursor* cursor; _GLFW_REQUIRE_INIT_OR_RETURN(NULL); if (shape != GLFW_ARROW_CURSOR && shape != GLFW_IBEAM_CURSOR && shape != GLFW_CROSSHAIR_CURSOR && shape != GLFW_HAND_CURSOR && shape != GLFW_HRESIZE_CURSOR && shape != GLFW_VRESIZE_CURSOR) { _glfwInputError(GLFW_INVALID_ENUM, "Invalid standard cursor 0x%08X", shape); return NULL; } cursor = calloc(1, sizeof(_GLFWcursor)); cursor->next = _glfw.cursorListHead; _glfw.cursorListHead = cursor; if (!_glfwPlatformCreateStandardCursor(cursor, shape)) { glfwDestroyCursor((GLFWcursor*) cursor); return NULL; } return (GLFWcursor*) cursor; } GLFWAPI void glfwDestroyCursor(GLFWcursor* handle) { _GLFWcursor* cursor = (_GLFWcursor*) handle; _GLFW_REQUIRE_INIT(); if (cursor == NULL) return; // Make sure the cursor is not being used by any window { _GLFWwindow* window; for (window = _glfw.windowListHead; window; window = window->next) { if (window->cursor == cursor) glfwSetCursor((GLFWwindow*) window, NULL); } } _glfwPlatformDestroyCursor(cursor); // Unlink cursor from global linked list { _GLFWcursor** prev = &_glfw.cursorListHead; while (*prev != cursor) prev = &((*prev)->next); *prev = cursor->next; } free(cursor); } GLFWAPI void glfwSetCursor(GLFWwindow* windowHandle, GLFWcursor* cursorHandle) { _GLFWwindow* window = (_GLFWwindow*) windowHandle; _GLFWcursor* cursor = (_GLFWcursor*) cursorHandle; assert(window != NULL); _GLFW_REQUIRE_INIT(); window->cursor = cursor; _glfwPlatformSetCursor(window, cursor); } GLFWAPI GLFWkeyfun glfwSetKeyCallback(GLFWwindow* handle, GLFWkeyfun cbfun) { _GLFWwindow* window = (_GLFWwindow*) handle; assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); _GLFW_SWAP_POINTERS(window->callbacks.key, cbfun); return cbfun; } GLFWAPI GLFWcharfun glfwSetCharCallback(GLFWwindow* handle, GLFWcharfun cbfun) { _GLFWwindow* window = (_GLFWwindow*) handle; assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); _GLFW_SWAP_POINTERS(window->callbacks.character, cbfun); return cbfun; } GLFWAPI GLFWcharmodsfun glfwSetCharModsCallback(GLFWwindow* handle, GLFWcharmodsfun cbfun) { _GLFWwindow* window = (_GLFWwindow*) handle; assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); _GLFW_SWAP_POINTERS(window->callbacks.charmods, cbfun); return cbfun; } GLFWAPI GLFWmousebuttonfun glfwSetMouseButtonCallback(GLFWwindow* handle, GLFWmousebuttonfun cbfun) { _GLFWwindow* window = (_GLFWwindow*) handle; assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); _GLFW_SWAP_POINTERS(window->callbacks.mouseButton, cbfun); return cbfun; } GLFWAPI GLFWcursorposfun glfwSetCursorPosCallback(GLFWwindow* handle, GLFWcursorposfun cbfun) { _GLFWwindow* window = (_GLFWwindow*) handle; assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); _GLFW_SWAP_POINTERS(window->callbacks.cursorPos, cbfun); return cbfun; } GLFWAPI GLFWcursorenterfun glfwSetCursorEnterCallback(GLFWwindow* handle, GLFWcursorenterfun cbfun) { _GLFWwindow* window = (_GLFWwindow*) handle; assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); _GLFW_SWAP_POINTERS(window->callbacks.cursorEnter, cbfun); return cbfun; } GLFWAPI GLFWscrollfun glfwSetScrollCallback(GLFWwindow* handle, GLFWscrollfun cbfun) { _GLFWwindow* window = (_GLFWwindow*) handle; assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); _GLFW_SWAP_POINTERS(window->callbacks.scroll, cbfun); return cbfun; } GLFWAPI GLFWdropfun glfwSetDropCallback(GLFWwindow* handle, GLFWdropfun cbfun) { _GLFWwindow* window = (_GLFWwindow*) handle; assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); _GLFW_SWAP_POINTERS(window->callbacks.drop, cbfun); return cbfun; } GLFWAPI int glfwJoystickPresent(int jid) { _GLFWjoystick* js; assert(jid >= GLFW_JOYSTICK_1); assert(jid <= GLFW_JOYSTICK_LAST); _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE); if (jid < 0 || jid > GLFW_JOYSTICK_LAST) { _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); return GLFW_FALSE; } js = _glfw.joysticks + jid; if (!js->present) return GLFW_FALSE; return _glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE); } GLFWAPI const float* glfwGetJoystickAxes(int jid, int* count) { _GLFWjoystick* js; assert(jid >= GLFW_JOYSTICK_1); assert(jid <= GLFW_JOYSTICK_LAST); assert(count != NULL); *count = 0; _GLFW_REQUIRE_INIT_OR_RETURN(NULL); if (jid < 0 || jid > GLFW_JOYSTICK_LAST) { _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); return NULL; } js = _glfw.joysticks + jid; if (!js->present) return NULL; if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_AXES)) return NULL; *count = js->axisCount; return js->axes; } GLFWAPI const unsigned char* glfwGetJoystickButtons(int jid, int* count) { _GLFWjoystick* js; assert(jid >= GLFW_JOYSTICK_1); assert(jid <= GLFW_JOYSTICK_LAST); assert(count != NULL); *count = 0; _GLFW_REQUIRE_INIT_OR_RETURN(NULL); if (jid < 0 || jid > GLFW_JOYSTICK_LAST) { _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); return NULL; } js = _glfw.joysticks + jid; if (!js->present) return NULL; if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_BUTTONS)) return NULL; if (_glfw.hints.init.hatButtons) *count = js->buttonCount + js->hatCount * 4; else *count = js->buttonCount; return js->buttons; } GLFWAPI const unsigned char* glfwGetJoystickHats(int jid, int* count) { _GLFWjoystick* js; assert(jid >= GLFW_JOYSTICK_1); assert(jid <= GLFW_JOYSTICK_LAST); assert(count != NULL); *count = 0; _GLFW_REQUIRE_INIT_OR_RETURN(NULL); if (jid < 0 || jid > GLFW_JOYSTICK_LAST) { _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); return NULL; } js = _glfw.joysticks + jid; if (!js->present) return NULL; if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_BUTTONS)) return NULL; *count = js->hatCount; return js->hats; } GLFWAPI const char* glfwGetJoystickName(int jid) { _GLFWjoystick* js; assert(jid >= GLFW_JOYSTICK_1); assert(jid <= GLFW_JOYSTICK_LAST); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); if (jid < 0 || jid > GLFW_JOYSTICK_LAST) { _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); return NULL; } js = _glfw.joysticks + jid; if (!js->present) return NULL; if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE)) return NULL; return js->name; } GLFWAPI const char* glfwGetJoystickGUID(int jid) { _GLFWjoystick* js; assert(jid >= GLFW_JOYSTICK_1); assert(jid <= GLFW_JOYSTICK_LAST); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); if (jid < 0 || jid > GLFW_JOYSTICK_LAST) { _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); return NULL; } js = _glfw.joysticks + jid; if (!js->present) return NULL; if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE)) return NULL; return js->guid; } GLFWAPI void glfwSetJoystickUserPointer(int jid, void* pointer) { _GLFWjoystick* js; assert(jid >= GLFW_JOYSTICK_1); assert(jid <= GLFW_JOYSTICK_LAST); _GLFW_REQUIRE_INIT(); js = _glfw.joysticks + jid; if (!js->present) return; js->userPointer = pointer; } GLFWAPI void* glfwGetJoystickUserPointer(int jid) { _GLFWjoystick* js; assert(jid >= GLFW_JOYSTICK_1); assert(jid <= GLFW_JOYSTICK_LAST); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); js = _glfw.joysticks + jid; if (!js->present) return NULL; return js->userPointer; } GLFWAPI GLFWjoystickfun glfwSetJoystickCallback(GLFWjoystickfun cbfun) { _GLFW_REQUIRE_INIT_OR_RETURN(NULL); _GLFW_SWAP_POINTERS(_glfw.callbacks.joystick, cbfun); return cbfun; } GLFWAPI int glfwUpdateGamepadMappings(const char* string) { int jid; const char* c = string; assert(string != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE); while (*c) { if ((*c >= '0' && *c <= '9') || (*c >= 'a' && *c <= 'f') || (*c >= 'A' && *c <= 'F')) { char line[1024]; const size_t length = strcspn(c, "\r\n"); if (length < sizeof(line)) { _GLFWmapping mapping = {{0}}; memcpy(line, c, length); line[length] = '\0'; if (parseMapping(&mapping, line)) { _GLFWmapping* previous = findMapping(mapping.guid); if (previous) *previous = mapping; else { _glfw.mappingCount++; _glfw.mappings = realloc(_glfw.mappings, sizeof(_GLFWmapping) * _glfw.mappingCount); _glfw.mappings[_glfw.mappingCount - 1] = mapping; } } } c += length; } else { c += strcspn(c, "\r\n"); c += strspn(c, "\r\n"); } } for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) { _GLFWjoystick* js = _glfw.joysticks + jid; if (js->present) js->mapping = findValidMapping(js); } return GLFW_TRUE; } GLFWAPI int glfwJoystickIsGamepad(int jid) { _GLFWjoystick* js; assert(jid >= GLFW_JOYSTICK_1); assert(jid <= GLFW_JOYSTICK_LAST); _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE); if (jid < 0 || jid > GLFW_JOYSTICK_LAST) { _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); return GLFW_FALSE; } js = _glfw.joysticks + jid; if (!js->present) return GLFW_FALSE; if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE)) return GLFW_FALSE; return js->mapping != NULL; } GLFWAPI const char* glfwGetGamepadName(int jid) { _GLFWjoystick* js; assert(jid >= GLFW_JOYSTICK_1); assert(jid <= GLFW_JOYSTICK_LAST); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); if (jid < 0 || jid > GLFW_JOYSTICK_LAST) { _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); return NULL; } js = _glfw.joysticks + jid; if (!js->present) return NULL; if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE)) return NULL; if (!js->mapping) return NULL; return js->mapping->name; } GLFWAPI int glfwGetGamepadState(int jid, GLFWgamepadstate* state) { int i; _GLFWjoystick* js; assert(jid >= GLFW_JOYSTICK_1); assert(jid <= GLFW_JOYSTICK_LAST); assert(state != NULL); memset(state, 0, sizeof(GLFWgamepadstate)); _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE); if (jid < 0 || jid > GLFW_JOYSTICK_LAST) { _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); return GLFW_FALSE; } js = _glfw.joysticks + jid; if (!js->present) return GLFW_FALSE; if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_ALL)) return GLFW_FALSE; if (!js->mapping) return GLFW_FALSE; for (i = 0; i <= GLFW_GAMEPAD_BUTTON_LAST; i++) { const _GLFWmapelement* e = js->mapping->buttons + i; if (e->type == _GLFW_JOYSTICK_AXIS) { const float value = js->axes[e->index] * e->axisScale + e->axisOffset; // HACK: This should be baked into the value transform // TODO: Bake into transform when implementing output modifiers if (e->axisOffset < 0 || (e->axisOffset == 0 && e->axisScale > 0)) { if (value >= 0.f) state->buttons[i] = GLFW_PRESS; } else { if (value <= 0.f) state->buttons[i] = GLFW_PRESS; } } else if (e->type == _GLFW_JOYSTICK_HATBIT) { const unsigned int hat = e->index >> 4; const unsigned int bit = e->index & 0xf; if (js->hats[hat] & bit) state->buttons[i] = GLFW_PRESS; } else if (e->type == _GLFW_JOYSTICK_BUTTON) state->buttons[i] = js->buttons[e->index]; } for (i = 0; i <= GLFW_GAMEPAD_AXIS_LAST; i++) { const _GLFWmapelement* e = js->mapping->axes + i; if (e->type == _GLFW_JOYSTICK_AXIS) { const float value = js->axes[e->index] * e->axisScale + e->axisOffset; state->axes[i] = _glfw_fminf(_glfw_fmaxf(value, -1.f), 1.f); } else if (e->type == _GLFW_JOYSTICK_HATBIT) { const unsigned int hat = e->index >> 4; const unsigned int bit = e->index & 0xf; if (js->hats[hat] & bit) state->axes[i] = 1.f; else state->axes[i] = -1.f; } else if (e->type == _GLFW_JOYSTICK_BUTTON) state->axes[i] = js->buttons[e->index] * 2.f - 1.f; } return GLFW_TRUE; } GLFWAPI void glfwSetClipboardString(GLFWwindow* handle, const char* string) { assert(string != NULL); _GLFW_REQUIRE_INIT(); _glfwPlatformSetClipboardString(string); } GLFWAPI const char* glfwGetClipboardString(GLFWwindow* handle) { _GLFW_REQUIRE_INIT_OR_RETURN(NULL); return _glfwPlatformGetClipboardString(); } GLFWAPI double glfwGetTime(void) { _GLFW_REQUIRE_INIT_OR_RETURN(0.0); return (double) (_glfwPlatformGetTimerValue() - _glfw.timer.offset) / _glfwPlatformGetTimerFrequency(); } GLFWAPI void glfwSetTime(double time) { _GLFW_REQUIRE_INIT(); if (time != time || time < 0.0 || time > 18446744073.0) { _glfwInputError(GLFW_INVALID_VALUE, "Invalid time %f", time); return; } _glfw.timer.offset = _glfwPlatformGetTimerValue() - (uint64_t) (time * _glfwPlatformGetTimerFrequency()); } GLFWAPI uint64_t glfwGetTimerValue(void) { _GLFW_REQUIRE_INIT_OR_RETURN(0); return _glfwPlatformGetTimerValue(); } GLFWAPI uint64_t glfwGetTimerFrequency(void) { _GLFW_REQUIRE_INIT_OR_RETURN(0); return _glfwPlatformGetTimerFrequency(); } #endif #ifndef HEADER_GUARD_MONITOR_C #define HEADER_GUARD_MONITOR_C //======================================================================== // GLFW 3.3.7 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2019 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== // Please use C89 style variable declarations in this file because VS 2010 //======================================================================== #include #include #include #include #include #include // Lexically compare video modes, used by qsort // static int compareVideoModes(const void* fp, const void* sp) { const GLFWvidmode* fm = fp; const GLFWvidmode* sm = sp; const int fbpp = fm->redBits + fm->greenBits + fm->blueBits; const int sbpp = sm->redBits + sm->greenBits + sm->blueBits; const int farea = fm->width * fm->height; const int sarea = sm->width * sm->height; // First sort on color bits per pixel if (fbpp != sbpp) return fbpp - sbpp; // Then sort on screen area if (farea != sarea) return farea - sarea; // Then sort on width if (fm->width != sm->width) return fm->width - sm->width; // Lastly sort on refresh rate return fm->refreshRate - sm->refreshRate; } // Retrieves the available modes for the specified monitor // static GLFWbool refreshVideoModes(_GLFWmonitor* monitor) { int modeCount; GLFWvidmode* modes; if (monitor->modes) return GLFW_TRUE; modes = _glfwPlatformGetVideoModes(monitor, &modeCount); if (!modes) return GLFW_FALSE; qsort(modes, modeCount, sizeof(GLFWvidmode), compareVideoModes); free(monitor->modes); monitor->modes = modes; monitor->modeCount = modeCount; return GLFW_TRUE; } ////////////////////////////////////////////////////////////////////////// ////// GLFW event API ////// ////////////////////////////////////////////////////////////////////////// // Notifies shared code of a monitor connection or disconnection // void _glfwInputMonitor(_GLFWmonitor* monitor, int action, int placement) { if (action == GLFW_CONNECTED) { _glfw.monitorCount++; _glfw.monitors = realloc(_glfw.monitors, sizeof(_GLFWmonitor*) * _glfw.monitorCount); if (placement == _GLFW_INSERT_FIRST) { memmove(_glfw.monitors + 1, _glfw.monitors, ((size_t) _glfw.monitorCount - 1) * sizeof(_GLFWmonitor*)); _glfw.monitors[0] = monitor; } else _glfw.monitors[_glfw.monitorCount - 1] = monitor; } else if (action == GLFW_DISCONNECTED) { int i; _GLFWwindow* window; for (window = _glfw.windowListHead; window; window = window->next) { if (window->monitor == monitor) { int width, height, xoff, yoff; _glfwPlatformGetWindowSize(window, &width, &height); _glfwPlatformSetWindowMonitor(window, NULL, 0, 0, width, height, 0); _glfwPlatformGetWindowFrameSize(window, &xoff, &yoff, NULL, NULL); _glfwPlatformSetWindowPos(window, xoff, yoff); } } for (i = 0; i < _glfw.monitorCount; i++) { if (_glfw.monitors[i] == monitor) { _glfw.monitorCount--; memmove(_glfw.monitors + i, _glfw.monitors + i + 1, ((size_t) _glfw.monitorCount - i) * sizeof(_GLFWmonitor*)); break; } } } if (_glfw.callbacks.monitor) _glfw.callbacks.monitor((GLFWmonitor*) monitor, action); if (action == GLFW_DISCONNECTED) _glfwFreeMonitor(monitor); } // Notifies shared code that a full screen window has acquired or released // a monitor // void _glfwInputMonitorWindow(_GLFWmonitor* monitor, _GLFWwindow* window) { monitor->window = window; } ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// // Allocates and returns a monitor object with the specified name and dimensions // _GLFWmonitor* _glfwAllocMonitor(const char* name, int widthMM, int heightMM) { _GLFWmonitor* monitor = calloc(1, sizeof(_GLFWmonitor)); monitor->widthMM = widthMM; monitor->heightMM = heightMM; strncpy(monitor->name, name, sizeof(monitor->name) - 1); return monitor; } // Frees a monitor object and any data associated with it // void _glfwFreeMonitor(_GLFWmonitor* monitor) { if (monitor == NULL) return; _glfwPlatformFreeMonitor(monitor); _glfwFreeGammaArrays(&monitor->originalRamp); _glfwFreeGammaArrays(&monitor->currentRamp); free(monitor->modes); free(monitor); } // Allocates red, green and blue value arrays of the specified size // void _glfwAllocGammaArrays(GLFWgammaramp* ramp, unsigned int size) { ramp->red = calloc(size, sizeof(unsigned short)); ramp->green = calloc(size, sizeof(unsigned short)); ramp->blue = calloc(size, sizeof(unsigned short)); ramp->size = size; } // Frees the red, green and blue value arrays and clears the struct // void _glfwFreeGammaArrays(GLFWgammaramp* ramp) { free(ramp->red); free(ramp->green); free(ramp->blue); memset(ramp, 0, sizeof(GLFWgammaramp)); } // Chooses the video mode most closely matching the desired one // const GLFWvidmode* _glfwChooseVideoMode(_GLFWmonitor* monitor, const GLFWvidmode* desired) { int i; unsigned int sizeDiff, leastSizeDiff = UINT_MAX; unsigned int rateDiff, leastRateDiff = UINT_MAX; unsigned int colorDiff, leastColorDiff = UINT_MAX; const GLFWvidmode* current; const GLFWvidmode* closest = NULL; if (!refreshVideoModes(monitor)) return NULL; for (i = 0; i < monitor->modeCount; i++) { current = monitor->modes + i; colorDiff = 0; if (desired->redBits != GLFW_DONT_CARE) colorDiff += abs(current->redBits - desired->redBits); if (desired->greenBits != GLFW_DONT_CARE) colorDiff += abs(current->greenBits - desired->greenBits); if (desired->blueBits != GLFW_DONT_CARE) colorDiff += abs(current->blueBits - desired->blueBits); sizeDiff = abs((current->width - desired->width) * (current->width - desired->width) + (current->height - desired->height) * (current->height - desired->height)); if (desired->refreshRate != GLFW_DONT_CARE) rateDiff = abs(current->refreshRate - desired->refreshRate); else rateDiff = UINT_MAX - current->refreshRate; if ((colorDiff < leastColorDiff) || (colorDiff == leastColorDiff && sizeDiff < leastSizeDiff) || (colorDiff == leastColorDiff && sizeDiff == leastSizeDiff && rateDiff < leastRateDiff)) { closest = current; leastSizeDiff = sizeDiff; leastRateDiff = rateDiff; leastColorDiff = colorDiff; } } return closest; } // Performs lexical comparison between two @ref GLFWvidmode structures // int _glfwCompareVideoModes(const GLFWvidmode* fm, const GLFWvidmode* sm) { return compareVideoModes(fm, sm); } // Splits a color depth into red, green and blue bit depths // void _glfwSplitBPP(int bpp, int* red, int* green, int* blue) { int delta; // We assume that by 32 the user really meant 24 if (bpp == 32) bpp = 24; // Convert "bits per pixel" to red, green & blue sizes *red = *green = *blue = bpp / 3; delta = bpp - (*red * 3); if (delta >= 1) *green = *green + 1; if (delta == 2) *red = *red + 1; } ////////////////////////////////////////////////////////////////////////// ////// GLFW public API ////// ////////////////////////////////////////////////////////////////////////// GLFWAPI GLFWmonitor** glfwGetMonitors(int* count) { assert(count != NULL); *count = 0; _GLFW_REQUIRE_INIT_OR_RETURN(NULL); *count = _glfw.monitorCount; return (GLFWmonitor**) _glfw.monitors; } GLFWAPI GLFWmonitor* glfwGetPrimaryMonitor(void) { _GLFW_REQUIRE_INIT_OR_RETURN(NULL); if (!_glfw.monitorCount) return NULL; return (GLFWmonitor*) _glfw.monitors[0]; } GLFWAPI void glfwGetMonitorPos(GLFWmonitor* handle, int* xpos, int* ypos) { _GLFWmonitor* monitor = (_GLFWmonitor*) handle; assert(monitor != NULL); if (xpos) *xpos = 0; if (ypos) *ypos = 0; _GLFW_REQUIRE_INIT(); _glfwPlatformGetMonitorPos(monitor, xpos, ypos); } GLFWAPI void glfwGetMonitorWorkarea(GLFWmonitor* handle, int* xpos, int* ypos, int* width, int* height) { _GLFWmonitor* monitor = (_GLFWmonitor*) handle; assert(monitor != NULL); if (xpos) *xpos = 0; if (ypos) *ypos = 0; if (width) *width = 0; if (height) *height = 0; _GLFW_REQUIRE_INIT(); _glfwPlatformGetMonitorWorkarea(monitor, xpos, ypos, width, height); } GLFWAPI void glfwGetMonitorPhysicalSize(GLFWmonitor* handle, int* widthMM, int* heightMM) { _GLFWmonitor* monitor = (_GLFWmonitor*) handle; assert(monitor != NULL); if (widthMM) *widthMM = 0; if (heightMM) *heightMM = 0; _GLFW_REQUIRE_INIT(); if (widthMM) *widthMM = monitor->widthMM; if (heightMM) *heightMM = monitor->heightMM; } GLFWAPI void glfwGetMonitorContentScale(GLFWmonitor* handle, float* xscale, float* yscale) { _GLFWmonitor* monitor = (_GLFWmonitor*) handle; assert(monitor != NULL); if (xscale) *xscale = 0.f; if (yscale) *yscale = 0.f; _GLFW_REQUIRE_INIT(); _glfwPlatformGetMonitorContentScale(monitor, xscale, yscale); } GLFWAPI const char* glfwGetMonitorName(GLFWmonitor* handle) { _GLFWmonitor* monitor = (_GLFWmonitor*) handle; assert(monitor != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); return monitor->name; } GLFWAPI void glfwSetMonitorUserPointer(GLFWmonitor* handle, void* pointer) { _GLFWmonitor* monitor = (_GLFWmonitor*) handle; assert(monitor != NULL); _GLFW_REQUIRE_INIT(); monitor->userPointer = pointer; } GLFWAPI void* glfwGetMonitorUserPointer(GLFWmonitor* handle) { _GLFWmonitor* monitor = (_GLFWmonitor*) handle; assert(monitor != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); return monitor->userPointer; } GLFWAPI GLFWmonitorfun glfwSetMonitorCallback(GLFWmonitorfun cbfun) { _GLFW_REQUIRE_INIT_OR_RETURN(NULL); _GLFW_SWAP_POINTERS(_glfw.callbacks.monitor, cbfun); return cbfun; } GLFWAPI const GLFWvidmode* glfwGetVideoModes(GLFWmonitor* handle, int* count) { _GLFWmonitor* monitor = (_GLFWmonitor*) handle; assert(monitor != NULL); assert(count != NULL); *count = 0; _GLFW_REQUIRE_INIT_OR_RETURN(NULL); if (!refreshVideoModes(monitor)) return NULL; *count = monitor->modeCount; return monitor->modes; } GLFWAPI const GLFWvidmode* glfwGetVideoMode(GLFWmonitor* handle) { _GLFWmonitor* monitor = (_GLFWmonitor*) handle; assert(monitor != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); _glfwPlatformGetVideoMode(monitor, &monitor->currentMode); return &monitor->currentMode; } GLFWAPI void glfwSetGamma(GLFWmonitor* handle, float gamma) { unsigned int i; unsigned short* values; GLFWgammaramp ramp; const GLFWgammaramp* original; assert(handle != NULL); assert(gamma > 0.f); assert(gamma <= FLT_MAX); _GLFW_REQUIRE_INIT(); if (gamma != gamma || gamma <= 0.f || gamma > FLT_MAX) { _glfwInputError(GLFW_INVALID_VALUE, "Invalid gamma value %f", gamma); return; } original = glfwGetGammaRamp(handle); if (!original) return; values = calloc(original->size, sizeof(unsigned short)); for (i = 0; i < original->size; i++) { float value; // Calculate intensity value = i / (float) (original->size - 1); // Apply gamma curve value = powf(value, 1.f / gamma) * 65535.f + 0.5f; // Clamp to value range value = _glfw_fminf(value, 65535.f); values[i] = (unsigned short) value; } ramp.red = values; ramp.green = values; ramp.blue = values; ramp.size = original->size; glfwSetGammaRamp(handle, &ramp); free(values); } GLFWAPI const GLFWgammaramp* glfwGetGammaRamp(GLFWmonitor* handle) { _GLFWmonitor* monitor = (_GLFWmonitor*) handle; assert(monitor != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); _glfwFreeGammaArrays(&monitor->currentRamp); if (!_glfwPlatformGetGammaRamp(monitor, &monitor->currentRamp)) return NULL; return &monitor->currentRamp; } GLFWAPI void glfwSetGammaRamp(GLFWmonitor* handle, const GLFWgammaramp* ramp) { _GLFWmonitor* monitor = (_GLFWmonitor*) handle; assert(monitor != NULL); assert(ramp != NULL); assert(ramp->size > 0); assert(ramp->red != NULL); assert(ramp->green != NULL); assert(ramp->blue != NULL); if (ramp->size <= 0) { _glfwInputError(GLFW_INVALID_VALUE, "Invalid gamma ramp size %i", ramp->size); return; } _GLFW_REQUIRE_INIT(); if (!monitor->originalRamp.size) { if (!_glfwPlatformGetGammaRamp(monitor, &monitor->originalRamp)) return; } _glfwPlatformSetGammaRamp(monitor, ramp); } #endif #ifndef HEADER_GUARD_VULKAN_C #define HEADER_GUARD_VULKAN_C //======================================================================== // GLFW 3.3.7 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2018 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== // Please use C89 style variable declarations in this file because VS 2010 //======================================================================== #include #include #include #define _GLFW_FIND_LOADER 1 #define _GLFW_REQUIRE_LOADER 2 ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// GLFWbool _glfwInitVulkan(int mode) { VkResult err; VkExtensionProperties* ep; uint32_t i, count; if (_glfw.vk.available) return GLFW_TRUE; #if !defined(_GLFW_VULKAN_STATIC) #if defined(_GLFW_VULKAN_LIBRARY) _glfw.vk.handle = _glfw_dlopen(_GLFW_VULKAN_LIBRARY); #elif defined(_GLFW_WIN32) _glfw.vk.handle = _glfw_dlopen("vulkan-1.dll"); #elif defined(_GLFW_COCOA) _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 if (!_glfw.vk.handle) { if (mode == _GLFW_REQUIRE_LOADER) _glfwInputError(GLFW_API_UNAVAILABLE, "Vulkan: Loader not found"); return GLFW_FALSE; } _glfw.vk.GetInstanceProcAddr = (PFN_vkGetInstanceProcAddr) _glfw_dlsym(_glfw.vk.handle, "vkGetInstanceProcAddr"); if (!_glfw.vk.GetInstanceProcAddr) { _glfwInputError(GLFW_API_UNAVAILABLE, "Vulkan: Loader does not export vkGetInstanceProcAddr"); _glfwTerminateVulkan(); return GLFW_FALSE; } _glfw.vk.EnumerateInstanceExtensionProperties = (PFN_vkEnumerateInstanceExtensionProperties) vkGetInstanceProcAddr(NULL, "vkEnumerateInstanceExtensionProperties"); if (!_glfw.vk.EnumerateInstanceExtensionProperties) { _glfwInputError(GLFW_API_UNAVAILABLE, "Vulkan: Failed to retrieve vkEnumerateInstanceExtensionProperties"); _glfwTerminateVulkan(); return GLFW_FALSE; } #endif // _GLFW_VULKAN_STATIC err = vkEnumerateInstanceExtensionProperties(NULL, &count, NULL); if (err) { // NOTE: This happens on systems with a loader but without any Vulkan ICD if (mode == _GLFW_REQUIRE_LOADER) { _glfwInputError(GLFW_API_UNAVAILABLE, "Vulkan: Failed to query instance extension count: %s", _glfwGetVulkanResultString(err)); } _glfwTerminateVulkan(); return GLFW_FALSE; } ep = calloc(count, sizeof(VkExtensionProperties)); err = vkEnumerateInstanceExtensionProperties(NULL, &count, ep); if (err) { _glfwInputError(GLFW_API_UNAVAILABLE, "Vulkan: Failed to query instance extensions: %s", _glfwGetVulkanResultString(err)); free(ep); _glfwTerminateVulkan(); return GLFW_FALSE; } for (i = 0; i < count; i++) { if (strcmp(ep[i].extensionName, "VK_KHR_surface") == 0) _glfw.vk.KHR_surface = GLFW_TRUE; #if defined(_GLFW_WIN32) else if (strcmp(ep[i].extensionName, "VK_KHR_win32_surface") == 0) _glfw.vk.KHR_win32_surface = GLFW_TRUE; #elif defined(_GLFW_COCOA) else if (strcmp(ep[i].extensionName, "VK_MVK_macos_surface") == 0) _glfw.vk.MVK_macos_surface = GLFW_TRUE; else if (strcmp(ep[i].extensionName, "VK_EXT_metal_surface") == 0) _glfw.vk.EXT_metal_surface = GLFW_TRUE; #elif defined(_GLFW_X11) else if (strcmp(ep[i].extensionName, "VK_KHR_xlib_surface") == 0) _glfw.vk.KHR_xlib_surface = GLFW_TRUE; else if (strcmp(ep[i].extensionName, "VK_KHR_xcb_surface") == 0) _glfw.vk.KHR_xcb_surface = GLFW_TRUE; #elif defined(_GLFW_WAYLAND) else if (strcmp(ep[i].extensionName, "VK_KHR_wayland_surface") == 0) _glfw.vk.KHR_wayland_surface = GLFW_TRUE; #endif } free(ep); _glfw.vk.available = GLFW_TRUE; _glfwPlatformGetRequiredInstanceExtensions(_glfw.vk.extensions); return GLFW_TRUE; } void _glfwTerminateVulkan(void) { #if !defined(_GLFW_VULKAN_STATIC) if (_glfw.vk.handle) _glfw_dlclose(_glfw.vk.handle); #endif } const char* _glfwGetVulkanResultString(VkResult result) { switch (result) { case VK_SUCCESS: return "Success"; case VK_NOT_READY: return "A fence or query has not yet completed"; case VK_TIMEOUT: return "A wait operation has not completed in the specified time"; case VK_EVENT_SET: return "An event is signaled"; case VK_EVENT_RESET: return "An event is unsignaled"; case VK_INCOMPLETE: return "A return array was too small for the result"; case VK_ERROR_OUT_OF_HOST_MEMORY: return "A host memory allocation has failed"; case VK_ERROR_OUT_OF_DEVICE_MEMORY: return "A device memory allocation has failed"; case VK_ERROR_INITIALIZATION_FAILED: return "Initialization of an object could not be completed for implementation-specific reasons"; case VK_ERROR_DEVICE_LOST: return "The logical or physical device has been lost"; case VK_ERROR_MEMORY_MAP_FAILED: return "Mapping of a memory object has failed"; case VK_ERROR_LAYER_NOT_PRESENT: return "A requested layer is not present or could not be loaded"; case VK_ERROR_EXTENSION_NOT_PRESENT: return "A requested extension is not supported"; case VK_ERROR_FEATURE_NOT_PRESENT: return "A requested feature is not supported"; case VK_ERROR_INCOMPATIBLE_DRIVER: return "The requested version of Vulkan is not supported by the driver or is otherwise incompatible"; case VK_ERROR_TOO_MANY_OBJECTS: return "Too many objects of the type have already been created"; case VK_ERROR_FORMAT_NOT_SUPPORTED: return "A requested format is not supported on this device"; case VK_ERROR_SURFACE_LOST_KHR: return "A surface is no longer available"; case VK_SUBOPTIMAL_KHR: return "A swapchain no longer matches the surface properties exactly, but can still be used"; case VK_ERROR_OUT_OF_DATE_KHR: return "A surface has changed in such a way that it is no longer compatible with the swapchain"; case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR: return "The display used by a swapchain does not use the same presentable image layout"; case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: return "The requested window is already connected to a VkSurfaceKHR, or to some other non-Vulkan API"; case VK_ERROR_VALIDATION_FAILED_EXT: return "A validation layer found an error"; default: return "ERROR: UNKNOWN VULKAN ERROR"; } } ////////////////////////////////////////////////////////////////////////// ////// GLFW public API ////// ////////////////////////////////////////////////////////////////////////// GLFWAPI int glfwVulkanSupported(void) { _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE); return _glfwInitVulkan(_GLFW_FIND_LOADER); } GLFWAPI const char** glfwGetRequiredInstanceExtensions(uint32_t* count) { assert(count != NULL); *count = 0; _GLFW_REQUIRE_INIT_OR_RETURN(NULL); if (!_glfwInitVulkan(_GLFW_REQUIRE_LOADER)) return NULL; if (!_glfw.vk.extensions[0]) return NULL; *count = 2; return (const char**) _glfw.vk.extensions; } GLFWAPI GLFWvkproc glfwGetInstanceProcAddress(VkInstance instance, const char* procname) { GLFWvkproc proc; assert(procname != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); if (!_glfwInitVulkan(_GLFW_REQUIRE_LOADER)) return NULL; proc = (GLFWvkproc) vkGetInstanceProcAddr(instance, procname); #if defined(_GLFW_VULKAN_STATIC) if (!proc) { if (strcmp(procname, "vkGetInstanceProcAddr") == 0) return (GLFWvkproc) vkGetInstanceProcAddr; } #else if (!proc) proc = (GLFWvkproc) _glfw_dlsym(_glfw.vk.handle, procname); #endif return proc; } GLFWAPI int glfwGetPhysicalDevicePresentationSupport(VkInstance instance, VkPhysicalDevice device, uint32_t queuefamily) { assert(instance != VK_NULL_HANDLE); assert(device != VK_NULL_HANDLE); _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE); if (!_glfwInitVulkan(_GLFW_REQUIRE_LOADER)) return GLFW_FALSE; if (!_glfw.vk.extensions[0]) { _glfwInputError(GLFW_API_UNAVAILABLE, "Vulkan: Window surface creation extensions not found"); return GLFW_FALSE; } return _glfwPlatformGetPhysicalDevicePresentationSupport(instance, device, queuefamily); } GLFWAPI VkResult glfwCreateWindowSurface(VkInstance instance, GLFWwindow* handle, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface) { _GLFWwindow* window = (_GLFWwindow*) handle; assert(instance != VK_NULL_HANDLE); assert(window != NULL); assert(surface != NULL); *surface = VK_NULL_HANDLE; _GLFW_REQUIRE_INIT_OR_RETURN(VK_ERROR_INITIALIZATION_FAILED); if (!_glfwInitVulkan(_GLFW_REQUIRE_LOADER)) return VK_ERROR_INITIALIZATION_FAILED; if (!_glfw.vk.extensions[0]) { _glfwInputError(GLFW_API_UNAVAILABLE, "Vulkan: Window surface creation extensions not found"); return VK_ERROR_EXTENSION_NOT_PRESENT; } if (window->context.client != GLFW_NO_API) { _glfwInputError(GLFW_INVALID_VALUE, "Vulkan: Window surface creation requires the window to have the client API set to GLFW_NO_API"); return VK_ERROR_NATIVE_WINDOW_IN_USE_KHR; } return _glfwPlatformCreateWindowSurface(instance, window, allocator, surface); } #endif #ifndef HEADER_GUARD_WINDOW_C #define HEADER_GUARD_WINDOW_C //======================================================================== // GLFW 3.3.7 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2019 Camilla Löwy // Copyright (c) 2012 Torsten Walluhn // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== // Please use C89 style variable declarations in this file because VS 2010 //======================================================================== #include #include #include #include ////////////////////////////////////////////////////////////////////////// ////// GLFW event API ////// ////////////////////////////////////////////////////////////////////////// // Notifies shared code that a window has lost or received input focus // void _glfwInputWindowFocus(_GLFWwindow* window, GLFWbool focused) { if (window->callbacks.focus) window->callbacks.focus((GLFWwindow*) window, focused); if (!focused) { int key, button; for (key = 0; key <= GLFW_KEY_LAST; key++) { if (window->keys[key] == GLFW_PRESS) { const int scancode = _glfwPlatformGetKeyScancode(key); _glfwInputKey(window, key, scancode, GLFW_RELEASE, 0); } } for (button = 0; button <= GLFW_MOUSE_BUTTON_LAST; button++) { if (window->mouseButtons[button] == GLFW_PRESS) _glfwInputMouseClick(window, button, GLFW_RELEASE, 0); } } } // Notifies shared code that a window has moved // The position is specified in content area relative screen coordinates // void _glfwInputWindowPos(_GLFWwindow* window, int x, int y) { if (window->callbacks.pos) window->callbacks.pos((GLFWwindow*) window, x, y); } // Notifies shared code that a window has been resized // The size is specified in screen coordinates // void _glfwInputWindowSize(_GLFWwindow* window, int width, int height) { if (window->callbacks.size) window->callbacks.size((GLFWwindow*) window, width, height); } // Notifies shared code that a window has been iconified or restored // void _glfwInputWindowIconify(_GLFWwindow* window, GLFWbool iconified) { if (window->callbacks.iconify) window->callbacks.iconify((GLFWwindow*) window, iconified); } // Notifies shared code that a window has been maximized or restored // void _glfwInputWindowMaximize(_GLFWwindow* window, GLFWbool maximized) { if (window->callbacks.maximize) window->callbacks.maximize((GLFWwindow*) window, maximized); } // Notifies shared code that a window framebuffer has been resized // The size is specified in pixels // void _glfwInputFramebufferSize(_GLFWwindow* window, int width, int height) { if (window->callbacks.fbsize) window->callbacks.fbsize((GLFWwindow*) window, width, height); } // Notifies shared code that a window content scale has changed // The scale is specified as the ratio between the current and default DPI // void _glfwInputWindowContentScale(_GLFWwindow* window, float xscale, float yscale) { if (window->callbacks.scale) window->callbacks.scale((GLFWwindow*) window, xscale, yscale); } // Notifies shared code that the window contents needs updating // void _glfwInputWindowDamage(_GLFWwindow* window) { if (window->callbacks.refresh) window->callbacks.refresh((GLFWwindow*) window); } // Notifies shared code that the user wishes to close a window // void _glfwInputWindowCloseRequest(_GLFWwindow* window) { window->shouldClose = GLFW_TRUE; if (window->callbacks.close) window->callbacks.close((GLFWwindow*) window); } // Notifies shared code that a window has changed its desired monitor // void _glfwInputWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor) { window->monitor = monitor; } ////////////////////////////////////////////////////////////////////////// ////// GLFW public API ////// ////////////////////////////////////////////////////////////////////////// GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, const char* title, GLFWmonitor* monitor, GLFWwindow* share) { _GLFWfbconfig fbconfig; _GLFWctxconfig ctxconfig; _GLFWwndconfig wndconfig; _GLFWwindow* window; assert(title != NULL); assert(width >= 0); assert(height >= 0); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); if (width <= 0 || height <= 0) { _glfwInputError(GLFW_INVALID_VALUE, "Invalid window size %ix%i", width, height); return NULL; } fbconfig = _glfw.hints.framebuffer; ctxconfig = _glfw.hints.context; wndconfig = _glfw.hints.window; wndconfig.width = width; wndconfig.height = height; wndconfig.title = title; ctxconfig.share = (_GLFWwindow*) share; if (!_glfwIsValidContextConfig(&ctxconfig)) return NULL; window = calloc(1, sizeof(_GLFWwindow)); window->next = _glfw.windowListHead; _glfw.windowListHead = window; window->videoMode.width = width; window->videoMode.height = height; window->videoMode.redBits = fbconfig.redBits; window->videoMode.greenBits = fbconfig.greenBits; window->videoMode.blueBits = fbconfig.blueBits; window->videoMode.refreshRate = _glfw.hints.refreshRate; window->monitor = (_GLFWmonitor*) monitor; window->resizable = wndconfig.resizable; window->decorated = wndconfig.decorated; window->autoIconify = wndconfig.autoIconify; window->floating = wndconfig.floating; 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; window->maxheight = GLFW_DONT_CARE; window->numer = GLFW_DONT_CARE; window->denom = GLFW_DONT_CARE; // Open the actual window and create its context if (!_glfwPlatformCreateWindow(window, &wndconfig, &ctxconfig, &fbconfig)) { glfwDestroyWindow((GLFWwindow*) window); 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; } void glfwDefaultWindowHints(void) { _GLFW_REQUIRE_INIT(); // The default is OpenGL with minimum version 1.0 memset(&_glfw.hints.context, 0, sizeof(_glfw.hints.context)); _glfw.hints.context.client = GLFW_OPENGL_API; _glfw.hints.context.source = GLFW_NATIVE_CONTEXT_API; _glfw.hints.context.major = 1; _glfw.hints.context.minor = 0; // The default is a focused, visible, resizable window with decorations memset(&_glfw.hints.window, 0, sizeof(_glfw.hints.window)); _glfw.hints.window.resizable = GLFW_TRUE; _glfw.hints.window.visible = GLFW_TRUE; _glfw.hints.window.decorated = GLFW_TRUE; _glfw.hints.window.focused = GLFW_TRUE; _glfw.hints.window.autoIconify = GLFW_TRUE; _glfw.hints.window.centerCursor = GLFW_TRUE; _glfw.hints.window.focusOnShow = GLFW_TRUE; // The default is 24 bits of color, 24 bits of depth and 8 bits of stencil, // double buffered memset(&_glfw.hints.framebuffer, 0, sizeof(_glfw.hints.framebuffer)); _glfw.hints.framebuffer.redBits = 8; _glfw.hints.framebuffer.greenBits = 8; _glfw.hints.framebuffer.blueBits = 8; _glfw.hints.framebuffer.alphaBits = 8; _glfw.hints.framebuffer.depthBits = 24; _glfw.hints.framebuffer.stencilBits = 8; _glfw.hints.framebuffer.doublebuffer = GLFW_TRUE; // The default is to select the highest available refresh rate _glfw.hints.refreshRate = GLFW_DONT_CARE; // The default is to use full Retina resolution framebuffers _glfw.hints.window.ns.retina = GLFW_TRUE; } GLFWAPI void glfwWindowHint(int hint, int value) { _GLFW_REQUIRE_INIT(); switch (hint) { case GLFW_RED_BITS: _glfw.hints.framebuffer.redBits = value; return; case GLFW_GREEN_BITS: _glfw.hints.framebuffer.greenBits = value; return; case GLFW_BLUE_BITS: _glfw.hints.framebuffer.blueBits = value; return; case GLFW_ALPHA_BITS: _glfw.hints.framebuffer.alphaBits = value; return; case GLFW_DEPTH_BITS: _glfw.hints.framebuffer.depthBits = value; return; case GLFW_STENCIL_BITS: _glfw.hints.framebuffer.stencilBits = value; return; case GLFW_ACCUM_RED_BITS: _glfw.hints.framebuffer.accumRedBits = value; return; case GLFW_ACCUM_GREEN_BITS: _glfw.hints.framebuffer.accumGreenBits = value; return; case GLFW_ACCUM_BLUE_BITS: _glfw.hints.framebuffer.accumBlueBits = value; return; case GLFW_ACCUM_ALPHA_BITS: _glfw.hints.framebuffer.accumAlphaBits = value; return; case GLFW_AUX_BUFFERS: _glfw.hints.framebuffer.auxBuffers = value; return; case GLFW_STEREO: _glfw.hints.framebuffer.stereo = value ? GLFW_TRUE : GLFW_FALSE; return; case GLFW_DOUBLEBUFFER: _glfw.hints.framebuffer.doublebuffer = value ? GLFW_TRUE : GLFW_FALSE; return; case GLFW_TRANSPARENT_FRAMEBUFFER: _glfw.hints.framebuffer.transparent = value ? GLFW_TRUE : GLFW_FALSE; return; case GLFW_SAMPLES: _glfw.hints.framebuffer.samples = value; return; case GLFW_SRGB_CAPABLE: _glfw.hints.framebuffer.sRGB = value ? GLFW_TRUE : GLFW_FALSE; return; case GLFW_RESIZABLE: _glfw.hints.window.resizable = value ? GLFW_TRUE : GLFW_FALSE; return; case GLFW_DECORATED: _glfw.hints.window.decorated = value ? GLFW_TRUE : GLFW_FALSE; return; case GLFW_FOCUSED: _glfw.hints.window.focused = value ? GLFW_TRUE : GLFW_FALSE; return; case GLFW_AUTO_ICONIFY: _glfw.hints.window.autoIconify = value ? GLFW_TRUE : GLFW_FALSE; return; case GLFW_FLOATING: _glfw.hints.window.floating = value ? GLFW_TRUE : GLFW_FALSE; return; case GLFW_MAXIMIZED: _glfw.hints.window.maximized = value ? GLFW_TRUE : GLFW_FALSE; return; case GLFW_VISIBLE: _glfw.hints.window.visible = value ? GLFW_TRUE : GLFW_FALSE; return; case GLFW_COCOA_RETINA_FRAMEBUFFER: _glfw.hints.window.ns.retina = value ? GLFW_TRUE : GLFW_FALSE; return; case GLFW_COCOA_GRAPHICS_SWITCHING: _glfw.hints.context.nsgl.offline = value ? GLFW_TRUE : GLFW_FALSE; return; case GLFW_SCALE_TO_MONITOR: _glfw.hints.window.scaleToMonitor = value ? GLFW_TRUE : GLFW_FALSE; return; case GLFW_CENTER_CURSOR: _glfw.hints.window.centerCursor = value ? GLFW_TRUE : GLFW_FALSE; return; case GLFW_FOCUS_ON_SHOW: _glfw.hints.window.focusOnShow = value ? GLFW_TRUE : GLFW_FALSE; return; case GLFW_CLIENT_API: _glfw.hints.context.client = value; return; case GLFW_CONTEXT_CREATION_API: _glfw.hints.context.source = value; return; case GLFW_CONTEXT_VERSION_MAJOR: _glfw.hints.context.major = value; return; case GLFW_CONTEXT_VERSION_MINOR: _glfw.hints.context.minor = value; return; case GLFW_CONTEXT_ROBUSTNESS: _glfw.hints.context.robustness = value; return; case GLFW_OPENGL_FORWARD_COMPAT: _glfw.hints.context.forward = value ? GLFW_TRUE : GLFW_FALSE; return; case GLFW_OPENGL_DEBUG_CONTEXT: _glfw.hints.context.debug = value ? GLFW_TRUE : GLFW_FALSE; return; case GLFW_CONTEXT_NO_ERROR: _glfw.hints.context.noerror = value ? GLFW_TRUE : GLFW_FALSE; return; case GLFW_OPENGL_PROFILE: _glfw.hints.context.profile = value; return; case GLFW_CONTEXT_RELEASE_BEHAVIOR: _glfw.hints.context.release = value; return; case GLFW_REFRESH_RATE: _glfw.hints.refreshRate = value; return; } _glfwInputError(GLFW_INVALID_ENUM, "Invalid window hint 0x%08X", hint); } GLFWAPI void glfwWindowHintString(int hint, const char* value) { assert(value != NULL); _GLFW_REQUIRE_INIT(); switch (hint) { case GLFW_COCOA_FRAME_NAME: strncpy(_glfw.hints.window.ns.frameName, value, sizeof(_glfw.hints.window.ns.frameName) - 1); return; case GLFW_X11_CLASS_NAME: strncpy(_glfw.hints.window.x11.className, value, sizeof(_glfw.hints.window.x11.className) - 1); return; case GLFW_X11_INSTANCE_NAME: strncpy(_glfw.hints.window.x11.instanceName, value, sizeof(_glfw.hints.window.x11.instanceName) - 1); return; } _glfwInputError(GLFW_INVALID_ENUM, "Invalid window hint string 0x%08X", hint); } GLFWAPI void glfwDestroyWindow(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; _GLFW_REQUIRE_INIT(); // Allow closing of NULL (to match the behavior of free) if (window == NULL) return; // Clear all callbacks to avoid exposing a half torn-down window object memset(&window->callbacks, 0, sizeof(window->callbacks)); // The window's context must not be current on another thread when the // window is destroyed if (window == _glfwPlatformGetTls(&_glfw.contextSlot)) glfwMakeContextCurrent(NULL); _glfwPlatformDestroyWindow(window); // Unlink window from global linked list { _GLFWwindow** prev = &_glfw.windowListHead; while (*prev != window) prev = &((*prev)->next); *prev = window->next; } free(window); } GLFWAPI int glfwWindowShouldClose(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(0); return window->shouldClose; } GLFWAPI void glfwSetWindowShouldClose(GLFWwindow* handle, int value) { _GLFWwindow* window = (_GLFWwindow*) handle; assert(window != NULL); _GLFW_REQUIRE_INIT(); window->shouldClose = value; } GLFWAPI void glfwSetWindowTitle(GLFWwindow* handle, const char* title) { _GLFWwindow* window = (_GLFWwindow*) handle; assert(window != NULL); assert(title != NULL); _GLFW_REQUIRE_INIT(); _glfwPlatformSetWindowTitle(window, title); } GLFWAPI void glfwSetWindowIcon(GLFWwindow* handle, int count, const GLFWimage* images) { _GLFWwindow* window = (_GLFWwindow*) handle; assert(window != NULL); assert(count >= 0); assert(count == 0 || images != NULL); _GLFW_REQUIRE_INIT(); _glfwPlatformSetWindowIcon(window, count, images); } GLFWAPI void glfwGetWindowPos(GLFWwindow* handle, int* xpos, int* ypos) { _GLFWwindow* window = (_GLFWwindow*) handle; assert(window != NULL); if (xpos) *xpos = 0; if (ypos) *ypos = 0; _GLFW_REQUIRE_INIT(); _glfwPlatformGetWindowPos(window, xpos, ypos); } GLFWAPI void glfwSetWindowPos(GLFWwindow* handle, int xpos, int ypos) { _GLFWwindow* window = (_GLFWwindow*) handle; assert(window != NULL); _GLFW_REQUIRE_INIT(); if (window->monitor) return; _glfwPlatformSetWindowPos(window, xpos, ypos); } GLFWAPI void glfwGetWindowSize(GLFWwindow* handle, int* width, int* height) { _GLFWwindow* window = (_GLFWwindow*) handle; assert(window != NULL); if (width) *width = 0; if (height) *height = 0; _GLFW_REQUIRE_INIT(); _glfwPlatformGetWindowSize(window, width, height); } GLFWAPI void glfwSetWindowSize(GLFWwindow* handle, int width, int height) { _GLFWwindow* window = (_GLFWwindow*) handle; assert(window != NULL); assert(width >= 0); assert(height >= 0); _GLFW_REQUIRE_INIT(); window->videoMode.width = width; window->videoMode.height = height; _glfwPlatformSetWindowSize(window, width, height); } GLFWAPI void glfwSetWindowSizeLimits(GLFWwindow* handle, int minwidth, int minheight, int maxwidth, int maxheight) { _GLFWwindow* window = (_GLFWwindow*) handle; assert(window != NULL); _GLFW_REQUIRE_INIT(); if (minwidth != GLFW_DONT_CARE && minheight != GLFW_DONT_CARE) { if (minwidth < 0 || minheight < 0) { _glfwInputError(GLFW_INVALID_VALUE, "Invalid window minimum size %ix%i", minwidth, minheight); return; } } if (maxwidth != GLFW_DONT_CARE && maxheight != GLFW_DONT_CARE) { if (maxwidth < 0 || maxheight < 0 || maxwidth < minwidth || maxheight < minheight) { _glfwInputError(GLFW_INVALID_VALUE, "Invalid window maximum size %ix%i", maxwidth, maxheight); return; } } window->minwidth = minwidth; window->minheight = minheight; window->maxwidth = maxwidth; window->maxheight = maxheight; if (window->monitor || !window->resizable) return; _glfwPlatformSetWindowSizeLimits(window, minwidth, minheight, maxwidth, maxheight); } GLFWAPI void glfwSetWindowAspectRatio(GLFWwindow* handle, int numer, int denom) { _GLFWwindow* window = (_GLFWwindow*) handle; assert(window != NULL); assert(numer != 0); assert(denom != 0); _GLFW_REQUIRE_INIT(); if (numer != GLFW_DONT_CARE && denom != GLFW_DONT_CARE) { if (numer <= 0 || denom <= 0) { _glfwInputError(GLFW_INVALID_VALUE, "Invalid window aspect ratio %i:%i", numer, denom); return; } } window->numer = numer; window->denom = denom; if (window->monitor || !window->resizable) return; _glfwPlatformSetWindowAspectRatio(window, numer, denom); } GLFWAPI void glfwGetFramebufferSize(GLFWwindow* handle, int* width, int* height) { _GLFWwindow* window = (_GLFWwindow*) handle; assert(window != NULL); if (width) *width = 0; if (height) *height = 0; _GLFW_REQUIRE_INIT(); _glfwPlatformGetFramebufferSize(window, width, height); } GLFWAPI void glfwGetWindowFrameSize(GLFWwindow* handle, int* left, int* top, int* right, int* bottom) { _GLFWwindow* window = (_GLFWwindow*) handle; assert(window != NULL); if (left) *left = 0; if (top) *top = 0; if (right) *right = 0; if (bottom) *bottom = 0; _GLFW_REQUIRE_INIT(); _glfwPlatformGetWindowFrameSize(window, left, top, right, bottom); } GLFWAPI void glfwGetWindowContentScale(GLFWwindow* handle, float* xscale, float* yscale) { _GLFWwindow* window = (_GLFWwindow*) handle; assert(window != NULL); if (xscale) *xscale = 0.f; if (yscale) *yscale = 0.f; _GLFW_REQUIRE_INIT(); _glfwPlatformGetWindowContentScale(window, xscale, yscale); } GLFWAPI float glfwGetWindowOpacity(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(1.f); return _glfwPlatformGetWindowOpacity(window); } GLFWAPI void glfwSetWindowOpacity(GLFWwindow* handle, float opacity) { _GLFWwindow* window = (_GLFWwindow*) handle; assert(window != NULL); assert(opacity == opacity); assert(opacity >= 0.f); assert(opacity <= 1.f); _GLFW_REQUIRE_INIT(); if (opacity != opacity || opacity < 0.f || opacity > 1.f) { _glfwInputError(GLFW_INVALID_VALUE, "Invalid window opacity %f", opacity); return; } _glfwPlatformSetWindowOpacity(window, opacity); } GLFWAPI void glfwIconifyWindow(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; assert(window != NULL); _GLFW_REQUIRE_INIT(); _glfwPlatformIconifyWindow(window); } GLFWAPI void glfwRestoreWindow(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; assert(window != NULL); _GLFW_REQUIRE_INIT(); _glfwPlatformRestoreWindow(window); } GLFWAPI void glfwMaximizeWindow(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; assert(window != NULL); _GLFW_REQUIRE_INIT(); if (window->monitor) return; _glfwPlatformMaximizeWindow(window); } GLFWAPI void glfwShowWindow(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; assert(window != NULL); _GLFW_REQUIRE_INIT(); if (window->monitor) return; _glfwPlatformShowWindow(window); if (window->focusOnShow) _glfwPlatformFocusWindow(window); } GLFWAPI void glfwRequestWindowAttention(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; assert(window != NULL); _GLFW_REQUIRE_INIT(); _glfwPlatformRequestWindowAttention(window); } GLFWAPI void glfwHideWindow(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; assert(window != NULL); _GLFW_REQUIRE_INIT(); if (window->monitor) return; _glfwPlatformHideWindow(window); } GLFWAPI void glfwFocusWindow(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; assert(window != NULL); _GLFW_REQUIRE_INIT(); _glfwPlatformFocusWindow(window); } GLFWAPI int glfwGetWindowAttrib(GLFWwindow* handle, int attrib) { _GLFWwindow* window = (_GLFWwindow*) handle; assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(0); switch (attrib) { case GLFW_FOCUSED: return _glfwPlatformWindowFocused(window); case GLFW_ICONIFIED: return _glfwPlatformWindowIconified(window); case GLFW_VISIBLE: return _glfwPlatformWindowVisible(window); case GLFW_MAXIMIZED: return _glfwPlatformWindowMaximized(window); case GLFW_HOVERED: return _glfwPlatformWindowHovered(window); case GLFW_FOCUS_ON_SHOW: return window->focusOnShow; case GLFW_TRANSPARENT_FRAMEBUFFER: return _glfwPlatformFramebufferTransparent(window); case GLFW_RESIZABLE: return window->resizable; case GLFW_DECORATED: return window->decorated; case GLFW_FLOATING: return window->floating; case GLFW_AUTO_ICONIFY: return window->autoIconify; case GLFW_CLIENT_API: return window->context.client; case GLFW_CONTEXT_CREATION_API: return window->context.source; case GLFW_CONTEXT_VERSION_MAJOR: return window->context.major; case GLFW_CONTEXT_VERSION_MINOR: return window->context.minor; case GLFW_CONTEXT_REVISION: return window->context.revision; case GLFW_CONTEXT_ROBUSTNESS: return window->context.robustness; case GLFW_OPENGL_FORWARD_COMPAT: return window->context.forward; case GLFW_OPENGL_DEBUG_CONTEXT: return window->context.debug; case GLFW_OPENGL_PROFILE: return window->context.profile; case GLFW_CONTEXT_RELEASE_BEHAVIOR: return window->context.release; case GLFW_CONTEXT_NO_ERROR: return window->context.noerror; } _glfwInputError(GLFW_INVALID_ENUM, "Invalid window attribute 0x%08X", attrib); return 0; } GLFWAPI void glfwSetWindowAttrib(GLFWwindow* handle, int attrib, int value) { _GLFWwindow* window = (_GLFWwindow*) handle; assert(window != NULL); _GLFW_REQUIRE_INIT(); value = value ? GLFW_TRUE : GLFW_FALSE; if (attrib == GLFW_AUTO_ICONIFY) window->autoIconify = value; else if (attrib == GLFW_RESIZABLE) { if (window->resizable == value) return; window->resizable = value; if (!window->monitor) _glfwPlatformSetWindowResizable(window, value); } else if (attrib == GLFW_DECORATED) { if (window->decorated == value) return; window->decorated = value; if (!window->monitor) _glfwPlatformSetWindowDecorated(window, value); } else if (attrib == GLFW_FLOATING) { if (window->floating == value) return; window->floating = value; if (!window->monitor) _glfwPlatformSetWindowFloating(window, value); } else if (attrib == GLFW_FOCUS_ON_SHOW) window->focusOnShow = value; else _glfwInputError(GLFW_INVALID_ENUM, "Invalid window attribute 0x%08X", attrib); } GLFWAPI GLFWmonitor* glfwGetWindowMonitor(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); return (GLFWmonitor*) window->monitor; } GLFWAPI void glfwSetWindowMonitor(GLFWwindow* wh, GLFWmonitor* mh, int xpos, int ypos, int width, int height, int refreshRate) { _GLFWwindow* window = (_GLFWwindow*) wh; _GLFWmonitor* monitor = (_GLFWmonitor*) mh; assert(window != NULL); assert(width >= 0); assert(height >= 0); _GLFW_REQUIRE_INIT(); if (width <= 0 || height <= 0) { _glfwInputError(GLFW_INVALID_VALUE, "Invalid window size %ix%i", width, height); return; } if (refreshRate < 0 && refreshRate != GLFW_DONT_CARE) { _glfwInputError(GLFW_INVALID_VALUE, "Invalid refresh rate %i", refreshRate); return; } window->videoMode.width = width; window->videoMode.height = height; window->videoMode.refreshRate = refreshRate; _glfwPlatformSetWindowMonitor(window, monitor, xpos, ypos, width, height, refreshRate); } GLFWAPI void glfwSetWindowUserPointer(GLFWwindow* handle, void* pointer) { _GLFWwindow* window = (_GLFWwindow*) handle; assert(window != NULL); _GLFW_REQUIRE_INIT(); window->userPointer = pointer; } GLFWAPI void* glfwGetWindowUserPointer(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); return window->userPointer; } GLFWAPI GLFWwindowposfun glfwSetWindowPosCallback(GLFWwindow* handle, GLFWwindowposfun cbfun) { _GLFWwindow* window = (_GLFWwindow*) handle; assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); _GLFW_SWAP_POINTERS(window->callbacks.pos, cbfun); return cbfun; } GLFWAPI GLFWwindowsizefun glfwSetWindowSizeCallback(GLFWwindow* handle, GLFWwindowsizefun cbfun) { _GLFWwindow* window = (_GLFWwindow*) handle; assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); _GLFW_SWAP_POINTERS(window->callbacks.size, cbfun); return cbfun; } GLFWAPI GLFWwindowclosefun glfwSetWindowCloseCallback(GLFWwindow* handle, GLFWwindowclosefun cbfun) { _GLFWwindow* window = (_GLFWwindow*) handle; assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); _GLFW_SWAP_POINTERS(window->callbacks.close, cbfun); return cbfun; } GLFWAPI GLFWwindowrefreshfun glfwSetWindowRefreshCallback(GLFWwindow* handle, GLFWwindowrefreshfun cbfun) { _GLFWwindow* window = (_GLFWwindow*) handle; assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); _GLFW_SWAP_POINTERS(window->callbacks.refresh, cbfun); return cbfun; } GLFWAPI GLFWwindowfocusfun glfwSetWindowFocusCallback(GLFWwindow* handle, GLFWwindowfocusfun cbfun) { _GLFWwindow* window = (_GLFWwindow*) handle; assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); _GLFW_SWAP_POINTERS(window->callbacks.focus, cbfun); return cbfun; } GLFWAPI GLFWwindowiconifyfun glfwSetWindowIconifyCallback(GLFWwindow* handle, GLFWwindowiconifyfun cbfun) { _GLFWwindow* window = (_GLFWwindow*) handle; assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); _GLFW_SWAP_POINTERS(window->callbacks.iconify, cbfun); return cbfun; } GLFWAPI GLFWwindowmaximizefun glfwSetWindowMaximizeCallback(GLFWwindow* handle, GLFWwindowmaximizefun cbfun) { _GLFWwindow* window = (_GLFWwindow*) handle; assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); _GLFW_SWAP_POINTERS(window->callbacks.maximize, cbfun); return cbfun; } GLFWAPI GLFWframebuffersizefun glfwSetFramebufferSizeCallback(GLFWwindow* handle, GLFWframebuffersizefun cbfun) { _GLFWwindow* window = (_GLFWwindow*) handle; assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); _GLFW_SWAP_POINTERS(window->callbacks.fbsize, cbfun); return cbfun; } GLFWAPI GLFWwindowcontentscalefun glfwSetWindowContentScaleCallback(GLFWwindow* handle, GLFWwindowcontentscalefun cbfun) { _GLFWwindow* window = (_GLFWwindow*) handle; assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); _GLFW_SWAP_POINTERS(window->callbacks.scale, cbfun); return cbfun; } GLFWAPI void glfwPollEvents(void) { _GLFW_REQUIRE_INIT(); _glfwPlatformPollEvents(); } GLFWAPI void glfwWaitEvents(void) { _GLFW_REQUIRE_INIT(); _glfwPlatformWaitEvents(); } GLFWAPI void glfwWaitEventsTimeout(double timeout) { _GLFW_REQUIRE_INIT(); assert(timeout == timeout); assert(timeout >= 0.0); assert(timeout <= DBL_MAX); if (timeout != timeout || timeout < 0.0 || timeout > DBL_MAX) { _glfwInputError(GLFW_INVALID_VALUE, "Invalid time %f", timeout); return; } _glfwPlatformWaitEventsTimeout(timeout); } GLFWAPI void glfwPostEmptyEvent(void) { _GLFW_REQUIRE_INIT(); _glfwPlatformPostEmptyEvent(); } #endif #ifdef _GLFW_WIN32 #ifdef _MSC_VER #define _CRT_SECURE_NO_WARNINGS #endif #ifndef _GLFW_USE_HYBRID_HPG #define _GLFW_USE_HYBRID_HPG 1 #endif #ifndef _UNICODE //< @r-lyeh: add guard #define _UNICODE #endif #ifdef MINGW #define UNICODE #define WINVER 0x0501 #endif #ifndef HEADER_GUARD_WIN32_INIT_C #define HEADER_GUARD_WIN32_INIT_C //======================================================================== // GLFW 3.3.7 Win32 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2019 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== // Please use C89 style variable declarations in this file because VS 2010 //======================================================================== #include #include static const GUID _glfw_GUID_DEVINTERFACE_HID = {0x4d1e55b2,0xf16f,0x11cf,{0x88,0xcb,0x00,0x11,0x11,0x00,0x00,0x30}}; #define GUID_DEVINTERFACE_HID _glfw_GUID_DEVINTERFACE_HID #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 // __declspec(dllexport) DWORD NvOptimusEnablement = 1; // Executables (but not DLLs) exporting this symbol with this value will be // automatically directed to the high-performance GPU on AMD PowerXpress systems // with up-to-date drivers // __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1; #endif // _GLFW_USE_HYBRID_HPG #if defined(_GLFW_BUILD_DLL) // GLFW DLL entry point // BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) { return TRUE; } #endif // _GLFW_BUILD_DLL // Load necessary libraries (DLLs) // static GLFWbool loadLibraries(void) { _glfw.win32.user32.instance = LoadLibraryA("user32.dll"); if (!_glfw.win32.user32.instance) { _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, "Win32: Failed to load user32.dll"); return GLFW_FALSE; } _glfw.win32.user32.SetProcessDPIAware_ = (PFN_SetProcessDPIAware) GetProcAddress(_glfw.win32.user32.instance, "SetProcessDPIAware"); _glfw.win32.user32.ChangeWindowMessageFilterEx_ = (PFN_ChangeWindowMessageFilterEx) GetProcAddress(_glfw.win32.user32.instance, "ChangeWindowMessageFilterEx"); _glfw.win32.user32.EnableNonClientDpiScaling_ = (PFN_EnableNonClientDpiScaling) GetProcAddress(_glfw.win32.user32.instance, "EnableNonClientDpiScaling"); _glfw.win32.user32.SetProcessDpiAwarenessContext_ = (PFN_SetProcessDpiAwarenessContext) GetProcAddress(_glfw.win32.user32.instance, "SetProcessDpiAwarenessContext"); _glfw.win32.user32.GetDpiForWindow_ = (PFN_GetDpiForWindow) 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) { _glfw.win32.dinput8.Create = (PFN_DirectInput8Create) GetProcAddress(_glfw.win32.dinput8.instance, "DirectInput8Create"); } { int i; const char* names[] = { "xinput1_4.dll", "xinput1_3.dll", "xinput9_1_0.dll", "xinput1_2.dll", "xinput1_1.dll", NULL }; for (i = 0; names[i]; i++) { _glfw.win32.xinput.instance = LoadLibraryA(names[i]); if (_glfw.win32.xinput.instance) { _glfw.win32.xinput.GetCapabilities = (PFN_XInputGetCapabilities) GetProcAddress(_glfw.win32.xinput.instance, "XInputGetCapabilities"); _glfw.win32.xinput.GetState = (PFN_XInputGetState) GetProcAddress(_glfw.win32.xinput.instance, "XInputGetState"); break; } } } _glfw.win32.dwmapi.instance = LoadLibraryA("dwmapi.dll"); if (_glfw.win32.dwmapi.instance) { _glfw.win32.dwmapi.IsCompositionEnabled = (PFN_DwmIsCompositionEnabled) GetProcAddress(_glfw.win32.dwmapi.instance, "DwmIsCompositionEnabled"); _glfw.win32.dwmapi.Flush = (PFN_DwmFlush) 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"); if (_glfw.win32.shcore.instance) { _glfw.win32.shcore.SetProcessDpiAwareness_ = (PFN_SetProcessDpiAwareness) GetProcAddress(_glfw.win32.shcore.instance, "SetProcessDpiAwareness"); _glfw.win32.shcore.GetDpiForMonitor_ = (PFN_GetDpiForMonitor) GetProcAddress(_glfw.win32.shcore.instance, "GetDpiForMonitor"); } _glfw.win32.ntdll.instance = LoadLibraryA("ntdll.dll"); if (_glfw.win32.ntdll.instance) { _glfw.win32.ntdll.RtlVerifyVersionInfo_ = (PFN_RtlVerifyVersionInfo) GetProcAddress(_glfw.win32.ntdll.instance, "RtlVerifyVersionInfo"); } return GLFW_TRUE; } // Unload used libraries (DLLs) // static void freeLibraries(void) { if (_glfw.win32.xinput.instance) FreeLibrary(_glfw.win32.xinput.instance); if (_glfw.win32.dinput8.instance) FreeLibrary(_glfw.win32.dinput8.instance); if (_glfw.win32.user32.instance) FreeLibrary(_glfw.win32.user32.instance); if (_glfw.win32.dwmapi.instance) FreeLibrary(_glfw.win32.dwmapi.instance); if (_glfw.win32.shcore.instance) FreeLibrary(_glfw.win32.shcore.instance); if (_glfw.win32.ntdll.instance) FreeLibrary(_glfw.win32.ntdll.instance); } // Create key code translation tables // static void createKeyTables(void) { int scancode; memset(_glfw.win32.keycodes, -1, sizeof(_glfw.win32.keycodes)); memset(_glfw.win32.scancodes, -1, sizeof(_glfw.win32.scancodes)); _glfw.win32.keycodes[0x00B] = GLFW_KEY_0; _glfw.win32.keycodes[0x002] = GLFW_KEY_1; _glfw.win32.keycodes[0x003] = GLFW_KEY_2; _glfw.win32.keycodes[0x004] = GLFW_KEY_3; _glfw.win32.keycodes[0x005] = GLFW_KEY_4; _glfw.win32.keycodes[0x006] = GLFW_KEY_5; _glfw.win32.keycodes[0x007] = GLFW_KEY_6; _glfw.win32.keycodes[0x008] = GLFW_KEY_7; _glfw.win32.keycodes[0x009] = GLFW_KEY_8; _glfw.win32.keycodes[0x00A] = GLFW_KEY_9; _glfw.win32.keycodes[0x01E] = GLFW_KEY_A; _glfw.win32.keycodes[0x030] = GLFW_KEY_B; _glfw.win32.keycodes[0x02E] = GLFW_KEY_C; _glfw.win32.keycodes[0x020] = GLFW_KEY_D; _glfw.win32.keycodes[0x012] = GLFW_KEY_E; _glfw.win32.keycodes[0x021] = GLFW_KEY_F; _glfw.win32.keycodes[0x022] = GLFW_KEY_G; _glfw.win32.keycodes[0x023] = GLFW_KEY_H; _glfw.win32.keycodes[0x017] = GLFW_KEY_I; _glfw.win32.keycodes[0x024] = GLFW_KEY_J; _glfw.win32.keycodes[0x025] = GLFW_KEY_K; _glfw.win32.keycodes[0x026] = GLFW_KEY_L; _glfw.win32.keycodes[0x032] = GLFW_KEY_M; _glfw.win32.keycodes[0x031] = GLFW_KEY_N; _glfw.win32.keycodes[0x018] = GLFW_KEY_O; _glfw.win32.keycodes[0x019] = GLFW_KEY_P; _glfw.win32.keycodes[0x010] = GLFW_KEY_Q; _glfw.win32.keycodes[0x013] = GLFW_KEY_R; _glfw.win32.keycodes[0x01F] = GLFW_KEY_S; _glfw.win32.keycodes[0x014] = GLFW_KEY_T; _glfw.win32.keycodes[0x016] = GLFW_KEY_U; _glfw.win32.keycodes[0x02F] = GLFW_KEY_V; _glfw.win32.keycodes[0x011] = GLFW_KEY_W; _glfw.win32.keycodes[0x02D] = GLFW_KEY_X; _glfw.win32.keycodes[0x015] = GLFW_KEY_Y; _glfw.win32.keycodes[0x02C] = GLFW_KEY_Z; _glfw.win32.keycodes[0x028] = GLFW_KEY_APOSTROPHE; _glfw.win32.keycodes[0x02B] = GLFW_KEY_BACKSLASH; _glfw.win32.keycodes[0x033] = GLFW_KEY_COMMA; _glfw.win32.keycodes[0x00D] = GLFW_KEY_EQUAL; _glfw.win32.keycodes[0x029] = GLFW_KEY_GRAVE_ACCENT; _glfw.win32.keycodes[0x01A] = GLFW_KEY_LEFT_BRACKET; _glfw.win32.keycodes[0x00C] = GLFW_KEY_MINUS; _glfw.win32.keycodes[0x034] = GLFW_KEY_PERIOD; _glfw.win32.keycodes[0x01B] = GLFW_KEY_RIGHT_BRACKET; _glfw.win32.keycodes[0x027] = GLFW_KEY_SEMICOLON; _glfw.win32.keycodes[0x035] = GLFW_KEY_SLASH; _glfw.win32.keycodes[0x056] = GLFW_KEY_WORLD_2; _glfw.win32.keycodes[0x00E] = GLFW_KEY_BACKSPACE; _glfw.win32.keycodes[0x153] = GLFW_KEY_DELETE; _glfw.win32.keycodes[0x14F] = GLFW_KEY_END; _glfw.win32.keycodes[0x01C] = GLFW_KEY_ENTER; _glfw.win32.keycodes[0x001] = GLFW_KEY_ESCAPE; _glfw.win32.keycodes[0x147] = GLFW_KEY_HOME; _glfw.win32.keycodes[0x152] = GLFW_KEY_INSERT; _glfw.win32.keycodes[0x15D] = GLFW_KEY_MENU; _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; _glfw.win32.keycodes[0x145] = GLFW_KEY_NUM_LOCK; _glfw.win32.keycodes[0x046] = GLFW_KEY_SCROLL_LOCK; _glfw.win32.keycodes[0x03B] = GLFW_KEY_F1; _glfw.win32.keycodes[0x03C] = GLFW_KEY_F2; _glfw.win32.keycodes[0x03D] = GLFW_KEY_F3; _glfw.win32.keycodes[0x03E] = GLFW_KEY_F4; _glfw.win32.keycodes[0x03F] = GLFW_KEY_F5; _glfw.win32.keycodes[0x040] = GLFW_KEY_F6; _glfw.win32.keycodes[0x041] = GLFW_KEY_F7; _glfw.win32.keycodes[0x042] = GLFW_KEY_F8; _glfw.win32.keycodes[0x043] = GLFW_KEY_F9; _glfw.win32.keycodes[0x044] = GLFW_KEY_F10; _glfw.win32.keycodes[0x057] = GLFW_KEY_F11; _glfw.win32.keycodes[0x058] = GLFW_KEY_F12; _glfw.win32.keycodes[0x064] = GLFW_KEY_F13; _glfw.win32.keycodes[0x065] = GLFW_KEY_F14; _glfw.win32.keycodes[0x066] = GLFW_KEY_F15; _glfw.win32.keycodes[0x067] = GLFW_KEY_F16; _glfw.win32.keycodes[0x068] = GLFW_KEY_F17; _glfw.win32.keycodes[0x069] = GLFW_KEY_F18; _glfw.win32.keycodes[0x06A] = GLFW_KEY_F19; _glfw.win32.keycodes[0x06B] = GLFW_KEY_F20; _glfw.win32.keycodes[0x06C] = GLFW_KEY_F21; _glfw.win32.keycodes[0x06D] = GLFW_KEY_F22; _glfw.win32.keycodes[0x06E] = GLFW_KEY_F23; _glfw.win32.keycodes[0x076] = GLFW_KEY_F24; _glfw.win32.keycodes[0x038] = GLFW_KEY_LEFT_ALT; _glfw.win32.keycodes[0x01D] = GLFW_KEY_LEFT_CONTROL; _glfw.win32.keycodes[0x02A] = GLFW_KEY_LEFT_SHIFT; _glfw.win32.keycodes[0x15B] = GLFW_KEY_LEFT_SUPER; _glfw.win32.keycodes[0x137] = GLFW_KEY_PRINT_SCREEN; _glfw.win32.keycodes[0x138] = GLFW_KEY_RIGHT_ALT; _glfw.win32.keycodes[0x11D] = GLFW_KEY_RIGHT_CONTROL; _glfw.win32.keycodes[0x036] = GLFW_KEY_RIGHT_SHIFT; _glfw.win32.keycodes[0x15C] = GLFW_KEY_RIGHT_SUPER; _glfw.win32.keycodes[0x150] = GLFW_KEY_DOWN; _glfw.win32.keycodes[0x14B] = GLFW_KEY_LEFT; _glfw.win32.keycodes[0x14D] = GLFW_KEY_RIGHT; _glfw.win32.keycodes[0x148] = GLFW_KEY_UP; _glfw.win32.keycodes[0x052] = GLFW_KEY_KP_0; _glfw.win32.keycodes[0x04F] = GLFW_KEY_KP_1; _glfw.win32.keycodes[0x050] = GLFW_KEY_KP_2; _glfw.win32.keycodes[0x051] = GLFW_KEY_KP_3; _glfw.win32.keycodes[0x04B] = GLFW_KEY_KP_4; _glfw.win32.keycodes[0x04C] = GLFW_KEY_KP_5; _glfw.win32.keycodes[0x04D] = GLFW_KEY_KP_6; _glfw.win32.keycodes[0x047] = GLFW_KEY_KP_7; _glfw.win32.keycodes[0x048] = GLFW_KEY_KP_8; _glfw.win32.keycodes[0x049] = GLFW_KEY_KP_9; _glfw.win32.keycodes[0x04E] = GLFW_KEY_KP_ADD; _glfw.win32.keycodes[0x053] = GLFW_KEY_KP_DECIMAL; _glfw.win32.keycodes[0x135] = GLFW_KEY_KP_DIVIDE; _glfw.win32.keycodes[0x11C] = GLFW_KEY_KP_ENTER; _glfw.win32.keycodes[0x059] = GLFW_KEY_KP_EQUAL; _glfw.win32.keycodes[0x037] = GLFW_KEY_KP_MULTIPLY; _glfw.win32.keycodes[0x04A] = GLFW_KEY_KP_SUBTRACT; for (scancode = 0; scancode < 512; scancode++) { if (_glfw.win32.keycodes[scancode] > 0) _glfw.win32.scancodes[_glfw.win32.keycodes[scancode]] = scancode; } } // Creates a dummy window for behind-the-scenes work // static GLFWbool createHelperWindow(void) { MSG msg; _glfw.win32.helperWindowHandle = CreateWindowExW(WS_EX_OVERLAPPEDWINDOW, _GLFW_WNDCLASSNAME, L"GLFW message window", WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0, 0, 1, 1, NULL, NULL, GetModuleHandleW(NULL), NULL); if (!_glfw.win32.helperWindowHandle) { _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, "Win32: Failed to create helper window"); return GLFW_FALSE; } // HACK: The command to the first ShowWindow call is ignored if the parent // process passed along a STARTUPINFO, so clear that with a no-op call ShowWindow(_glfw.win32.helperWindowHandle, SW_HIDE); // Register for HID device notifications { DEV_BROADCAST_DEVICEINTERFACE_W dbi; ZeroMemory(&dbi, sizeof(dbi)); dbi.dbcc_size = sizeof(dbi); dbi.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; dbi.dbcc_classguid = GUID_DEVINTERFACE_HID; _glfw.win32.deviceNotificationHandle = RegisterDeviceNotificationW(_glfw.win32.helperWindowHandle, (DEV_BROADCAST_HDR*) &dbi, DEVICE_NOTIFY_WINDOW_HANDLE); } while (PeekMessageW(&msg, _glfw.win32.helperWindowHandle, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessageW(&msg); } return GLFW_TRUE; } ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// // Returns a wide string version of the specified UTF-8 string // WCHAR* _glfwCreateWideStringFromUTF8Win32(const char* source) { WCHAR* target; int count; count = MultiByteToWideChar(CP_UTF8, 0, source, -1, NULL, 0); if (!count) { _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, "Win32: Failed to convert string from UTF-8"); return NULL; } target = calloc(count, sizeof(WCHAR)); if (!MultiByteToWideChar(CP_UTF8, 0, source, -1, target, count)) { _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, "Win32: Failed to convert string from UTF-8"); free(target); return NULL; } return target; } // Returns a UTF-8 string version of the specified wide string // char* _glfwCreateUTF8FromWideStringWin32(const WCHAR* source) { char* target; int size; size = WideCharToMultiByte(CP_UTF8, 0, source, -1, NULL, 0, NULL, NULL); if (!size) { _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, "Win32: Failed to convert string to UTF-8"); return NULL; } target = calloc(size, 1); if (!WideCharToMultiByte(CP_UTF8, 0, source, -1, target, size, NULL, NULL)) { _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, "Win32: Failed to convert string to UTF-8"); free(target); return NULL; } return target; } // Reports the specified error, appending information about the last Win32 error // void _glfwInputErrorWin32(int error, const char* description) { WCHAR buffer[_GLFW_MESSAGE_SIZE] = L""; char message[_GLFW_MESSAGE_SIZE] = ""; FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK, NULL, GetLastError() & 0xffff, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buffer, sizeof(buffer) / sizeof(WCHAR), NULL); WideCharToMultiByte(CP_UTF8, 0, buffer, -1, message, sizeof(message), NULL, NULL); _glfwInputError(error, "%s: %s", description, message); } // Updates key names according to the current keyboard layout // void _glfwUpdateKeyNamesWin32(void) { int key; BYTE state[256] = {0}; memset(_glfw.win32.keynames, 0, sizeof(_glfw.win32.keynames)); for (key = GLFW_KEY_SPACE; key <= GLFW_KEY_LAST; key++) { UINT vk; int scancode, length; WCHAR chars[16]; scancode = _glfw.win32.scancodes[key]; if (scancode == -1) continue; if (key >= GLFW_KEY_KP_0 && key <= GLFW_KEY_KP_ADD) { const UINT vks[] = { VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, VK_NUMPAD4, VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7, VK_NUMPAD8, VK_NUMPAD9, VK_DECIMAL, VK_DIVIDE, VK_MULTIPLY, VK_SUBTRACT, VK_ADD }; vk = vks[key - GLFW_KEY_KP_0]; } else vk = MapVirtualKeyW(scancode, MAPVK_VSC_TO_VK); length = ToUnicode(vk, scancode, state, chars, sizeof(chars) / sizeof(WCHAR), 0); if (length == -1) { length = ToUnicode(vk, scancode, state, chars, sizeof(chars) / sizeof(WCHAR), 0); } if (length < 1) continue; WideCharToMultiByte(CP_UTF8, 0, chars, 1, _glfw.win32.keynames[key], sizeof(_glfw.win32.keynames[key]), NULL, NULL); } } // Replacement for IsWindowsVersionOrGreater, as we cannot rely on the // application having a correct embedded manifest // BOOL _glfwIsWindowsVersionOrGreaterWin32(WORD major, WORD minor, WORD sp) { OSVERSIONINFOEXW osvi = { sizeof(osvi), major, minor, 0, 0, {0}, sp }; DWORD mask = VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR; ULONGLONG cond = VerSetConditionMask(0, VER_MAJORVERSION, VER_GREATER_EQUAL); cond = VerSetConditionMask(cond, VER_MINORVERSION, VER_GREATER_EQUAL); cond = VerSetConditionMask(cond, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL); // HACK: Use RtlVerifyVersionInfo instead of VerifyVersionInfoW as the // latter lies unless the user knew to embed a non-default manifest // announcing support for Windows 10 via supportedOS GUID return RtlVerifyVersionInfo(&osvi, mask, cond) == 0; } // Checks whether we are on at least the specified build of Windows 10 // BOOL _glfwIsWindows10BuildOrGreaterWin32(WORD build) { OSVERSIONINFOEXW osvi = { sizeof(osvi), 10, 0, build }; DWORD mask = VER_MAJORVERSION | VER_MINORVERSION | VER_BUILDNUMBER; ULONGLONG cond = VerSetConditionMask(0, VER_MAJORVERSION, VER_GREATER_EQUAL); cond = VerSetConditionMask(cond, VER_MINORVERSION, VER_GREATER_EQUAL); cond = VerSetConditionMask(cond, VER_BUILDNUMBER, VER_GREATER_EQUAL); // HACK: Use RtlVerifyVersionInfo instead of VerifyVersionInfoW as the // latter lies unless the user knew to embed a non-default manifest // announcing support for Windows 10 via supportedOS GUID return RtlVerifyVersionInfo(&osvi, mask, cond) == 0; } ////////////////////////////////////////////////////////////////////////// ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// int _glfwPlatformInit(void) { // To make SetForegroundWindow work as we want, we need to fiddle // with the FOREGROUNDLOCKTIMEOUT system setting (we do this as early // as possible in the hope of still being the foreground process) SystemParametersInfoW(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, &_glfw.win32.foregroundLockTimeout, 0); SystemParametersInfoW(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, UIntToPtr(0), SPIF_SENDCHANGE); if (!loadLibraries()) return GLFW_FALSE; createKeyTables(); _glfwUpdateKeyNamesWin32(); if (_glfwIsWindows10CreatorsUpdateOrGreaterWin32()) SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); else if (IsWindows8Point1OrGreater()) SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE); else if (IsWindowsVistaOrGreater()) SetProcessDPIAware(); if (!_glfwRegisterWindowClassWin32()) return GLFW_FALSE; if (!createHelperWindow()) return GLFW_FALSE; _glfwInitTimerWin32(); _glfwInitJoysticksWin32(); _glfwPollMonitorsWin32(); return GLFW_TRUE; } void _glfwPlatformTerminate(void) { if (_glfw.win32.deviceNotificationHandle) UnregisterDeviceNotification(_glfw.win32.deviceNotificationHandle); if (_glfw.win32.helperWindowHandle) DestroyWindow(_glfw.win32.helperWindowHandle); _glfwUnregisterWindowClassWin32(); // Restore previous foreground lock timeout system setting SystemParametersInfoW(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, UIntToPtr(_glfw.win32.foregroundLockTimeout), SPIF_SENDCHANGE); free(_glfw.win32.clipboardString); free(_glfw.win32.rawInput); _glfwTerminateWGL(); _glfwTerminateEGL(); _glfwTerminateJoysticksWin32(); freeLibraries(); } const char* _glfwPlatformGetVersionString(void) { return _GLFW_VERSION_NUMBER " Win32 WGL EGL OSMesa" #if defined(__MINGW32__) " MinGW" #elif defined(_MSC_VER) " VisualC" #endif #if defined(_GLFW_USE_HYBRID_HPG) || defined(_GLFW_USE_OPTIMUS_HPG) " hybrid-GPU" #endif #if defined(_GLFW_BUILD_DLL) " DLL" #endif ; } #endif #ifndef HEADER_GUARD_WIN32_JOYSTICK_C #define HEADER_GUARD_WIN32_JOYSTICK_C //======================================================================== // GLFW 3.3.7 Win32 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2019 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== // Please use C89 style variable declarations in this file because VS 2010 //======================================================================== #include #include #define _GLFW_TYPE_AXIS 0 #define _GLFW_TYPE_SLIDER 1 #define _GLFW_TYPE_BUTTON 2 #define _GLFW_TYPE_POV 3 // Data produced with DirectInput device object enumeration // typedef struct _GLFWobjenumWin32 { IDirectInputDevice8W* device; _GLFWjoyobjectWin32* objects; int objectCount; int axisCount; int sliderCount; int buttonCount; int povCount; } _GLFWobjenumWin32; // Define local copies of the necessary GUIDs // static const GUID _glfw_IID_IDirectInput8W = {0xbf798031,0x483a,0x4da2,{0xaa,0x99,0x5d,0x64,0xed,0x36,0x97,0x00}}; static const GUID _glfw_GUID_XAxis = {0xa36d02e0,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}}; static const GUID _glfw_GUID_YAxis = {0xa36d02e1,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}}; static const GUID _glfw_GUID_ZAxis = {0xa36d02e2,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}}; static const GUID _glfw_GUID_RxAxis = {0xa36d02f4,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}}; static const GUID _glfw_GUID_RyAxis = {0xa36d02f5,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}}; static const GUID _glfw_GUID_RzAxis = {0xa36d02e3,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}}; static const GUID _glfw_GUID_Slider = {0xa36d02e4,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}}; static const GUID _glfw_GUID_POV = {0xa36d02f2,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}}; #define IID_IDirectInput8W _glfw_IID_IDirectInput8W #define GUID_XAxis _glfw_GUID_XAxis #define GUID_YAxis _glfw_GUID_YAxis #define GUID_ZAxis _glfw_GUID_ZAxis #define GUID_RxAxis _glfw_GUID_RxAxis #define GUID_RyAxis _glfw_GUID_RyAxis #define GUID_RzAxis _glfw_GUID_RzAxis #define GUID_Slider _glfw_GUID_Slider #define GUID_POV _glfw_GUID_POV // Object data array for our clone of c_dfDIJoystick // Generated with https://github.com/elmindreda/c_dfDIJoystick2 // static DIOBJECTDATAFORMAT _glfwObjectDataFormats[] = { { &GUID_XAxis,DIJOFS_X,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION }, { &GUID_YAxis,DIJOFS_Y,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION }, { &GUID_ZAxis,DIJOFS_Z,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION }, { &GUID_RxAxis,DIJOFS_RX,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION }, { &GUID_RyAxis,DIJOFS_RY,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION }, { &GUID_RzAxis,DIJOFS_RZ,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION }, { &GUID_Slider,DIJOFS_SLIDER(0),DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION }, { &GUID_Slider,DIJOFS_SLIDER(1),DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION }, { &GUID_POV,DIJOFS_POV(0),DIDFT_POV|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, { &GUID_POV,DIJOFS_POV(1),DIDFT_POV|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, { &GUID_POV,DIJOFS_POV(2),DIDFT_POV|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, { &GUID_POV,DIJOFS_POV(3),DIDFT_POV|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, { NULL,DIJOFS_BUTTON(0),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, { NULL,DIJOFS_BUTTON(1),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, { NULL,DIJOFS_BUTTON(2),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, { NULL,DIJOFS_BUTTON(3),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, { NULL,DIJOFS_BUTTON(4),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, { NULL,DIJOFS_BUTTON(5),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, { NULL,DIJOFS_BUTTON(6),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, { NULL,DIJOFS_BUTTON(7),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, { NULL,DIJOFS_BUTTON(8),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, { NULL,DIJOFS_BUTTON(9),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, { NULL,DIJOFS_BUTTON(10),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, { NULL,DIJOFS_BUTTON(11),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, { NULL,DIJOFS_BUTTON(12),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, { NULL,DIJOFS_BUTTON(13),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, { NULL,DIJOFS_BUTTON(14),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, { NULL,DIJOFS_BUTTON(15),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, { NULL,DIJOFS_BUTTON(16),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, { NULL,DIJOFS_BUTTON(17),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, { NULL,DIJOFS_BUTTON(18),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, { NULL,DIJOFS_BUTTON(19),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, { NULL,DIJOFS_BUTTON(20),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, { NULL,DIJOFS_BUTTON(21),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, { NULL,DIJOFS_BUTTON(22),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, { NULL,DIJOFS_BUTTON(23),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, { NULL,DIJOFS_BUTTON(24),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, { NULL,DIJOFS_BUTTON(25),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, { NULL,DIJOFS_BUTTON(26),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, { NULL,DIJOFS_BUTTON(27),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, { NULL,DIJOFS_BUTTON(28),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, { NULL,DIJOFS_BUTTON(29),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, { NULL,DIJOFS_BUTTON(30),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, { NULL,DIJOFS_BUTTON(31),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 }, }; // Our clone of c_dfDIJoystick // static const DIDATAFORMAT _glfwDataFormat = { sizeof(DIDATAFORMAT), sizeof(DIOBJECTDATAFORMAT), DIDFT_ABSAXIS, sizeof(DIJOYSTATE), sizeof(_glfwObjectDataFormats) / sizeof(DIOBJECTDATAFORMAT), _glfwObjectDataFormats }; // Returns a description fitting the specified XInput capabilities // static const char* getDeviceDescription(const XINPUT_CAPABILITIES* xic) { switch (xic->SubType) { case XINPUT_DEVSUBTYPE_WHEEL: return "XInput Wheel"; case XINPUT_DEVSUBTYPE_ARCADE_STICK: return "XInput Arcade Stick"; case XINPUT_DEVSUBTYPE_FLIGHT_STICK: return "XInput Flight Stick"; case XINPUT_DEVSUBTYPE_DANCE_PAD: return "XInput Dance Pad"; case XINPUT_DEVSUBTYPE_GUITAR: return "XInput Guitar"; case XINPUT_DEVSUBTYPE_DRUM_KIT: return "XInput Drum Kit"; case XINPUT_DEVSUBTYPE_GAMEPAD: { if (xic->Flags & XINPUT_CAPS_WIRELESS) return "Wireless Xbox Controller"; else return "Xbox Controller"; } } return "Unknown XInput Device"; } // Lexically compare device objects // static int compareJoystickObjects(const void* first, const void* second) { const _GLFWjoyobjectWin32* fo = first; const _GLFWjoyobjectWin32* so = second; if (fo->type != so->type) return fo->type - so->type; return fo->offset - so->offset; } // Checks whether the specified device supports XInput // Technique from FDInputJoystickManager::IsXInputDeviceFast in ZDoom // static GLFWbool supportsXInput(const GUID* guid) { UINT i, count = 0; RAWINPUTDEVICELIST* ridl; GLFWbool result = GLFW_FALSE; if (GetRawInputDeviceList(NULL, &count, sizeof(RAWINPUTDEVICELIST)) != 0) return GLFW_FALSE; ridl = calloc(count, sizeof(RAWINPUTDEVICELIST)); if (GetRawInputDeviceList(ridl, &count, sizeof(RAWINPUTDEVICELIST)) == (UINT) -1) { free(ridl); return GLFW_FALSE; } for (i = 0; i < count; i++) { RID_DEVICE_INFO rdi; char name[256]; UINT size; if (ridl[i].dwType != RIM_TYPEHID) continue; ZeroMemory(&rdi, sizeof(rdi)); rdi.cbSize = sizeof(rdi); size = sizeof(rdi); if ((INT) GetRawInputDeviceInfoA(ridl[i].hDevice, RIDI_DEVICEINFO, &rdi, &size) == -1) { continue; } if (MAKELONG(rdi.hid.dwVendorId, rdi.hid.dwProductId) != (LONG) guid->Data1) continue; memset(name, 0, sizeof(name)); size = sizeof(name); if ((INT) GetRawInputDeviceInfoA(ridl[i].hDevice, RIDI_DEVICENAME, name, &size) == -1) { break; } name[sizeof(name) - 1] = '\0'; if (strstr(name, "IG_")) { result = GLFW_TRUE; break; } } free(ridl); return result; } // Frees all resources associated with the specified joystick // static void closeJoystick(_GLFWjoystick* js) { if (js->win32.device) { IDirectInputDevice8_Unacquire(js->win32.device); IDirectInputDevice8_Release(js->win32.device); } free(js->win32.objects); _glfwFreeJoystick(js); _glfwInputJoystick(js, GLFW_DISCONNECTED); } // DirectInput device object enumeration callback // Insights gleaned from SDL // static BOOL CALLBACK deviceObjectCallback(const DIDEVICEOBJECTINSTANCEW* doi, void* user) { _GLFWobjenumWin32* data = user; _GLFWjoyobjectWin32* object = data->objects + data->objectCount; if (DIDFT_GETTYPE(doi->dwType) & DIDFT_AXIS) { DIPROPRANGE dipr; if (memcmp(&doi->guidType, &GUID_Slider, sizeof(GUID)) == 0) object->offset = DIJOFS_SLIDER(data->sliderCount); else if (memcmp(&doi->guidType, &GUID_XAxis, sizeof(GUID)) == 0) object->offset = DIJOFS_X; else if (memcmp(&doi->guidType, &GUID_YAxis, sizeof(GUID)) == 0) object->offset = DIJOFS_Y; else if (memcmp(&doi->guidType, &GUID_ZAxis, sizeof(GUID)) == 0) object->offset = DIJOFS_Z; else if (memcmp(&doi->guidType, &GUID_RxAxis, sizeof(GUID)) == 0) object->offset = DIJOFS_RX; else if (memcmp(&doi->guidType, &GUID_RyAxis, sizeof(GUID)) == 0) object->offset = DIJOFS_RY; else if (memcmp(&doi->guidType, &GUID_RzAxis, sizeof(GUID)) == 0) object->offset = DIJOFS_RZ; else return DIENUM_CONTINUE; ZeroMemory(&dipr, sizeof(dipr)); dipr.diph.dwSize = sizeof(dipr); dipr.diph.dwHeaderSize = sizeof(dipr.diph); dipr.diph.dwObj = doi->dwType; dipr.diph.dwHow = DIPH_BYID; dipr.lMin = -32768; dipr.lMax = 32767; if (FAILED(IDirectInputDevice8_SetProperty(data->device, DIPROP_RANGE, &dipr.diph))) { return DIENUM_CONTINUE; } if (memcmp(&doi->guidType, &GUID_Slider, sizeof(GUID)) == 0) { object->type = _GLFW_TYPE_SLIDER; data->sliderCount++; } else { object->type = _GLFW_TYPE_AXIS; data->axisCount++; } } else if (DIDFT_GETTYPE(doi->dwType) & DIDFT_BUTTON) { object->offset = DIJOFS_BUTTON(data->buttonCount); object->type = _GLFW_TYPE_BUTTON; data->buttonCount++; } else if (DIDFT_GETTYPE(doi->dwType) & DIDFT_POV) { object->offset = DIJOFS_POV(data->povCount); object->type = _GLFW_TYPE_POV; data->povCount++; } data->objectCount++; return DIENUM_CONTINUE; } // DirectInput device enumeration callback // static BOOL CALLBACK deviceCallback(const DIDEVICEINSTANCE* di, void* user) { int jid = 0; DIDEVCAPS dc; DIPROPDWORD dipd; IDirectInputDevice8W* device; //< @r-lyeh +W (tcc) _GLFWobjenumWin32 data; _GLFWjoystick* js; char guid[33]; char name[256]; for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) { js = _glfw.joysticks + jid; if (js->present) { if (memcmp(&js->win32.guid, &di->guidInstance, sizeof(GUID)) == 0) return DIENUM_CONTINUE; } } if (supportsXInput(&di->guidProduct)) return DIENUM_CONTINUE; if (FAILED(IDirectInput8_CreateDevice(_glfw.win32.dinput8.api, &di->guidInstance, &device, NULL))) { _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to create device"); return DIENUM_CONTINUE; } if (FAILED(IDirectInputDevice8_SetDataFormat(device, &_glfwDataFormat))) { _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to set device data format"); IDirectInputDevice8_Release(device); return DIENUM_CONTINUE; } ZeroMemory(&dc, sizeof(dc)); dc.dwSize = sizeof(dc); if (FAILED(IDirectInputDevice8_GetCapabilities(device, &dc))) { _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to query device capabilities"); IDirectInputDevice8_Release(device); return DIENUM_CONTINUE; } ZeroMemory(&dipd, sizeof(dipd)); dipd.diph.dwSize = sizeof(dipd); dipd.diph.dwHeaderSize = sizeof(dipd.diph); dipd.diph.dwHow = DIPH_DEVICE; dipd.dwData = DIPROPAXISMODE_ABS; if (FAILED(IDirectInputDevice8_SetProperty(device, DIPROP_AXISMODE, &dipd.diph))) { _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to set device axis mode"); IDirectInputDevice8_Release(device); return DIENUM_CONTINUE; } memset(&data, 0, sizeof(data)); data.device = device; data.objects = calloc(dc.dwAxes + (size_t) dc.dwButtons + dc.dwPOVs, sizeof(_GLFWjoyobjectWin32)); if (FAILED(IDirectInputDevice8_EnumObjects(device, deviceObjectCallback, &data, DIDFT_AXIS | DIDFT_BUTTON | DIDFT_POV))) { _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to enumerate device objects"); IDirectInputDevice8_Release(device); free(data.objects); return DIENUM_CONTINUE; } qsort(data.objects, data.objectCount, sizeof(_GLFWjoyobjectWin32), compareJoystickObjects); if (!WideCharToMultiByte(CP_UTF8, 0, di->tszInstanceName, -1, name, sizeof(name), NULL, NULL)) { _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to convert joystick name to UTF-8"); IDirectInputDevice8_Release(device); free(data.objects); return DIENUM_STOP; } // Generate a joystick GUID that matches the SDL 2.0.5+ one if (memcmp(&di->guidProduct.Data4[2], "PIDVID", 6) == 0) { sprintf(guid, "03000000%02x%02x0000%02x%02x000000000000", (uint8_t) di->guidProduct.Data1, (uint8_t) (di->guidProduct.Data1 >> 8), (uint8_t) (di->guidProduct.Data1 >> 16), (uint8_t) (di->guidProduct.Data1 >> 24)); } else { sprintf(guid, "05000000%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x00", name[0], name[1], name[2], name[3], name[4], name[5], name[6], name[7], name[8], name[9], name[10]); } js = _glfwAllocJoystick(name, guid, data.axisCount + data.sliderCount, data.buttonCount, data.povCount); if (!js) { IDirectInputDevice8_Release(device); free(data.objects); return DIENUM_STOP; } js->win32.device = device; js->win32.guid = di->guidInstance; js->win32.objects = data.objects; js->win32.objectCount = data.objectCount; _glfwInputJoystick(js, GLFW_CONNECTED); return DIENUM_CONTINUE; } ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// // Initialize joystick interface // void _glfwInitJoysticksWin32(void) { if (_glfw.win32.dinput8.instance) { if (FAILED(DirectInput8Create(GetModuleHandleW(NULL), DIRECTINPUT_VERSION, &IID_IDirectInput8W, (void**) &_glfw.win32.dinput8.api, NULL))) { _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to create interface"); } } _glfwDetectJoystickConnectionWin32(); } // Close all opened joystick handles // void _glfwTerminateJoysticksWin32(void) { int jid; for (jid = GLFW_JOYSTICK_1; jid <= GLFW_JOYSTICK_LAST; jid++) closeJoystick(_glfw.joysticks + jid); if (_glfw.win32.dinput8.api) IDirectInput8_Release(_glfw.win32.dinput8.api); } // Checks for new joysticks after DBT_DEVICEARRIVAL // void _glfwDetectJoystickConnectionWin32(void) { if (_glfw.win32.xinput.instance) { DWORD index; for (index = 0; index < XUSER_MAX_COUNT; index++) { int jid; char guid[33]; XINPUT_CAPABILITIES xic; _GLFWjoystick* js; for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) { if (_glfw.joysticks[jid].present && _glfw.joysticks[jid].win32.device == NULL && _glfw.joysticks[jid].win32.index == index) { break; } } if (jid <= GLFW_JOYSTICK_LAST) continue; if (XInputGetCapabilities(index, 0, &xic) != ERROR_SUCCESS) continue; // Generate a joystick GUID that matches the SDL 2.0.5+ one sprintf(guid, "78696e707574%02x000000000000000000", xic.SubType & 0xff); js = _glfwAllocJoystick(getDeviceDescription(&xic), guid, 6, 10, 1); if (!js) continue; js->win32.index = index; _glfwInputJoystick(js, GLFW_CONNECTED); } } if (_glfw.win32.dinput8.api) { if (FAILED(IDirectInput8_EnumDevices(_glfw.win32.dinput8.api, DI8DEVCLASS_GAMECTRL, deviceCallback, NULL, DIEDFL_ALLDEVICES))) { _glfwInputError(GLFW_PLATFORM_ERROR, "Failed to enumerate DirectInput8 devices"); return; } } } // Checks for joystick disconnection after DBT_DEVICEREMOVECOMPLETE // void _glfwDetectJoystickDisconnectionWin32(void) { int jid; for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) { _GLFWjoystick* js = _glfw.joysticks + jid; if (js->present) _glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE); } } ////////////////////////////////////////////////////////////////////////// ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode) { if (js->win32.device) { int i, ai = 0, bi = 0, pi = 0; HRESULT result; DIJOYSTATE state; IDirectInputDevice8_Poll(js->win32.device); result = IDirectInputDevice8_GetDeviceState(js->win32.device, sizeof(state), &state); if (result == DIERR_NOTACQUIRED || result == DIERR_INPUTLOST) { IDirectInputDevice8_Acquire(js->win32.device); IDirectInputDevice8_Poll(js->win32.device); result = IDirectInputDevice8_GetDeviceState(js->win32.device, sizeof(state), &state); } if (FAILED(result)) { closeJoystick(js); return GLFW_FALSE; } if (mode == _GLFW_POLL_PRESENCE) return GLFW_TRUE; for (i = 0; i < js->win32.objectCount; i++) { const void* data = (char*) &state + js->win32.objects[i].offset; switch (js->win32.objects[i].type) { case _GLFW_TYPE_AXIS: case _GLFW_TYPE_SLIDER: { const float value = (*((LONG*) data) + 0.5f) / 32767.5f; _glfwInputJoystickAxis(js, ai, value); ai++; break; } case _GLFW_TYPE_BUTTON: { const char value = (*((BYTE*) data) & 0x80) != 0; _glfwInputJoystickButton(js, bi, value); bi++; break; } case _GLFW_TYPE_POV: { const int states[9] = { GLFW_HAT_UP, GLFW_HAT_RIGHT_UP, GLFW_HAT_RIGHT, GLFW_HAT_RIGHT_DOWN, GLFW_HAT_DOWN, GLFW_HAT_LEFT_DOWN, GLFW_HAT_LEFT, GLFW_HAT_LEFT_UP, GLFW_HAT_CENTERED }; // Screams of horror are appropriate at this point int stateIndex = LOWORD(*(DWORD*) data) / (45 * DI_DEGREES); if (stateIndex < 0 || stateIndex > 8) stateIndex = 8; _glfwInputJoystickHat(js, pi, states[stateIndex]); pi++; break; } } } } else { int i, dpad = 0; DWORD result; XINPUT_STATE xis; const WORD buttons[10] = { XINPUT_GAMEPAD_A, XINPUT_GAMEPAD_B, XINPUT_GAMEPAD_X, XINPUT_GAMEPAD_Y, XINPUT_GAMEPAD_LEFT_SHOULDER, XINPUT_GAMEPAD_RIGHT_SHOULDER, XINPUT_GAMEPAD_BACK, XINPUT_GAMEPAD_START, XINPUT_GAMEPAD_LEFT_THUMB, XINPUT_GAMEPAD_RIGHT_THUMB }; result = XInputGetState(js->win32.index, &xis); if (result != ERROR_SUCCESS) { if (result == ERROR_DEVICE_NOT_CONNECTED) closeJoystick(js); return GLFW_FALSE; } if (mode == _GLFW_POLL_PRESENCE) return GLFW_TRUE; _glfwInputJoystickAxis(js, 0, (xis.Gamepad.sThumbLX + 0.5f) / 32767.5f); _glfwInputJoystickAxis(js, 1, -(xis.Gamepad.sThumbLY + 0.5f) / 32767.5f); _glfwInputJoystickAxis(js, 2, (xis.Gamepad.sThumbRX + 0.5f) / 32767.5f); _glfwInputJoystickAxis(js, 3, -(xis.Gamepad.sThumbRY + 0.5f) / 32767.5f); _glfwInputJoystickAxis(js, 4, xis.Gamepad.bLeftTrigger / 127.5f - 1.f); _glfwInputJoystickAxis(js, 5, xis.Gamepad.bRightTrigger / 127.5f - 1.f); for (i = 0; i < 10; i++) { const char value = (xis.Gamepad.wButtons & buttons[i]) ? 1 : 0; _glfwInputJoystickButton(js, i, value); } if (xis.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP) dpad |= GLFW_HAT_UP; if (xis.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) dpad |= GLFW_HAT_RIGHT; if (xis.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN) dpad |= GLFW_HAT_DOWN; if (xis.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT) dpad |= GLFW_HAT_LEFT; _glfwInputJoystickHat(js, 0, dpad); } return GLFW_TRUE; } void _glfwPlatformUpdateGamepadGUID(char* guid) { if (strcmp(guid + 20, "504944564944") == 0) { char original[33]; strncpy(original, guid, sizeof(original) - 1); sprintf(guid, "03000000%.4s0000%.4s000000000000", original, original + 4); } } #endif #ifndef HEADER_GUARD_WIN32_MONITOR_C #define HEADER_GUARD_WIN32_MONITOR_C //======================================================================== // GLFW 3.3.7 Win32 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2019 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== // Please use C89 style variable declarations in this file because VS 2010 //======================================================================== #include #include #include #include #include // Callback for EnumDisplayMonitors in createMonitor // static BOOL CALLBACK monitorCallback(HMONITOR handle, HDC dc, RECT* rect, LPARAM data) { #ifdef __TINYC__ //< @r-lyeh MONITORINFOEXW mi = { sizeof(MONITORINFOEXW) }; //< @r-lyeh #else //< @r-lyeh MONITORINFOEXW mi; ZeroMemory(&mi, sizeof(mi)); mi.cbSize = sizeof(mi); #endif //< @r-lyeh if (GetMonitorInfoW(handle, (MONITORINFO*) &mi)) { _GLFWmonitor* monitor = (_GLFWmonitor*) data; if (wcscmp(mi.szDevice, monitor->win32.adapterName) == 0) monitor->win32.handle = handle; } return TRUE; } // Create monitor from an adapter and (optionally) a display // static _GLFWmonitor* createMonitor(DISPLAY_DEVICEW* adapter, DISPLAY_DEVICEW* display) { _GLFWmonitor* monitor; int widthMM, heightMM; char* name; HDC dc; DEVMODEW dm; RECT rect; if (display) name = _glfwCreateUTF8FromWideStringWin32(display->DeviceString); else name = _glfwCreateUTF8FromWideStringWin32(adapter->DeviceString); if (!name) return NULL; ZeroMemory(&dm, sizeof(dm)); dm.dmSize = sizeof(dm); EnumDisplaySettingsW(adapter->DeviceName, ENUM_CURRENT_SETTINGS, &dm); dc = CreateDCW(L"DISPLAY", adapter->DeviceName, NULL, NULL); if (IsWindows8Point1OrGreater()) { widthMM = GetDeviceCaps(dc, HORZSIZE); heightMM = GetDeviceCaps(dc, VERTSIZE); } else { widthMM = (int) (dm.dmPelsWidth * 25.4f / GetDeviceCaps(dc, LOGPIXELSX)); heightMM = (int) (dm.dmPelsHeight * 25.4f / GetDeviceCaps(dc, LOGPIXELSY)); } DeleteDC(dc); monitor = _glfwAllocMonitor(name, widthMM, heightMM); free(name); if (adapter->StateFlags & DISPLAY_DEVICE_MODESPRUNED) monitor->win32.modesPruned = GLFW_TRUE; wcscpy(monitor->win32.adapterName, adapter->DeviceName); WideCharToMultiByte(CP_UTF8, 0, adapter->DeviceName, -1, monitor->win32.publicAdapterName, sizeof(monitor->win32.publicAdapterName), NULL, NULL); if (display) { wcscpy(monitor->win32.displayName, display->DeviceName); WideCharToMultiByte(CP_UTF8, 0, display->DeviceName, -1, monitor->win32.publicDisplayName, sizeof(monitor->win32.publicDisplayName), NULL, NULL); } rect.left = dm.dmPosition.x; rect.top = dm.dmPosition.y; rect.right = dm.dmPosition.x + dm.dmPelsWidth; rect.bottom = dm.dmPosition.y + dm.dmPelsHeight; EnumDisplayMonitors(NULL, &rect, monitorCallback, (LPARAM) monitor); return monitor; } ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// // Poll for changes in the set of connected monitors // void _glfwPollMonitorsWin32(void) { int i, disconnectedCount; _GLFWmonitor** disconnected = NULL; DWORD adapterIndex, displayIndex; DISPLAY_DEVICEW adapter, display; _GLFWmonitor* monitor; disconnectedCount = _glfw.monitorCount; if (disconnectedCount) { disconnected = calloc(_glfw.monitorCount, sizeof(_GLFWmonitor*)); memcpy(disconnected, _glfw.monitors, _glfw.monitorCount * sizeof(_GLFWmonitor*)); } for (adapterIndex = 0; ; adapterIndex++) { int type = _GLFW_INSERT_LAST; ZeroMemory(&adapter, sizeof(adapter)); adapter.cb = sizeof(adapter); if (!EnumDisplayDevicesW(NULL, adapterIndex, &adapter, 0)) break; if (!(adapter.StateFlags & DISPLAY_DEVICE_ACTIVE)) continue; if (adapter.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) type = _GLFW_INSERT_FIRST; for (displayIndex = 0; ; displayIndex++) { ZeroMemory(&display, sizeof(display)); display.cb = sizeof(display); if (!EnumDisplayDevicesW(adapter.DeviceName, displayIndex, &display, 0)) break; if (!(display.StateFlags & DISPLAY_DEVICE_ACTIVE)) continue; for (i = 0; i < disconnectedCount; i++) { if (disconnected[i] && wcscmp(disconnected[i]->win32.displayName, display.DeviceName) == 0) { disconnected[i] = NULL; // handle may have changed, update EnumDisplayMonitors(NULL, NULL, monitorCallback, (LPARAM) _glfw.monitors[i]); break; } } if (i < disconnectedCount) continue; monitor = createMonitor(&adapter, &display); if (!monitor) { free(disconnected); return; } _glfwInputMonitor(monitor, GLFW_CONNECTED, type); type = _GLFW_INSERT_LAST; } // HACK: If an active adapter does not have any display devices // (as sometimes happens), add it directly as a monitor if (displayIndex == 0) { for (i = 0; i < disconnectedCount; i++) { if (disconnected[i] && wcscmp(disconnected[i]->win32.adapterName, adapter.DeviceName) == 0) { disconnected[i] = NULL; break; } } if (i < disconnectedCount) continue; monitor = createMonitor(&adapter, NULL); if (!monitor) { free(disconnected); return; } _glfwInputMonitor(monitor, GLFW_CONNECTED, type); } } for (i = 0; i < disconnectedCount; i++) { if (disconnected[i]) _glfwInputMonitor(disconnected[i], GLFW_DISCONNECTED, 0); } free(disconnected); } // Change the current video mode // void _glfwSetVideoModeWin32(_GLFWmonitor* monitor, const GLFWvidmode* desired) { GLFWvidmode current; const GLFWvidmode* best; DEVMODEW dm; LONG result; best = _glfwChooseVideoMode(monitor, desired); _glfwPlatformGetVideoMode(monitor, ¤t); if (_glfwCompareVideoModes(¤t, best) == 0) return; ZeroMemory(&dm, sizeof(dm)); dm.dmSize = sizeof(dm); dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_DISPLAYFREQUENCY; dm.dmPelsWidth = best->width; dm.dmPelsHeight = best->height; dm.dmBitsPerPel = best->redBits + best->greenBits + best->blueBits; dm.dmDisplayFrequency = best->refreshRate; if (dm.dmBitsPerPel < 15 || dm.dmBitsPerPel >= 24) dm.dmBitsPerPel = 32; result = ChangeDisplaySettingsExW(monitor->win32.adapterName, &dm, NULL, CDS_FULLSCREEN, NULL); if (result == DISP_CHANGE_SUCCESSFUL) monitor->win32.modeChanged = GLFW_TRUE; else { const char* description = "Unknown error"; if (result == DISP_CHANGE_BADDUALVIEW) description = "The system uses DualView"; else if (result == DISP_CHANGE_BADFLAGS) description = "Invalid flags"; else if (result == DISP_CHANGE_BADMODE) description = "Graphics mode not supported"; else if (result == DISP_CHANGE_BADPARAM) description = "Invalid parameter"; else if (result == DISP_CHANGE_FAILED) description = "Graphics mode failed"; else if (result == DISP_CHANGE_NOTUPDATED) description = "Failed to write to registry"; else if (result == DISP_CHANGE_RESTART) description = "Computer restart required"; _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to set video mode: %s", description); } } // Restore the previously saved (original) video mode // void _glfwRestoreVideoModeWin32(_GLFWmonitor* monitor) { if (monitor->win32.modeChanged) { ChangeDisplaySettingsExW(monitor->win32.adapterName, NULL, NULL, CDS_FULLSCREEN, NULL); monitor->win32.modeChanged = GLFW_FALSE; } } void _glfwGetMonitorContentScaleWin32(HMONITOR handle, float* xscale, float* yscale) { UINT xdpi, ydpi; if (xscale) *xscale = 0.f; if (yscale) *yscale = 0.f; if (IsWindows8Point1OrGreater()) { 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); xdpi = GetDeviceCaps(dc, LOGPIXELSX); ydpi = GetDeviceCaps(dc, LOGPIXELSY); ReleaseDC(NULL, dc); } if (xscale) *xscale = xdpi / (float) USER_DEFAULT_SCREEN_DPI; if (yscale) *yscale = ydpi / (float) USER_DEFAULT_SCREEN_DPI; } ////////////////////////////////////////////////////////////////////////// ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor) { } void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) { DEVMODEW dm; ZeroMemory(&dm, sizeof(dm)); dm.dmSize = sizeof(dm); EnumDisplaySettingsExW(monitor->win32.adapterName, ENUM_CURRENT_SETTINGS, &dm, EDS_ROTATEDMODE); if (xpos) *xpos = dm.dmPosition.x; if (ypos) *ypos = dm.dmPosition.y; } void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor, float* xscale, float* yscale) { _glfwGetMonitorContentScaleWin32(monitor->win32.handle, xscale, yscale); } void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor, int* xpos, int* ypos, int* width, int* height) { MONITORINFO mi = { sizeof(mi) }; GetMonitorInfoW(monitor->win32.handle, &mi); if (xpos) *xpos = mi.rcWork.left; if (ypos) *ypos = mi.rcWork.top; if (width) *width = mi.rcWork.right - mi.rcWork.left; if (height) *height = mi.rcWork.bottom - mi.rcWork.top; } GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count) { int modeIndex = 0, size = 0; GLFWvidmode* result = NULL; *count = 0; for (;;) { int i; GLFWvidmode mode; DEVMODEW dm; ZeroMemory(&dm, sizeof(dm)); dm.dmSize = sizeof(dm); if (!EnumDisplaySettingsW(monitor->win32.adapterName, modeIndex, &dm)) break; modeIndex++; // Skip modes with less than 15 BPP if (dm.dmBitsPerPel < 15) continue; mode.width = dm.dmPelsWidth; mode.height = dm.dmPelsHeight; mode.refreshRate = dm.dmDisplayFrequency; _glfwSplitBPP(dm.dmBitsPerPel, &mode.redBits, &mode.greenBits, &mode.blueBits); for (i = 0; i < *count; i++) { if (_glfwCompareVideoModes(result + i, &mode) == 0) break; } // Skip duplicate modes if (i < *count) continue; if (monitor->win32.modesPruned) { // Skip modes not supported by the connected displays if (ChangeDisplaySettingsExW(monitor->win32.adapterName, &dm, NULL, CDS_TEST, NULL) != DISP_CHANGE_SUCCESSFUL) { continue; } } if (*count == size) { size += 128; result = (GLFWvidmode*) realloc(result, size * sizeof(GLFWvidmode)); } (*count)++; result[*count - 1] = mode; } if (!*count) { // HACK: Report the current mode if no valid modes were found result = calloc(1, sizeof(GLFWvidmode)); _glfwPlatformGetVideoMode(monitor, result); *count = 1; } return result; } void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode) { DEVMODEW dm; ZeroMemory(&dm, sizeof(dm)); dm.dmSize = sizeof(dm); EnumDisplaySettingsW(monitor->win32.adapterName, ENUM_CURRENT_SETTINGS, &dm); mode->width = dm.dmPelsWidth; mode->height = dm.dmPelsHeight; mode->refreshRate = dm.dmDisplayFrequency; _glfwSplitBPP(dm.dmBitsPerPel, &mode->redBits, &mode->greenBits, &mode->blueBits); } GLFWbool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) { HDC dc; WORD values[3][256]; dc = CreateDCW(L"DISPLAY", monitor->win32.adapterName, NULL, NULL); GetDeviceGammaRamp(dc, values); DeleteDC(dc); _glfwAllocGammaArrays(ramp, 256); memcpy(ramp->red, values[0], sizeof(values[0])); memcpy(ramp->green, values[1], sizeof(values[1])); memcpy(ramp->blue, values[2], sizeof(values[2])); return GLFW_TRUE; } void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) { HDC dc; WORD values[3][256]; if (ramp->size != 256) { _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Gamma ramp size must be 256"); return; } memcpy(values[0], ramp->red, sizeof(values[0])); memcpy(values[1], ramp->green, sizeof(values[1])); memcpy(values[2], ramp->blue, sizeof(values[2])); dc = CreateDCW(L"DISPLAY", monitor->win32.adapterName, NULL, NULL); SetDeviceGammaRamp(dc, values); DeleteDC(dc); } ////////////////////////////////////////////////////////////////////////// ////// GLFW native API ////// ////////////////////////////////////////////////////////////////////////// GLFWAPI const char* glfwGetWin32Adapter(GLFWmonitor* handle) { _GLFWmonitor* monitor = (_GLFWmonitor*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(NULL); return monitor->win32.publicAdapterName; } GLFWAPI const char* glfwGetWin32Monitor(GLFWmonitor* handle) { _GLFWmonitor* monitor = (_GLFWmonitor*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(NULL); return monitor->win32.publicDisplayName; } #endif #ifndef HEADER_GUARD_WIN32_TIME_C #define HEADER_GUARD_WIN32_TIME_C //======================================================================== // GLFW 3.3.7 Win32 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2017 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== // Please use C89 style variable declarations in this file because VS 2010 //======================================================================== ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// // Initialise timer // void _glfwInitTimerWin32(void) { QueryPerformanceFrequency((LARGE_INTEGER*) &_glfw.timer.win32.frequency); } ////////////////////////////////////////////////////////////////////////// ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// uint64_t _glfwPlatformGetTimerValue(void) { uint64_t value; QueryPerformanceCounter((LARGE_INTEGER*) &value); return value; } uint64_t _glfwPlatformGetTimerFrequency(void) { return _glfw.timer.win32.frequency; } #endif #ifndef HEADER_GUARD_WIN32_THREAD_C #define HEADER_GUARD_WIN32_THREAD_C //======================================================================== // GLFW 3.3.7 Win32 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2017 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== // Please use C89 style variable declarations in this file because VS 2010 //======================================================================== #include ////////////////////////////////////////////////////////////////////////// ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// GLFWbool _glfwPlatformCreateTls(_GLFWtls* tls) { assert(tls->win32.allocated == GLFW_FALSE); tls->win32.index = TlsAlloc(); if (tls->win32.index == TLS_OUT_OF_INDEXES) { _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, "Win32: Failed to allocate TLS index"); return GLFW_FALSE; } tls->win32.allocated = GLFW_TRUE; return GLFW_TRUE; } void _glfwPlatformDestroyTls(_GLFWtls* tls) { if (tls->win32.allocated) TlsFree(tls->win32.index); memset(tls, 0, sizeof(_GLFWtls)); } void* _glfwPlatformGetTls(_GLFWtls* tls) { assert(tls->win32.allocated == GLFW_TRUE); return TlsGetValue(tls->win32.index); } void _glfwPlatformSetTls(_GLFWtls* tls, void* value) { assert(tls->win32.allocated == GLFW_TRUE); TlsSetValue(tls->win32.index, value); } GLFWbool _glfwPlatformCreateMutex(_GLFWmutex* mutex) { assert(mutex->win32.allocated == GLFW_FALSE); InitializeCriticalSection(&mutex->win32.section); return mutex->win32.allocated = GLFW_TRUE; } void _glfwPlatformDestroyMutex(_GLFWmutex* mutex) { if (mutex->win32.allocated) DeleteCriticalSection(&mutex->win32.section); memset(mutex, 0, sizeof(_GLFWmutex)); } void _glfwPlatformLockMutex(_GLFWmutex* mutex) { assert(mutex->win32.allocated == GLFW_TRUE); EnterCriticalSection(&mutex->win32.section); } void _glfwPlatformUnlockMutex(_GLFWmutex* mutex) { assert(mutex->win32.allocated == GLFW_TRUE); LeaveCriticalSection(&mutex->win32.section); } #endif #ifndef HEADER_GUARD_WIN32_WINDOW_C #define HEADER_GUARD_WIN32_WINDOW_C //======================================================================== // GLFW 3.3.7 Win32 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2019 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== // Please use C89 style variable declarations in this file because VS 2010 //======================================================================== #include #include #include #include #include #include // Returns the window style for the specified window // static DWORD getWindowStyle(const _GLFWwindow* window) { DWORD style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN; if (window->monitor) style |= WS_POPUP; else { style |= WS_SYSMENU | WS_MINIMIZEBOX; if (window->decorated) { style |= WS_CAPTION; if (window->resizable) style |= WS_MAXIMIZEBOX | WS_THICKFRAME; } else style |= WS_POPUP; } return style; } // Returns the extended window style for the specified window // static DWORD getWindowExStyle(const _GLFWwindow* window) { DWORD style = WS_EX_APPWINDOW; if (window->monitor || window->floating) style |= WS_EX_TOPMOST; return style; } // Returns the image whose area most closely matches the desired one // static const GLFWimage* chooseImage(int count, const GLFWimage* images, int width, int height) { int i, leastDiff = INT_MAX; const GLFWimage* closest = NULL; for (i = 0; i < count; i++) { const int currDiff = abs(images[i].width * images[i].height - width * height); if (currDiff < leastDiff) { closest = images + i; leastDiff = currDiff; } } return closest; } // Creates an RGBA icon or cursor // static HICON createIcon(const GLFWimage* image, int xhot, int yhot, GLFWbool icon) { int i; HDC dc; HICON handle; HBITMAP color, mask; BITMAPV5HEADER bi; ICONINFO ii; unsigned char* target = NULL; unsigned char* source = image->pixels; ZeroMemory(&bi, sizeof(bi)); bi.bV5Size = sizeof(bi); bi.bV5Width = image->width; bi.bV5Height = -image->height; bi.bV5Planes = 1; bi.bV5BitCount = 32; bi.bV5Compression = BI_BITFIELDS; bi.bV5RedMask = 0x00ff0000; bi.bV5GreenMask = 0x0000ff00; bi.bV5BlueMask = 0x000000ff; bi.bV5AlphaMask = 0xff000000; dc = GetDC(NULL); color = CreateDIBSection(dc, (BITMAPINFO*) &bi, DIB_RGB_COLORS, (void**) &target, NULL, (DWORD) 0); ReleaseDC(NULL, dc); if (!color) { _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, "Win32: Failed to create RGBA bitmap"); return NULL; } mask = CreateBitmap(image->width, image->height, 1, 1, NULL); if (!mask) { _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, "Win32: Failed to create mask bitmap"); DeleteObject(color); return NULL; } for (i = 0; i < image->width * image->height; i++) { target[0] = source[2]; target[1] = source[1]; target[2] = source[0]; target[3] = source[3]; target += 4; source += 4; } ZeroMemory(&ii, sizeof(ii)); ii.fIcon = icon; ii.xHotspot = xhot; ii.yHotspot = yhot; ii.hbmMask = mask; ii.hbmColor = color; handle = CreateIconIndirect(&ii); DeleteObject(color); DeleteObject(mask); if (!handle) { if (icon) { _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, "Win32: Failed to create icon"); } else { _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, "Win32: Failed to create cursor"); } } 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; const float ratio = (float) window->numer / (float) window->denom; if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) dpi = GetDpiForWindow(window->win32.handle); getFullWindowSize(getWindowStyle(window), getWindowExStyle(window), 0, 0, &xoff, &yoff, dpi); 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); } else if (edge == WMSZ_TOPLEFT || edge == WMSZ_TOPRIGHT) { area->top = area->bottom - yoff - (int) ((area->right - area->left - xoff) / ratio); } else if (edge == WMSZ_TOP || edge == WMSZ_BOTTOM) { area->right = area->left + xoff + (int) ((area->bottom - area->top - yoff) * ratio); } } // Updates the cursor image according to its cursor mode // static void updateCursorImage(_GLFWwindow* window) { if (window->cursorMode == GLFW_CURSOR_NORMAL) { if (window->cursor) SetCursor(window->cursor->win32.handle); else SetCursor(LoadCursorW(NULL, IDC_ARROW)); } else SetCursor(NULL); } // Updates the cursor clip rect // static void updateClipRect(_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); } // Enables WM_INPUT messages for the mouse for the specified window // static void enableRawMouseMotion(_GLFWwindow* window) { const RAWINPUTDEVICE rid = { 0x01, 0x02, 0, window->win32.handle }; if (!RegisterRawInputDevices(&rid, 1, sizeof(rid))) { _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, "Win32: Failed to register raw input device"); } } // Disables WM_INPUT messages for the mouse // static void disableRawMouseMotion(_GLFWwindow* window) { const RAWINPUTDEVICE rid = { 0x01, 0x02, RIDEV_REMOVE, NULL }; if (!RegisterRawInputDevices(&rid, 1, sizeof(rid))) { _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, "Win32: Failed to remove raw input device"); } } // Apply disabled cursor mode to a focused window // static void disableCursor(_GLFWwindow* window) { _glfw.win32.disabledCursorWindow = window; _glfwPlatformGetCursorPos(window, &_glfw.win32.restoreCursorPosX, &_glfw.win32.restoreCursorPosY); updateCursorImage(window); _glfwCenterCursorInContentArea(window); updateClipRect(window); if (window->rawMouseMotion) enableRawMouseMotion(window); } // Exit disabled cursor mode for the specified window // static void enableCursor(_GLFWwindow* window) { if (window->rawMouseMotion) disableRawMouseMotion(window); _glfw.win32.disabledCursorWindow = NULL; updateClipRect(NULL); _glfwPlatformSetCursorPos(window, _glfw.win32.restoreCursorPosX, _glfw.win32.restoreCursorPosY); updateCursorImage(window); } // Returns whether the cursor is in the content area of the specified window // static GLFWbool cursorInContentArea(_GLFWwindow* window) { RECT area; POINT pos; if (!GetCursorPos(&pos)) return GLFW_FALSE; if (WindowFromPoint(pos) != window->win32.handle) return GLFW_FALSE; GetClientRect(window->win32.handle, &area); ClientToScreen(window->win32.handle, (POINT*) &area.left); ClientToScreen(window->win32.handle, (POINT*) &area.right); return PtInRect(&area, pos); } // Update native window styles to match attributes // static void updateWindowStyles(const _GLFWwindow* window) { RECT rect; DWORD style = GetWindowLongW(window->win32.handle, GWL_STYLE); style &= ~(WS_OVERLAPPEDWINDOW | WS_POPUP); style |= getWindowStyle(window); GetClientRect(window->win32.handle, &rect); if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) { AdjustWindowRectExForDpi(&rect, style, FALSE, getWindowExStyle(window), GetDpiForWindow(window->win32.handle)); } else AdjustWindowRectEx(&rect, style, FALSE, getWindowExStyle(window)); ClientToScreen(window->win32.handle, (POINT*) &rect.left); ClientToScreen(window->win32.handle, (POINT*) &rect.right); SetWindowLongW(window->win32.handle, GWL_STYLE, style); SetWindowPos(window->win32.handle, HWND_TOP, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOZORDER); } // Update window framebuffer transparency // static void updateFramebufferTransparency(const _GLFWwindow* window) { BOOL composition, opaque; DWORD color; if (!IsWindowsVistaOrGreater()) return; if (FAILED(DwmIsCompositionEnabled(&composition)) || !composition) return; if (IsWindows8OrGreater() || (SUCCEEDED(DwmGetColorizationColor(&color, &opaque)) && !opaque)) { HRGN region = CreateRectRgn(0, 0, -1, -1); DWM_BLURBEHIND bb = {0}; bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION; bb.hRgnBlur = region; bb.fEnable = TRUE; DwmEnableBlurBehindWindow(window->win32.handle, &bb); DeleteObject(region); } else { // 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); } } // Retrieves and translates modifier keys // static int getKeyMods(void) { int mods = 0; if (GetKeyState(VK_SHIFT) & 0x8000) mods |= GLFW_MOD_SHIFT; if (GetKeyState(VK_CONTROL) & 0x8000) mods |= GLFW_MOD_CONTROL; if (GetKeyState(VK_MENU) & 0x8000) mods |= GLFW_MOD_ALT; if ((GetKeyState(VK_LWIN) | GetKeyState(VK_RWIN)) & 0x8000) mods |= GLFW_MOD_SUPER; if (GetKeyState(VK_CAPITAL) & 1) mods |= GLFW_MOD_CAPS_LOCK; if (GetKeyState(VK_NUMLOCK) & 1) mods |= GLFW_MOD_NUM_LOCK; return mods; } static void fitToMonitor(_GLFWwindow* window) { MONITORINFO mi = { sizeof(mi) }; GetMonitorInfoW(window->monitor->win32.handle, &mi); SetWindowPos(window->win32.handle, HWND_TOPMOST, mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right - mi.rcMonitor.left, mi.rcMonitor.bottom - mi.rcMonitor.top, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOCOPYBITS); } // Make the specified window and its video mode active on its monitor // static void acquireMonitor(_GLFWwindow* window) { if (!_glfw.win32.acquiredMonitorCount) { SetThreadExecutionState(ES_CONTINUOUS | ES_DISPLAY_REQUIRED); // HACK: When mouse trails are enabled the cursor becomes invisible when // the OpenGL ICD switches to page flipping if (IsWindowsXPOrGreater()) { SystemParametersInfoW(SPI_GETMOUSETRAILS, 0, &_glfw.win32.mouseTrailSize, 0); SystemParametersInfoW(SPI_SETMOUSETRAILS, 0, 0, 0); } } if (!window->monitor->window) _glfw.win32.acquiredMonitorCount++; _glfwSetVideoModeWin32(window->monitor, &window->videoMode); _glfwInputMonitorWindow(window->monitor, window); } // Remove the window and restore the original video mode // static void releaseMonitor(_GLFWwindow* window) { if (window->monitor->window != window) return; _glfw.win32.acquiredMonitorCount--; if (!_glfw.win32.acquiredMonitorCount) { SetThreadExecutionState(ES_CONTINUOUS); // HACK: Restore mouse trail length saved in acquireMonitor if (IsWindowsXPOrGreater()) 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) { if (rect.right - rect.left > window->maxwidth) rect.right = rect.left + window->maxwidth; if (rect.bottom - rect.top > window->maxheight) 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)); } if (rect.bottom > mi.rcWork.bottom) 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, WPARAM wParam, LPARAM lParam) { _GLFWwindow* window = GetPropW(hWnd, L"GLFW"); if (!window) { // This is the message handling for the hidden helper window // and for a regular window during its initial creation switch (uMsg) { case WM_NCCREATE: { if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) { 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; } case WM_DISPLAYCHANGE: _glfwPollMonitorsWin32(); break; case WM_DEVICECHANGE: { if (wParam == DBT_DEVICEARRIVAL) { DEV_BROADCAST_HDR* dbh = (DEV_BROADCAST_HDR*) lParam; if (dbh && dbh->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) _glfwDetectJoystickConnectionWin32(); } else if (wParam == DBT_DEVICEREMOVECOMPLETE) { DEV_BROADCAST_HDR* dbh = (DEV_BROADCAST_HDR*) lParam; if (dbh && dbh->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) _glfwDetectJoystickDisconnectionWin32(); } break; } } return DefWindowProcW(hWnd, uMsg, wParam, lParam); } switch (uMsg) { case WM_MOUSEACTIVATE: { // HACK: Postpone cursor disabling when the window was activated by // clicking a caption button if (HIWORD(lParam) == WM_LBUTTONDOWN) { if (LOWORD(lParam) != HTCLIENT) window->win32.frameAction = GLFW_TRUE; } break; } case WM_CAPTURECHANGED: { // HACK: Disable the cursor once the caption button action has been // completed or cancelled if (lParam == 0 && window->win32.frameAction) { if (window->cursorMode == GLFW_CURSOR_DISABLED) disableCursor(window); window->win32.frameAction = GLFW_FALSE; } break; } case WM_SETFOCUS: { _glfwInputWindowFocus(window, GLFW_TRUE); // HACK: Do not disable cursor while the user is interacting with // a caption button if (window->win32.frameAction) break; if (window->cursorMode == GLFW_CURSOR_DISABLED) disableCursor(window); return 0; } case WM_KILLFOCUS: { if (window->cursorMode == GLFW_CURSOR_DISABLED) enableCursor(window); if (window->monitor && window->autoIconify) _glfwPlatformIconifyWindow(window); _glfwInputWindowFocus(window, GLFW_FALSE); return 0; } case WM_SYSCOMMAND: { switch (wParam & 0xfff0) { case SC_SCREENSAVE: case SC_MONITORPOWER: { if (window->monitor) { // We are running in full screen mode, so disallow // screen saver and screen blanking return 0; } else break; } // User trying to access application menu using ALT? case SC_KEYMENU: return 0; } break; } case WM_CLOSE: { _glfwInputWindowCloseRequest(window); return 0; } case WM_INPUTLANGCHANGE: { _glfwUpdateKeyNamesWin32(); break; } case WM_CHAR: case WM_SYSCHAR: { if (wParam >= 0xd800 && wParam <= 0xdbff) window->win32.highSurrogate = (WCHAR) wParam; else { uint32_t codepoint = 0; 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 // Returning TRUE here announces support for this message return TRUE; } _glfwInputChar(window, (uint32_t) wParam, getKeyMods(), GLFW_TRUE); return 0; } case WM_KEYDOWN: case WM_SYSKEYDOWN: case WM_KEYUP: case WM_SYSKEYUP: { int key, scancode; const int action = (HIWORD(lParam) & KF_UP) ? GLFW_RELEASE : GLFW_PRESS; const int mods = getKeyMods(); scancode = (HIWORD(lParam) & (KF_EXTENDED | 0xff)); if (!scancode) { // NOTE: Some synthetic key messages have a scancode of zero // HACK: Map the virtual key back to a usable scancode scancode = MapVirtualKeyW((UINT) wParam, MAPVK_VK_TO_VSC); } key = _glfw.win32.keycodes[scancode]; // The Ctrl keys require special handling if (wParam == VK_CONTROL) { if (HIWORD(lParam) & KF_EXTENDED) { // Right side keys have the extended key bit set key = GLFW_KEY_RIGHT_CONTROL; } else { // NOTE: Alt Gr sends Left Ctrl followed by Right Alt // HACK: We only want one event for Alt Gr, so if we detect // this sequence we discard this Left Ctrl message now // and later report Right Alt normally MSG next; const DWORD time = GetMessageTime(); if (PeekMessageW(&next, NULL, 0, 0, PM_NOREMOVE)) { if (next.message == WM_KEYDOWN || next.message == WM_SYSKEYDOWN || next.message == WM_KEYUP || next.message == WM_SYSKEYUP) { if (next.wParam == VK_MENU && (HIWORD(next.lParam) & KF_EXTENDED) && next.time == time) { // Next message is Right Alt down so discard this break; } } } // This is a regular Left Ctrl message key = GLFW_KEY_LEFT_CONTROL; } } else if (wParam == VK_PROCESSKEY) { // IME notifies that keys have been filtered by setting the // virtual key-code to VK_PROCESSKEY break; } if (action == GLFW_RELEASE && wParam == VK_SHIFT) { // HACK: Release both Shift keys on Shift up event, as when both // are pressed the first release does not emit any event // NOTE: The other half of this is in _glfwPlatformPollEvents _glfwInputKey(window, GLFW_KEY_LEFT_SHIFT, scancode, action, mods); _glfwInputKey(window, GLFW_KEY_RIGHT_SHIFT, scancode, action, mods); } else if (wParam == VK_SNAPSHOT) { // HACK: Key down is not reported for the Print Screen key _glfwInputKey(window, key, scancode, GLFW_PRESS, mods); _glfwInputKey(window, key, scancode, GLFW_RELEASE, mods); } else _glfwInputKey(window, key, scancode, action, mods); break; } case WM_LBUTTONDOWN: case WM_RBUTTONDOWN: case WM_MBUTTONDOWN: case WM_XBUTTONDOWN: case WM_LBUTTONUP: case WM_RBUTTONUP: case WM_MBUTTONUP: case WM_XBUTTONUP: { int i, button, action; if (uMsg == WM_LBUTTONDOWN || uMsg == WM_LBUTTONUP) button = GLFW_MOUSE_BUTTON_LEFT; else if (uMsg == WM_RBUTTONDOWN || uMsg == WM_RBUTTONUP) button = GLFW_MOUSE_BUTTON_RIGHT; else if (uMsg == WM_MBUTTONDOWN || uMsg == WM_MBUTTONUP) button = GLFW_MOUSE_BUTTON_MIDDLE; else if (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) button = GLFW_MOUSE_BUTTON_4; else button = GLFW_MOUSE_BUTTON_5; if (uMsg == WM_LBUTTONDOWN || uMsg == WM_RBUTTONDOWN || uMsg == WM_MBUTTONDOWN || uMsg == WM_XBUTTONDOWN) { action = GLFW_PRESS; } else action = GLFW_RELEASE; for (i = 0; i <= GLFW_MOUSE_BUTTON_LAST; i++) { if (window->mouseButtons[i] == GLFW_PRESS) break; } if (i > GLFW_MOUSE_BUTTON_LAST) SetCapture(hWnd); _glfwInputMouseClick(window, button, action, getKeyMods()); for (i = 0; i <= GLFW_MOUSE_BUTTON_LAST; i++) { if (window->mouseButtons[i] == GLFW_PRESS) break; } if (i > GLFW_MOUSE_BUTTON_LAST) ReleaseCapture(); if (uMsg == WM_XBUTTONDOWN || uMsg == WM_XBUTTONUP) return TRUE; return 0; } case WM_MOUSEMOVE: { const int x = GET_X_LPARAM(lParam); const int y = GET_Y_LPARAM(lParam); if (!window->win32.cursorTracked) { TRACKMOUSEEVENT tme; ZeroMemory(&tme, sizeof(tme)); tme.cbSize = sizeof(tme); tme.dwFlags = TME_LEAVE; tme.hwndTrack = window->win32.handle; TrackMouseEvent(&tme); window->win32.cursorTracked = GLFW_TRUE; _glfwInputCursorEnter(window, GLFW_TRUE); } if (window->cursorMode == GLFW_CURSOR_DISABLED) { const int dx = x - window->win32.lastCursorPosX; const int dy = y - window->win32.lastCursorPosY; if (_glfw.win32.disabledCursorWindow != window) break; if (window->rawMouseMotion) break; _glfwInputCursorPos(window, window->virtualCursorPosX + dx, window->virtualCursorPosY + dy); } else _glfwInputCursorPos(window, x, y); window->win32.lastCursorPosX = x; window->win32.lastCursorPosY = y; return 0; } case WM_INPUT: { UINT size = 0; HRAWINPUT ri = (HRAWINPUT) lParam; RAWINPUT* data = NULL; int dx, dy; if (_glfw.win32.disabledCursorWindow != window) break; if (!window->rawMouseMotion) break; GetRawInputData(ri, RID_INPUT, NULL, &size, sizeof(RAWINPUTHEADER)); if (size > (UINT) _glfw.win32.rawInputSize) { free(_glfw.win32.rawInput); _glfw.win32.rawInput = calloc(size, 1); _glfw.win32.rawInputSize = size; } size = _glfw.win32.rawInputSize; if (GetRawInputData(ri, RID_INPUT, _glfw.win32.rawInput, &size, sizeof(RAWINPUTHEADER)) == (UINT) -1) { _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to retrieve raw input data"); break; } data = _glfw.win32.rawInput; if (data->data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE) { dx = data->data.mouse.lLastX - window->win32.lastCursorPosX; dy = data->data.mouse.lLastY - window->win32.lastCursorPosY; } else { dx = data->data.mouse.lLastX; dy = data->data.mouse.lLastY; } _glfwInputCursorPos(window, window->virtualCursorPosX + dx, window->virtualCursorPosY + dy); window->win32.lastCursorPosX += dx; window->win32.lastCursorPosY += dy; break; } case WM_MOUSELEAVE: { window->win32.cursorTracked = GLFW_FALSE; _glfwInputCursorEnter(window, GLFW_FALSE); return 0; } case WM_MOUSEWHEEL: { _glfwInputScroll(window, 0.0, (SHORT) HIWORD(wParam) / (double) WHEEL_DELTA); return 0; } case WM_MOUSEHWHEEL: { // This message is only sent on Windows Vista and later // NOTE: The X-axis is inverted for consistency with macOS and X11 _glfwInputScroll(window, -((SHORT) HIWORD(wParam) / (double) WHEEL_DELTA), 0.0); return 0; } case WM_ENTERSIZEMOVE: case WM_ENTERMENULOOP: { if (window->win32.frameAction) break; // HACK: Enable the cursor while the user is moving or // resizing the window or using the window menu if (window->cursorMode == GLFW_CURSOR_DISABLED) enableCursor(window); break; } case WM_EXITSIZEMOVE: case WM_EXITMENULOOP: { if (window->win32.frameAction) break; // HACK: Disable the cursor once the user is done moving or // resizing the window or using the menu if (window->cursorMode == GLFW_CURSOR_DISABLED) disableCursor(window); break; } 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 (window->win32.iconified != iconified) _glfwInputWindowIconify(window, iconified); if (window->win32.maximized != maximized) _glfwInputWindowMaximize(window, maximized); 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) releaseMonitor(window); else { acquireMonitor(window); fitToMonitor(window); } } window->win32.iconified = iconified; window->win32.maximized = maximized; return 0; } case WM_MOVE: { if (_glfw.win32.disabledCursorWindow == window) updateClipRect(window); // NOTE: This cannot use LOWORD/HIWORD recommended by MSDN, as // those macros do not handle negative window positions correctly _glfwInputWindowPos(window, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); return 0; } case WM_SIZING: { if (window->numer == GLFW_DONT_CARE || window->denom == GLFW_DONT_CARE) { break; } applyAspectRatio(window, (int) wParam, (RECT*) lParam); return TRUE; } case WM_GETMINMAXINFO: { int xoff, yoff; UINT dpi = USER_DEFAULT_SCREEN_DPI; MINMAXINFO* mmi = (MINMAXINFO*) lParam; if (window->monitor) break; if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) dpi = GetDpiForWindow(window->win32.handle); getFullWindowSize(getWindowStyle(window), getWindowExStyle(window), 0, 0, &xoff, &yoff, dpi); if (window->minwidth != GLFW_DONT_CARE && window->minheight != GLFW_DONT_CARE) { mmi->ptMinTrackSize.x = window->minwidth + xoff; mmi->ptMinTrackSize.y = window->minheight + yoff; } if (window->maxwidth != GLFW_DONT_CARE && window->maxheight != GLFW_DONT_CARE) { mmi->ptMaxTrackSize.x = window->maxwidth + xoff; mmi->ptMaxTrackSize.y = window->maxheight + yoff; } if (!window->decorated) { MONITORINFO mi; const HMONITOR mh = MonitorFromWindow(window->win32.handle, MONITOR_DEFAULTTONEAREST); ZeroMemory(&mi, sizeof(mi)); mi.cbSize = sizeof(mi); GetMonitorInfoW(mh, &mi); mmi->ptMaxPosition.x = mi.rcWork.left - mi.rcMonitor.left; mmi->ptMaxPosition.y = mi.rcWork.top - mi.rcMonitor.top; mmi->ptMaxSize.x = mi.rcWork.right - mi.rcWork.left; mmi->ptMaxSize.y = mi.rcWork.bottom - mi.rcWork.top; } return 0; } case WM_PAINT: { _glfwInputWindowDamage(window); break; } case WM_ERASEBKGND: { return TRUE; } case WM_NCACTIVATE: case WM_NCPAINT: { // Prevent title bar from being drawn after restoring a minimized // undecorated window if (!window->decorated) return TRUE; break; } case WM_DWMCOMPOSITIONCHANGED: case WM_DWMCOLORIZATIONCOLORCHANGED: { if (window->win32.transparent) updateFramebufferTransparency(window); return 0; } case WM_GETDPISCALEDSIZE: { if (window->win32.scaleToMonitor) break; // Adjust the window size to keep the content area size constant if (_glfwIsWindows10CreatorsUpdateOrGreaterWin32()) { RECT source = {0}, target = {0}; SIZE* size = (SIZE*) lParam; AdjustWindowRectExForDpi(&source, getWindowStyle(window), FALSE, getWindowExStyle(window), GetDpiForWindow(window->win32.handle)); AdjustWindowRectExForDpi(&target, getWindowStyle(window), FALSE, getWindowExStyle(window), LOWORD(wParam)); size->cx += (target.right - target.left) - (source.right - source.left); size->cy += (target.bottom - target.top) - (source.bottom - source.top); return TRUE; } break; } case WM_DPICHANGED: { const float xscale = HIWORD(wParam) / (float) USER_DEFAULT_SCREEN_DPI; const float yscale = LOWORD(wParam) / (float) USER_DEFAULT_SCREEN_DPI; // 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, suggested->left, suggested->top, suggested->right - suggested->left, suggested->bottom - suggested->top, SWP_NOACTIVATE | SWP_NOZORDER); } _glfwInputWindowContentScale(window, xscale, yscale); break; } case WM_SETCURSOR: { if (LOWORD(lParam) == HTCLIENT) { updateCursorImage(window); return TRUE; } break; } case WM_DROPFILES: { HDROP drop = (HDROP) wParam; POINT pt; int i; const int count = DragQueryFileW(drop, 0xffffffff, NULL, 0); char** paths = calloc(count, sizeof(char*)); // Move the mouse to the position of the drop DragQueryPoint(drop, &pt); _glfwInputCursorPos(window, pt.x, pt.y); for (i = 0; i < count; i++) { const UINT length = DragQueryFileW(drop, i, NULL, 0); WCHAR* buffer = calloc((size_t) length + 1, sizeof(WCHAR)); DragQueryFileW(drop, i, buffer, length + 1); paths[i] = _glfwCreateUTF8FromWideStringWin32(buffer); free(buffer); } _glfwInputDrop(window, count, (const char**) paths); for (i = 0; i < count; i++) free(paths[i]); free(paths); DragFinish(drop); return 0; } } return DefWindowProcW(hWnd, uMsg, wParam, lParam); } // Creates the GLFW window // static int createNativeWindow(_GLFWwindow* window, const _GLFWwndconfig* wndconfig, const _GLFWfbconfig* fbconfig) { int xpos, ypos, fullWidth, fullHeight; WCHAR* wideTitle; DWORD style = getWindowStyle(window); DWORD exStyle = getWindowExStyle(window); if (window->monitor) { GLFWvidmode mode; // 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; } else { xpos = CW_USEDEFAULT; ypos = CW_USEDEFAULT; window->win32.maximized = wndconfig->maximized; if (wndconfig->maximized) style |= WS_MAXIMIZE; getFullWindowSize(style, exStyle, wndconfig->width, wndconfig->height, &fullWidth, &fullHeight, USER_DEFAULT_SCREEN_DPI); } wideTitle = _glfwCreateWideStringFromUTF8Win32(wndconfig->title); if (!wideTitle) return GLFW_FALSE; window->win32.handle = CreateWindowExW(exStyle, _GLFW_WNDCLASSNAME, wideTitle, style, xpos, ypos, fullWidth, fullHeight, NULL, // No parent window NULL, // No window menu GetModuleHandleW(NULL), (LPVOID) wndconfig); free(wideTitle); if (!window->win32.handle) { _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, "Win32: Failed to create window"); return GLFW_FALSE; } SetPropW(window->win32.handle, L"GLFW", window); if (IsWindows7OrGreater()) { ChangeWindowMessageFilterEx(window->win32.handle, WM_DROPFILES, MSGFLT_ALLOW, NULL); ChangeWindowMessageFilterEx(window->win32.handle, WM_COPYDATA, MSGFLT_ALLOW, NULL); ChangeWindowMessageFilterEx(window->win32.handle, WM_COPYGLOBALDATA, MSGFLT_ALLOW, NULL); } window->win32.scaleToMonitor = wndconfig->scaleToMonitor; 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; _glfwGetMonitorContentScaleWin32(mh, &xscale, &yscale); if (xscale > 0.f && yscale > 0.f) { rect.right = (int) (rect.right * xscale); rect.bottom = (int) (rect.bottom * yscale); } } if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) { AdjustWindowRectExForDpi(&rect, style, FALSE, exStyle, GetDpiForWindow(window->win32.handle)); } else AdjustWindowRectEx(&rect, style, FALSE, exStyle); 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); if (fbconfig->transparent) { updateFramebufferTransparency(window); window->win32.transparent = GLFW_TRUE; } _glfwPlatformGetWindowSize(window, &window->win32.width, &window->win32.height); return GLFW_TRUE; } ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// // Registers the GLFW window class // GLFWbool _glfwRegisterWindowClassWin32(void) { WNDCLASSEXW wc; 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.hCursor = LoadCursorW(NULL, IDC_ARROW); wc.lpszClassName = _GLFW_WNDCLASSNAME; // Load user-provided icon if available wc.hIcon = LoadImageW(GetModuleHandleW(NULL), L"GLFW_ICON", IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED); if (!wc.hIcon) { // No user-provided icon found, load default icon wc.hIcon = LoadImageW(NULL, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED); } if (!RegisterClassExW(&wc)) { _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, "Win32: Failed to register window class"); return GLFW_FALSE; } return GLFW_TRUE; } // Unregisters the GLFW window class // void _glfwUnregisterWindowClassWin32(void) { UnregisterClassW(_GLFW_WNDCLASSNAME, GetModuleHandleW(NULL)); } ////////////////////////////////////////////////////////////////////////// ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// int _glfwPlatformCreateWindow(_GLFWwindow* window, const _GLFWwndconfig* wndconfig, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig) { if (!createNativeWindow(window, wndconfig, fbconfig)) return GLFW_FALSE; if (ctxconfig->client != GLFW_NO_API) { if (ctxconfig->source == GLFW_NATIVE_CONTEXT_API) { if (!_glfwInitWGL()) return GLFW_FALSE; if (!_glfwCreateContextWGL(window, ctxconfig, fbconfig)) return GLFW_FALSE; } else if (ctxconfig->source == GLFW_EGL_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 (window->monitor) { _glfwPlatformShowWindow(window); _glfwPlatformFocusWindow(window); acquireMonitor(window); fitToMonitor(window); } return GLFW_TRUE; } void _glfwPlatformDestroyWindow(_GLFWwindow* window) { if (window->monitor) releaseMonitor(window); if (window->context.destroy) window->context.destroy(window); if (_glfw.win32.disabledCursorWindow == window) _glfw.win32.disabledCursorWindow = NULL; if (window->win32.handle) { RemovePropW(window->win32.handle, L"GLFW"); DestroyWindow(window->win32.handle); window->win32.handle = NULL; } if (window->win32.bigIcon) DestroyIcon(window->win32.bigIcon); if (window->win32.smallIcon) DestroyIcon(window->win32.smallIcon); } void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title) { WCHAR* wideTitle = _glfwCreateWideStringFromUTF8Win32(title); if (!wideTitle) return; SetWindowTextW(window->win32.handle, wideTitle); free(wideTitle); } void _glfwPlatformSetWindowIcon(_GLFWwindow* window, int count, const GLFWimage* images) { HICON bigIcon = NULL, smallIcon = NULL; if (count) { const GLFWimage* bigImage = chooseImage(count, images, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON)); const GLFWimage* smallImage = chooseImage(count, images, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON)); bigIcon = createIcon(bigImage, 0, 0, GLFW_TRUE); smallIcon = createIcon(smallImage, 0, 0, GLFW_TRUE); } else { bigIcon = (HICON) GetClassLongPtrW(window->win32.handle, GCLP_HICON); smallIcon = (HICON) GetClassLongPtrW(window->win32.handle, GCLP_HICONSM); } 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); if (window->win32.smallIcon) DestroyIcon(window->win32.smallIcon); if (count) { window->win32.bigIcon = bigIcon; window->win32.smallIcon = smallIcon; } } void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos) { POINT pos = { 0, 0 }; ClientToScreen(window->win32.handle, &pos); if (xpos) *xpos = pos.x; if (ypos) *ypos = pos.y; } void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos) { RECT rect = { xpos, ypos, xpos, ypos }; if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) { AdjustWindowRectExForDpi(&rect, getWindowStyle(window), FALSE, getWindowExStyle(window), GetDpiForWindow(window->win32.handle)); } else { AdjustWindowRectEx(&rect, getWindowStyle(window), FALSE, getWindowExStyle(window)); } SetWindowPos(window->win32.handle, NULL, rect.left, rect.top, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE); } void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height) { RECT area; GetClientRect(window->win32.handle, &area); if (width) *width = area.right; if (height) *height = area.bottom; } void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) { if (window->monitor) { if (window->monitor->window == window) { acquireMonitor(window); fitToMonitor(window); } } else { RECT rect = { 0, 0, width, height }; if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) { AdjustWindowRectExForDpi(&rect, getWindowStyle(window), FALSE, getWindowExStyle(window), GetDpiForWindow(window->win32.handle)); } else { AdjustWindowRectEx(&rect, getWindowStyle(window), FALSE, getWindowExStyle(window)); } SetWindowPos(window->win32.handle, HWND_TOP, 0, 0, rect.right - rect.left, rect.bottom - rect.top, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOZORDER); } } void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window, int minwidth, int minheight, int maxwidth, int maxheight) { RECT area; if ((minwidth == GLFW_DONT_CARE || minheight == GLFW_DONT_CARE) && (maxwidth == GLFW_DONT_CARE || maxheight == GLFW_DONT_CARE)) { return; } GetWindowRect(window->win32.handle, &area); MoveWindow(window->win32.handle, area.left, area.top, area.right - area.left, area.bottom - area.top, TRUE); } void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom) { RECT area; if (numer == GLFW_DONT_CARE || denom == GLFW_DONT_CARE) return; GetWindowRect(window->win32.handle, &area); applyAspectRatio(window, WMSZ_BOTTOMRIGHT, &area); MoveWindow(window->win32.handle, area.left, area.top, area.right - area.left, area.bottom - area.top, TRUE); } void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height) { _glfwPlatformGetWindowSize(window, width, height); } void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, int* left, int* top, int* right, int* bottom) { RECT rect; int width, height; _glfwPlatformGetWindowSize(window, &width, &height); SetRect(&rect, 0, 0, width, height); if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) { AdjustWindowRectExForDpi(&rect, getWindowStyle(window), FALSE, getWindowExStyle(window), GetDpiForWindow(window->win32.handle)); } else { AdjustWindowRectEx(&rect, getWindowStyle(window), FALSE, getWindowExStyle(window)); } if (left) *left = -rect.left; if (top) *top = -rect.top; if (right) *right = rect.right - width; if (bottom) *bottom = rect.bottom - height; } void _glfwPlatformGetWindowContentScale(_GLFWwindow* window, float* xscale, float* yscale) { const HANDLE handle = MonitorFromWindow(window->win32.handle, MONITOR_DEFAULTTONEAREST); _glfwGetMonitorContentScaleWin32(handle, xscale, yscale); } void _glfwPlatformIconifyWindow(_GLFWwindow* window) { ShowWindow(window->win32.handle, SW_MINIMIZE); } void _glfwPlatformRestoreWindow(_GLFWwindow* window) { ShowWindow(window->win32.handle, SW_RESTORE); } void _glfwPlatformMaximizeWindow(_GLFWwindow* window) { if (IsWindowVisible(window->win32.handle)) ShowWindow(window->win32.handle, SW_MAXIMIZE); else maximizeWindowManually(window); } void _glfwPlatformShowWindow(_GLFWwindow* window) { ShowWindow(window->win32.handle, SW_SHOWNA); } void _glfwPlatformHideWindow(_GLFWwindow* window) { ShowWindow(window->win32.handle, SW_HIDE); } void _glfwPlatformRequestWindowAttention(_GLFWwindow* window) { FlashWindow(window->win32.handle, TRUE); } void _glfwPlatformFocusWindow(_GLFWwindow* window) { BringWindowToTop(window->win32.handle); SetForegroundWindow(window->win32.handle); SetFocus(window->win32.handle); } void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor, int xpos, int ypos, int width, int height, int refreshRate) { if (window->monitor == monitor) { if (monitor) { if (monitor->window == window) { acquireMonitor(window); fitToMonitor(window); } } else { RECT rect = { xpos, ypos, xpos + width, ypos + height }; if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) { AdjustWindowRectExForDpi(&rect, getWindowStyle(window), FALSE, getWindowExStyle(window), GetDpiForWindow(window->win32.handle)); } else { AdjustWindowRectEx(&rect, getWindowStyle(window), FALSE, getWindowExStyle(window)); } SetWindowPos(window->win32.handle, HWND_TOP, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOCOPYBITS | SWP_NOACTIVATE | SWP_NOZORDER); } return; } if (window->monitor) releaseMonitor(window); _glfwInputWindowMonitor(window, monitor); if (window->monitor) { MONITORINFO mi = { sizeof(mi) }; UINT flags = SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOCOPYBITS; if (window->decorated) { DWORD style = GetWindowLongW(window->win32.handle, GWL_STYLE); style &= ~WS_OVERLAPPEDWINDOW; style |= getWindowStyle(window); SetWindowLongW(window->win32.handle, GWL_STYLE, style); flags |= SWP_FRAMECHANGED; } acquireMonitor(window); GetMonitorInfoW(window->monitor->win32.handle, &mi); SetWindowPos(window->win32.handle, HWND_TOPMOST, mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right - mi.rcMonitor.left, mi.rcMonitor.bottom - mi.rcMonitor.top, flags); } else { HWND after; RECT rect = { xpos, ypos, xpos + width, ypos + height }; DWORD style = GetWindowLongW(window->win32.handle, GWL_STYLE); UINT flags = SWP_NOACTIVATE | SWP_NOCOPYBITS; if (window->decorated) { style &= ~WS_POPUP; style |= getWindowStyle(window); SetWindowLongW(window->win32.handle, GWL_STYLE, style); flags |= SWP_FRAMECHANGED; } if (window->floating) after = HWND_TOPMOST; else after = HWND_NOTOPMOST; if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) { AdjustWindowRectExForDpi(&rect, getWindowStyle(window), FALSE, getWindowExStyle(window), GetDpiForWindow(window->win32.handle)); } else { AdjustWindowRectEx(&rect, getWindowStyle(window), FALSE, getWindowExStyle(window)); } SetWindowPos(window->win32.handle, after, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, flags); } } int _glfwPlatformWindowFocused(_GLFWwindow* window) { return window->win32.handle == GetActiveWindow(); } int _glfwPlatformWindowIconified(_GLFWwindow* window) { return IsIconic(window->win32.handle); } int _glfwPlatformWindowVisible(_GLFWwindow* window) { return IsWindowVisible(window->win32.handle); } int _glfwPlatformWindowMaximized(_GLFWwindow* window) { return IsZoomed(window->win32.handle); } int _glfwPlatformWindowHovered(_GLFWwindow* window) { return cursorInContentArea(window); } int _glfwPlatformFramebufferTransparent(_GLFWwindow* window) { BOOL composition, opaque; DWORD color; if (!window->win32.transparent) return GLFW_FALSE; if (!IsWindowsVistaOrGreater()) return GLFW_FALSE; 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) { updateWindowStyles(window); } void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled) { updateWindowStyles(window); } void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled) { const HWND after = enabled ? HWND_TOPMOST : HWND_NOTOPMOST; SetWindowPos(window->win32.handle, after, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); } float _glfwPlatformGetWindowOpacity(_GLFWwindow* window) { BYTE alpha; DWORD flags; if ((GetWindowLongW(window->win32.handle, GWL_EXSTYLE) & WS_EX_LAYERED) && GetLayeredWindowAttributes(window->win32.handle, NULL, &alpha, &flags)) { if (flags & LWA_ALPHA) return alpha / 255.f; } return 1.f; } void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity) { if (opacity < 1.f) { const BYTE alpha = (BYTE) (255 * opacity); DWORD style = GetWindowLongW(window->win32.handle, GWL_EXSTYLE); style |= WS_EX_LAYERED; SetWindowLongW(window->win32.handle, GWL_EXSTYLE, style); SetLayeredWindowAttributes(window->win32.handle, 0, alpha, LWA_ALPHA); } else { DWORD style = GetWindowLongW(window->win32.handle, GWL_EXSTYLE); style &= ~WS_EX_LAYERED; SetWindowLongW(window->win32.handle, GWL_EXSTYLE, style); } } void _glfwPlatformSetRawMouseMotion(_GLFWwindow *window, GLFWbool enabled) { if (_glfw.win32.disabledCursorWindow != window) return; if (enabled) enableRawMouseMotion(window); else disableRawMouseMotion(window); } GLFWbool _glfwPlatformRawMouseMotionSupported(void) { return GLFW_TRUE; } void _glfwPlatformPollEvents(void) { MSG msg; HWND handle; _GLFWwindow* window; while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) { if (msg.message == WM_QUIT) { // NOTE: While GLFW does not itself post WM_QUIT, other processes // may post it to this one, for example Task Manager // HACK: Treat WM_QUIT as a close on all windows window = _glfw.windowListHead; while (window) { _glfwInputWindowCloseRequest(window); window = window->next; } } else { TranslateMessage(&msg); DispatchMessageW(&msg); } } // HACK: Release modifier keys that the system did not emit KEYUP for // NOTE: Shift keys on Windows tend to "stick" when both are pressed as // no key up message is generated by the first key release // NOTE: Windows key is not reported as released by the Win+V hotkey // Other Win hotkeys are handled implicitly by _glfwInputWindowFocus // because they change the input focus // NOTE: The other half of this is in the WM_*KEY* handler in windowProc handle = GetActiveWindow(); if (handle) { window = GetPropW(handle, L"GLFW"); if (window) { int i; const int keys[4][2] = { { VK_LSHIFT, GLFW_KEY_LEFT_SHIFT }, { VK_RSHIFT, GLFW_KEY_RIGHT_SHIFT }, { VK_LWIN, GLFW_KEY_LEFT_SUPER }, { VK_RWIN, GLFW_KEY_RIGHT_SUPER } }; for (i = 0; i < 4; i++) { const int vk = keys[i][0]; const int key = keys[i][1]; const int scancode = _glfw.win32.scancodes[key]; if ((GetKeyState(vk) & 0x8000)) continue; if (window->keys[key] != GLFW_PRESS) continue; _glfwInputKey(window, key, scancode, GLFW_RELEASE, getKeyMods()); } } } window = _glfw.win32.disabledCursorWindow; if (window) { int width, height; _glfwPlatformGetWindowSize(window, &width, &height); // NOTE: Re-center the cursor only if it has moved since the last call, // to avoid breaking glfwWaitEvents with WM_MOUSEMOVE if (window->win32.lastCursorPosX != width / 2 || window->win32.lastCursorPosY != height / 2) { _glfwPlatformSetCursorPos(window, width / 2, height / 2); } } } void _glfwPlatformWaitEvents(void) { WaitMessage(); _glfwPlatformPollEvents(); } void _glfwPlatformWaitEventsTimeout(double timeout) { MsgWaitForMultipleObjects(0, NULL, FALSE, (DWORD) (timeout * 1e3), QS_ALLEVENTS); _glfwPlatformPollEvents(); } void _glfwPlatformPostEmptyEvent(void) { PostMessageW(_glfw.win32.helperWindowHandle, WM_NULL, 0, 0); } void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos) { POINT pos; if (GetCursorPos(&pos)) { ScreenToClient(window->win32.handle, &pos); if (xpos) *xpos = pos.x; if (ypos) *ypos = pos.y; } } void _glfwPlatformSetCursorPos(_GLFWwindow* window, double xpos, double ypos) { POINT pos = { (int) xpos, (int) ypos }; // Store the new position so it can be recognized later window->win32.lastCursorPosX = pos.x; window->win32.lastCursorPosY = pos.y; ClientToScreen(window->win32.handle, &pos); SetCursorPos(pos.x, pos.y); } void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) { if (mode == GLFW_CURSOR_DISABLED) { if (_glfwPlatformWindowFocused(window)) disableCursor(window); } else if (_glfw.win32.disabledCursorWindow == window) enableCursor(window); else if (cursorInContentArea(window)) updateCursorImage(window); } const char* _glfwPlatformGetScancodeName(int scancode) { if (scancode < 0 || scancode > (KF_EXTENDED | 0xff) || _glfw.win32.keycodes[scancode] == GLFW_KEY_UNKNOWN) { _glfwInputError(GLFW_INVALID_VALUE, "Invalid scancode %i", scancode); return NULL; } return _glfw.win32.keynames[_glfw.win32.keycodes[scancode]]; } int _glfwPlatformGetKeyScancode(int key) { return _glfw.win32.scancodes[key]; } int _glfwPlatformCreateCursor(_GLFWcursor* cursor, const GLFWimage* image, int xhot, int yhot) { cursor->win32.handle = (HCURSOR) createIcon(image, xhot, yhot, GLFW_FALSE); if (!cursor->win32.handle) return GLFW_FALSE; return GLFW_TRUE; } int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape) { int id = 0; if (shape == GLFW_ARROW_CURSOR) id = OCR_NORMAL; else if (shape == GLFW_IBEAM_CURSOR) id = OCR_IBEAM; else if (shape == GLFW_CROSSHAIR_CURSOR) id = OCR_CROSS; else if (shape == GLFW_HAND_CURSOR) id = OCR_HAND; else if (shape == GLFW_HRESIZE_CURSOR) id = OCR_SIZEWE; else if (shape == GLFW_VRESIZE_CURSOR) id = OCR_SIZENS; else return GLFW_FALSE; cursor->win32.handle = LoadImageW(NULL, MAKEINTRESOURCEW(id), IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE | LR_SHARED); if (!cursor->win32.handle) { _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, "Win32: Failed to create standard cursor"); return GLFW_FALSE; } return GLFW_TRUE; } void _glfwPlatformDestroyCursor(_GLFWcursor* cursor) { if (cursor->win32.handle) DestroyIcon((HICON) cursor->win32.handle); } void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) { if (cursorInContentArea(window)) updateCursorImage(window); } void _glfwPlatformSetClipboardString(const char* string) { int characterCount; HANDLE object; WCHAR* buffer; characterCount = MultiByteToWideChar(CP_UTF8, 0, string, -1, NULL, 0); if (!characterCount) return; object = GlobalAlloc(GMEM_MOVEABLE, characterCount * sizeof(WCHAR)); if (!object) { _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, "Win32: Failed to allocate global handle for clipboard"); return; } buffer = GlobalLock(object); if (!buffer) { _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, "Win32: Failed to lock global handle"); GlobalFree(object); return; } MultiByteToWideChar(CP_UTF8, 0, string, -1, buffer, characterCount); GlobalUnlock(object); if (!OpenClipboard(_glfw.win32.helperWindowHandle)) { _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, "Win32: Failed to open clipboard"); GlobalFree(object); return; } EmptyClipboard(); SetClipboardData(CF_UNICODETEXT, object); CloseClipboard(); } const char* _glfwPlatformGetClipboardString(void) { HANDLE object; WCHAR* buffer; if (!OpenClipboard(_glfw.win32.helperWindowHandle)) { _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, "Win32: Failed to open clipboard"); return NULL; } object = GetClipboardData(CF_UNICODETEXT); if (!object) { _glfwInputErrorWin32(GLFW_FORMAT_UNAVAILABLE, "Win32: Failed to convert clipboard to string"); CloseClipboard(); return NULL; } buffer = GlobalLock(object); if (!buffer) { _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, "Win32: Failed to lock global handle"); CloseClipboard(); return NULL; } free(_glfw.win32.clipboardString); _glfw.win32.clipboardString = _glfwCreateUTF8FromWideStringWin32(buffer); GlobalUnlock(object); CloseClipboard(); return _glfw.win32.clipboardString; } void _glfwPlatformGetRequiredInstanceExtensions(char** extensions) { if (!_glfw.vk.KHR_surface || !_glfw.vk.KHR_win32_surface) return; extensions[0] = "VK_KHR_surface"; extensions[1] = "VK_KHR_win32_surface"; } int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, VkPhysicalDevice device, uint32_t queuefamily) { PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR vkGetPhysicalDeviceWin32PresentationSupportKHR = (PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR) vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceWin32PresentationSupportKHR"); if (!vkGetPhysicalDeviceWin32PresentationSupportKHR) { _glfwInputError(GLFW_API_UNAVAILABLE, "Win32: Vulkan instance missing VK_KHR_win32_surface extension"); return GLFW_FALSE; } return vkGetPhysicalDeviceWin32PresentationSupportKHR(device, queuefamily); } VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, _GLFWwindow* window, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface) { VkResult err; VkWin32SurfaceCreateInfoKHR sci; PFN_vkCreateWin32SurfaceKHR vkCreateWin32SurfaceKHR; vkCreateWin32SurfaceKHR = (PFN_vkCreateWin32SurfaceKHR) vkGetInstanceProcAddr(instance, "vkCreateWin32SurfaceKHR"); if (!vkCreateWin32SurfaceKHR) { _glfwInputError(GLFW_API_UNAVAILABLE, "Win32: Vulkan instance missing VK_KHR_win32_surface extension"); return VK_ERROR_EXTENSION_NOT_PRESENT; } memset(&sci, 0, sizeof(sci)); sci.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; sci.hinstance = GetModuleHandleW(NULL); sci.hwnd = window->win32.handle; err = vkCreateWin32SurfaceKHR(instance, &sci, allocator, surface); if (err) { _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to create Vulkan surface: %s", _glfwGetVulkanResultString(err)); } return err; } ////////////////////////////////////////////////////////////////////////// ////// GLFW native API ////// ////////////////////////////////////////////////////////////////////////// GLFWAPI HWND glfwGetWin32Window(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(NULL); return window->win32.handle; } #endif #ifndef HEADER_GUARD_WGL_CONTEXT_C #define HEADER_GUARD_WGL_CONTEXT_C //======================================================================== // GLFW 3.3.7 WGL - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2019 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== // Please use C89 style variable declarations in this file because VS 2010 //======================================================================== #include #include #include // Return the value corresponding to the specified attribute // static int findPixelFormatAttribValue(const int* attribs, int attribCount, const int* values, int attrib) { int i; for (i = 0; i < attribCount; i++) { if (attribs[i] == attrib) return values[i]; } _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, "WGL: Unknown pixel format attribute requested"); return 0; } #define addAttrib(a) \ { \ assert((size_t) attribCount < sizeof(attribs) / sizeof(attribs[0])); \ attribs[attribCount++] = a; \ } #define findAttribValue(a) \ findPixelFormatAttribValue(attribs, attribCount, values, a) // Return a list of available and usable framebuffer configs // static int choosePixelFormat(_GLFWwindow* window, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig) { _GLFWfbconfig* usableConfigs; const _GLFWfbconfig* closest; int i, pixelFormat, nativeCount, usableCount = 0, attribCount = 0; int attribs[40]; int values[sizeof(attribs) / sizeof(attribs[0])]; 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); addAttrib(WGL_ACCELERATION_ARB); addAttrib(WGL_RED_BITS_ARB); addAttrib(WGL_RED_SHIFT_ARB); addAttrib(WGL_GREEN_BITS_ARB); addAttrib(WGL_GREEN_SHIFT_ARB); addAttrib(WGL_BLUE_BITS_ARB); addAttrib(WGL_BLUE_SHIFT_ARB); addAttrib(WGL_ALPHA_BITS_ARB); addAttrib(WGL_ALPHA_SHIFT_ARB); addAttrib(WGL_DEPTH_BITS_ARB); addAttrib(WGL_STENCIL_BITS_ARB); addAttrib(WGL_ACCUM_BITS_ARB); addAttrib(WGL_ACCUM_RED_BITS_ARB); addAttrib(WGL_ACCUM_GREEN_BITS_ARB); addAttrib(WGL_ACCUM_BLUE_BITS_ARB); addAttrib(WGL_ACCUM_ALPHA_BITS_ARB); addAttrib(WGL_AUX_BUFFERS_ARB); addAttrib(WGL_STEREO_ARB); addAttrib(WGL_DOUBLE_BUFFER_ARB); if (_glfw.wgl.ARB_multisample) addAttrib(WGL_SAMPLES_ARB); if (ctxconfig->client == GLFW_OPENGL_API) { if (_glfw.wgl.ARB_framebuffer_sRGB || _glfw.wgl.EXT_framebuffer_sRGB) addAttrib(WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB); } else { if (_glfw.wgl.EXT_colorspace) addAttrib(WGL_COLORSPACE_EXT); } } else { nativeCount = DescribePixelFormat(window->context.wgl.dc, 1, sizeof(PIXELFORMATDESCRIPTOR), NULL); } usableConfigs = calloc(nativeCount, sizeof(_GLFWfbconfig)); for (i = 0; i < nativeCount; i++) { _GLFWfbconfig* u = usableConfigs + usableCount; pixelFormat = i + 1; if (_glfw.wgl.ARB_pixel_format) { // Get pixel format attributes through "modern" extension if (!wglGetPixelFormatAttribivARB(window->context.wgl.dc, pixelFormat, 0, attribCount, attribs, values)) { _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, "WGL: Failed to retrieve pixel format attributes"); free(usableConfigs); return 0; } if (!findAttribValue(WGL_SUPPORT_OPENGL_ARB) || !findAttribValue(WGL_DRAW_TO_WINDOW_ARB)) { continue; } if (findAttribValue(WGL_PIXEL_TYPE_ARB) != WGL_TYPE_RGBA_ARB) continue; 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); u->alphaBits = findAttribValue(WGL_ALPHA_BITS_ARB); u->depthBits = findAttribValue(WGL_DEPTH_BITS_ARB); u->stencilBits = findAttribValue(WGL_STENCIL_BITS_ARB); u->accumRedBits = findAttribValue(WGL_ACCUM_RED_BITS_ARB); u->accumGreenBits = findAttribValue(WGL_ACCUM_GREEN_BITS_ARB); u->accumBlueBits = findAttribValue(WGL_ACCUM_BLUE_BITS_ARB); u->accumAlphaBits = findAttribValue(WGL_ACCUM_ALPHA_BITS_ARB); u->auxBuffers = findAttribValue(WGL_AUX_BUFFERS_ARB); if (findAttribValue(WGL_STEREO_ARB)) u->stereo = GLFW_TRUE; if (_glfw.wgl.ARB_multisample) u->samples = findAttribValue(WGL_SAMPLES_ARB); if (ctxconfig->client == GLFW_OPENGL_API) { if (_glfw.wgl.ARB_framebuffer_sRGB || _glfw.wgl.EXT_framebuffer_sRGB) { if (findAttribValue(WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB)) u->sRGB = GLFW_TRUE; } } else { if (_glfw.wgl.EXT_colorspace) { if (findAttribValue(WGL_COLORSPACE_EXT) == WGL_COLORSPACE_SRGB_EXT) u->sRGB = GLFW_TRUE; } } } else { // Get pixel format attributes through legacy PFDs PIXELFORMATDESCRIPTOR pfd; if (!DescribePixelFormat(window->context.wgl.dc, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd)) { _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, "WGL: Failed to describe pixel format"); free(usableConfigs); return 0; } if (!(pfd.dwFlags & PFD_DRAW_TO_WINDOW) || !(pfd.dwFlags & PFD_SUPPORT_OPENGL)) { continue; } if (!(pfd.dwFlags & PFD_GENERIC_ACCELERATED) && (pfd.dwFlags & PFD_GENERIC_FORMAT)) { continue; } 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; u->alphaBits = pfd.cAlphaBits; u->depthBits = pfd.cDepthBits; u->stencilBits = pfd.cStencilBits; u->accumRedBits = pfd.cAccumRedBits; u->accumGreenBits = pfd.cAccumGreenBits; u->accumBlueBits = pfd.cAccumBlueBits; u->accumAlphaBits = pfd.cAccumAlphaBits; u->auxBuffers = pfd.cAuxBuffers; if (pfd.dwFlags & PFD_STEREO) u->stereo = GLFW_TRUE; } u->handle = pixelFormat; usableCount++; } if (!usableCount) { _glfwInputError(GLFW_API_UNAVAILABLE, "WGL: The driver does not appear to support OpenGL"); free(usableConfigs); return 0; } closest = _glfwChooseFBConfig(fbconfig, usableConfigs, usableCount); if (!closest) { _glfwInputError(GLFW_FORMAT_UNAVAILABLE, "WGL: Failed to find a suitable pixel format"); free(usableConfigs); return 0; } pixelFormat = (int) closest->handle; free(usableConfigs); return pixelFormat; } #undef addAttrib #undef findAttribValue static void makeContextCurrentWGL(_GLFWwindow* window) { if (window) { if (wglMakeCurrent(window->context.wgl.dc, window->context.wgl.handle)) _glfwPlatformSetTls(&_glfw.contextSlot, window); else { _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, "WGL: Failed to make context current"); _glfwPlatformSetTls(&_glfw.contextSlot, NULL); } } else { if (!wglMakeCurrent(NULL, NULL)) { _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, "WGL: Failed to clear current context"); } _glfwPlatformSetTls(&_glfw.contextSlot, NULL); } } static void swapBuffersWGL(_GLFWwindow* window) { if (!window->monitor) { // HACK: Use DwmFlush when desktop composition is enabled on Windows Vista and 7 if (!IsWindows8OrGreater() && IsWindowsVistaOrGreater()) { BOOL enabled = FALSE; if (SUCCEEDED(DwmIsCompositionEnabled(&enabled)) && enabled) { int count = abs(window->context.wgl.interval); while (count--) DwmFlush(); } } } SwapBuffers(window->context.wgl.dc); } static void swapIntervalWGL(int interval) { _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot); assert(window != NULL); window->context.wgl.interval = interval; if (!window->monitor) { // HACK: Disable WGL swap interval when desktop composition is enabled on Windows // Vista and 7 to avoid interfering with DWM vsync if (!IsWindows8OrGreater() && IsWindowsVistaOrGreater()) { BOOL enabled = FALSE; if (SUCCEEDED(DwmIsCompositionEnabled(&enabled)) && enabled) interval = 0; } } if (_glfw.wgl.EXT_swap_control) wglSwapIntervalEXT(interval); } static int extensionSupportedWGL(const char* extension) { const char* extensions = NULL; if (_glfw.wgl.GetExtensionsStringARB) extensions = wglGetExtensionsStringARB(wglGetCurrentDC()); else if (_glfw.wgl.GetExtensionsStringEXT) extensions = wglGetExtensionsStringEXT(); if (!extensions) return GLFW_FALSE; return _glfwStringInExtensionString(extension, extensions); } static GLFWglproc getProcAddressWGL(const char* procname) { const GLFWglproc proc = (GLFWglproc) wglGetProcAddress(procname); if (proc) return proc; return (GLFWglproc) GetProcAddress(_glfw.wgl.instance, procname); } static void destroyContextWGL(_GLFWwindow* window) { if (window->context.wgl.handle) { wglDeleteContext(window->context.wgl.handle); window->context.wgl.handle = NULL; } } ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// // Initialize WGL // GLFWbool _glfwInitWGL(void) { PIXELFORMATDESCRIPTOR pfd; HGLRC prc, rc; HDC pdc, dc; if (_glfw.wgl.instance) return GLFW_TRUE; _glfw.wgl.instance = LoadLibraryA("opengl32.dll"); if (!_glfw.wgl.instance) { _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, "WGL: Failed to load opengl32.dll"); return GLFW_FALSE; } _glfw.wgl.CreateContext = (PFN_wglCreateContext) GetProcAddress(_glfw.wgl.instance, "wglCreateContext"); _glfw.wgl.DeleteContext = (PFN_wglDeleteContext) GetProcAddress(_glfw.wgl.instance, "wglDeleteContext"); _glfw.wgl.GetProcAddress = (PFN_wglGetProcAddress) GetProcAddress(_glfw.wgl.instance, "wglGetProcAddress"); _glfw.wgl.GetCurrentDC = (PFN_wglGetCurrentDC) GetProcAddress(_glfw.wgl.instance, "wglGetCurrentDC"); _glfw.wgl.GetCurrentContext = (PFN_wglGetCurrentContext) GetProcAddress(_glfw.wgl.instance, "wglGetCurrentContext"); _glfw.wgl.MakeCurrent = (PFN_wglMakeCurrent) GetProcAddress(_glfw.wgl.instance, "wglMakeCurrent"); _glfw.wgl.ShareLists = (PFN_wglShareLists) GetProcAddress(_glfw.wgl.instance, "wglShareLists"); // NOTE: A dummy context has to be created for opengl32.dll to load the // OpenGL ICD, from which we can then query WGL extensions // NOTE: This code will accept the Microsoft GDI ICD; accelerated context // creation failure occurs during manual pixel format enumeration dc = GetDC(_glfw.win32.helperWindowHandle); ZeroMemory(&pfd, sizeof(pfd)); pfd.nSize = sizeof(pfd); pfd.nVersion = 1; pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; pfd.iPixelType = PFD_TYPE_RGBA; pfd.cColorBits = 24; if (!SetPixelFormat(dc, ChoosePixelFormat(dc, &pfd), &pfd)) { _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, "WGL: Failed to set pixel format for dummy context"); return GLFW_FALSE; } rc = wglCreateContext(dc); if (!rc) { _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, "WGL: Failed to create dummy context"); return GLFW_FALSE; } pdc = wglGetCurrentDC(); prc = wglGetCurrentContext(); if (!wglMakeCurrent(dc, rc)) { _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, "WGL: Failed to make dummy context current"); wglMakeCurrent(pdc, prc); wglDeleteContext(rc); return GLFW_FALSE; } // NOTE: Functions must be loaded first as they're needed to retrieve the // extension string that tells us whether the functions are supported _glfw.wgl.GetExtensionsStringEXT = (PFNWGLGETEXTENSIONSSTRINGEXTPROC) wglGetProcAddress("wglGetExtensionsStringEXT"); _glfw.wgl.GetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC) wglGetProcAddress("wglGetExtensionsStringARB"); _glfw.wgl.CreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC) wglGetProcAddress("wglCreateContextAttribsARB"); _glfw.wgl.SwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC) wglGetProcAddress("wglSwapIntervalEXT"); _glfw.wgl.GetPixelFormatAttribivARB = (PFNWGLGETPIXELFORMATATTRIBIVARBPROC) wglGetProcAddress("wglGetPixelFormatAttribivARB"); // NOTE: WGL_ARB_extensions_string and WGL_EXT_extensions_string are not // checked below as we are already using them _glfw.wgl.ARB_multisample = extensionSupportedWGL("WGL_ARB_multisample"); _glfw.wgl.ARB_framebuffer_sRGB = extensionSupportedWGL("WGL_ARB_framebuffer_sRGB"); _glfw.wgl.EXT_framebuffer_sRGB = extensionSupportedWGL("WGL_EXT_framebuffer_sRGB"); _glfw.wgl.ARB_create_context = extensionSupportedWGL("WGL_ARB_create_context"); _glfw.wgl.ARB_create_context_profile = extensionSupportedWGL("WGL_ARB_create_context_profile"); _glfw.wgl.EXT_create_context_es2_profile = extensionSupportedWGL("WGL_EXT_create_context_es2_profile"); _glfw.wgl.ARB_create_context_robustness = extensionSupportedWGL("WGL_ARB_create_context_robustness"); _glfw.wgl.ARB_create_context_no_error = extensionSupportedWGL("WGL_ARB_create_context_no_error"); _glfw.wgl.EXT_swap_control = extensionSupportedWGL("WGL_EXT_swap_control"); _glfw.wgl.EXT_colorspace = extensionSupportedWGL("WGL_EXT_colorspace"); _glfw.wgl.ARB_pixel_format = extensionSupportedWGL("WGL_ARB_pixel_format"); _glfw.wgl.ARB_context_flush_control = extensionSupportedWGL("WGL_ARB_context_flush_control"); wglMakeCurrent(pdc, prc); wglDeleteContext(rc); return GLFW_TRUE; } // Terminate WGL // void _glfwTerminateWGL(void) { if (_glfw.wgl.instance) FreeLibrary(_glfw.wgl.instance); } #define setAttrib(a, v) \ { \ assert(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \ attribs[index++] = a; \ attribs[index++] = v; \ } // Create the OpenGL or OpenGL ES context // GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig) { int attribs[40]; int pixelFormat; PIXELFORMATDESCRIPTOR pfd; HGLRC share = NULL; if (ctxconfig->share) share = ctxconfig->share->context.wgl.handle; window->context.wgl.dc = GetDC(window->win32.handle); if (!window->context.wgl.dc) { _glfwInputError(GLFW_PLATFORM_ERROR, "WGL: Failed to retrieve DC for window"); return GLFW_FALSE; } pixelFormat = choosePixelFormat(window, ctxconfig, fbconfig); if (!pixelFormat) return GLFW_FALSE; if (!DescribePixelFormat(window->context.wgl.dc, pixelFormat, sizeof(pfd), &pfd)) { _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, "WGL: Failed to retrieve PFD for selected pixel format"); return GLFW_FALSE; } if (!SetPixelFormat(window->context.wgl.dc, pixelFormat, &pfd)) { _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, "WGL: Failed to set selected pixel format"); return GLFW_FALSE; } if (ctxconfig->client == GLFW_OPENGL_API) { if (ctxconfig->forward) { if (!_glfw.wgl.ARB_create_context) { _glfwInputError(GLFW_VERSION_UNAVAILABLE, "WGL: A forward compatible OpenGL context requested but WGL_ARB_create_context is unavailable"); return GLFW_FALSE; } } if (ctxconfig->profile) { if (!_glfw.wgl.ARB_create_context_profile) { _glfwInputError(GLFW_VERSION_UNAVAILABLE, "WGL: OpenGL profile requested but WGL_ARB_create_context_profile is unavailable"); return GLFW_FALSE; } } } else { if (!_glfw.wgl.ARB_create_context || !_glfw.wgl.ARB_create_context_profile || !_glfw.wgl.EXT_create_context_es2_profile) { _glfwInputError(GLFW_API_UNAVAILABLE, "WGL: OpenGL ES requested but WGL_ARB_create_context_es2_profile is unavailable"); return GLFW_FALSE; } } if (_glfw.wgl.ARB_create_context) { int index = 0, mask = 0, flags = 0; if (ctxconfig->client == GLFW_OPENGL_API) { if (ctxconfig->forward) flags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE) mask |= WGL_CONTEXT_CORE_PROFILE_BIT_ARB; else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE) mask |= WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; } else mask |= WGL_CONTEXT_ES2_PROFILE_BIT_EXT; if (ctxconfig->debug) flags |= WGL_CONTEXT_DEBUG_BIT_ARB; if (ctxconfig->robustness) { if (_glfw.wgl.ARB_create_context_robustness) { if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION) { setAttrib(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, WGL_NO_RESET_NOTIFICATION_ARB); } else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET) { setAttrib(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, WGL_LOSE_CONTEXT_ON_RESET_ARB); } flags |= WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB; } } if (ctxconfig->release) { if (_glfw.wgl.ARB_context_flush_control) { if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE) { setAttrib(WGL_CONTEXT_RELEASE_BEHAVIOR_ARB, WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB); } else if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_FLUSH) { setAttrib(WGL_CONTEXT_RELEASE_BEHAVIOR_ARB, WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB); } } } if (ctxconfig->noerror) { if (_glfw.wgl.ARB_create_context_no_error) setAttrib(WGL_CONTEXT_OPENGL_NO_ERROR_ARB, GLFW_TRUE); } // NOTE: Only request an explicitly versioned context when necessary, as // explicitly requesting version 1.0 does not always return the // highest version supported by the driver if (ctxconfig->major != 1 || ctxconfig->minor != 0) { setAttrib(WGL_CONTEXT_MAJOR_VERSION_ARB, ctxconfig->major); setAttrib(WGL_CONTEXT_MINOR_VERSION_ARB, ctxconfig->minor); } if (flags) setAttrib(WGL_CONTEXT_FLAGS_ARB, flags); if (mask) setAttrib(WGL_CONTEXT_PROFILE_MASK_ARB, mask); setAttrib(0, 0); window->context.wgl.handle = wglCreateContextAttribsARB(window->context.wgl.dc, share, attribs); if (!window->context.wgl.handle) { const DWORD error = GetLastError(); if (error == (0xc0070000 | ERROR_INVALID_VERSION_ARB)) { if (ctxconfig->client == GLFW_OPENGL_API) { _glfwInputError(GLFW_VERSION_UNAVAILABLE, "WGL: Driver does not support OpenGL version %i.%i", ctxconfig->major, ctxconfig->minor); } else { _glfwInputError(GLFW_VERSION_UNAVAILABLE, "WGL: Driver does not support OpenGL ES version %i.%i", ctxconfig->major, ctxconfig->minor); } } else if (error == (0xc0070000 | ERROR_INVALID_PROFILE_ARB)) { _glfwInputError(GLFW_VERSION_UNAVAILABLE, "WGL: Driver does not support the requested OpenGL profile"); } else if (error == (0xc0070000 | ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB)) { _glfwInputError(GLFW_INVALID_VALUE, "WGL: The share context is not compatible with the requested context"); } else { if (ctxconfig->client == GLFW_OPENGL_API) { _glfwInputError(GLFW_VERSION_UNAVAILABLE, "WGL: Failed to create OpenGL context"); } else { _glfwInputError(GLFW_VERSION_UNAVAILABLE, "WGL: Failed to create OpenGL ES context"); } } return GLFW_FALSE; } } else { window->context.wgl.handle = wglCreateContext(window->context.wgl.dc); if (!window->context.wgl.handle) { _glfwInputErrorWin32(GLFW_VERSION_UNAVAILABLE, "WGL: Failed to create OpenGL context"); return GLFW_FALSE; } if (share) { if (!wglShareLists(share, window->context.wgl.handle)) { _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, "WGL: Failed to enable sharing with specified OpenGL context"); return GLFW_FALSE; } } } window->context.makeCurrent = makeContextCurrentWGL; window->context.swapBuffers = swapBuffersWGL; window->context.swapInterval = swapIntervalWGL; window->context.extensionSupported = extensionSupportedWGL; window->context.getProcAddress = getProcAddressWGL; window->context.destroy = destroyContextWGL; return GLFW_TRUE; } #undef setAttrib ////////////////////////////////////////////////////////////////////////// ////// GLFW native API ////// ////////////////////////////////////////////////////////////////////////// GLFWAPI HGLRC glfwGetWGLContext(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(NULL); if (window->context.source != GLFW_NATIVE_CONTEXT_API) { _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); return NULL; } return window->context.wgl.handle; } #endif #endif #ifdef _GLFW_OSMESA #ifndef HEADER_GUARD_NULL_INIT_C #define HEADER_GUARD_NULL_INIT_C //======================================================================== // GLFW 3.3.7 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2016 Google Inc. // Copyright (c) 2016-2017 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== // It is fine to use C99 in this file because it will not be built with VS //======================================================================== ////////////////////////////////////////////////////////////////////////// ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// int _glfwPlatformInit(void) { _glfwInitTimerPOSIX(); return GLFW_TRUE; } void _glfwPlatformTerminate(void) { _glfwTerminateOSMesa(); } const char* _glfwPlatformGetVersionString(void) { return _GLFW_VERSION_NUMBER " null OSMesa"; } #endif #ifndef HEADER_GUARD_NULL_MONITOR_C #define HEADER_GUARD_NULL_MONITOR_C //======================================================================== // GLFW 3.3.7 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2016 Google Inc. // Copyright (c) 2016-2019 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== // It is fine to use C99 in this file because it will not be built with VS //======================================================================== ////////////////////////////////////////////////////////////////////////// ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor) { } void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) { } void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor, float* xscale, float* yscale) { if (xscale) *xscale = 1.f; if (yscale) *yscale = 1.f; } void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor, int* xpos, int* ypos, int* width, int* height) { } GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found) { return NULL; } void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode) { } GLFWbool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) { return GLFW_FALSE; } void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) { } #endif #ifndef HEADER_GUARD_NULL_WINDOW_C #define HEADER_GUARD_NULL_WINDOW_C //======================================================================== // GLFW 3.3.7 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2016 Google Inc. // Copyright (c) 2016-2019 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== // It is fine to use C99 in this file because it will not be built with VS //======================================================================== static int createNativeWindow(_GLFWwindow* window, const _GLFWwndconfig* wndconfig) { window->null.width = wndconfig->width; window->null.height = wndconfig->height; return GLFW_TRUE; } ////////////////////////////////////////////////////////////////////////// ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// int _glfwPlatformCreateWindow(_GLFWwindow* window, const _GLFWwndconfig* wndconfig, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig) { if (!createNativeWindow(window, wndconfig)) return GLFW_FALSE; if (ctxconfig->client != GLFW_NO_API) { if (ctxconfig->source == GLFW_NATIVE_CONTEXT_API || ctxconfig->source == GLFW_OSMESA_CONTEXT_API) { if (!_glfwInitOSMesa()) return GLFW_FALSE; if (!_glfwCreateContextOSMesa(window, ctxconfig, fbconfig)) return GLFW_FALSE; } else { _glfwInputError(GLFW_API_UNAVAILABLE, "Null: EGL not available"); return GLFW_FALSE; } } return GLFW_TRUE; } void _glfwPlatformDestroyWindow(_GLFWwindow* window) { if (window->context.destroy) window->context.destroy(window); } void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title) { } void _glfwPlatformSetWindowIcon(_GLFWwindow* window, int count, const GLFWimage* images) { } void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor, int xpos, int ypos, int width, int height, int refreshRate) { } void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos) { } void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos) { } void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height) { if (width) *width = window->null.width; if (height) *height = window->null.height; } void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) { window->null.width = width; window->null.height = height; } void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window, int minwidth, int minheight, int maxwidth, int maxheight) { } void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int n, int d) { } void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height) { if (width) *width = window->null.width; if (height) *height = window->null.height; } void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, int* left, int* top, int* right, int* bottom) { } void _glfwPlatformGetWindowContentScale(_GLFWwindow* window, float* xscale, float* yscale) { if (xscale) *xscale = 1.f; if (yscale) *yscale = 1.f; } void _glfwPlatformIconifyWindow(_GLFWwindow* window) { } void _glfwPlatformRestoreWindow(_GLFWwindow* window) { } void _glfwPlatformMaximizeWindow(_GLFWwindow* window) { } int _glfwPlatformWindowMaximized(_GLFWwindow* window) { return GLFW_FALSE; } int _glfwPlatformWindowHovered(_GLFWwindow* window) { return GLFW_FALSE; } int _glfwPlatformFramebufferTransparent(_GLFWwindow* window) { return GLFW_FALSE; } void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled) { } void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled) { } void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled) { } float _glfwPlatformGetWindowOpacity(_GLFWwindow* window) { return 1.f; } void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity) { } void _glfwPlatformSetRawMouseMotion(_GLFWwindow *window, GLFWbool enabled) { } GLFWbool _glfwPlatformRawMouseMotionSupported(void) { return GLFW_FALSE; } void _glfwPlatformShowWindow(_GLFWwindow* window) { } void _glfwPlatformRequestWindowAttention(_GLFWwindow* window) { } void _glfwPlatformUnhideWindow(_GLFWwindow* window) { } void _glfwPlatformHideWindow(_GLFWwindow* window) { } void _glfwPlatformFocusWindow(_GLFWwindow* window) { } int _glfwPlatformWindowFocused(_GLFWwindow* window) { return GLFW_FALSE; } int _glfwPlatformWindowIconified(_GLFWwindow* window) { return GLFW_FALSE; } int _glfwPlatformWindowVisible(_GLFWwindow* window) { return GLFW_FALSE; } void _glfwPlatformPollEvents(void) { } void _glfwPlatformWaitEvents(void) { } void _glfwPlatformWaitEventsTimeout(double timeout) { } void _glfwPlatformPostEmptyEvent(void) { } void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos) { } void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y) { } void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) { } int _glfwPlatformCreateCursor(_GLFWcursor* cursor, const GLFWimage* image, int xhot, int yhot) { return GLFW_TRUE; } int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape) { return GLFW_TRUE; } void _glfwPlatformDestroyCursor(_GLFWcursor* cursor) { } void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) { } void _glfwPlatformSetClipboardString(const char* string) { } const char* _glfwPlatformGetClipboardString(void) { return NULL; } const char* _glfwPlatformGetScancodeName(int scancode) { return ""; } int _glfwPlatformGetKeyScancode(int key) { return -1; } void _glfwPlatformGetRequiredInstanceExtensions(char** extensions) { } int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, VkPhysicalDevice device, uint32_t queuefamily) { return GLFW_FALSE; } VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, _GLFWwindow* window, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface) { // This seems like the most appropriate error to return here return VK_ERROR_INITIALIZATION_FAILED; } #endif #ifndef HEADER_GUARD_NULL_JOYSTICK_C #define HEADER_GUARD_NULL_JOYSTICK_C //======================================================================== // GLFW 3.3.7 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2016-2017 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== // It is fine to use C99 in this file because it will not be built with VS //======================================================================== ////////////////////////////////////////////////////////////////////////// ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode) { return GLFW_FALSE; } void _glfwPlatformUpdateGamepadGUID(char* guid) { } #endif #endif #ifdef _GLFW_X11 #ifndef HEADER_GUARD_X11_INIT_C #define HEADER_GUARD_X11_INIT_C //======================================================================== // GLFW 3.3.7 X11 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2019 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== // It is fine to use C99 in this file because it will not be built with VS //======================================================================== #include #include #include #include #include #include #include #include #include // 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 translateKeySyms(const KeySym* keysyms, int width) { if (width > 1) { switch (keysyms[1]) { case XK_KP_0: return GLFW_KEY_KP_0; case XK_KP_1: return GLFW_KEY_KP_1; case XK_KP_2: return GLFW_KEY_KP_2; case XK_KP_3: return GLFW_KEY_KP_3; case XK_KP_4: return GLFW_KEY_KP_4; case XK_KP_5: return GLFW_KEY_KP_5; case XK_KP_6: return GLFW_KEY_KP_6; case XK_KP_7: return GLFW_KEY_KP_7; case XK_KP_8: return GLFW_KEY_KP_8; case XK_KP_9: return GLFW_KEY_KP_9; case XK_KP_Separator: case XK_KP_Decimal: return GLFW_KEY_KP_DECIMAL; case XK_KP_Equal: return GLFW_KEY_KP_EQUAL; case XK_KP_Enter: return GLFW_KEY_KP_ENTER; default: break; } } switch (keysyms[0]) { case XK_Escape: return GLFW_KEY_ESCAPE; case XK_Tab: return GLFW_KEY_TAB; case XK_Shift_L: return GLFW_KEY_LEFT_SHIFT; case XK_Shift_R: return GLFW_KEY_RIGHT_SHIFT; case XK_Control_L: return GLFW_KEY_LEFT_CONTROL; case XK_Control_R: return GLFW_KEY_RIGHT_CONTROL; case XK_Meta_L: case XK_Alt_L: return GLFW_KEY_LEFT_ALT; case XK_Mode_switch: // Mapped to Alt_R on many keyboards case XK_ISO_Level3_Shift: // AltGr on at least some machines case XK_Meta_R: case XK_Alt_R: return GLFW_KEY_RIGHT_ALT; case XK_Super_L: return GLFW_KEY_LEFT_SUPER; case XK_Super_R: return GLFW_KEY_RIGHT_SUPER; case XK_Menu: return GLFW_KEY_MENU; case XK_Num_Lock: return GLFW_KEY_NUM_LOCK; case XK_Caps_Lock: return GLFW_KEY_CAPS_LOCK; case XK_Print: return GLFW_KEY_PRINT_SCREEN; case XK_Scroll_Lock: return GLFW_KEY_SCROLL_LOCK; case XK_Pause: return GLFW_KEY_PAUSE; case XK_Delete: return GLFW_KEY_DELETE; case XK_BackSpace: return GLFW_KEY_BACKSPACE; case XK_Return: return GLFW_KEY_ENTER; case XK_Home: return GLFW_KEY_HOME; case XK_End: return GLFW_KEY_END; case XK_Page_Up: return GLFW_KEY_PAGE_UP; case XK_Page_Down: return GLFW_KEY_PAGE_DOWN; case XK_Insert: return GLFW_KEY_INSERT; case XK_Left: return GLFW_KEY_LEFT; case XK_Right: return GLFW_KEY_RIGHT; case XK_Down: return GLFW_KEY_DOWN; case XK_Up: return GLFW_KEY_UP; case XK_F1: return GLFW_KEY_F1; case XK_F2: return GLFW_KEY_F2; case XK_F3: return GLFW_KEY_F3; case XK_F4: return GLFW_KEY_F4; case XK_F5: return GLFW_KEY_F5; case XK_F6: return GLFW_KEY_F6; case XK_F7: return GLFW_KEY_F7; case XK_F8: return GLFW_KEY_F8; case XK_F9: return GLFW_KEY_F9; case XK_F10: return GLFW_KEY_F10; case XK_F11: return GLFW_KEY_F11; case XK_F12: return GLFW_KEY_F12; case XK_F13: return GLFW_KEY_F13; case XK_F14: return GLFW_KEY_F14; case XK_F15: return GLFW_KEY_F15; case XK_F16: return GLFW_KEY_F16; case XK_F17: return GLFW_KEY_F17; case XK_F18: return GLFW_KEY_F18; case XK_F19: return GLFW_KEY_F19; case XK_F20: return GLFW_KEY_F20; case XK_F21: return GLFW_KEY_F21; case XK_F22: return GLFW_KEY_F22; case XK_F23: return GLFW_KEY_F23; case XK_F24: return GLFW_KEY_F24; case XK_F25: return GLFW_KEY_F25; // Numeric keypad case XK_KP_Divide: return GLFW_KEY_KP_DIVIDE; case XK_KP_Multiply: return GLFW_KEY_KP_MULTIPLY; case XK_KP_Subtract: return GLFW_KEY_KP_SUBTRACT; case XK_KP_Add: return GLFW_KEY_KP_ADD; // These should have been detected in secondary keysym test above! case XK_KP_Insert: return GLFW_KEY_KP_0; case XK_KP_End: return GLFW_KEY_KP_1; case XK_KP_Down: return GLFW_KEY_KP_2; case XK_KP_Page_Down: return GLFW_KEY_KP_3; case XK_KP_Left: return GLFW_KEY_KP_4; case XK_KP_Right: return GLFW_KEY_KP_6; case XK_KP_Home: return GLFW_KEY_KP_7; case XK_KP_Up: return GLFW_KEY_KP_8; case XK_KP_Page_Up: return GLFW_KEY_KP_9; case XK_KP_Delete: return GLFW_KEY_KP_DECIMAL; case XK_KP_Equal: return GLFW_KEY_KP_EQUAL; case XK_KP_Enter: return GLFW_KEY_KP_ENTER; // Last resort: Check for printable keys (should not happen if the XKB // extension is available). This will give a layout dependent mapping // (which is wrong, and we may miss some keys, especially on non-US // keyboards), but it's better than nothing... case XK_a: return GLFW_KEY_A; case XK_b: return GLFW_KEY_B; case XK_c: return GLFW_KEY_C; case XK_d: return GLFW_KEY_D; case XK_e: return GLFW_KEY_E; case XK_f: return GLFW_KEY_F; case XK_g: return GLFW_KEY_G; case XK_h: return GLFW_KEY_H; case XK_i: return GLFW_KEY_I; case XK_j: return GLFW_KEY_J; case XK_k: return GLFW_KEY_K; case XK_l: return GLFW_KEY_L; case XK_m: return GLFW_KEY_M; case XK_n: return GLFW_KEY_N; case XK_o: return GLFW_KEY_O; case XK_p: return GLFW_KEY_P; case XK_q: return GLFW_KEY_Q; case XK_r: return GLFW_KEY_R; case XK_s: return GLFW_KEY_S; case XK_t: return GLFW_KEY_T; case XK_u: return GLFW_KEY_U; case XK_v: return GLFW_KEY_V; case XK_w: return GLFW_KEY_W; case XK_x: return GLFW_KEY_X; case XK_y: return GLFW_KEY_Y; case XK_z: return GLFW_KEY_Z; case XK_1: return GLFW_KEY_1; case XK_2: return GLFW_KEY_2; case XK_3: return GLFW_KEY_3; case XK_4: return GLFW_KEY_4; case XK_5: return GLFW_KEY_5; case XK_6: return GLFW_KEY_6; case XK_7: return GLFW_KEY_7; case XK_8: return GLFW_KEY_8; case XK_9: return GLFW_KEY_9; case XK_0: return GLFW_KEY_0; case XK_space: return GLFW_KEY_SPACE; case XK_minus: return GLFW_KEY_MINUS; case XK_equal: return GLFW_KEY_EQUAL; case XK_bracketleft: return GLFW_KEY_LEFT_BRACKET; case XK_bracketright: return GLFW_KEY_RIGHT_BRACKET; case XK_backslash: return GLFW_KEY_BACKSLASH; case XK_semicolon: return GLFW_KEY_SEMICOLON; case XK_apostrophe: return GLFW_KEY_APOSTROPHE; case XK_grave: return GLFW_KEY_GRAVE_ACCENT; case XK_comma: return GLFW_KEY_COMMA; case XK_period: return GLFW_KEY_PERIOD; case XK_slash: return GLFW_KEY_SLASH; case XK_less: return GLFW_KEY_WORLD_1; // At least in some layouts... default: break; } // No matching translation was found return GLFW_KEY_UNKNOWN; } // Create key code translation tables // static void createKeyTables(void) { int scancode, scancodeMin, scancodeMax; memset(_glfw.x11.keycodes, -1, sizeof(_glfw.x11.keycodes)); memset(_glfw.x11.scancodes, -1, sizeof(_glfw.x11.scancodes)); if (_glfw.x11.xkb.available) { // Use XKB to determine physical key locations independently of the // current keyboard layout XkbDescPtr desc = XkbGetMap(_glfw.x11.display, 0, XkbUseCoreKbd); 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 = scancodeMin; scancode <= scancodeMax; scancode++) { int 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; } } // 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); 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) { 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 // static GLFWbool hasUsableInputMethodStyle(void) { GLFWbool found = GLFW_FALSE; XIMStyles* styles = NULL; if (XGetIMValues(_glfw.x11.im, XNQueryInputStyle, &styles, NULL) != NULL) return GLFW_FALSE; for (unsigned int i = 0; i < styles->count_styles; i++) { if (styles->supported_styles[i] == (XIMPreeditNothing | XIMStatusNothing)) { found = GLFW_TRUE; break; } } XFree(styles); return found; } // Check whether the specified atom is supported // static Atom getAtomIfSupported(Atom* supportedAtoms, unsigned long atomCount, const char* atomName) { const Atom atom = XInternAtom(_glfw.x11.display, atomName, False); for (unsigned long i = 0; i < atomCount; i++) { if (supportedAtoms[i] == atom) return atom; } return None; } // Check whether the running window manager is EWMH-compliant // static void detectEWMH(void) { // First we read the _NET_SUPPORTING_WM_CHECK property on the root window Window* windowFromRoot = NULL; if (!_glfwGetWindowPropertyX11(_glfw.x11.root, _glfw.x11.NET_SUPPORTING_WM_CHECK, XA_WINDOW, (unsigned char**) &windowFromRoot)) { return; } _glfwGrabErrorHandlerX11(); // If it exists, it should be the XID of a top-level window // Then we look for the same property on that window Window* windowFromChild = NULL; if (!_glfwGetWindowPropertyX11(*windowFromRoot, _glfw.x11.NET_SUPPORTING_WM_CHECK, XA_WINDOW, (unsigned char**) &windowFromChild)) { XFree(windowFromRoot); return; } _glfwReleaseErrorHandlerX11(); // If the property exists, it should contain the XID of the window if (*windowFromRoot != *windowFromChild) { XFree(windowFromRoot); XFree(windowFromChild); return; } XFree(windowFromRoot); XFree(windowFromChild); // We are now fairly sure that an EWMH-compliant WM is currently running // We can now start querying the WM about what features it supports by // looking in the _NET_SUPPORTED property on the root window // It should contain a list of supported EWMH protocol and state atoms Atom* supportedAtoms = NULL; const unsigned long atomCount = _glfwGetWindowPropertyX11(_glfw.x11.root, _glfw.x11.NET_SUPPORTED, XA_ATOM, (unsigned char**) &supportedAtoms); // See which of the atoms we support that are supported by the WM _glfw.x11.NET_WM_STATE = getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_STATE"); _glfw.x11.NET_WM_STATE_ABOVE = getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_STATE_ABOVE"); _glfw.x11.NET_WM_STATE_FULLSCREEN = getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_STATE_FULLSCREEN"); _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT = getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_STATE_MAXIMIZED_VERT"); _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ = getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_STATE_MAXIMIZED_HORZ"); _glfw.x11.NET_WM_STATE_DEMANDS_ATTENTION = getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_STATE_DEMANDS_ATTENTION"); _glfw.x11.NET_WM_FULLSCREEN_MONITORS = getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_FULLSCREEN_MONITORS"); _glfw.x11.NET_WM_WINDOW_TYPE = getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_WINDOW_TYPE"); _glfw.x11.NET_WM_WINDOW_TYPE_NORMAL = getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_WINDOW_TYPE_NORMAL"); _glfw.x11.NET_WORKAREA = getAtomIfSupported(supportedAtoms, atomCount, "_NET_WORKAREA"); _glfw.x11.NET_CURRENT_DESKTOP = getAtomIfSupported(supportedAtoms, atomCount, "_NET_CURRENT_DESKTOP"); _glfw.x11.NET_ACTIVE_WINDOW = getAtomIfSupported(supportedAtoms, atomCount, "_NET_ACTIVE_WINDOW"); _glfw.x11.NET_FRAME_EXTENTS = getAtomIfSupported(supportedAtoms, atomCount, "_NET_FRAME_EXTENTS"); _glfw.x11.NET_REQUEST_FRAME_EXTENTS = getAtomIfSupported(supportedAtoms, atomCount, "_NET_REQUEST_FRAME_EXTENTS"); if (supportedAtoms) XFree(supportedAtoms); } // Look for and initialize supported X11 extensions // 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) _glfw_dlsym(_glfw.x11.vidmode.handle, "XF86VidModeQueryExtension"); _glfw.x11.vidmode.GetGammaRamp = (PFN_XF86VidModeGetGammaRamp) _glfw_dlsym(_glfw.x11.vidmode.handle, "XF86VidModeGetGammaRamp"); _glfw.x11.vidmode.SetGammaRamp = (PFN_XF86VidModeSetGammaRamp) _glfw_dlsym(_glfw.x11.vidmode.handle, "XF86VidModeSetGammaRamp"); _glfw.x11.vidmode.GetGammaRampSize = (PFN_XF86VidModeGetGammaRampSize) _glfw_dlsym(_glfw.x11.vidmode.handle, "XF86VidModeGetGammaRampSize"); _glfw.x11.vidmode.available = XF86VidModeQueryExtension(_glfw.x11.display, &_glfw.x11.vidmode.eventBase, &_glfw.x11.vidmode.errorBase); } #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 if (_glfw.x11.xi.handle) { _glfw.x11.xi.QueryVersion = (PFN_XIQueryVersion) _glfw_dlsym(_glfw.x11.xi.handle, "XIQueryVersion"); _glfw.x11.xi.SelectEvents = (PFN_XISelectEvents) _glfw_dlsym(_glfw.x11.xi.handle, "XISelectEvents"); if (XQueryExtension(_glfw.x11.display, "XInputExtension", &_glfw.x11.xi.majorOpcode, &_glfw.x11.xi.eventBase, &_glfw.x11.xi.errorBase)) { _glfw.x11.xi.major = 2; _glfw.x11.xi.minor = 0; if (XIQueryVersion(_glfw.x11.display, &_glfw.x11.xi.major, &_glfw.x11.xi.minor) == Success) { _glfw.x11.xi.available = GLFW_TRUE; } } } #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 if (_glfw.x11.randr.handle) { _glfw.x11.randr.AllocGamma = (PFN_XRRAllocGamma) _glfw_dlsym(_glfw.x11.randr.handle, "XRRAllocGamma"); _glfw.x11.randr.FreeGamma = (PFN_XRRFreeGamma) _glfw_dlsym(_glfw.x11.randr.handle, "XRRFreeGamma"); _glfw.x11.randr.FreeCrtcInfo = (PFN_XRRFreeCrtcInfo) _glfw_dlsym(_glfw.x11.randr.handle, "XRRFreeCrtcInfo"); _glfw.x11.randr.FreeGamma = (PFN_XRRFreeGamma) _glfw_dlsym(_glfw.x11.randr.handle, "XRRFreeGamma"); _glfw.x11.randr.FreeOutputInfo = (PFN_XRRFreeOutputInfo) _glfw_dlsym(_glfw.x11.randr.handle, "XRRFreeOutputInfo"); _glfw.x11.randr.FreeScreenResources = (PFN_XRRFreeScreenResources) _glfw_dlsym(_glfw.x11.randr.handle, "XRRFreeScreenResources"); _glfw.x11.randr.GetCrtcGamma = (PFN_XRRGetCrtcGamma) _glfw_dlsym(_glfw.x11.randr.handle, "XRRGetCrtcGamma"); _glfw.x11.randr.GetCrtcGammaSize = (PFN_XRRGetCrtcGammaSize) _glfw_dlsym(_glfw.x11.randr.handle, "XRRGetCrtcGammaSize"); _glfw.x11.randr.GetCrtcInfo = (PFN_XRRGetCrtcInfo) _glfw_dlsym(_glfw.x11.randr.handle, "XRRGetCrtcInfo"); _glfw.x11.randr.GetOutputInfo = (PFN_XRRGetOutputInfo) _glfw_dlsym(_glfw.x11.randr.handle, "XRRGetOutputInfo"); _glfw.x11.randr.GetOutputPrimary = (PFN_XRRGetOutputPrimary) _glfw_dlsym(_glfw.x11.randr.handle, "XRRGetOutputPrimary"); _glfw.x11.randr.GetScreenResourcesCurrent = (PFN_XRRGetScreenResourcesCurrent) _glfw_dlsym(_glfw.x11.randr.handle, "XRRGetScreenResourcesCurrent"); _glfw.x11.randr.QueryExtension = (PFN_XRRQueryExtension) _glfw_dlsym(_glfw.x11.randr.handle, "XRRQueryExtension"); _glfw.x11.randr.QueryVersion = (PFN_XRRQueryVersion) _glfw_dlsym(_glfw.x11.randr.handle, "XRRQueryVersion"); _glfw.x11.randr.SelectInput = (PFN_XRRSelectInput) _glfw_dlsym(_glfw.x11.randr.handle, "XRRSelectInput"); _glfw.x11.randr.SetCrtcConfig = (PFN_XRRSetCrtcConfig) _glfw_dlsym(_glfw.x11.randr.handle, "XRRSetCrtcConfig"); _glfw.x11.randr.SetCrtcGamma = (PFN_XRRSetCrtcGamma) _glfw_dlsym(_glfw.x11.randr.handle, "XRRSetCrtcGamma"); _glfw.x11.randr.UpdateConfiguration = (PFN_XRRUpdateConfiguration) _glfw_dlsym(_glfw.x11.randr.handle, "XRRUpdateConfiguration"); if (XRRQueryExtension(_glfw.x11.display, &_glfw.x11.randr.eventBase, &_glfw.x11.randr.errorBase)) { if (XRRQueryVersion(_glfw.x11.display, &_glfw.x11.randr.major, &_glfw.x11.randr.minor)) { // The GLFW RandR path requires at least version 1.3 if (_glfw.x11.randr.major > 1 || _glfw.x11.randr.minor >= 3) _glfw.x11.randr.available = GLFW_TRUE; } else { _glfwInputError(GLFW_PLATFORM_ERROR, "X11: Failed to query RandR version"); } } } if (_glfw.x11.randr.available) { XRRScreenResources* sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root); if (!sr->ncrtc || !XRRGetCrtcGammaSize(_glfw.x11.display, sr->crtcs[0])) { // This is likely an older Nvidia driver with broken gamma support // Flag it as useless and fall back to xf86vm gamma, if available _glfw.x11.randr.gammaBroken = GLFW_TRUE; } if (!sr->ncrtc) { // A system without CRTCs is likely a system with broken RandR // Disable the RandR monitor path and fall back to core functions _glfw.x11.randr.monitorBroken = GLFW_TRUE; } XRRFreeScreenResources(sr); } if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) { XRRSelectInput(_glfw.x11.display, _glfw.x11.root, RROutputChangeNotifyMask); } #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 if (_glfw.x11.xcursor.handle) { _glfw.x11.xcursor.ImageCreate = (PFN_XcursorImageCreate) _glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorImageCreate"); _glfw.x11.xcursor.ImageDestroy = (PFN_XcursorImageDestroy) _glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorImageDestroy"); _glfw.x11.xcursor.ImageLoadCursor = (PFN_XcursorImageLoadCursor) _glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorImageLoadCursor"); } #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 if (_glfw.x11.xinerama.handle) { _glfw.x11.xinerama.IsActive = (PFN_XineramaIsActive) _glfw_dlsym(_glfw.x11.xinerama.handle, "XineramaIsActive"); _glfw.x11.xinerama.QueryExtension = (PFN_XineramaQueryExtension) _glfw_dlsym(_glfw.x11.xinerama.handle, "XineramaQueryExtension"); _glfw.x11.xinerama.QueryScreens = (PFN_XineramaQueryScreens) _glfw_dlsym(_glfw.x11.xinerama.handle, "XineramaQueryScreens"); if (XineramaQueryExtension(_glfw.x11.display, &_glfw.x11.xinerama.major, &_glfw.x11.xinerama.minor)) { if (XineramaIsActive(_glfw.x11.display)) _glfw.x11.xinerama.available = GLFW_TRUE; } } _glfw.x11.xkb.major = 1; _glfw.x11.xkb.minor = 0; _glfw.x11.xkb.available = XkbQueryExtension(_glfw.x11.display, &_glfw.x11.xkb.majorOpcode, &_glfw.x11.xkb.eventBase, &_glfw.x11.xkb.errorBase, &_glfw.x11.xkb.major, &_glfw.x11.xkb.minor); if (_glfw.x11.xkb.available) { Bool supported; if (XkbSetDetectableAutoRepeat(_glfw.x11.display, True, &supported)) { if (supported) _glfw.x11.xkb.detectable = GLFW_TRUE; } XkbStateRec state; if (XkbGetState(_glfw.x11.display, XkbUseCoreKbd, &state) == Success) _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 if (_glfw.x11.x11xcb.handle) { _glfw.x11.x11xcb.GetXCBConnection = (PFN_XGetXCBConnection) _glfw_dlsym(_glfw.x11.x11xcb.handle, "XGetXCBConnection"); } #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 if (_glfw.x11.xrender.handle) { _glfw.x11.xrender.QueryExtension = (PFN_XRenderQueryExtension) _glfw_dlsym(_glfw.x11.xrender.handle, "XRenderQueryExtension"); _glfw.x11.xrender.QueryVersion = (PFN_XRenderQueryVersion) _glfw_dlsym(_glfw.x11.xrender.handle, "XRenderQueryVersion"); _glfw.x11.xrender.FindVisualFormat = (PFN_XRenderFindVisualFormat) _glfw_dlsym(_glfw.x11.xrender.handle, "XRenderFindVisualFormat"); if (XRenderQueryExtension(_glfw.x11.display, &_glfw.x11.xrender.errorBase, &_glfw.x11.xrender.eventBase)) { if (XRenderQueryVersion(_glfw.x11.display, &_glfw.x11.xrender.major, &_glfw.x11.xrender.minor)) { _glfw.x11.xrender.available = GLFW_TRUE; } } } // Update the key code LUT // FIXME: We should listen to XkbMapNotify events to track changes to // the keyboard mapping. createKeyTables(); // String format atoms _glfw.x11.NULL_ = XInternAtom(_glfw.x11.display, "NULL", False); _glfw.x11.UTF8_STRING = XInternAtom(_glfw.x11.display, "UTF8_STRING", False); _glfw.x11.ATOM_PAIR = XInternAtom(_glfw.x11.display, "ATOM_PAIR", False); // Custom selection property atom _glfw.x11.GLFW_SELECTION = XInternAtom(_glfw.x11.display, "GLFW_SELECTION", False); // ICCCM standard clipboard atoms _glfw.x11.TARGETS = XInternAtom(_glfw.x11.display, "TARGETS", False); _glfw.x11.MULTIPLE = XInternAtom(_glfw.x11.display, "MULTIPLE", False); _glfw.x11.PRIMARY = XInternAtom(_glfw.x11.display, "PRIMARY", False); _glfw.x11.INCR = XInternAtom(_glfw.x11.display, "INCR", False); _glfw.x11.CLIPBOARD = XInternAtom(_glfw.x11.display, "CLIPBOARD", False); // Clipboard manager atoms _glfw.x11.CLIPBOARD_MANAGER = XInternAtom(_glfw.x11.display, "CLIPBOARD_MANAGER", False); _glfw.x11.SAVE_TARGETS = XInternAtom(_glfw.x11.display, "SAVE_TARGETS", False); // Xdnd (drag and drop) atoms _glfw.x11.XdndAware = XInternAtom(_glfw.x11.display, "XdndAware", False); _glfw.x11.XdndEnter = XInternAtom(_glfw.x11.display, "XdndEnter", False); _glfw.x11.XdndPosition = XInternAtom(_glfw.x11.display, "XdndPosition", False); _glfw.x11.XdndStatus = XInternAtom(_glfw.x11.display, "XdndStatus", False); _glfw.x11.XdndActionCopy = XInternAtom(_glfw.x11.display, "XdndActionCopy", False); _glfw.x11.XdndDrop = XInternAtom(_glfw.x11.display, "XdndDrop", False); _glfw.x11.XdndFinished = XInternAtom(_glfw.x11.display, "XdndFinished", False); _glfw.x11.XdndSelection = XInternAtom(_glfw.x11.display, "XdndSelection", False); _glfw.x11.XdndTypeList = XInternAtom(_glfw.x11.display, "XdndTypeList", False); _glfw.x11.text_uri_list = XInternAtom(_glfw.x11.display, "text/uri-list", False); // ICCCM, EWMH and Motif window property atoms // These can be set safely even without WM support // The EWMH atoms that require WM support are handled in detectEWMH _glfw.x11.WM_PROTOCOLS = XInternAtom(_glfw.x11.display, "WM_PROTOCOLS", False); _glfw.x11.WM_STATE = XInternAtom(_glfw.x11.display, "WM_STATE", False); _glfw.x11.WM_DELETE_WINDOW = XInternAtom(_glfw.x11.display, "WM_DELETE_WINDOW", False); _glfw.x11.NET_SUPPORTED = XInternAtom(_glfw.x11.display, "_NET_SUPPORTED", False); _glfw.x11.NET_SUPPORTING_WM_CHECK = XInternAtom(_glfw.x11.display, "_NET_SUPPORTING_WM_CHECK", False); _glfw.x11.NET_WM_ICON = XInternAtom(_glfw.x11.display, "_NET_WM_ICON", False); _glfw.x11.NET_WM_PING = XInternAtom(_glfw.x11.display, "_NET_WM_PING", False); _glfw.x11.NET_WM_PID = XInternAtom(_glfw.x11.display, "_NET_WM_PID", False); _glfw.x11.NET_WM_NAME = XInternAtom(_glfw.x11.display, "_NET_WM_NAME", False); _glfw.x11.NET_WM_ICON_NAME = XInternAtom(_glfw.x11.display, "_NET_WM_ICON_NAME", False); _glfw.x11.NET_WM_BYPASS_COMPOSITOR = XInternAtom(_glfw.x11.display, "_NET_WM_BYPASS_COMPOSITOR", False); _glfw.x11.NET_WM_WINDOW_OPACITY = XInternAtom(_glfw.x11.display, "_NET_WM_WINDOW_OPACITY", False); _glfw.x11.MOTIF_WM_HINTS = XInternAtom(_glfw.x11.display, "_MOTIF_WM_HINTS", False); // The compositing manager selection name contains the screen number { char name[32]; snprintf(name, sizeof(name), "_NET_WM_CM_S%u", _glfw.x11.screen); _glfw.x11.NET_WM_CM_Sx = XInternAtom(_glfw.x11.display, name, False); } // Detect whether an EWMH-conformant window manager is running detectEWMH(); return GLFW_TRUE; } // Retrieve system content scale via folklore heuristics // static void getSystemContentScale(float* xscale, float* yscale) { // Start by assuming the default X11 DPI // NOTE: Some desktop environments (KDE) may remove the Xft.dpi field when it // would be set to 96, so assume that is the case if we cannot find it float xdpi = 96.f, ydpi = 96.f; // NOTE: Basing the scale on Xft.dpi where available should provide the most // consistent user experience (matches Qt, Gtk, etc), although not // always the most accurate one char* rms = XResourceManagerString(_glfw.x11.display); if (rms) { XrmDatabase db = XrmGetStringDatabase(rms); if (db) { XrmValue value; char* type = NULL; if (XrmGetResource(db, "Xft.dpi", "Xft.Dpi", &type, &value)) { if (type && strcmp(type, "String") == 0) xdpi = ydpi = atof(value.addr); } XrmDestroyDatabase(db); } } *xscale = xdpi / 96.f; *yscale = ydpi / 96.f; } // Create a blank cursor for hidden and disabled cursor modes // static Cursor createHiddenCursor(void) { unsigned char pixels[16 * 16 * 4] = { 0 }; GLFWimage image = { 16, 16, pixels }; return _glfwCreateCursorX11(&image, 0, 0); } // Create a helper window for IPC // static Window createHelperWindow(void) { XSetWindowAttributes wa; wa.event_mask = PropertyChangeMask; return XCreateWindow(_glfw.x11.display, _glfw.x11.root, 0, 0, 1, 1, 0, 0, InputOnly, DefaultVisual(_glfw.x11.display, _glfw.x11.screen), 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; } ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// // Sets the X error handler callback // void _glfwGrabErrorHandlerX11(void) { _glfw.x11.errorCode = Success; XSetErrorHandler(errorHandler); } // Clears the X error handler callback // void _glfwReleaseErrorHandlerX11(void) { // Synchronize to make sure all commands are processed XSync(_glfw.x11.display, False); XSetErrorHandler(NULL); } // Reports the specified error, appending information about the last X error // void _glfwInputErrorX11(int error, const char* message) { char buffer[_GLFW_MESSAGE_SIZE]; XGetErrorText(_glfw.x11.display, _glfw.x11.errorCode, buffer, sizeof(buffer)); _glfwInputError(error, "%s: %s", message, buffer); } // Creates a native cursor object from the specified image and hotspot // Cursor _glfwCreateCursorX11(const GLFWimage* image, int xhot, int yhot) { int i; Cursor cursor; if (!_glfw.x11.xcursor.handle) return None; XcursorImage* native = XcursorImageCreate(image->width, image->height); if (native == NULL) return None; native->xhot = xhot; native->yhot = yhot; unsigned char* source = (unsigned char*) image->pixels; XcursorPixel* target = native->pixels; for (i = 0; i < image->width * image->height; i++, target++, source += 4) { unsigned int alpha = source[3]; *target = (alpha << 24) | ((unsigned char) ((source[0] * alpha) / 255) << 16) | ((unsigned char) ((source[1] * alpha) / 255) << 8) | ((unsigned char) ((source[2] * alpha) / 255) << 0); } cursor = XcursorImageLoadCursor(_glfw.x11.display, native); XcursorImageDestroy(native); return cursor; } ////////////////////////////////////////////////////////////////////////// ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// int _glfwPlatformInit(void) { // 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, ""); XInitThreads(); XrmInitialize(); _glfw.x11.display = XOpenDisplay(NULL); if (!_glfw.x11.display) { const char* display = getenv("DISPLAY"); if (display) { _glfwInputError(GLFW_PLATFORM_ERROR, "X11: Failed to open display %s", display); } else { _glfwInputError(GLFW_PLATFORM_ERROR, "X11: The DISPLAY environment variable is missing"); } return GLFW_FALSE; } _glfw.x11.screen = DefaultScreen(_glfw.x11.display); _glfw.x11.root = RootWindow(_glfw.x11.display, _glfw.x11.screen); _glfw.x11.context = XUniqueContext(); getSystemContentScale(&_glfw.x11.contentScaleX, &_glfw.x11.contentScaleY); if (!createEmptyEventPipe()) return GLFW_FALSE; if (!initExtensions()) return GLFW_FALSE; _glfw.x11.helperWindowHandle = createHelperWindow(); _glfw.x11.hiddenCursorHandle = createHiddenCursor(); if (XSupportsLocale()) { XSetLocaleModifiers(""); _glfw.x11.im = XOpenIM(_glfw.x11.display, 0, NULL, NULL); if (_glfw.x11.im) { if (!hasUsableInputMethodStyle()) { XCloseIM(_glfw.x11.im); _glfw.x11.im = NULL; } } } #if defined(__linux__) if (!_glfwInitJoysticksLinux()) return GLFW_FALSE; #endif _glfwInitTimerPOSIX(); _glfwPollMonitorsX11(); return GLFW_TRUE; } void _glfwPlatformTerminate(void) { if (_glfw.x11.helperWindowHandle) { if (XGetSelectionOwner(_glfw.x11.display, _glfw.x11.CLIPBOARD) == _glfw.x11.helperWindowHandle) { _glfwPushSelectionToManagerX11(); } XDestroyWindow(_glfw.x11.display, _glfw.x11.helperWindowHandle); _glfw.x11.helperWindowHandle = None; } if (_glfw.x11.hiddenCursorHandle) { XFreeCursor(_glfw.x11.display, _glfw.x11.hiddenCursorHandle); _glfw.x11.hiddenCursorHandle = (Cursor) 0; } free(_glfw.x11.primarySelectionString); free(_glfw.x11.clipboardString); if (_glfw.x11.im) { XCloseIM(_glfw.x11.im); _glfw.x11.im = NULL; } if (_glfw.x11.display) { XCloseDisplay(_glfw.x11.display); _glfw.x11.display = NULL; } if (_glfw.x11.x11xcb.handle) { _glfw_dlclose(_glfw.x11.x11xcb.handle); _glfw.x11.x11xcb.handle = NULL; } if (_glfw.x11.xcursor.handle) { _glfw_dlclose(_glfw.x11.xcursor.handle); _glfw.x11.xcursor.handle = NULL; } if (_glfw.x11.randr.handle) { _glfw_dlclose(_glfw.x11.randr.handle); _glfw.x11.randr.handle = NULL; } if (_glfw.x11.xinerama.handle) { _glfw_dlclose(_glfw.x11.xinerama.handle); _glfw.x11.xinerama.handle = NULL; } if (_glfw.x11.xrender.handle) { _glfw_dlclose(_glfw.x11.xrender.handle); _glfw.x11.xrender.handle = NULL; } if (_glfw.x11.vidmode.handle) { _glfw_dlclose(_glfw.x11.vidmode.handle); _glfw.x11.vidmode.handle = NULL; } if (_glfw.x11.xi.handle) { _glfw_dlclose(_glfw.x11.xi.handle); _glfw.x11.xi.handle = NULL; } // NOTE: These need to be unloaded after XCloseDisplay, as they register // cleanup callbacks that get called by that function _glfwTerminateEGL(); _glfwTerminateGLX(); #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) { return _GLFW_VERSION_NUMBER " X11 GLX EGL OSMesa" #if defined(_POSIX_TIMERS) && defined(_POSIX_MONOTONIC_CLOCK) " clock_gettime" #else " gettimeofday" #endif #if defined(__linux__) " evdev" #endif #if defined(_GLFW_BUILD_DLL) " shared" #endif ; } #endif #ifndef HEADER_GUARD_X11_MONITOR_C #define HEADER_GUARD_X11_MONITOR_C //======================================================================== // GLFW 3.3.7 X11 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2019 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== // It is fine to use C99 in this file because it will not be built with VS //======================================================================== #include #include #include #include // Check whether the display mode should be included in enumeration // static GLFWbool modeIsGood(const XRRModeInfo* mi) { return (mi->modeFlags & RR_Interlace) == 0; } // Calculates the refresh rate, in Hz, from the specified RandR mode info // static int calculateRefreshRate(const XRRModeInfo* mi) { if (mi->hTotal && mi->vTotal) return (int) round((double) mi->dotClock / ((double) mi->hTotal * (double) mi->vTotal)); else return 0; } // Returns the mode info for a RandR mode XID // static const XRRModeInfo* getModeInfo(const XRRScreenResources* sr, RRMode id) { for (int i = 0; i < sr->nmode; i++) { if (sr->modes[i].id == id) return sr->modes + i; } return NULL; } // Convert RandR mode info to GLFW video mode // static GLFWvidmode vidmodeFromModeInfo(const XRRModeInfo* mi, const XRRCrtcInfo* ci) { GLFWvidmode mode; if (ci->rotation == RR_Rotate_90 || ci->rotation == RR_Rotate_270) { mode.width = mi->height; mode.height = mi->width; } else { mode.width = mi->width; mode.height = mi->height; } mode.refreshRate = calculateRefreshRate(mi); _glfwSplitBPP(DefaultDepth(_glfw.x11.display, _glfw.x11.screen), &mode.redBits, &mode.greenBits, &mode.blueBits); return mode; } ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// // Poll for changes in the set of connected monitors // void _glfwPollMonitorsX11(void) { if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) { int disconnectedCount, screenCount = 0; _GLFWmonitor** disconnected = NULL; XineramaScreenInfo* screens = NULL; XRRScreenResources* sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root); RROutput primary = XRRGetOutputPrimary(_glfw.x11.display, _glfw.x11.root); if (_glfw.x11.xinerama.available) screens = XineramaQueryScreens(_glfw.x11.display, &screenCount); disconnectedCount = _glfw.monitorCount; if (disconnectedCount) { disconnected = calloc(_glfw.monitorCount, sizeof(_GLFWmonitor*)); memcpy(disconnected, _glfw.monitors, _glfw.monitorCount * sizeof(_GLFWmonitor*)); } for (int i = 0; i < sr->noutput; i++) { int j, type, widthMM, heightMM; XRROutputInfo* oi = XRRGetOutputInfo(_glfw.x11.display, sr, sr->outputs[i]); if (oi->connection != RR_Connected || oi->crtc == None) { XRRFreeOutputInfo(oi); continue; } for (j = 0; j < disconnectedCount; j++) { if (disconnected[j] && disconnected[j]->x11.output == sr->outputs[i]) { disconnected[j] = NULL; break; } } if (j < disconnectedCount) { XRRFreeOutputInfo(oi); continue; } XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, oi->crtc); if (ci->rotation == RR_Rotate_90 || ci->rotation == RR_Rotate_270) { widthMM = oi->mm_height; heightMM = oi->mm_width; } else { widthMM = oi->mm_width; heightMM = oi->mm_height; } if (widthMM <= 0 || heightMM <= 0) { // HACK: If RandR does not provide a physical size, assume the // 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); heightMM = (int) (ci->height * 25.4f / 96.f); } _GLFWmonitor* monitor = _glfwAllocMonitor(oi->name, widthMM, heightMM); monitor->x11.output = sr->outputs[i]; monitor->x11.crtc = oi->crtc; for (j = 0; j < screenCount; j++) { if (screens[j].x_org == ci->x && screens[j].y_org == ci->y && screens[j].width == ci->width && screens[j].height == ci->height) { monitor->x11.index = j; break; } } if (monitor->x11.output == primary) type = _GLFW_INSERT_FIRST; else type = _GLFW_INSERT_LAST; _glfwInputMonitor(monitor, GLFW_CONNECTED, type); XRRFreeOutputInfo(oi); XRRFreeCrtcInfo(ci); } XRRFreeScreenResources(sr); if (screens) XFree(screens); for (int i = 0; i < disconnectedCount; i++) { if (disconnected[i]) _glfwInputMonitor(disconnected[i], GLFW_DISCONNECTED, 0); } free(disconnected); } else { const int widthMM = DisplayWidthMM(_glfw.x11.display, _glfw.x11.screen); const int heightMM = DisplayHeightMM(_glfw.x11.display, _glfw.x11.screen); _glfwInputMonitor(_glfwAllocMonitor("Display", widthMM, heightMM), GLFW_CONNECTED, _GLFW_INSERT_FIRST); } } // Set the current video mode for the specified monitor // void _glfwSetVideoModeX11(_GLFWmonitor* monitor, const GLFWvidmode* desired) { if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) { GLFWvidmode current; RRMode native = None; const GLFWvidmode* best = _glfwChooseVideoMode(monitor, desired); _glfwPlatformGetVideoMode(monitor, ¤t); if (_glfwCompareVideoModes(¤t, best) == 0) return; XRRScreenResources* sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root); XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc); XRROutputInfo* oi = XRRGetOutputInfo(_glfw.x11.display, sr, monitor->x11.output); for (int i = 0; i < oi->nmode; i++) { const XRRModeInfo* mi = getModeInfo(sr, oi->modes[i]); if (!modeIsGood(mi)) continue; const GLFWvidmode mode = vidmodeFromModeInfo(mi, ci); if (_glfwCompareVideoModes(best, &mode) == 0) { native = mi->id; break; } } if (native) { if (monitor->x11.oldMode == None) monitor->x11.oldMode = ci->mode; XRRSetCrtcConfig(_glfw.x11.display, sr, monitor->x11.crtc, CurrentTime, ci->x, ci->y, native, ci->rotation, ci->outputs, ci->noutput); } XRRFreeOutputInfo(oi); XRRFreeCrtcInfo(ci); XRRFreeScreenResources(sr); } } // Restore the saved (original) video mode for the specified monitor // void _glfwRestoreVideoModeX11(_GLFWmonitor* monitor) { if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) { if (monitor->x11.oldMode == None) return; XRRScreenResources* sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root); XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc); XRRSetCrtcConfig(_glfw.x11.display, sr, monitor->x11.crtc, CurrentTime, ci->x, ci->y, monitor->x11.oldMode, ci->rotation, ci->outputs, ci->noutput); XRRFreeCrtcInfo(ci); XRRFreeScreenResources(sr); monitor->x11.oldMode = None; } } ////////////////////////////////////////////////////////////////////////// ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor) { } void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) { if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) { XRRScreenResources* sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root); XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc); if (ci) { if (xpos) *xpos = ci->x; if (ypos) *ypos = ci->y; XRRFreeCrtcInfo(ci); } XRRFreeScreenResources(sr); } } void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor, float* xscale, float* yscale) { if (xscale) *xscale = _glfw.x11.contentScaleX; if (yscale) *yscale = _glfw.x11.contentScaleY; } void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor, int* xpos, int* ypos, int* width, int* height) { int areaX = 0, areaY = 0, areaWidth = 0, areaHeight = 0; if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) { XRRScreenResources* sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root); XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc); areaX = ci->x; areaY = ci->y; const XRRModeInfo* mi = getModeInfo(sr, ci->mode); if (ci->rotation == RR_Rotate_90 || ci->rotation == RR_Rotate_270) { areaWidth = mi->height; areaHeight = mi->width; } else { areaWidth = mi->width; areaHeight = mi->height; } XRRFreeCrtcInfo(ci); XRRFreeScreenResources(sr); } else { areaWidth = DisplayWidth(_glfw.x11.display, _glfw.x11.screen); areaHeight = DisplayHeight(_glfw.x11.display, _glfw.x11.screen); } if (_glfw.x11.NET_WORKAREA && _glfw.x11.NET_CURRENT_DESKTOP) { Atom* extents = NULL; Atom* desktop = NULL; const unsigned long extentCount = _glfwGetWindowPropertyX11(_glfw.x11.root, _glfw.x11.NET_WORKAREA, XA_CARDINAL, (unsigned char**) &extents); if (_glfwGetWindowPropertyX11(_glfw.x11.root, _glfw.x11.NET_CURRENT_DESKTOP, XA_CARDINAL, (unsigned char**) &desktop) > 0) { if (extentCount >= 4 && *desktop < extentCount / 4) { const int globalX = extents[*desktop * 4 + 0]; const int globalY = extents[*desktop * 4 + 1]; const int globalWidth = extents[*desktop * 4 + 2]; const int globalHeight = extents[*desktop * 4 + 3]; if (areaX < globalX) { areaWidth -= globalX - areaX; areaX = globalX; } if (areaY < globalY) { areaHeight -= globalY - areaY; areaY = globalY; } if (areaX + areaWidth > globalX + globalWidth) areaWidth = globalX - areaX + globalWidth; if (areaY + areaHeight > globalY + globalHeight) areaHeight = globalY - areaY + globalHeight; } } if (extents) XFree(extents); if (desktop) XFree(desktop); } if (xpos) *xpos = areaX; if (ypos) *ypos = areaY; if (width) *width = areaWidth; if (height) *height = areaHeight; } GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count) { GLFWvidmode* result; *count = 0; if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) { XRRScreenResources* sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root); XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc); XRROutputInfo* oi = XRRGetOutputInfo(_glfw.x11.display, sr, monitor->x11.output); result = calloc(oi->nmode, sizeof(GLFWvidmode)); for (int i = 0; i < oi->nmode; i++) { const XRRModeInfo* mi = getModeInfo(sr, oi->modes[i]); if (!modeIsGood(mi)) continue; const GLFWvidmode mode = vidmodeFromModeInfo(mi, ci); int j; for (j = 0; j < *count; j++) { if (_glfwCompareVideoModes(result + j, &mode) == 0) break; } // Skip duplicate modes if (j < *count) continue; (*count)++; result[*count - 1] = mode; } XRRFreeOutputInfo(oi); XRRFreeCrtcInfo(ci); XRRFreeScreenResources(sr); } else { *count = 1; result = calloc(1, sizeof(GLFWvidmode)); _glfwPlatformGetVideoMode(monitor, result); } return result; } void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode) { if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) { XRRScreenResources* sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root); XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc); if (ci) { const XRRModeInfo* mi = getModeInfo(sr, ci->mode); if (mi) // mi can be NULL if the monitor has been disconnected *mode = vidmodeFromModeInfo(mi, ci); XRRFreeCrtcInfo(ci); } XRRFreeScreenResources(sr); } else { mode->width = DisplayWidth(_glfw.x11.display, _glfw.x11.screen); mode->height = DisplayHeight(_glfw.x11.display, _glfw.x11.screen); mode->refreshRate = 0; _glfwSplitBPP(DefaultDepth(_glfw.x11.display, _glfw.x11.screen), &mode->redBits, &mode->greenBits, &mode->blueBits); } } GLFWbool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) { if (_glfw.x11.randr.available && !_glfw.x11.randr.gammaBroken) { const size_t size = XRRGetCrtcGammaSize(_glfw.x11.display, monitor->x11.crtc); XRRCrtcGamma* gamma = XRRGetCrtcGamma(_glfw.x11.display, monitor->x11.crtc); _glfwAllocGammaArrays(ramp, size); memcpy(ramp->red, gamma->red, size * sizeof(unsigned short)); memcpy(ramp->green, gamma->green, size * sizeof(unsigned short)); memcpy(ramp->blue, gamma->blue, size * sizeof(unsigned short)); XRRFreeGamma(gamma); return GLFW_TRUE; } else if (_glfw.x11.vidmode.available) { int size; XF86VidModeGetGammaRampSize(_glfw.x11.display, _glfw.x11.screen, &size); _glfwAllocGammaArrays(ramp, size); XF86VidModeGetGammaRamp(_glfw.x11.display, _glfw.x11.screen, ramp->size, ramp->red, ramp->green, ramp->blue); return GLFW_TRUE; } else { _glfwInputError(GLFW_PLATFORM_ERROR, "X11: Gamma ramp access not supported by server"); return GLFW_FALSE; } } void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) { if (_glfw.x11.randr.available && !_glfw.x11.randr.gammaBroken) { if (XRRGetCrtcGammaSize(_glfw.x11.display, monitor->x11.crtc) != ramp->size) { _glfwInputError(GLFW_PLATFORM_ERROR, "X11: Gamma ramp size must match current ramp size"); return; } XRRCrtcGamma* gamma = XRRAllocGamma(ramp->size); memcpy(gamma->red, ramp->red, ramp->size * sizeof(unsigned short)); memcpy(gamma->green, ramp->green, ramp->size * sizeof(unsigned short)); memcpy(gamma->blue, ramp->blue, ramp->size * sizeof(unsigned short)); XRRSetCrtcGamma(_glfw.x11.display, monitor->x11.crtc, gamma); XRRFreeGamma(gamma); } else if (_glfw.x11.vidmode.available) { XF86VidModeSetGammaRamp(_glfw.x11.display, _glfw.x11.screen, ramp->size, (unsigned short*) ramp->red, (unsigned short*) ramp->green, (unsigned short*) ramp->blue); } else { _glfwInputError(GLFW_PLATFORM_ERROR, "X11: Gamma ramp access not supported by server"); } } ////////////////////////////////////////////////////////////////////////// ////// GLFW native API ////// ////////////////////////////////////////////////////////////////////////// GLFWAPI RRCrtc glfwGetX11Adapter(GLFWmonitor* handle) { _GLFWmonitor* monitor = (_GLFWmonitor*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(None); return monitor->x11.crtc; } GLFWAPI RROutput glfwGetX11Monitor(GLFWmonitor* handle) { _GLFWmonitor* monitor = (_GLFWmonitor*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(None); return monitor->x11.output; } #endif #ifndef HEADER_GUARD_X11_WINDOW_C #define HEADER_GUARD_X11_WINDOW_C //======================================================================== // GLFW 3.3.7 X11 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2019 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== // It is fine to use C99 in this file because it will not be built with VS //======================================================================== #ifndef _GNU_SOURCE //< @r-lyeh: add missing guard #define _GNU_SOURCE #endif #include #include #include #include #include #include #include #include #include #include #include // Action for EWMH client messages #define _NET_WM_STATE_REMOVE 0 #define _NET_WM_STATE_ADD 1 #define _NET_WM_STATE_TOGGLE 2 // Additional mouse button names for XButtonEvent #define Button6 6 #define Button7 7 // Motif WM hints flags #define MWM_HINTS_DECORATIONS 2 #define MWM_DECOR_ALL 1 #define _GLFW_XDND_VERSION 5 // 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; } } } // 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 int 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 int 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) // static GLFWbool waitForVisibilityNotify(_GLFWwindow* window) { XEvent dummy; double timeout = 0.1; while (!XCheckTypedWindowEvent(_glfw.x11.display, window->x11.handle, VisibilityNotify, &dummy)) { if (!waitForX11Event(&timeout)) return GLFW_FALSE; } return GLFW_TRUE; } // Returns whether the window is iconified // static int getWindowState(_GLFWwindow* window) { int result = WithdrawnState; struct { CARD32 state; Window icon; } *state = NULL; if (_glfwGetWindowPropertyX11(window->x11.handle, _glfw.x11.WM_STATE, _glfw.x11.WM_STATE, (unsigned char**) &state) >= 2) { result = state->state; } if (state) XFree(state); return result; } // Returns whether the event is a selection event // static Bool isSelectionEvent(Display* display, XEvent* event, XPointer pointer) { if (event->xany.window != _glfw.x11.helperWindowHandle) return False; return event->type == SelectionRequest || event->type == SelectionNotify || event->type == SelectionClear; } // Returns whether it is a _NET_FRAME_EXTENTS event for the specified window // static Bool isFrameExtentsEvent(Display* display, XEvent* event, XPointer pointer) { _GLFWwindow* window = (_GLFWwindow*) pointer; return event->type == PropertyNotify && event->xproperty.state == PropertyNewValue && event->xproperty.window == window->x11.handle && event->xproperty.atom == _glfw.x11.NET_FRAME_EXTENTS; } // Returns whether it is a property event for the specified selection transfer // static Bool isSelPropNewValueNotify(Display* display, XEvent* event, XPointer pointer) { XEvent* notification = (XEvent*) pointer; return event->type == PropertyNotify && event->xproperty.state == PropertyNewValue && event->xproperty.window == notification->xselection.requestor && event->xproperty.atom == notification->xselection.property; } // Translates an X event modifier state mask // static int translateState(int state) { int mods = 0; if (state & ShiftMask) mods |= GLFW_MOD_SHIFT; if (state & ControlMask) mods |= GLFW_MOD_CONTROL; if (state & Mod1Mask) mods |= GLFW_MOD_ALT; if (state & Mod4Mask) mods |= GLFW_MOD_SUPER; if (state & LockMask) mods |= GLFW_MOD_CAPS_LOCK; if (state & Mod2Mask) mods |= GLFW_MOD_NUM_LOCK; return mods; } // Translates an X11 key code to a GLFW key token // static int translateKey(int scancode) { // Use the pre-filled LUT (see createKeyTables() in x11_init.c) if (scancode < 0 || scancode > 255) return GLFW_KEY_UNKNOWN; return _glfw.x11.keycodes[scancode]; } // Sends an EWMH or ICCCM event to the window manager // static void sendEventToWM(_GLFWwindow* window, Atom type, long a, long b, long c, long d, long e) { XEvent event = { ClientMessage }; event.xclient.window = window->x11.handle; event.xclient.format = 32; // Data is 32-bit longs event.xclient.message_type = type; event.xclient.data.l[0] = a; event.xclient.data.l[1] = b; event.xclient.data.l[2] = c; event.xclient.data.l[3] = d; event.xclient.data.l[4] = e; XSendEvent(_glfw.x11.display, _glfw.x11.root, False, SubstructureNotifyMask | SubstructureRedirectMask, &event); } // Updates the normal hints according to the window settings // static void updateNormalHints(_GLFWwindow* window, int width, int height) { XSizeHints* hints = XAllocSizeHints(); if (!window->monitor) { if (window->resizable) { if (window->minwidth != GLFW_DONT_CARE && window->minheight != GLFW_DONT_CARE) { hints->flags |= PMinSize; hints->min_width = window->minwidth; hints->min_height = window->minheight; } if (window->maxwidth != GLFW_DONT_CARE && window->maxheight != GLFW_DONT_CARE) { hints->flags |= PMaxSize; hints->max_width = window->maxwidth; hints->max_height = window->maxheight; } if (window->numer != GLFW_DONT_CARE && window->denom != GLFW_DONT_CARE) { hints->flags |= PAspect; hints->min_aspect.x = hints->max_aspect.x = window->numer; hints->min_aspect.y = hints->max_aspect.y = window->denom; } } else { 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); } // Updates the full screen status of the window // static void updateWindowMode(_GLFWwindow* window) { if (window->monitor) { if (_glfw.x11.xinerama.available && _glfw.x11.NET_WM_FULLSCREEN_MONITORS) { sendEventToWM(window, _glfw.x11.NET_WM_FULLSCREEN_MONITORS, window->monitor->x11.index, window->monitor->x11.index, window->monitor->x11.index, window->monitor->x11.index, 0); } if (_glfw.x11.NET_WM_STATE && _glfw.x11.NET_WM_STATE_FULLSCREEN) { sendEventToWM(window, _glfw.x11.NET_WM_STATE, _NET_WM_STATE_ADD, _glfw.x11.NET_WM_STATE_FULLSCREEN, 0, 1, 0); } else { // This is the butcher's way of removing window decorations // Setting the override-redirect attribute on a window makes the // window manager ignore the window completely (ICCCM, section 4) // The good thing is that this makes undecorated full screen windows // easy to do; the bad thing is that we have to do everything // manually and some things (like iconify/restore) won't work at // all, as those are tasks usually performed by the window manager XSetWindowAttributes attributes; attributes.override_redirect = True; XChangeWindowAttributes(_glfw.x11.display, window->x11.handle, CWOverrideRedirect, &attributes); window->x11.overrideRedirect = GLFW_TRUE; } // Enable compositor bypass if (!window->x11.transparent) { const unsigned long value = 1; XChangeProperty(_glfw.x11.display, window->x11.handle, _glfw.x11.NET_WM_BYPASS_COMPOSITOR, XA_CARDINAL, 32, PropModeReplace, (unsigned char*) &value, 1); } } else { if (_glfw.x11.xinerama.available && _glfw.x11.NET_WM_FULLSCREEN_MONITORS) { XDeleteProperty(_glfw.x11.display, window->x11.handle, _glfw.x11.NET_WM_FULLSCREEN_MONITORS); } if (_glfw.x11.NET_WM_STATE && _glfw.x11.NET_WM_STATE_FULLSCREEN) { sendEventToWM(window, _glfw.x11.NET_WM_STATE, _NET_WM_STATE_REMOVE, _glfw.x11.NET_WM_STATE_FULLSCREEN, 0, 1, 0); } else { XSetWindowAttributes attributes; attributes.override_redirect = False; XChangeWindowAttributes(_glfw.x11.display, window->x11.handle, CWOverrideRedirect, &attributes); window->x11.overrideRedirect = GLFW_FALSE; } // Disable compositor bypass if (!window->x11.transparent) { XDeleteProperty(_glfw.x11.display, window->x11.handle, _glfw.x11.NET_WM_BYPASS_COMPOSITOR); } } } // 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; } // 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 uint32_t decodeUTF8(const char** s) { uint32_t codepoint = 0, count = 0; static const uint32_t offsets[] = { 0x00000000u, 0x00003080u, 0x000e2080u, 0x03c82080u, 0xfa082080u, 0x82082080u }; do { codepoint = (codepoint << 6) + (unsigned char) **s; (*s)++; count++; } while ((**s & 0xc0) == 0x80); assert(count <= 6); return codepoint - offsets[count - 1]; } #endif /*X_HAVE_UTF8_STRING*/ // Convert the specified Latin-1 string to UTF-8 // static char* convertLatin1toUTF8(const char* source) { size_t size = 1; const char* sp; for (sp = source; *sp; sp++) size += (*sp & 0x80) ? 2 : 1; char* target = calloc(size, 1); char* tp = target; for (sp = source; *sp; sp++) tp += _glfwEncodeUTF8(tp, *sp); return target; } // Updates the cursor image according to its cursor mode // static void updateCursorImage(_GLFWwindow* window) { if (window->cursorMode == GLFW_CURSOR_NORMAL) { if (window->cursor) { XDefineCursor(_glfw.x11.display, window->x11.handle, window->cursor->x11.handle); } else XUndefineCursor(_glfw.x11.display, window->x11.handle); } else { XDefineCursor(_glfw.x11.display, window->x11.handle, _glfw.x11.hiddenCursorHandle); } } // Enable XI2 raw mouse motion events // static void enableRawMouseMotion(_GLFWwindow* window) { XIEventMask em; unsigned char mask[XIMaskLen(XI_RawMotion)] = { 0 }; em.deviceid = XIAllMasterDevices; em.mask_len = sizeof(mask); em.mask = mask; XISetMask(mask, XI_RawMotion); XISelectEvents(_glfw.x11.display, _glfw.x11.root, &em, 1); } // Disable XI2 raw mouse motion events // static void disableRawMouseMotion(_GLFWwindow* window) { XIEventMask em; unsigned char mask[] = { 0 }; em.deviceid = XIAllMasterDevices; em.mask_len = sizeof(mask); em.mask = mask; XISelectEvents(_glfw.x11.display, _glfw.x11.root, &em, 1); } // Apply disabled cursor mode to a focused window // static void disableCursor(_GLFWwindow* window) { if (window->rawMouseMotion) enableRawMouseMotion(window); _glfw.x11.disabledCursorWindow = window; _glfwPlatformGetCursorPos(window, &_glfw.x11.restoreCursorPosX, &_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); } // Exit disabled cursor mode for the specified window // static void enableCursor(_GLFWwindow* window) { if (window->rawMouseMotion) disableRawMouseMotion(window); _glfw.x11.disabledCursorWindow = NULL; XUngrabPointer(_glfw.x11.display, CurrentTime); _glfwPlatformSetCursorPos(window, _glfw.x11.restoreCursorPosX, _glfw.x11.restoreCursorPosY); updateCursorImage(window); } // Create the X11 window (and its colormap) // static GLFWbool createNativeWindow(_GLFWwindow* window, const _GLFWwndconfig* wndconfig, Visual* visual, int depth) { int width = wndconfig->width; int height = wndconfig->height; if (wndconfig->scaleToMonitor) { width *= _glfw.x11.contentScaleX; height *= _glfw.x11.contentScaleY; } // Create a colormap based on the visual used by the current context window->x11.colormap = XCreateColormap(_glfw.x11.display, _glfw.x11.root, visual, AllocNone); window->x11.transparent = _glfwIsVisualTransparentX11(visual); XSetWindowAttributes wa = { 0 }; wa.colormap = window->x11.colormap; wa.event_mask = StructureNotifyMask | KeyPressMask | KeyReleaseMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask | ExposureMask | FocusChangeMask | VisibilityChangeMask | EnterWindowMask | LeaveWindowMask | PropertyChangeMask; _glfwGrabErrorHandlerX11(); window->x11.parent = _glfw.x11.root; window->x11.handle = XCreateWindow(_glfw.x11.display, _glfw.x11.root, 0, 0, // Position width, height, 0, // Border width depth, // Color depth InputOutput, visual, CWBorderPixel | CWColormap | CWEventMask, &wa); _glfwReleaseErrorHandlerX11(); if (!window->x11.handle) { _glfwInputErrorX11(GLFW_PLATFORM_ERROR, "X11: Failed to create window"); return GLFW_FALSE; } XSaveContext(_glfw.x11.display, window->x11.handle, _glfw.x11.context, (XPointer) window); if (!wndconfig->decorated) _glfwPlatformSetWindowDecorated(window, GLFW_FALSE); if (_glfw.x11.NET_WM_STATE && !window->monitor) { Atom states[3]; int count = 0; if (wndconfig->floating) { if (_glfw.x11.NET_WM_STATE_ABOVE) states[count++] = _glfw.x11.NET_WM_STATE_ABOVE; } if (wndconfig->maximized) { if (_glfw.x11.NET_WM_STATE_MAXIMIZED_VERT && _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ) { states[count++] = _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT; states[count++] = _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ; window->x11.maximized = GLFW_TRUE; } } if (count) { XChangeProperty(_glfw.x11.display, window->x11.handle, _glfw.x11.NET_WM_STATE, XA_ATOM, 32, PropModeReplace, (unsigned char*) states, count); } } // Declare the WM protocols supported by GLFW { Atom protocols[] = { _glfw.x11.WM_DELETE_WINDOW, _glfw.x11.NET_WM_PING }; XSetWMProtocols(_glfw.x11.display, window->x11.handle, protocols, sizeof(protocols) / sizeof(Atom)); } // Declare our PID { const long pid = getpid(); XChangeProperty(_glfw.x11.display, window->x11.handle, _glfw.x11.NET_WM_PID, XA_CARDINAL, 32, PropModeReplace, (unsigned char*) &pid, 1); } if (_glfw.x11.NET_WM_WINDOW_TYPE && _glfw.x11.NET_WM_WINDOW_TYPE_NORMAL) { Atom type = _glfw.x11.NET_WM_WINDOW_TYPE_NORMAL; XChangeProperty(_glfw.x11.display, window->x11.handle, _glfw.x11.NET_WM_WINDOW_TYPE, XA_ATOM, 32, PropModeReplace, (unsigned char*) &type, 1); } // Set ICCCM WM_HINTS property { XWMHints* hints = XAllocWMHints(); if (!hints) { _glfwInputError(GLFW_OUT_OF_MEMORY, "X11: Failed to allocate WM hints"); return GLFW_FALSE; } hints->flags = StateHint; hints->initial_state = NormalState; XSetWMHints(_glfw.x11.display, window->x11.handle, hints); XFree(hints); } updateNormalHints(window, width, height); // Set ICCCM WM_CLASS property { XClassHint* hint = XAllocClassHint(); if (strlen(wndconfig->x11.instanceName) && strlen(wndconfig->x11.className)) { hint->res_name = (char*) wndconfig->x11.instanceName; hint->res_class = (char*) wndconfig->x11.className; } else { const char* resourceName = getenv("RESOURCE_NAME"); if (resourceName && strlen(resourceName)) hint->res_name = (char*) resourceName; else if (strlen(wndconfig->title)) hint->res_name = (char*) wndconfig->title; else hint->res_name = (char*) "glfw-application"; if (strlen(wndconfig->title)) hint->res_class = (char*) wndconfig->title; else hint->res_class = (char*) "GLFW-Application"; } XSetClassHint(_glfw.x11.display, window->x11.handle, hint); XFree(hint); } // Announce support for Xdnd (drag and drop) { const Atom version = _GLFW_XDND_VERSION; XChangeProperty(_glfw.x11.display, window->x11.handle, _glfw.x11.XdndAware, XA_ATOM, 32, PropModeReplace, (unsigned char*) &version, 1); } _glfwPlatformSetWindowTitle(window, wndconfig->title); if (_glfw.x11.im) { window->x11.ic = XCreateIC(_glfw.x11.im, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, XNClientWindow, window->x11.handle, XNFocusWindow, window->x11.handle, NULL); } if (window->x11.ic) { unsigned long filter = 0; if (XGetICValues(window->x11.ic, XNFilterEvents, &filter, NULL) == NULL) XSelectInput(_glfw.x11.display, window->x11.handle, wa.event_mask | filter); } _glfwPlatformGetWindowPos(window, &window->x11.xpos, &window->x11.ypos); _glfwPlatformGetWindowSize(window, &window->x11.width, &window->x11.height); return GLFW_TRUE; } // Set the specified property to the selection converted to the requested target // static Atom writeTargetToProperty(const XSelectionRequestEvent* request) { int i; char* selectionString = NULL; const Atom formats[] = { _glfw.x11.UTF8_STRING, XA_STRING }; const int formatCount = sizeof(formats) / sizeof(formats[0]); if (request->selection == _glfw.x11.PRIMARY) selectionString = _glfw.x11.primarySelectionString; else selectionString = _glfw.x11.clipboardString; if (request->property == None) { // The requester is a legacy client (ICCCM section 2.2) // We don't support legacy clients, so fail here return None; } if (request->target == _glfw.x11.TARGETS) { // The list of supported targets was requested const Atom targets[] = { _glfw.x11.TARGETS, _glfw.x11.MULTIPLE, _glfw.x11.UTF8_STRING, XA_STRING }; XChangeProperty(_glfw.x11.display, request->requestor, request->property, XA_ATOM, 32, PropModeReplace, (unsigned char*) targets, sizeof(targets) / sizeof(targets[0])); return request->property; } if (request->target == _glfw.x11.MULTIPLE) { // Multiple conversions were requested Atom* targets; unsigned long i, count; count = _glfwGetWindowPropertyX11(request->requestor, request->property, _glfw.x11.ATOM_PAIR, (unsigned char**) &targets); for (i = 0; i < count; i += 2) { int j; for (j = 0; j < formatCount; j++) { if (targets[i] == formats[j]) break; } if (j < formatCount) { XChangeProperty(_glfw.x11.display, request->requestor, targets[i + 1], targets[i], 8, PropModeReplace, (unsigned char *) selectionString, strlen(selectionString)); } else targets[i + 1] = None; } XChangeProperty(_glfw.x11.display, request->requestor, request->property, _glfw.x11.ATOM_PAIR, 32, PropModeReplace, (unsigned char*) targets, count); XFree(targets); return request->property; } if (request->target == _glfw.x11.SAVE_TARGETS) { // The request is a check whether we support SAVE_TARGETS // It should be handled as a no-op side effect target XChangeProperty(_glfw.x11.display, request->requestor, request->property, _glfw.x11.NULL_, 32, PropModeReplace, NULL, 0); return request->property; } // Conversion to a data target was requested for (i = 0; i < formatCount; i++) { if (request->target == formats[i]) { // The requested target is one we support XChangeProperty(_glfw.x11.display, request->requestor, request->property, request->target, 8, PropModeReplace, (unsigned char *) selectionString, strlen(selectionString)); return request->property; } } // The requested target is not supported 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; XEvent reply = { SelectionNotify }; reply.xselection.property = writeTargetToProperty(request); reply.xselection.display = request->display; reply.xselection.requestor = request->requestor; reply.xselection.selection = request->selection; reply.xselection.target = request->target; reply.xselection.time = request->time; XSendEvent(_glfw.x11.display, request->requestor, False, 0, &reply); } static const char* getSelectionString(Atom selection) { char** selectionString = NULL; const Atom targets[] = { _glfw.x11.UTF8_STRING, XA_STRING }; const size_t targetCount = sizeof(targets) / sizeof(targets[0]); if (selection == _glfw.x11.PRIMARY) selectionString = &_glfw.x11.primarySelectionString; else selectionString = &_glfw.x11.clipboardString; if (XGetSelectionOwner(_glfw.x11.display, selection) == _glfw.x11.helperWindowHandle) { // Instead of doing a large number of X round-trips just to put this // string into a window property and then read it back, just return it return *selectionString; } free(*selectionString); *selectionString = NULL; for (size_t i = 0; i < targetCount; i++) { char* data; Atom actualType; int actualFormat; unsigned long itemCount, bytesAfter; XEvent notification, dummy; XConvertSelection(_glfw.x11.display, selection, targets[i], _glfw.x11.GLFW_SELECTION, _glfw.x11.helperWindowHandle, CurrentTime); while (!XCheckTypedWindowEvent(_glfw.x11.display, _glfw.x11.helperWindowHandle, SelectionNotify, ¬ification)) { waitForX11Event(NULL); } if (notification.xselection.property == None) continue; XCheckIfEvent(_glfw.x11.display, &dummy, isSelPropNewValueNotify, (XPointer) ¬ification); XGetWindowProperty(_glfw.x11.display, notification.xselection.requestor, notification.xselection.property, 0, LONG_MAX, True, AnyPropertyType, &actualType, &actualFormat, &itemCount, &bytesAfter, (unsigned char**) &data); if (actualType == _glfw.x11.INCR) { size_t size = 1; char* string = NULL; for (;;) { while (!XCheckIfEvent(_glfw.x11.display, &dummy, isSelPropNewValueNotify, (XPointer) ¬ification)) { waitForX11Event(NULL); } XFree(data); XGetWindowProperty(_glfw.x11.display, notification.xselection.requestor, notification.xselection.property, 0, LONG_MAX, True, AnyPropertyType, &actualType, &actualFormat, &itemCount, &bytesAfter, (unsigned char**) &data); if (itemCount) { size += itemCount; string = realloc(string, size); string[size - itemCount - 1] = '\0'; strcat(string, data); } if (!itemCount) { if (targets[i] == XA_STRING) { *selectionString = convertLatin1toUTF8(string); free(string); } else *selectionString = string; break; } } } else if (actualType == targets[i]) { if (targets[i] == XA_STRING) *selectionString = convertLatin1toUTF8(data); else *selectionString = _glfw_strdup(data); } XFree(data); if (*selectionString) break; } if (!*selectionString) { _glfwInputError(GLFW_FORMAT_UNAVAILABLE, "X11: Failed to convert selection to string"); } return *selectionString; } // Make the specified window and its video mode active on its monitor // static void acquireMonitor(_GLFWwindow* window) { if (_glfw.x11.saver.count == 0) { // Remember old screen saver settings XGetScreenSaver(_glfw.x11.display, &_glfw.x11.saver.timeout, &_glfw.x11.saver.interval, &_glfw.x11.saver.blanking, &_glfw.x11.saver.exposure); // Disable screen saver XSetScreenSaver(_glfw.x11.display, 0, 0, DontPreferBlanking, DefaultExposures); } if (!window->monitor->window) _glfw.x11.saver.count++; _glfwSetVideoModeX11(window->monitor, &window->videoMode); if (window->x11.overrideRedirect) { int xpos, ypos; GLFWvidmode mode; // Manually position the window over its monitor _glfwPlatformGetMonitorPos(window->monitor, &xpos, &ypos); _glfwPlatformGetVideoMode(window->monitor, &mode); XMoveResizeWindow(_glfw.x11.display, window->x11.handle, xpos, ypos, mode.width, mode.height); } _glfwInputMonitorWindow(window->monitor, window); } // Remove the window and restore the original video mode // static void releaseMonitor(_GLFWwindow* window) { if (window->monitor->window != window) return; _glfwInputMonitorWindow(window->monitor, NULL); _glfwRestoreVideoModeX11(window->monitor); _glfw.x11.saver.count--; if (_glfw.x11.saver.count == 0) { // Restore old screen saver settings XSetScreenSaver(_glfw.x11.display, _glfw.x11.saver.timeout, _glfw.x11.saver.interval, _glfw.x11.saver.blanking, _glfw.x11.saver.exposure); } } // Process the specified X event // static void processEvent(XEvent *event) { int keycode = 0; Bool filtered = False; // HACK: Save scancode as some IMs clear the field in XFilterEvent if (event->type == KeyPress || event->type == KeyRelease) keycode = event->xkey.keycode; if (_glfw.x11.im) filtered = XFilterEvent(event, None); if (_glfw.x11.randr.available) { if (event->type == _glfw.x11.randr.eventBase + RRNotify) { XRRUpdateConfiguration(event); _glfwPollMonitorsX11(); return; } } if (_glfw.x11.xkb.available) { if (event->type == _glfw.x11.xkb.eventBase + XkbEventCode) { if (((XkbEvent*) event)->any.xkb_type == XkbStateNotify && (((XkbEvent*) event)->state.changed & XkbGroupStateMask)) { _glfw.x11.xkb.group = ((XkbEvent*) event)->state.group; } return; } } if (event->type == GenericEvent) { if (_glfw.x11.xi.available) { _GLFWwindow* window = _glfw.x11.disabledCursorWindow; if (window && window->rawMouseMotion && event->xcookie.extension == _glfw.x11.xi.majorOpcode && XGetEventData(_glfw.x11.display, &event->xcookie) && event->xcookie.evtype == XI_RawMotion) { XIRawEvent* re = event->xcookie.data; if (re->valuators.mask_len) { const double* values = re->raw_values; double xpos = window->virtualCursorPosX; double ypos = window->virtualCursorPosY; if (XIMaskIsSet(re->valuators.mask, 0)) { xpos += *values; values++; } if (XIMaskIsSet(re->valuators.mask, 1)) ypos += *values; _glfwInputCursorPos(window, xpos, ypos); } } XFreeEventData(_glfw.x11.display, &event->xcookie); } return; } if (event->type == SelectionClear) { handleSelectionClear(event); return; } else if (event->type == SelectionRequest) { handleSelectionRequest(event); return; } _GLFWwindow* window = NULL; if (XFindContext(_glfw.x11.display, event->xany.window, _glfw.x11.context, (XPointer*) &window) != 0) { // This is an event for a window that has already been destroyed return; } switch (event->type) { case ReparentNotify: { window->x11.parent = event->xreparent.parent; return; } case KeyPress: { const int key = translateKey(keycode); const int mods = translateState(event->xkey.state); const int plain = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT)); if (window->x11.ic) { // 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.keyPressTimes[keycode] = event->xkey.time; } if (!filtered) { int count; Status status; #if defined(X_HAVE_UTF8_STRING) char buffer[100]; char* chars = buffer; count = Xutf8LookupString(window->x11.ic, &event->xkey, buffer, sizeof(buffer) - 1, NULL, &status); if (status == XBufferOverflow) { chars = calloc(count + 1, 1); count = Xutf8LookupString(window->x11.ic, &event->xkey, chars, count, NULL, &status); } if (status == XLookupChars || status == XLookupBoth) { const char* c = chars; chars[count] = '\0'; while (c - chars < count) _glfwInputChar(window, decodeUTF8(&c), mods, plain); } #else /*X_HAVE_UTF8_STRING*/ wchar_t buffer[16]; wchar_t* chars = buffer; count = XwcLookupString(window->x11.ic, &event->xkey, buffer, sizeof(buffer) / sizeof(wchar_t), NULL, &status); if (status == XBufferOverflow) { chars = calloc(count, sizeof(wchar_t)); count = XwcLookupString(window->x11.ic, &event->xkey, chars, count, NULL, &status); } if (status == XLookupChars || status == XLookupBoth) { int i; for (i = 0; i < count; i++) _glfwInputChar(window, chars[i], mods, plain); } #endif /*X_HAVE_UTF8_STRING*/ if (chars != buffer) free(chars); } } else { KeySym keysym; XLookupString(&event->xkey, NULL, 0, &keysym, NULL); _glfwInputKey(window, key, keycode, GLFW_PRESS, mods); const uint32_t codepoint = _glfwKeySym2Unicode(keysym); if (codepoint != GLFW_INVALID_CODEPOINT) _glfwInputChar(window, codepoint, mods, plain); } return; } case KeyRelease: { const int key = translateKey(keycode); const int mods = translateState(event->xkey.state); if (!_glfw.x11.xkb.detectable) { // HACK: Key repeat events will arrive as KeyRelease/KeyPress // pairs with similar or identical time stamps // The key repeat logic in _glfwInputKey expects only key // presses to repeat, so detect and discard release events if (XEventsQueued(_glfw.x11.display, QueuedAfterReading)) { XEvent next; XPeekEvent(_glfw.x11.display, &next); if (next.type == KeyPress && next.xkey.window == event->xkey.window && next.xkey.keycode == keycode) { // HACK: The time of repeat events sometimes doesn't // match that of the press event, so add an // epsilon // Toshiyuki Takahashi can press a button // 16 times per second so it's fairly safe to // assume that no human is pressing the key 50 // times per second (value is ms) if ((next.xkey.time - event->xkey.time) < 20) { // This is very likely a server-generated key repeat // event, so ignore it return; } } } } _glfwInputKey(window, key, keycode, GLFW_RELEASE, mods); return; } case ButtonPress: { const int mods = translateState(event->xbutton.state); if (event->xbutton.button == Button1) _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_LEFT, GLFW_PRESS, mods); else if (event->xbutton.button == Button2) _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_MIDDLE, GLFW_PRESS, mods); else if (event->xbutton.button == Button3) _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_RIGHT, GLFW_PRESS, mods); // Modern X provides scroll events as mouse button presses else if (event->xbutton.button == Button4) _glfwInputScroll(window, 0.0, 1.0); else if (event->xbutton.button == Button5) _glfwInputScroll(window, 0.0, -1.0); else if (event->xbutton.button == Button6) _glfwInputScroll(window, 1.0, 0.0); else if (event->xbutton.button == Button7) _glfwInputScroll(window, -1.0, 0.0); else { // Additional buttons after 7 are treated as regular buttons // We subtract 4 to fill the gap left by scroll input above _glfwInputMouseClick(window, event->xbutton.button - Button1 - 4, GLFW_PRESS, mods); } return; } case ButtonRelease: { const int mods = translateState(event->xbutton.state); if (event->xbutton.button == Button1) { _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_LEFT, GLFW_RELEASE, mods); } else if (event->xbutton.button == Button2) { _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_MIDDLE, GLFW_RELEASE, mods); } else if (event->xbutton.button == Button3) { _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_RIGHT, GLFW_RELEASE, mods); } else if (event->xbutton.button > Button7) { // Additional buttons after 7 are treated as regular buttons // We subtract 4 to fill the gap left by scroll input above _glfwInputMouseClick(window, event->xbutton.button - Button1 - 4, GLFW_RELEASE, mods); } return; } case EnterNotify: { // XEnterWindowEvent is XCrossingEvent const int x = event->xcrossing.x; const int y = event->xcrossing.y; // HACK: This is a workaround for WMs (KWM, Fluxbox) that otherwise // ignore the defined cursor for hidden cursor mode if (window->cursorMode == GLFW_CURSOR_HIDDEN) updateCursorImage(window); _glfwInputCursorEnter(window, GLFW_TRUE); _glfwInputCursorPos(window, x, y); window->x11.lastCursorPosX = x; window->x11.lastCursorPosY = y; return; } case LeaveNotify: { _glfwInputCursorEnter(window, GLFW_FALSE); return; } case MotionNotify: { const int x = event->xmotion.x; const int y = event->xmotion.y; if (x != window->x11.warpCursorPosX || y != window->x11.warpCursorPosY) { // The cursor was moved by something other than GLFW if (window->cursorMode == GLFW_CURSOR_DISABLED) { if (_glfw.x11.disabledCursorWindow != window) return; if (window->rawMouseMotion) return; const int dx = x - window->x11.lastCursorPosX; const int dy = y - window->x11.lastCursorPosY; _glfwInputCursorPos(window, window->virtualCursorPosX + dx, window->virtualCursorPosY + dy); } else _glfwInputCursorPos(window, x, y); } window->x11.lastCursorPosX = x; window->x11.lastCursorPosY = y; return; } case ConfigureNotify: { if (event->xconfigure.width != window->x11.width || event->xconfigure.height != window->x11.height) { _glfwInputFramebufferSize(window, event->xconfigure.width, event->xconfigure.height); _glfwInputWindowSize(window, event->xconfigure.width, event->xconfigure.height); window->x11.width = event->xconfigure.width; window->x11.height = event->xconfigure.height; } int xpos = event->xconfigure.x; int ypos = event->xconfigure.y; // NOTE: ConfigureNotify events from the server are in local // coordinates, so if we are reparented we need to translate // 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, _glfw.x11.root, xpos, ypos, &xpos, &ypos, &dummy); _glfwReleaseErrorHandlerX11(); if (_glfw.x11.errorCode == BadWindow) return; } if (xpos != window->x11.xpos || ypos != window->x11.ypos) { _glfwInputWindowPos(window, xpos, ypos); window->x11.xpos = xpos; window->x11.ypos = ypos; } return; } case ClientMessage: { // Custom client message, probably from the window manager if (filtered) return; if (event->xclient.message_type == None) return; if (event->xclient.message_type == _glfw.x11.WM_PROTOCOLS) { const Atom protocol = event->xclient.data.l[0]; if (protocol == None) return; if (protocol == _glfw.x11.WM_DELETE_WINDOW) { // The window manager was asked to close the window, for // example by the user pressing a 'close' window decoration // button _glfwInputWindowCloseRequest(window); } else if (protocol == _glfw.x11.NET_WM_PING) { // The window manager is pinging the application to ensure // it's still responding to events XEvent reply = *event; reply.xclient.window = _glfw.x11.root; XSendEvent(_glfw.x11.display, _glfw.x11.root, False, SubstructureNotifyMask | SubstructureRedirectMask, &reply); } } else if (event->xclient.message_type == _glfw.x11.XdndEnter) { // A drag operation has entered the window unsigned long i, count; Atom* formats = NULL; const GLFWbool list = event->xclient.data.l[1] & 1; _glfw.x11.xdnd.source = event->xclient.data.l[0]; _glfw.x11.xdnd.version = event->xclient.data.l[1] >> 24; _glfw.x11.xdnd.format = None; if (_glfw.x11.xdnd.version > _GLFW_XDND_VERSION) return; if (list) { count = _glfwGetWindowPropertyX11(_glfw.x11.xdnd.source, _glfw.x11.XdndTypeList, XA_ATOM, (unsigned char**) &formats); } else { count = 3; formats = (Atom*) event->xclient.data.l + 2; } for (i = 0; i < count; i++) { if (formats[i] == _glfw.x11.text_uri_list) { _glfw.x11.xdnd.format = _glfw.x11.text_uri_list; break; } } if (list && formats) XFree(formats); } else if (event->xclient.message_type == _glfw.x11.XdndDrop) { // The drag operation has finished by dropping on the window Time time = CurrentTime; if (_glfw.x11.xdnd.version > _GLFW_XDND_VERSION) return; if (_glfw.x11.xdnd.format) { if (_glfw.x11.xdnd.version >= 1) time = event->xclient.data.l[2]; // Request the chosen format from the source window XConvertSelection(_glfw.x11.display, _glfw.x11.XdndSelection, _glfw.x11.xdnd.format, _glfw.x11.XdndSelection, window->x11.handle, time); } else if (_glfw.x11.xdnd.version >= 2) { XEvent reply = { ClientMessage }; reply.xclient.window = _glfw.x11.xdnd.source; reply.xclient.message_type = _glfw.x11.XdndFinished; reply.xclient.format = 32; reply.xclient.data.l[0] = window->x11.handle; reply.xclient.data.l[1] = 0; // The drag was rejected reply.xclient.data.l[2] = None; XSendEvent(_glfw.x11.display, _glfw.x11.xdnd.source, False, NoEventMask, &reply); XFlush(_glfw.x11.display); } } else if (event->xclient.message_type == _glfw.x11.XdndPosition) { // The drag operation has moved over the window const int xabs = (event->xclient.data.l[2] >> 16) & 0xffff; const int yabs = (event->xclient.data.l[2]) & 0xffff; Window dummy; int xpos, ypos; if (_glfw.x11.xdnd.version > _GLFW_XDND_VERSION) return; XTranslateCoordinates(_glfw.x11.display, _glfw.x11.root, window->x11.handle, xabs, yabs, &xpos, &ypos, &dummy); _glfwInputCursorPos(window, xpos, ypos); XEvent reply = { ClientMessage }; reply.xclient.window = _glfw.x11.xdnd.source; reply.xclient.message_type = _glfw.x11.XdndStatus; reply.xclient.format = 32; reply.xclient.data.l[0] = window->x11.handle; reply.xclient.data.l[2] = 0; // Specify an empty rectangle reply.xclient.data.l[3] = 0; if (_glfw.x11.xdnd.format) { // Reply that we are ready to copy the dragged data reply.xclient.data.l[1] = 1; // Accept with no rectangle if (_glfw.x11.xdnd.version >= 2) reply.xclient.data.l[4] = _glfw.x11.XdndActionCopy; } XSendEvent(_glfw.x11.display, _glfw.x11.xdnd.source, False, NoEventMask, &reply); XFlush(_glfw.x11.display); } return; } case SelectionNotify: { if (event->xselection.property == _glfw.x11.XdndSelection) { // The converted data from the drag operation has arrived char* data; const unsigned long result = _glfwGetWindowPropertyX11(event->xselection.requestor, event->xselection.property, event->xselection.target, (unsigned char**) &data); if (result) { int i, count; char** paths = parseUriList(data, &count); _glfwInputDrop(window, count, (const char**) paths); for (i = 0; i < count; i++) free(paths[i]); free(paths); } if (data) XFree(data); if (_glfw.x11.xdnd.version >= 2) { XEvent reply = { ClientMessage }; reply.xclient.window = _glfw.x11.xdnd.source; reply.xclient.message_type = _glfw.x11.XdndFinished; reply.xclient.format = 32; reply.xclient.data.l[0] = window->x11.handle; reply.xclient.data.l[1] = result; reply.xclient.data.l[2] = _glfw.x11.XdndActionCopy; XSendEvent(_glfw.x11.display, _glfw.x11.xdnd.source, False, NoEventMask, &reply); XFlush(_glfw.x11.display); } } return; } case FocusIn: { if (event->xfocus.mode == NotifyGrab || event->xfocus.mode == NotifyUngrab) { // Ignore focus events from popup indicator windows, window menu // key chords and window dragging return; } if (window->cursorMode == GLFW_CURSOR_DISABLED) disableCursor(window); if (window->x11.ic) XSetICFocus(window->x11.ic); _glfwInputWindowFocus(window, GLFW_TRUE); return; } case FocusOut: { if (event->xfocus.mode == NotifyGrab || event->xfocus.mode == NotifyUngrab) { // Ignore focus events from popup indicator windows, window menu // key chords and window dragging return; } if (window->cursorMode == GLFW_CURSOR_DISABLED) enableCursor(window); if (window->x11.ic) XUnsetICFocus(window->x11.ic); if (window->monitor && window->autoIconify) _glfwPlatformIconifyWindow(window); _glfwInputWindowFocus(window, GLFW_FALSE); return; } case Expose: { _glfwInputWindowDamage(window); return; } case PropertyNotify: { if (event->xproperty.state != PropertyNewValue) return; if (event->xproperty.atom == _glfw.x11.WM_STATE) { const int state = getWindowState(window); if (state != IconicState && state != NormalState) return; const GLFWbool iconified = (state == IconicState); if (window->x11.iconified != iconified) { if (window->monitor) { if (iconified) releaseMonitor(window); else acquireMonitor(window); } window->x11.iconified = iconified; _glfwInputWindowIconify(window, iconified); } } else if (event->xproperty.atom == _glfw.x11.NET_WM_STATE) { const GLFWbool maximized = _glfwPlatformWindowMaximized(window); if (window->x11.maximized != maximized) { window->x11.maximized = maximized; _glfwInputWindowMaximize(window, maximized); } } return; } case DestroyNotify: return; } } ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// // Retrieve a single window property of the specified type // Inspired by fghGetWindowProperty from freeglut // unsigned long _glfwGetWindowPropertyX11(Window window, Atom property, Atom type, unsigned char** value) { Atom actualType; int actualFormat; unsigned long itemCount, bytesAfter; XGetWindowProperty(_glfw.x11.display, window, property, 0, LONG_MAX, False, type, &actualType, &actualFormat, &itemCount, &bytesAfter, value); return itemCount; } GLFWbool _glfwIsVisualTransparentX11(Visual* visual) { if (!_glfw.x11.xrender.available) return GLFW_FALSE; XRenderPictFormat* pf = XRenderFindVisualFormat(_glfw.x11.display, visual); return pf && pf->direct.alphaMask; } // Push contents of our selection to clipboard manager // void _glfwPushSelectionToManagerX11(void) { XConvertSelection(_glfw.x11.display, _glfw.x11.CLIPBOARD_MANAGER, _glfw.x11.SAVE_TARGETS, None, _glfw.x11.helperWindowHandle, CurrentTime); for (;;) { XEvent event; while (XCheckIfEvent(_glfw.x11.display, &event, isSelectionEvent, NULL)) { switch (event.type) { case SelectionRequest: handleSelectionRequest(&event); break; case SelectionClear: handleSelectionClear(&event); break; case SelectionNotify: { if (event.xselection.target == _glfw.x11.SAVE_TARGETS) { // This means one of two things; either the selection // was not owned, which means there is no clipboard // manager, or the transfer to the clipboard manager has // completed // In either case, it means we are done here return; } break; } } } waitForX11Event(NULL); } } ////////////////////////////////////////////////////////////////////////// ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// int _glfwPlatformCreateWindow(_GLFWwindow* window, const _GLFWwndconfig* wndconfig, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig) { Visual* visual = NULL; int depth; if (ctxconfig->client != GLFW_NO_API) { if (ctxconfig->source == GLFW_NATIVE_CONTEXT_API) { if (!_glfwInitGLX()) return GLFW_FALSE; if (!_glfwChooseVisualGLX(wndconfig, ctxconfig, fbconfig, &visual, &depth)) return GLFW_FALSE; } else if (ctxconfig->source == GLFW_EGL_CONTEXT_API) { if (!_glfwInitEGL()) return GLFW_FALSE; if (!_glfwChooseVisualEGL(wndconfig, ctxconfig, fbconfig, &visual, &depth)) return GLFW_FALSE; } else if (ctxconfig->source == GLFW_OSMESA_CONTEXT_API) { if (!_glfwInitOSMesa()) return GLFW_FALSE; } } if (!visual) { visual = DefaultVisual(_glfw.x11.display, _glfw.x11.screen); depth = DefaultDepth(_glfw.x11.display, _glfw.x11.screen); } if (!createNativeWindow(window, wndconfig, visual, depth)) return GLFW_FALSE; if (ctxconfig->client != GLFW_NO_API) { if (ctxconfig->source == GLFW_NATIVE_CONTEXT_API) { if (!_glfwCreateContextGLX(window, ctxconfig, fbconfig)) return GLFW_FALSE; } else if (ctxconfig->source == GLFW_EGL_CONTEXT_API) { if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig)) return GLFW_FALSE; } else if (ctxconfig->source == GLFW_OSMESA_CONTEXT_API) { if (!_glfwCreateContextOSMesa(window, ctxconfig, fbconfig)) return GLFW_FALSE; } } if (window->monitor) { _glfwPlatformShowWindow(window); updateWindowMode(window); acquireMonitor(window); } XFlush(_glfw.x11.display); return GLFW_TRUE; } void _glfwPlatformDestroyWindow(_GLFWwindow* window) { if (_glfw.x11.disabledCursorWindow == window) _glfw.x11.disabledCursorWindow = NULL; if (window->monitor) releaseMonitor(window); if (window->x11.ic) { XDestroyIC(window->x11.ic); window->x11.ic = NULL; } if (window->context.destroy) window->context.destroy(window); if (window->x11.handle) { XDeleteContext(_glfw.x11.display, window->x11.handle, _glfw.x11.context); XUnmapWindow(_glfw.x11.display, window->x11.handle); XDestroyWindow(_glfw.x11.display, window->x11.handle); window->x11.handle = (Window) 0; } if (window->x11.colormap) { XFreeColormap(_glfw.x11.display, window->x11.colormap); window->x11.colormap = (Colormap) 0; } XFlush(_glfw.x11.display); } void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title) { #if defined(X_HAVE_UTF8_STRING) Xutf8SetWMProperties(_glfw.x11.display, window->x11.handle, title, title, NULL, 0, NULL, NULL, NULL); #else // This may be a slightly better fallback than using XStoreName and // XSetIconName, which always store their arguments using STRING XmbSetWMProperties(_glfw.x11.display, window->x11.handle, title, title, NULL, 0, NULL, NULL, NULL); #endif XChangeProperty(_glfw.x11.display, window->x11.handle, _glfw.x11.NET_WM_NAME, _glfw.x11.UTF8_STRING, 8, PropModeReplace, (unsigned char*) title, strlen(title)); XChangeProperty(_glfw.x11.display, window->x11.handle, _glfw.x11.NET_WM_ICON_NAME, _glfw.x11.UTF8_STRING, 8, PropModeReplace, (unsigned char*) title, strlen(title)); XFlush(_glfw.x11.display); } void _glfwPlatformSetWindowIcon(_GLFWwindow* window, int count, const GLFWimage* images) { if (count) { int i, j, longCount = 0; for (i = 0; i < count; i++) longCount += 2 + images[i].width * images[i].height; unsigned long* icon = calloc(longCount, sizeof(unsigned long)); unsigned long* target = icon; for (i = 0; i < count; i++) { *target++ = images[i].width; *target++ = images[i].height; for (j = 0; j < images[i].width * images[i].height; j++) { *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, PropModeReplace, (unsigned char*) icon, longCount); free(icon); } else { XDeleteProperty(_glfw.x11.display, window->x11.handle, _glfw.x11.NET_WM_ICON); } XFlush(_glfw.x11.display); } void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos) { Window dummy; int x, y; XTranslateCoordinates(_glfw.x11.display, window->x11.handle, _glfw.x11.root, 0, 0, &x, &y, &dummy); if (xpos) *xpos = x; if (ypos) *ypos = y; } void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos) { // HACK: Explicitly setting PPosition to any value causes some WMs, notably // Compiz and Metacity, to honor the position of unmapped windows if (!_glfwPlatformWindowVisible(window)) { long supplied; XSizeHints* hints = XAllocSizeHints(); if (XGetWMNormalHints(_glfw.x11.display, window->x11.handle, hints, &supplied)) { hints->flags |= PPosition; hints->x = hints->y = 0; XSetWMNormalHints(_glfw.x11.display, window->x11.handle, hints); } XFree(hints); } XMoveWindow(_glfw.x11.display, window->x11.handle, xpos, ypos); XFlush(_glfw.x11.display); } void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height) { XWindowAttributes attribs; XGetWindowAttributes(_glfw.x11.display, window->x11.handle, &attribs); if (width) *width = attribs.width; if (height) *height = attribs.height; } void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) { if (window->monitor) { if (window->monitor->window == window) acquireMonitor(window); } else { if (!window->resizable) updateNormalHints(window, width, height); XResizeWindow(_glfw.x11.display, window->x11.handle, width, height); } XFlush(_glfw.x11.display); } void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window, int minwidth, int minheight, int maxwidth, int maxheight) { int width, height; _glfwPlatformGetWindowSize(window, &width, &height); updateNormalHints(window, width, height); XFlush(_glfw.x11.display); } void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom) { int width, height; _glfwPlatformGetWindowSize(window, &width, &height); updateNormalHints(window, width, height); XFlush(_glfw.x11.display); } void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height) { _glfwPlatformGetWindowSize(window, width, height); } void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, int* left, int* top, int* right, int* bottom) { long* extents = NULL; if (window->monitor || !window->decorated) return; if (_glfw.x11.NET_FRAME_EXTENTS == None) return; if (!_glfwPlatformWindowVisible(window) && _glfw.x11.NET_REQUEST_FRAME_EXTENTS) { XEvent event; double timeout = 0.5; // Ensure _NET_FRAME_EXTENTS is set, allowing glfwGetWindowFrameSize to // function before the window is mapped sendEventToWM(window, _glfw.x11.NET_REQUEST_FRAME_EXTENTS, 0, 0, 0, 0, 0); // HACK: Use a timeout because earlier versions of some window managers // (at least Unity, Fluxbox and Xfwm) failed to send the reply // They have been fixed but broken versions are still in the wild // If you are affected by this and your window manager is NOT // listed above, PLEASE report it to their and our issue trackers while (!XCheckIfEvent(_glfw.x11.display, &event, isFrameExtentsEvent, (XPointer) window)) { if (!waitForX11Event(&timeout)) { _glfwInputError(GLFW_PLATFORM_ERROR, "X11: The window manager has a broken _NET_REQUEST_FRAME_EXTENTS implementation; please report this issue"); return; } } } if (_glfwGetWindowPropertyX11(window->x11.handle, _glfw.x11.NET_FRAME_EXTENTS, XA_CARDINAL, (unsigned char**) &extents) == 4) { if (left) *left = extents[0]; if (top) *top = extents[2]; if (right) *right = extents[1]; if (bottom) *bottom = extents[3]; } if (extents) XFree(extents); } void _glfwPlatformGetWindowContentScale(_GLFWwindow* window, float* xscale, float* yscale) { if (xscale) *xscale = _glfw.x11.contentScaleX; if (yscale) *yscale = _glfw.x11.contentScaleY; } void _glfwPlatformIconifyWindow(_GLFWwindow* window) { if (window->x11.overrideRedirect) { // Override-redirect windows cannot be iconified or restored, as those // tasks are performed by the window manager _glfwInputError(GLFW_PLATFORM_ERROR, "X11: Iconification of full screen windows requires a WM that supports EWMH full screen"); return; } XIconifyWindow(_glfw.x11.display, window->x11.handle, _glfw.x11.screen); XFlush(_glfw.x11.display); } void _glfwPlatformRestoreWindow(_GLFWwindow* window) { if (window->x11.overrideRedirect) { // Override-redirect windows cannot be iconified or restored, as those // tasks are performed by the window manager _glfwInputError(GLFW_PLATFORM_ERROR, "X11: Iconification of full screen windows requires a WM that supports EWMH full screen"); return; } if (_glfwPlatformWindowIconified(window)) { XMapWindow(_glfw.x11.display, window->x11.handle); waitForVisibilityNotify(window); } else if (_glfwPlatformWindowVisible(window)) { if (_glfw.x11.NET_WM_STATE && _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT && _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ) { sendEventToWM(window, _glfw.x11.NET_WM_STATE, _NET_WM_STATE_REMOVE, _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT, _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ, 1, 0); } } XFlush(_glfw.x11.display); } void _glfwPlatformMaximizeWindow(_GLFWwindow* window) { if (!_glfw.x11.NET_WM_STATE || !_glfw.x11.NET_WM_STATE_MAXIMIZED_VERT || !_glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ) { return; } if (_glfwPlatformWindowVisible(window)) { sendEventToWM(window, _glfw.x11.NET_WM_STATE, _NET_WM_STATE_ADD, _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT, _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ, 1, 0); } else { Atom* states = NULL; unsigned long count = _glfwGetWindowPropertyX11(window->x11.handle, _glfw.x11.NET_WM_STATE, XA_ATOM, (unsigned char**) &states); // NOTE: We don't check for failure as this property may not exist yet // and that's fine (and we'll create it implicitly with append) Atom missing[2] = { _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT, _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ }; unsigned long missingCount = 2; for (unsigned long i = 0; i < count; i++) { for (unsigned long j = 0; j < missingCount; j++) { if (states[i] == missing[j]) { missing[j] = missing[missingCount - 1]; missingCount--; } } } if (states) XFree(states); if (!missingCount) return; XChangeProperty(_glfw.x11.display, window->x11.handle, _glfw.x11.NET_WM_STATE, XA_ATOM, 32, PropModeAppend, (unsigned char*) missing, missingCount); } XFlush(_glfw.x11.display); } void _glfwPlatformShowWindow(_GLFWwindow* window) { if (_glfwPlatformWindowVisible(window)) return; XMapWindow(_glfw.x11.display, window->x11.handle); waitForVisibilityNotify(window); } void _glfwPlatformHideWindow(_GLFWwindow* window) { XUnmapWindow(_glfw.x11.display, window->x11.handle); XFlush(_glfw.x11.display); } void _glfwPlatformRequestWindowAttention(_GLFWwindow* window) { if (!_glfw.x11.NET_WM_STATE || !_glfw.x11.NET_WM_STATE_DEMANDS_ATTENTION) return; sendEventToWM(window, _glfw.x11.NET_WM_STATE, _NET_WM_STATE_ADD, _glfw.x11.NET_WM_STATE_DEMANDS_ATTENTION, 0, 1, 0); } void _glfwPlatformFocusWindow(_GLFWwindow* window) { if (_glfw.x11.NET_ACTIVE_WINDOW) sendEventToWM(window, _glfw.x11.NET_ACTIVE_WINDOW, 1, 0, 0, 0, 0); else if (_glfwPlatformWindowVisible(window)) { XRaiseWindow(_glfw.x11.display, window->x11.handle); XSetInputFocus(_glfw.x11.display, window->x11.handle, RevertToParent, CurrentTime); } XFlush(_glfw.x11.display); } void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor, int xpos, int ypos, int width, int height, int refreshRate) { if (window->monitor == monitor) { if (monitor) { if (monitor->window == window) acquireMonitor(window); } else { if (!window->resizable) updateNormalHints(window, width, height); XMoveResizeWindow(_glfw.x11.display, window->x11.handle, xpos, ypos, width, height); } XFlush(_glfw.x11.display); return; } if (window->monitor) { _glfwPlatformSetWindowDecorated(window, window->decorated); _glfwPlatformSetWindowFloating(window, window->floating); releaseMonitor(window); } _glfwInputWindowMonitor(window, monitor); updateNormalHints(window, width, height); if (window->monitor) { if (!_glfwPlatformWindowVisible(window)) { XMapRaised(_glfw.x11.display, window->x11.handle); waitForVisibilityNotify(window); } updateWindowMode(window); acquireMonitor(window); } else { updateWindowMode(window); XMoveResizeWindow(_glfw.x11.display, window->x11.handle, xpos, ypos, width, height); } XFlush(_glfw.x11.display); } int _glfwPlatformWindowFocused(_GLFWwindow* window) { Window focused; int state; XGetInputFocus(_glfw.x11.display, &focused, &state); return window->x11.handle == focused; } int _glfwPlatformWindowIconified(_GLFWwindow* window) { return getWindowState(window) == IconicState; } int _glfwPlatformWindowVisible(_GLFWwindow* window) { XWindowAttributes wa; XGetWindowAttributes(_glfw.x11.display, window->x11.handle, &wa); return wa.map_state == IsViewable; } int _glfwPlatformWindowMaximized(_GLFWwindow* window) { Atom* states; unsigned long i; GLFWbool maximized = GLFW_FALSE; if (!_glfw.x11.NET_WM_STATE || !_glfw.x11.NET_WM_STATE_MAXIMIZED_VERT || !_glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ) { return maximized; } const unsigned long count = _glfwGetWindowPropertyX11(window->x11.handle, _glfw.x11.NET_WM_STATE, XA_ATOM, (unsigned char**) &states); for (i = 0; i < count; i++) { if (states[i] == _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT || states[i] == _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ) { maximized = GLFW_TRUE; break; } } if (states) XFree(states); return maximized; } int _glfwPlatformWindowHovered(_GLFWwindow* window) { Window w = _glfw.x11.root; while (w) { Window root; int rootX, rootY, childX, childY; unsigned int mask; _glfwGrabErrorHandlerX11(); 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; } return GLFW_FALSE; } int _glfwPlatformFramebufferTransparent(_GLFWwindow* window) { if (!window->x11.transparent) return GLFW_FALSE; return XGetSelectionOwner(_glfw.x11.display, _glfw.x11.NET_WM_CM_Sx) != None; } void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled) { int width, height; _glfwPlatformGetWindowSize(window, &width, &height); updateNormalHints(window, width, height); } void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled) { struct { unsigned long flags; unsigned long functions; unsigned long decorations; long input_mode; unsigned long status; } hints = {0}; hints.flags = MWM_HINTS_DECORATIONS; hints.decorations = enabled ? MWM_DECOR_ALL : 0; XChangeProperty(_glfw.x11.display, window->x11.handle, _glfw.x11.MOTIF_WM_HINTS, _glfw.x11.MOTIF_WM_HINTS, 32, PropModeReplace, (unsigned char*) &hints, sizeof(hints) / sizeof(long)); } void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled) { if (!_glfw.x11.NET_WM_STATE || !_glfw.x11.NET_WM_STATE_ABOVE) return; if (_glfwPlatformWindowVisible(window)) { const long action = enabled ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE; sendEventToWM(window, _glfw.x11.NET_WM_STATE, action, _glfw.x11.NET_WM_STATE_ABOVE, 0, 1, 0); } else { Atom* states = NULL; unsigned long i, count; count = _glfwGetWindowPropertyX11(window->x11.handle, _glfw.x11.NET_WM_STATE, XA_ATOM, (unsigned char**) &states); // NOTE: We don't check for failure as this property may not exist yet // and that's fine (and we'll create it implicitly with append) if (enabled) { for (i = 0; i < count; i++) { if (states[i] == _glfw.x11.NET_WM_STATE_ABOVE) break; } 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) { for (i = 0; i < count; i++) { if (states[i] == _glfw.x11.NET_WM_STATE_ABOVE) break; } 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); } } if (states) XFree(states); } XFlush(_glfw.x11.display); } float _glfwPlatformGetWindowOpacity(_GLFWwindow* window) { float opacity = 1.f; if (XGetSelectionOwner(_glfw.x11.display, _glfw.x11.NET_WM_CM_Sx)) { CARD32* value = NULL; if (_glfwGetWindowPropertyX11(window->x11.handle, _glfw.x11.NET_WM_WINDOW_OPACITY, XA_CARDINAL, (unsigned char**) &value)) { opacity = (float) (*value / (double) 0xffffffffu); } if (value) XFree(value); } return opacity; } void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity) { const CARD32 value = (CARD32) (0xffffffffu * (double) opacity); XChangeProperty(_glfw.x11.display, window->x11.handle, _glfw.x11.NET_WM_WINDOW_OPACITY, XA_CARDINAL, 32, PropModeReplace, (unsigned char*) &value, 1); } void _glfwPlatformSetRawMouseMotion(_GLFWwindow *window, GLFWbool enabled) { if (!_glfw.x11.xi.available) return; if (_glfw.x11.disabledCursorWindow != window) return; if (enabled) enableRawMouseMotion(window); else disableRawMouseMotion(window); } GLFWbool _glfwPlatformRawMouseMotionSupported(void) { return _glfw.x11.xi.available; } void _glfwPlatformPollEvents(void) { drainEmptyEvents(); #if defined(__linux__) _glfwDetectJoystickConnectionLinux(); #endif XPending(_glfw.x11.display); while (XQLength(_glfw.x11.display)) { XEvent event; XNextEvent(_glfw.x11.display, &event); processEvent(&event); } _GLFWwindow* window = _glfw.x11.disabledCursorWindow; if (window) { int width, height; _glfwPlatformGetWindowSize(window, &width, &height); // NOTE: Re-center the cursor only if it has moved since the last call, // to avoid breaking glfwWaitEvents with MotionNotify if (window->x11.lastCursorPosX != width / 2 || window->x11.lastCursorPosY != height / 2) { _glfwPlatformSetCursorPos(window, width / 2, height / 2); } } XFlush(_glfw.x11.display); } void _glfwPlatformWaitEvents(void) { waitForAnyEvent(NULL); _glfwPlatformPollEvents(); } void _glfwPlatformWaitEventsTimeout(double timeout) { waitForAnyEvent(&timeout); _glfwPlatformPollEvents(); } void _glfwPlatformPostEmptyEvent(void) { writeEmptyEvent(); } void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos) { Window root, child; int rootX, rootY, childX, childY; unsigned int mask; XQueryPointer(_glfw.x11.display, window->x11.handle, &root, &child, &rootX, &rootY, &childX, &childY, &mask); if (xpos) *xpos = childX; if (ypos) *ypos = childY; } void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y) { // Store the new position so it can be recognized later window->x11.warpCursorPosX = (int) x; window->x11.warpCursorPosY = (int) y; XWarpPointer(_glfw.x11.display, None, window->x11.handle, 0,0,0,0, (int) x, (int) y); XFlush(_glfw.x11.display); } void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) { if (mode == GLFW_CURSOR_DISABLED) { if (_glfwPlatformWindowFocused(window)) disableCursor(window); } else if (_glfw.x11.disabledCursorWindow == window) enableCursor(window); else updateCursorImage(window); XFlush(_glfw.x11.display); } const char* _glfwPlatformGetScancodeName(int scancode) { if (!_glfw.x11.xkb.available) return NULL; if (scancode < 0 || scancode > 0xff || _glfw.x11.keycodes[scancode] == GLFW_KEY_UNKNOWN) { _glfwInputError(GLFW_INVALID_VALUE, "Invalid scancode %i", scancode); return NULL; } const int key = _glfw.x11.keycodes[scancode]; const KeySym keysym = XkbKeycodeToKeysym(_glfw.x11.display, scancode, _glfw.x11.xkb.group, 0); if (keysym == NoSymbol) return NULL; const uint32_t codepoint = _glfwKeySym2Unicode(keysym); if (codepoint == GLFW_INVALID_CODEPOINT) return NULL; const size_t count = _glfwEncodeUTF8(_glfw.x11.keynames[key], codepoint); if (count == 0) return NULL; _glfw.x11.keynames[key][count] = '\0'; return _glfw.x11.keynames[key]; } int _glfwPlatformGetKeyScancode(int key) { return _glfw.x11.scancodes[key]; } int _glfwPlatformCreateCursor(_GLFWcursor* cursor, const GLFWimage* image, int xhot, int yhot) { cursor->x11.handle = _glfwCreateCursorX11(image, xhot, yhot); if (!cursor->x11.handle) return GLFW_FALSE; return GLFW_TRUE; } int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape) { int native = 0; if (shape == GLFW_ARROW_CURSOR) native = XC_left_ptr; else if (shape == GLFW_IBEAM_CURSOR) native = XC_xterm; else if (shape == GLFW_CROSSHAIR_CURSOR) native = XC_crosshair; else if (shape == GLFW_HAND_CURSOR) native = XC_hand2; else if (shape == GLFW_HRESIZE_CURSOR) native = XC_sb_h_double_arrow; else if (shape == GLFW_VRESIZE_CURSOR) native = XC_sb_v_double_arrow; else return GLFW_FALSE; cursor->x11.handle = XCreateFontCursor(_glfw.x11.display, native); if (!cursor->x11.handle) { _glfwInputError(GLFW_PLATFORM_ERROR, "X11: Failed to create standard cursor"); return GLFW_FALSE; } return GLFW_TRUE; } void _glfwPlatformDestroyCursor(_GLFWcursor* cursor) { if (cursor->x11.handle) XFreeCursor(_glfw.x11.display, cursor->x11.handle); } void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) { if (window->cursorMode == GLFW_CURSOR_NORMAL) { updateCursorImage(window); XFlush(_glfw.x11.display); } } void _glfwPlatformSetClipboardString(const char* string) { char* copy = _glfw_strdup(string); free(_glfw.x11.clipboardString); _glfw.x11.clipboardString = copy; XSetSelectionOwner(_glfw.x11.display, _glfw.x11.CLIPBOARD, _glfw.x11.helperWindowHandle, CurrentTime); if (XGetSelectionOwner(_glfw.x11.display, _glfw.x11.CLIPBOARD) != _glfw.x11.helperWindowHandle) { _glfwInputError(GLFW_PLATFORM_ERROR, "X11: Failed to become owner of clipboard selection"); } } const char* _glfwPlatformGetClipboardString(void) { return getSelectionString(_glfw.x11.CLIPBOARD); } void _glfwPlatformGetRequiredInstanceExtensions(char** extensions) { if (!_glfw.vk.KHR_surface) return; if (!_glfw.vk.KHR_xcb_surface || !_glfw.x11.x11xcb.handle) { if (!_glfw.vk.KHR_xlib_surface) return; } extensions[0] = "VK_KHR_surface"; // NOTE: VK_KHR_xcb_surface is preferred due to some early ICDs exposing but // not correctly implementing VK_KHR_xlib_surface if (_glfw.vk.KHR_xcb_surface && _glfw.x11.x11xcb.handle) extensions[1] = "VK_KHR_xcb_surface"; else extensions[1] = "VK_KHR_xlib_surface"; } int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, VkPhysicalDevice device, uint32_t queuefamily) { VisualID visualID = XVisualIDFromVisual(DefaultVisual(_glfw.x11.display, _glfw.x11.screen)); if (_glfw.vk.KHR_xcb_surface && _glfw.x11.x11xcb.handle) { PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR vkGetPhysicalDeviceXcbPresentationSupportKHR = (PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR) vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceXcbPresentationSupportKHR"); if (!vkGetPhysicalDeviceXcbPresentationSupportKHR) { _glfwInputError(GLFW_API_UNAVAILABLE, "X11: Vulkan instance missing VK_KHR_xcb_surface extension"); return GLFW_FALSE; } xcb_connection_t* connection = XGetXCBConnection(_glfw.x11.display); if (!connection) { _glfwInputError(GLFW_PLATFORM_ERROR, "X11: Failed to retrieve XCB connection"); return GLFW_FALSE; } return vkGetPhysicalDeviceXcbPresentationSupportKHR(device, queuefamily, connection, visualID); } else { PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR vkGetPhysicalDeviceXlibPresentationSupportKHR = (PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR) vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceXlibPresentationSupportKHR"); if (!vkGetPhysicalDeviceXlibPresentationSupportKHR) { _glfwInputError(GLFW_API_UNAVAILABLE, "X11: Vulkan instance missing VK_KHR_xlib_surface extension"); return GLFW_FALSE; } return vkGetPhysicalDeviceXlibPresentationSupportKHR(device, queuefamily, _glfw.x11.display, visualID); } } VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, _GLFWwindow* window, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface) { if (_glfw.vk.KHR_xcb_surface && _glfw.x11.x11xcb.handle) { VkResult err; VkXcbSurfaceCreateInfoKHR sci; PFN_vkCreateXcbSurfaceKHR vkCreateXcbSurfaceKHR; xcb_connection_t* connection = XGetXCBConnection(_glfw.x11.display); if (!connection) { _glfwInputError(GLFW_PLATFORM_ERROR, "X11: Failed to retrieve XCB connection"); return VK_ERROR_EXTENSION_NOT_PRESENT; } vkCreateXcbSurfaceKHR = (PFN_vkCreateXcbSurfaceKHR) vkGetInstanceProcAddr(instance, "vkCreateXcbSurfaceKHR"); if (!vkCreateXcbSurfaceKHR) { _glfwInputError(GLFW_API_UNAVAILABLE, "X11: Vulkan instance missing VK_KHR_xcb_surface extension"); return VK_ERROR_EXTENSION_NOT_PRESENT; } memset(&sci, 0, sizeof(sci)); sci.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR; sci.connection = connection; sci.window = window->x11.handle; err = vkCreateXcbSurfaceKHR(instance, &sci, allocator, surface); if (err) { _glfwInputError(GLFW_PLATFORM_ERROR, "X11: Failed to create Vulkan XCB surface: %s", _glfwGetVulkanResultString(err)); } return err; } else { VkResult err; VkXlibSurfaceCreateInfoKHR sci; PFN_vkCreateXlibSurfaceKHR vkCreateXlibSurfaceKHR; vkCreateXlibSurfaceKHR = (PFN_vkCreateXlibSurfaceKHR) vkGetInstanceProcAddr(instance, "vkCreateXlibSurfaceKHR"); if (!vkCreateXlibSurfaceKHR) { _glfwInputError(GLFW_API_UNAVAILABLE, "X11: Vulkan instance missing VK_KHR_xlib_surface extension"); return VK_ERROR_EXTENSION_NOT_PRESENT; } memset(&sci, 0, sizeof(sci)); sci.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR; sci.dpy = _glfw.x11.display; sci.window = window->x11.handle; err = vkCreateXlibSurfaceKHR(instance, &sci, allocator, surface); if (err) { _glfwInputError(GLFW_PLATFORM_ERROR, "X11: Failed to create Vulkan X11 surface: %s", _glfwGetVulkanResultString(err)); } return err; } } ////////////////////////////////////////////////////////////////////////// ////// GLFW native API ////// ////////////////////////////////////////////////////////////////////////// GLFWAPI Display* glfwGetX11Display(void) { _GLFW_REQUIRE_INIT_OR_RETURN(NULL); return _glfw.x11.display; } GLFWAPI Window glfwGetX11Window(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(None); return window->x11.handle; } GLFWAPI void glfwSetX11SelectionString(const char* string) { _GLFW_REQUIRE_INIT(); free(_glfw.x11.primarySelectionString); _glfw.x11.primarySelectionString = _glfw_strdup(string); XSetSelectionOwner(_glfw.x11.display, _glfw.x11.PRIMARY, _glfw.x11.helperWindowHandle, CurrentTime); if (XGetSelectionOwner(_glfw.x11.display, _glfw.x11.PRIMARY) != _glfw.x11.helperWindowHandle) { _glfwInputError(GLFW_PLATFORM_ERROR, "X11: Failed to become owner of primary selection"); } } GLFWAPI const char* glfwGetX11SelectionString(void) { _GLFW_REQUIRE_INIT_OR_RETURN(NULL); return getSelectionString(_glfw.x11.PRIMARY); } #endif #ifndef HEADER_GUARD_GLX_CONTEXT_C #define HEADER_GUARD_GLX_CONTEXT_C //======================================================================== // GLFW 3.3.7 GLX - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2019 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== // It is fine to use C99 in this file because it will not be built with VS //======================================================================== #include #include #include #ifndef GLXBadProfileARB #define GLXBadProfileARB 13 #endif // Returns the specified attribute of the specified GLXFBConfig // static int getGLXFBConfigAttrib(GLXFBConfig fbconfig, int attrib) { int value; glXGetFBConfigAttrib(_glfw.x11.display, fbconfig, attrib, &value); return value; } // Return the GLXFBConfig most closely matching the specified hints // static GLFWbool chooseGLXFBConfig(const _GLFWfbconfig* desired, GLXFBConfig* result) { GLXFBConfig* nativeConfigs; _GLFWfbconfig* usableConfigs; const _GLFWfbconfig* closest; int i, nativeCount, usableCount; const char* vendor; GLFWbool trustWindowBit = GLFW_TRUE; // HACK: This is a (hopefully temporary) workaround for Chromium // (VirtualBox GL) not setting the window bit on any GLXFBConfigs vendor = glXGetClientString(_glfw.x11.display, GLX_VENDOR); if (vendor && strcmp(vendor, "Chromium") == 0) trustWindowBit = GLFW_FALSE; nativeConfigs = glXGetFBConfigs(_glfw.x11.display, _glfw.x11.screen, &nativeCount); if (!nativeConfigs || !nativeCount) { _glfwInputError(GLFW_API_UNAVAILABLE, "GLX: No GLXFBConfigs returned"); return GLFW_FALSE; } usableConfigs = calloc(nativeCount, sizeof(_GLFWfbconfig)); usableCount = 0; for (i = 0; i < nativeCount; i++) { const GLXFBConfig n = nativeConfigs[i]; _GLFWfbconfig* u = usableConfigs + usableCount; // Only consider RGBA GLXFBConfigs if (!(getGLXFBConfigAttrib(n, GLX_RENDER_TYPE) & GLX_RGBA_BIT)) continue; // Only consider window GLXFBConfigs if (!(getGLXFBConfigAttrib(n, GLX_DRAWABLE_TYPE) & GLX_WINDOW_BIT)) { if (trustWindowBit) continue; } if (getGLXFBConfigAttrib(n, GLX_DOUBLEBUFFER) != desired->doublebuffer) continue; if (desired->transparent) { XVisualInfo* vi = glXGetVisualFromFBConfig(_glfw.x11.display, n); if (vi) { u->transparent = _glfwIsVisualTransparentX11(vi->visual); XFree(vi); } } u->redBits = getGLXFBConfigAttrib(n, GLX_RED_SIZE); u->greenBits = getGLXFBConfigAttrib(n, GLX_GREEN_SIZE); u->blueBits = getGLXFBConfigAttrib(n, GLX_BLUE_SIZE); u->alphaBits = getGLXFBConfigAttrib(n, GLX_ALPHA_SIZE); u->depthBits = getGLXFBConfigAttrib(n, GLX_DEPTH_SIZE); u->stencilBits = getGLXFBConfigAttrib(n, GLX_STENCIL_SIZE); u->accumRedBits = getGLXFBConfigAttrib(n, GLX_ACCUM_RED_SIZE); u->accumGreenBits = getGLXFBConfigAttrib(n, GLX_ACCUM_GREEN_SIZE); u->accumBlueBits = getGLXFBConfigAttrib(n, GLX_ACCUM_BLUE_SIZE); u->accumAlphaBits = getGLXFBConfigAttrib(n, GLX_ACCUM_ALPHA_SIZE); u->auxBuffers = getGLXFBConfigAttrib(n, GLX_AUX_BUFFERS); if (getGLXFBConfigAttrib(n, GLX_STEREO)) u->stereo = GLFW_TRUE; if (_glfw.glx.ARB_multisample) u->samples = getGLXFBConfigAttrib(n, GLX_SAMPLES); if (_glfw.glx.ARB_framebuffer_sRGB || _glfw.glx.EXT_framebuffer_sRGB) u->sRGB = getGLXFBConfigAttrib(n, GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB); u->handle = (uintptr_t) n; usableCount++; } closest = _glfwChooseFBConfig(desired, usableConfigs, usableCount); if (closest) *result = (GLXFBConfig) closest->handle; XFree(nativeConfigs); free(usableConfigs); return closest != NULL; } // Create the OpenGL context using legacy API // static GLXContext createLegacyContextGLX(_GLFWwindow* window, GLXFBConfig fbconfig, GLXContext share) { return glXCreateNewContext(_glfw.x11.display, fbconfig, GLX_RGBA_TYPE, share, True); } static void makeContextCurrentGLX(_GLFWwindow* window) { if (window) { if (!glXMakeCurrent(_glfw.x11.display, window->context.glx.window, window->context.glx.handle)) { _glfwInputError(GLFW_PLATFORM_ERROR, "GLX: Failed to make context current"); return; } } else { if (!glXMakeCurrent(_glfw.x11.display, None, NULL)) { _glfwInputError(GLFW_PLATFORM_ERROR, "GLX: Failed to clear current context"); return; } } _glfwPlatformSetTls(&_glfw.contextSlot, window); } static void swapBuffersGLX(_GLFWwindow* window) { glXSwapBuffers(_glfw.x11.display, window->context.glx.window); } static void swapIntervalGLX(int interval) { _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot); if (_glfw.glx.EXT_swap_control) { _glfw.glx.SwapIntervalEXT(_glfw.x11.display, window->context.glx.window, interval); } else if (_glfw.glx.MESA_swap_control) _glfw.glx.SwapIntervalMESA(interval); else if (_glfw.glx.SGI_swap_control) { if (interval > 0) _glfw.glx.SwapIntervalSGI(interval); } } static int extensionSupportedGLX(const char* extension) { const char* extensions = glXQueryExtensionsString(_glfw.x11.display, _glfw.x11.screen); if (extensions) { if (_glfwStringInExtensionString(extension, extensions)) return GLFW_TRUE; } return GLFW_FALSE; } static GLFWglproc getProcAddressGLX(const char* procname) { if (_glfw.glx.GetProcAddress) return _glfw.glx.GetProcAddress((const GLubyte*) procname); else if (_glfw.glx.GetProcAddressARB) return _glfw.glx.GetProcAddressARB((const GLubyte*) procname); else return _glfw_dlsym(_glfw.glx.handle, procname); } static void destroyContextGLX(_GLFWwindow* window) { if (window->context.glx.window) { glXDestroyWindow(_glfw.x11.display, window->context.glx.window); window->context.glx.window = None; } if (window->context.glx.handle) { glXDestroyContext(_glfw.x11.display, window->context.glx.handle); window->context.glx.handle = NULL; } } ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// // Initialize GLX // GLFWbool _glfwInitGLX(void) { int i; const char* sonames[] = { #if defined(_GLFW_GLX_LIBRARY) _GLFW_GLX_LIBRARY, #elif defined(__CYGWIN__) "libGL-1.so", #elif defined(__OpenBSD__) || defined(__NetBSD__) "libGL.so", #else "libGL.so.1", "libGL.so", #endif NULL }; if (_glfw.glx.handle) return GLFW_TRUE; for (i = 0; sonames[i]; i++) { _glfw.glx.handle = _glfw_dlopen(sonames[i]); if (_glfw.glx.handle) break; } if (!_glfw.glx.handle) { _glfwInputError(GLFW_API_UNAVAILABLE, "GLX: Failed to load GLX"); return GLFW_FALSE; } _glfw.glx.GetFBConfigs = _glfw_dlsym(_glfw.glx.handle, "glXGetFBConfigs"); _glfw.glx.GetFBConfigAttrib = _glfw_dlsym(_glfw.glx.handle, "glXGetFBConfigAttrib"); _glfw.glx.GetClientString = _glfw_dlsym(_glfw.glx.handle, "glXGetClientString"); _glfw.glx.QueryExtension = _glfw_dlsym(_glfw.glx.handle, "glXQueryExtension"); _glfw.glx.QueryVersion = _glfw_dlsym(_glfw.glx.handle, "glXQueryVersion"); _glfw.glx.DestroyContext = _glfw_dlsym(_glfw.glx.handle, "glXDestroyContext"); _glfw.glx.MakeCurrent = _glfw_dlsym(_glfw.glx.handle, "glXMakeCurrent"); _glfw.glx.SwapBuffers = _glfw_dlsym(_glfw.glx.handle, "glXSwapBuffers"); _glfw.glx.QueryExtensionsString = _glfw_dlsym(_glfw.glx.handle, "glXQueryExtensionsString"); _glfw.glx.CreateNewContext = _glfw_dlsym(_glfw.glx.handle, "glXCreateNewContext"); _glfw.glx.CreateWindow = _glfw_dlsym(_glfw.glx.handle, "glXCreateWindow"); _glfw.glx.DestroyWindow = _glfw_dlsym(_glfw.glx.handle, "glXDestroyWindow"); _glfw.glx.GetVisualFromFBConfig = _glfw_dlsym(_glfw.glx.handle, "glXGetVisualFromFBConfig"); if (!_glfw.glx.GetFBConfigs || !_glfw.glx.GetFBConfigAttrib || !_glfw.glx.GetClientString || !_glfw.glx.QueryExtension || !_glfw.glx.QueryVersion || !_glfw.glx.DestroyContext || !_glfw.glx.MakeCurrent || !_glfw.glx.SwapBuffers || !_glfw.glx.QueryExtensionsString || !_glfw.glx.CreateNewContext || !_glfw.glx.CreateWindow || !_glfw.glx.DestroyWindow || !_glfw.glx.GetVisualFromFBConfig) { _glfwInputError(GLFW_PLATFORM_ERROR, "GLX: Failed to load required entry points"); 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)) { _glfwInputError(GLFW_API_UNAVAILABLE, "GLX: GLX extension not found"); return GLFW_FALSE; } if (!glXQueryVersion(_glfw.x11.display, &_glfw.glx.major, &_glfw.glx.minor)) { _glfwInputError(GLFW_API_UNAVAILABLE, "GLX: Failed to query GLX version"); return GLFW_FALSE; } if (_glfw.glx.major == 1 && _glfw.glx.minor < 3) { _glfwInputError(GLFW_API_UNAVAILABLE, "GLX: GLX version 1.3 is required"); return GLFW_FALSE; } if (extensionSupportedGLX("GLX_EXT_swap_control")) { _glfw.glx.SwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC) getProcAddressGLX("glXSwapIntervalEXT"); if (_glfw.glx.SwapIntervalEXT) _glfw.glx.EXT_swap_control = GLFW_TRUE; } if (extensionSupportedGLX("GLX_SGI_swap_control")) { _glfw.glx.SwapIntervalSGI = (PFNGLXSWAPINTERVALSGIPROC) getProcAddressGLX("glXSwapIntervalSGI"); if (_glfw.glx.SwapIntervalSGI) _glfw.glx.SGI_swap_control = GLFW_TRUE; } if (extensionSupportedGLX("GLX_MESA_swap_control")) { _glfw.glx.SwapIntervalMESA = (PFNGLXSWAPINTERVALMESAPROC) getProcAddressGLX("glXSwapIntervalMESA"); if (_glfw.glx.SwapIntervalMESA) _glfw.glx.MESA_swap_control = GLFW_TRUE; } if (extensionSupportedGLX("GLX_ARB_multisample")) _glfw.glx.ARB_multisample = GLFW_TRUE; if (extensionSupportedGLX("GLX_ARB_framebuffer_sRGB")) _glfw.glx.ARB_framebuffer_sRGB = GLFW_TRUE; if (extensionSupportedGLX("GLX_EXT_framebuffer_sRGB")) _glfw.glx.EXT_framebuffer_sRGB = GLFW_TRUE; if (extensionSupportedGLX("GLX_ARB_create_context")) { _glfw.glx.CreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC) getProcAddressGLX("glXCreateContextAttribsARB"); if (_glfw.glx.CreateContextAttribsARB) _glfw.glx.ARB_create_context = GLFW_TRUE; } if (extensionSupportedGLX("GLX_ARB_create_context_robustness")) _glfw.glx.ARB_create_context_robustness = GLFW_TRUE; if (extensionSupportedGLX("GLX_ARB_create_context_profile")) _glfw.glx.ARB_create_context_profile = GLFW_TRUE; if (extensionSupportedGLX("GLX_EXT_create_context_es2_profile")) _glfw.glx.EXT_create_context_es2_profile = GLFW_TRUE; if (extensionSupportedGLX("GLX_ARB_create_context_no_error")) _glfw.glx.ARB_create_context_no_error = GLFW_TRUE; if (extensionSupportedGLX("GLX_ARB_context_flush_control")) _glfw.glx.ARB_context_flush_control = GLFW_TRUE; return GLFW_TRUE; } // Terminate GLX // void _glfwTerminateGLX(void) { // NOTE: This function must not call any X11 functions, as it is called // after XCloseDisplay (see _glfwPlatformTerminate for details) if (_glfw.glx.handle) { _glfw_dlclose(_glfw.glx.handle); _glfw.glx.handle = NULL; } } #define setAttrib(a, v) \ { \ assert(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \ attribs[index++] = a; \ attribs[index++] = v; \ } // Create the OpenGL or OpenGL ES context // GLFWbool _glfwCreateContextGLX(_GLFWwindow* window, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig) { int attribs[40]; GLXFBConfig native = NULL; GLXContext share = NULL; if (ctxconfig->share) share = ctxconfig->share->context.glx.handle; if (!chooseGLXFBConfig(fbconfig, &native)) { _glfwInputError(GLFW_FORMAT_UNAVAILABLE, "GLX: Failed to find a suitable GLXFBConfig"); return GLFW_FALSE; } if (ctxconfig->client == GLFW_OPENGL_ES_API) { if (!_glfw.glx.ARB_create_context || !_glfw.glx.ARB_create_context_profile || !_glfw.glx.EXT_create_context_es2_profile) { _glfwInputError(GLFW_API_UNAVAILABLE, "GLX: OpenGL ES requested but GLX_EXT_create_context_es2_profile is unavailable"); return GLFW_FALSE; } } if (ctxconfig->forward) { if (!_glfw.glx.ARB_create_context) { _glfwInputError(GLFW_VERSION_UNAVAILABLE, "GLX: Forward compatibility requested but GLX_ARB_create_context_profile is unavailable"); return GLFW_FALSE; } } if (ctxconfig->profile) { if (!_glfw.glx.ARB_create_context || !_glfw.glx.ARB_create_context_profile) { _glfwInputError(GLFW_VERSION_UNAVAILABLE, "GLX: An OpenGL profile requested but GLX_ARB_create_context_profile is unavailable"); return GLFW_FALSE; } } _glfwGrabErrorHandlerX11(); if (_glfw.glx.ARB_create_context) { int index = 0, mask = 0, flags = 0; if (ctxconfig->client == GLFW_OPENGL_API) { if (ctxconfig->forward) flags |= GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE) mask |= GLX_CONTEXT_CORE_PROFILE_BIT_ARB; else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE) mask |= GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; } else mask |= GLX_CONTEXT_ES2_PROFILE_BIT_EXT; if (ctxconfig->debug) flags |= GLX_CONTEXT_DEBUG_BIT_ARB; if (ctxconfig->robustness) { if (_glfw.glx.ARB_create_context_robustness) { if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION) { setAttrib(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, GLX_NO_RESET_NOTIFICATION_ARB); } else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET) { setAttrib(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, GLX_LOSE_CONTEXT_ON_RESET_ARB); } flags |= GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB; } } if (ctxconfig->release) { if (_glfw.glx.ARB_context_flush_control) { if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE) { setAttrib(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB, GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB); } else if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_FLUSH) { setAttrib(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB, GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB); } } } if (ctxconfig->noerror) { if (_glfw.glx.ARB_create_context_no_error) setAttrib(GLX_CONTEXT_OPENGL_NO_ERROR_ARB, GLFW_TRUE); } // NOTE: Only request an explicitly versioned context when necessary, as // explicitly requesting version 1.0 does not always return the // highest version supported by the driver if (ctxconfig->major != 1 || ctxconfig->minor != 0) { setAttrib(GLX_CONTEXT_MAJOR_VERSION_ARB, ctxconfig->major); setAttrib(GLX_CONTEXT_MINOR_VERSION_ARB, ctxconfig->minor); } if (mask) setAttrib(GLX_CONTEXT_PROFILE_MASK_ARB, mask); if (flags) setAttrib(GLX_CONTEXT_FLAGS_ARB, flags); setAttrib(None, None); window->context.glx.handle = _glfw.glx.CreateContextAttribsARB(_glfw.x11.display, native, share, True, attribs); // HACK: This is a fallback for broken versions of the Mesa // implementation of GLX_ARB_create_context_profile that fail // default 1.0 context creation with a GLXBadProfileARB error in // violation of the extension spec if (!window->context.glx.handle) { if (_glfw.x11.errorCode == _glfw.glx.errorBase + GLXBadProfileARB && ctxconfig->client == GLFW_OPENGL_API && ctxconfig->profile == GLFW_OPENGL_ANY_PROFILE && ctxconfig->forward == GLFW_FALSE) { window->context.glx.handle = createLegacyContextGLX(window, native, share); } } } else { window->context.glx.handle = createLegacyContextGLX(window, native, share); } _glfwReleaseErrorHandlerX11(); if (!window->context.glx.handle) { _glfwInputErrorX11(GLFW_VERSION_UNAVAILABLE, "GLX: Failed to create context"); return GLFW_FALSE; } window->context.glx.window = glXCreateWindow(_glfw.x11.display, native, window->x11.handle, NULL); if (!window->context.glx.window) { _glfwInputError(GLFW_PLATFORM_ERROR, "GLX: Failed to create window"); return GLFW_FALSE; } window->context.makeCurrent = makeContextCurrentGLX; window->context.swapBuffers = swapBuffersGLX; window->context.swapInterval = swapIntervalGLX; window->context.extensionSupported = extensionSupportedGLX; window->context.getProcAddress = getProcAddressGLX; window->context.destroy = destroyContextGLX; return GLFW_TRUE; } #undef setAttrib // Returns the Visual and depth of the chosen GLXFBConfig // GLFWbool _glfwChooseVisualGLX(const _GLFWwndconfig* wndconfig, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig, Visual** visual, int* depth) { GLXFBConfig native; XVisualInfo* result; if (!chooseGLXFBConfig(fbconfig, &native)) { _glfwInputError(GLFW_FORMAT_UNAVAILABLE, "GLX: Failed to find a suitable GLXFBConfig"); return GLFW_FALSE; } result = glXGetVisualFromFBConfig(_glfw.x11.display, native); if (!result) { _glfwInputError(GLFW_PLATFORM_ERROR, "GLX: Failed to retrieve Visual for GLXFBConfig"); return GLFW_FALSE; } *visual = result->visual; *depth = result->depth; XFree(result); return GLFW_TRUE; } ////////////////////////////////////////////////////////////////////////// ////// GLFW native API ////// ////////////////////////////////////////////////////////////////////////// GLFWAPI GLXContext glfwGetGLXContext(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(NULL); if (window->context.source != GLFW_NATIVE_CONTEXT_API) { _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); return NULL; } return window->context.glx.handle; } GLFWAPI GLXWindow glfwGetGLXWindow(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(None); if (window->context.source != GLFW_NATIVE_CONTEXT_API) { _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); return None; } return window->context.glx.window; } #endif #endif #ifdef _GLFW_WAYLAND #ifndef HEADER_GUARD_WL_INIT_C #define HEADER_GUARD_WL_INIT_C //======================================================================== // GLFW 3.3.7 Wayland - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2014 Jonas Ådahl // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== // It is fine to use C99 in this file because it will not be built with VS //======================================================================== #ifndef _POSIX_C_SOURCE //< @r-lyeh: add guard #define _POSIX_C_SOURCE 200809L #endif #include #include #include #include #include #include #include #include #include #include #include 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.pointerEnterSerial = 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.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 = 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); window->wl.cursorPosX = x; window->wl.cursorPosY = y; switch (window->wl.decorations.focus) { case mainWindow: _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); return; } } 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; 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.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; struct itimerspec timer = {}; timerfd_settime(_glfw.wl.timerfd, 0, &timer, NULL); _glfw.wl.serial = serial; _glfw.wl.keyboardFocus = NULL; _glfwInputWindowFocus(window, GLFW_FALSE); } 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; } } GLFWbool _glfwInputTextWayland(_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); } } return xkb_keymap_key_repeats(_glfw.wl.xkb.keymap, keycode); } static void keyboardHandleKey(void* data, 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; _glfwInputKey(window, key, scancode, action, _glfw.wl.xkb.modifiers); struct itimerspec timer = {}; if (action == GLFW_PRESS) { const GLFWbool shouldRepeat = _glfwInputTextWayland(window, scancode); if (shouldRepeat && _glfw.wl.keyboardRepeatRate > 0) { _glfw.wl.keyboardLastKey = key; _glfw.wl.keyboardLastScancode = scancode; 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) { _glfw.wl.serial = serial; if (!_glfw.wl.xkb.keymap) return; xkb_state_update_mask(_glfw.wl.xkb.state, modsDepressed, modsLatched, modsLocked, 0, 0, group); const xkb_mod_mask_t 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); unsigned int mods = 0; if (mask & _glfw.wl.xkb.controlMask) mods |= GLFW_MOD_CONTROL; if (mask & _glfw.wl.xkb.altMask) mods |= GLFW_MOD_ALT; if (mask & _glfw.wl.xkb.shiftMask) mods |= GLFW_MOD_SHIFT; if (mask & _glfw.wl.xkb.superMask) mods |= GLFW_MOD_SUPER; if (mask & _glfw.wl.xkb.capsLockMask) mods |= GLFW_MOD_CAPS_LOCK; if (mask & _glfw.wl.xkb.numLockMask) mods |= GLFW_MOD_NUM_LOCK; _glfw.wl.xkb.modifiers = mods; } #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_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; } } ////////////////////////////////////////////////////////////////////////// ////// 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.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_serialize_mods = (PFN_xkb_state_serialize_mods) _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_state_serialize_mods"); _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.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; } _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 | TFD_NONBLOCK); 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 | TFD_NONBLOCK); } 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.clipboardSize = 4096; _glfw.wl.clipboardString = calloc(_glfw.wl.clipboardSize, 1); if (!_glfw.wl.clipboardString) { _glfwInputError(GLFW_OUT_OF_MEMORY, "Wayland: Unable to allocate clipboard memory"); return GLFW_FALSE; } } 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; } 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; } 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); free(_glfw.wl.clipboardString); free(_glfw.wl.clipboardSendString); } const char* _glfwPlatformGetVersionString(void) { return _GLFW_VERSION_NUMBER " Wayland EGL OSMesa" #if defined(_POSIX_TIMERS) && defined(_POSIX_MONOTONIC_CLOCK) " clock_gettime" #else " gettimeofday" #endif " evdev" #if defined(_GLFW_BUILD_DLL) " shared" #endif ; } #endif #ifndef HEADER_GUARD_WL_MONITOR_C #define HEADER_GUARD_WL_MONITOR_C //======================================================================== // GLFW 3.3.7 Wayland - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2014 Jonas Ådahl // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== // It is fine to use C99 in this file because it will not be built with VS //======================================================================== #include #include #include #include #include static void outputHandleGeometry(void* data, struct wl_output* output, int32_t x, int32_t y, int32_t physicalWidth, int32_t physicalHeight, int32_t subpixel, const char* make, const char* model, int32_t transform) { struct _GLFWmonitor *monitor = data; monitor->wl.x = x; monitor->wl.y = y; monitor->widthMM = physicalWidth; monitor->heightMM = physicalHeight; snprintf(monitor->name, sizeof(monitor->name), "%s %s", make, model); } static void outputHandleMode(void* data, struct wl_output* output, uint32_t flags, int32_t width, int32_t height, int32_t refresh) { struct _GLFWmonitor *monitor = data; GLFWvidmode mode; mode.width = width; mode.height = height; mode.redBits = 8; mode.greenBits = 8; mode.blueBits = 8; mode.refreshRate = (int) round(refresh / 1000.0); monitor->modeCount++; monitor->modes = realloc(monitor->modes, monitor->modeCount * sizeof(GLFWvidmode)); monitor->modes[monitor->modeCount - 1] = mode; if (flags & WL_OUTPUT_MODE_CURRENT) monitor->wl.currentMode = monitor->modeCount - 1; } static void outputHandleDone(void* data, struct wl_output* output) { struct _GLFWmonitor *monitor = data; 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); } _glfwInputMonitor(monitor, GLFW_CONNECTED, _GLFW_INSERT_LAST); } static void outputHandleScale(void* data, struct wl_output* output, int32_t factor) { struct _GLFWmonitor *monitor = data; monitor->wl.scale = factor; } static const struct wl_output_listener outputListener = { outputHandleGeometry, outputHandleMode, outputHandleDone, outputHandleScale, }; ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// void _glfwAddOutputWayland(uint32_t name, uint32_t version) { _GLFWmonitor *monitor; struct wl_output *output; if (version < 2) { _glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: Unsupported output interface version"); return; } // The actual name of this output will be set in the geometry handler. monitor = _glfwAllocMonitor("", 0, 0); output = wl_registry_bind(_glfw.wl.registry, name, &wl_output_interface, 2); if (!output) { _glfwFreeMonitor(monitor); return; } monitor->wl.scale = 1; monitor->wl.output = output; monitor->wl.name = name; wl_output_add_listener(output, &outputListener, monitor); } ////////////////////////////////////////////////////////////////////////// ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor) { if (monitor->wl.output) wl_output_destroy(monitor->wl.output); } void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) { if (xpos) *xpos = monitor->wl.x; if (ypos) *ypos = monitor->wl.y; } void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor, float* xscale, float* yscale) { if (xscale) *xscale = (float) monitor->wl.scale; if (yscale) *yscale = (float) monitor->wl.scale; } void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor, int* xpos, int* ypos, int* width, int* height) { if (xpos) *xpos = monitor->wl.x; if (ypos) *ypos = monitor->wl.y; if (width) *width = monitor->modes[monitor->wl.currentMode].width; if (height) *height = monitor->modes[monitor->wl.currentMode].height; } GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found) { *found = monitor->modeCount; return monitor->modes; } void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode) { *mode = monitor->modes[monitor->wl.currentMode]; } GLFWbool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) { _glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: Gamma ramp access is not available"); return GLFW_FALSE; } void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) { _glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: Gamma ramp access is not available"); } ////////////////////////////////////////////////////////////////////////// ////// GLFW native API ////// ////////////////////////////////////////////////////////////////////////// GLFWAPI struct wl_output* glfwGetWaylandMonitor(GLFWmonitor* handle) { _GLFWmonitor* monitor = (_GLFWmonitor*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(NULL); return monitor->wl.output; } #endif #ifndef HEADER_GUARD_WL_WINDOW_C #define HEADER_GUARD_WL_WINDOW_C //======================================================================== // GLFW 3.3.7 Wayland - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2014 Jonas Ådahl // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== // It is fine to use C99 in this file because it will not be built with VS //======================================================================== #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include 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: %s", length, strerror(errno)); 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: %s", strerror(errno)); 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; } // 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 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->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 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) { // 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. int maxScale = 1; for (int i = 0; i < window->wl.monitorsCount; i++) { const int scale = window->wl.monitors[i]->wl.scale; if (maxScale < scale) maxScale = scale; } // Only change the framebuffer size if the scale changed. if (window->wl.scale != maxScale) { window->wl.scale = maxScale; wl_surface_set_buffer_scale(window->wl.surface, maxScale); 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 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; } 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 GLFWbool createSurface(_GLFWwindow* window, const _GLFWwndconfig* wndconfig, const _GLFWfbconfig* fbconfig) { 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; window->wl.title = _glfw_strdup(wndconfig->title); window->wl.transparent = fbconfig->transparent; if (!window->wl.transparent) setOpaqueRegion(window); if (window->monitor || wndconfig->visible) { if (!createXdgSurface(window)) return GLFW_FALSE; window->wl.visible = GLFW_TRUE; } 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.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 != 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 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 void handleEvents(double* timeout) { GLFWbool event = GLFW_FALSE; struct pollfd fds[] = { { wl_display_get_fd(_glfw.wl.display), POLLIN }, { _glfw.wl.timerfd, POLLIN }, { _glfw.wl.cursorTimerfd, POLLIN }, }; while (!event) { while (wl_display_prepare_read(_glfw.wl.display) != 0) wl_display_dispatch_pending(_glfw.wl.display); // 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, 3, 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.timerfd, &repeats, sizeof(repeats)) == 8) { for (uint64_t i = 0; i < repeats; i++) { _glfwInputKey(_glfw.wl.keyboardFocus, _glfw.wl.keyboardLastKey, _glfw.wl.keyboardLastScancode, GLFW_PRESS, _glfw.wl.xkb.modifiers); _glfwInputTextWayland(_glfw.wl.keyboardFocus, _glfw.wl.keyboardLastScancode); } event = GLFW_TRUE; } } if (fds[2].revents & POLLIN) { uint64_t repeats; if (read(_glfw.wl.cursorTimerfd, &repeats, sizeof(repeats)) == 8) { incrementCursorImage(_glfw.wl.pointerFocus); event = GLFW_TRUE; } } } } // 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) { if (!createSurface(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) { 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; } } 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); if (width) *width *= window->wl.scale; if (height) *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) { // 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 if (_glfw.wl.wmBase) { if (!window->wl.xdg.toplevel) createXdgSurface(window); } else if (!window->wl.shellSurface) createShellSurface(window); window->wl.visible = GLFW_TRUE; _glfwInputWindowDamage(window); } } void _glfwPlatformHideWindow(_GLFWwindow* window) { if (window->wl.visible) { window->wl.visible = GLFW_FALSE; 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 (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) { 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; } 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) { 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* 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.pointerEnterSerial, 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.pointerEnterSerial, 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_OUT_OF_MEMORY, "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(NULL); for (;;) { // 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'; return _glfw.wl.clipboardString; } void _glfwPlatformGetRequiredInstanceExtensions(char** extensions) { if (!_glfw.vk.KHR_surface || !_glfw.vk.KHR_wayland_surface) return; extensions[0] = "VK_KHR_surface"; extensions[1] = "VK_KHR_wayland_surface"; } int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, VkPhysicalDevice device, uint32_t queuefamily) { PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR vkGetPhysicalDeviceWaylandPresentationSupportKHR = (PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR) vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceWaylandPresentationSupportKHR"); if (!vkGetPhysicalDeviceWaylandPresentationSupportKHR) { _glfwInputError(GLFW_API_UNAVAILABLE, "Wayland: Vulkan instance missing VK_KHR_wayland_surface extension"); return VK_NULL_HANDLE; } return vkGetPhysicalDeviceWaylandPresentationSupportKHR(device, queuefamily, _glfw.wl.display); } VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, _GLFWwindow* window, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface) { VkResult err; VkWaylandSurfaceCreateInfoKHR sci; PFN_vkCreateWaylandSurfaceKHR vkCreateWaylandSurfaceKHR; vkCreateWaylandSurfaceKHR = (PFN_vkCreateWaylandSurfaceKHR) vkGetInstanceProcAddr(instance, "vkCreateWaylandSurfaceKHR"); if (!vkCreateWaylandSurfaceKHR) { _glfwInputError(GLFW_API_UNAVAILABLE, "Wayland: Vulkan instance missing VK_KHR_wayland_surface extension"); return VK_ERROR_EXTENSION_NOT_PRESENT; } memset(&sci, 0, sizeof(sci)); sci.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR; sci.display = _glfw.wl.display; sci.surface = window->wl.surface; err = vkCreateWaylandSurfaceKHR(instance, &sci, allocator, surface); if (err) { _glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: Failed to create Vulkan surface: %s", _glfwGetVulkanResultString(err)); } return err; } ////////////////////////////////////////////////////////////////////////// ////// GLFW native API ////// ////////////////////////////////////////////////////////////////////////// GLFWAPI struct wl_display* glfwGetWaylandDisplay(void) { _GLFW_REQUIRE_INIT_OR_RETURN(NULL); return _glfw.wl.display; } GLFWAPI struct wl_surface* glfwGetWaylandWindow(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(NULL); return window->wl.surface; } #endif #endif #ifdef _GLFW_COCOA #ifndef HEADER_GUARD_COCOA_INIT_M #define HEADER_GUARD_COCOA_INIT_M //======================================================================== // GLFW 3.3.7 macOS - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2009-2019 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== // It is fine to use C99 in this file because it will not be built with VS //======================================================================== #include // For MAXPATHLEN // Needed for _NSGetProgname #include // Change to our application bundle's resources directory, if present // static void changeToResourcesDirectory(void) { char resourcesPath[MAXPATHLEN]; CFBundleRef bundle = CFBundleGetMainBundle(); if (!bundle) return; CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(bundle); CFStringRef last = CFURLCopyLastPathComponent(resourcesURL); if (CFStringCompare(CFSTR("Resources"), last, 0) != kCFCompareEqualTo) { CFRelease(last); CFRelease(resourcesURL); return; } CFRelease(last); if (!CFURLGetFileSystemRepresentation(resourcesURL, true, (UInt8*) resourcesPath, MAXPATHLEN)) { CFRelease(resourcesURL); return; } CFRelease(resourcesURL); chdir(resourcesPath); } // Set up the menu bar (manually) // This is nasty, nasty stuff -- calls to undocumented semi-private APIs that // could go away at any moment, lots of stuff that really should be // localize(d|able), etc. Add a nib to save us this horror. // static void createMenuBar(void) { size_t i; NSString* appName = nil; NSDictionary* bundleInfo = [[NSBundle mainBundle] infoDictionary]; NSString* nameKeys[] = { @"CFBundleDisplayName", @"CFBundleName", @"CFBundleExecutable", }; // Try to figure out what the calling application is called for (i = 0; i < sizeof(nameKeys) / sizeof(nameKeys[0]); i++) { id name = bundleInfo[nameKeys[i]]; if (name && [name isKindOfClass:[NSString class]] && ![name isEqualToString:@""]) { appName = name; break; } } if (!appName) { char** progname = _NSGetProgname(); if (progname && *progname) appName = @(*progname); else appName = @"GLFW Application"; } NSMenu* bar = [[NSMenu alloc] init]; [NSApp setMainMenu:bar]; NSMenuItem* appMenuItem = [bar addItemWithTitle:@"" action:NULL keyEquivalent:@""]; NSMenu* appMenu = [[NSMenu alloc] init]; [appMenuItem setSubmenu:appMenu]; [appMenu addItemWithTitle:[NSString stringWithFormat:@"About %@", appName] action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""]; [appMenu addItem:[NSMenuItem separatorItem]]; NSMenu* servicesMenu = [[NSMenu alloc] init]; [NSApp setServicesMenu:servicesMenu]; [[appMenu addItemWithTitle:@"Services" action:NULL keyEquivalent:@""] setSubmenu:servicesMenu]; [servicesMenu release]; [appMenu addItem:[NSMenuItem separatorItem]]; [appMenu addItemWithTitle:[NSString stringWithFormat:@"Hide %@", appName] action:@selector(hide:) keyEquivalent:@"h"]; [[appMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"] setKeyEquivalentModifierMask:NSEventModifierFlagOption | NSEventModifierFlagCommand]; [appMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""]; [appMenu addItem:[NSMenuItem separatorItem]]; [appMenu addItemWithTitle:[NSString stringWithFormat:@"Quit %@", appName] action:@selector(terminate:) keyEquivalent:@"q"]; NSMenuItem* windowMenuItem = [bar addItemWithTitle:@"" action:NULL keyEquivalent:@""]; [bar release]; NSMenu* windowMenu = [[NSMenu alloc] initWithTitle:@"Window"]; [NSApp setWindowsMenu:windowMenu]; [windowMenuItem setSubmenu:windowMenu]; [windowMenu addItemWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"]; [windowMenu addItemWithTitle:@"Zoom" action:@selector(performZoom:) keyEquivalent:@""]; [windowMenu addItem:[NSMenuItem separatorItem]]; [windowMenu addItemWithTitle:@"Bring All to Front" action:@selector(arrangeInFront:) keyEquivalent:@""]; // TODO: Make this appear at the bottom of the menu (for consistency) [windowMenu addItem:[NSMenuItem separatorItem]]; [[windowMenu addItemWithTitle:@"Enter Full Screen" action:@selector(toggleFullScreen:) keyEquivalent:@"f"] setKeyEquivalentModifierMask:NSEventModifierFlagControl | NSEventModifierFlagCommand]; // Prior to Snow Leopard, we need to use this oddly-named semi-private API // to get the application menu working properly. SEL setAppleMenuSelector = NSSelectorFromString(@"setAppleMenu:"); [NSApp performSelector:setAppleMenuSelector withObject:appMenu]; } // Create key code translation tables // static void createKeyTables(void) { int scancode; memset(_glfw.ns.keycodes, -1, sizeof(_glfw.ns.keycodes)); memset(_glfw.ns.scancodes, -1, sizeof(_glfw.ns.scancodes)); _glfw.ns.keycodes[0x1D] = GLFW_KEY_0; _glfw.ns.keycodes[0x12] = GLFW_KEY_1; _glfw.ns.keycodes[0x13] = GLFW_KEY_2; _glfw.ns.keycodes[0x14] = GLFW_KEY_3; _glfw.ns.keycodes[0x15] = GLFW_KEY_4; _glfw.ns.keycodes[0x17] = GLFW_KEY_5; _glfw.ns.keycodes[0x16] = GLFW_KEY_6; _glfw.ns.keycodes[0x1A] = GLFW_KEY_7; _glfw.ns.keycodes[0x1C] = GLFW_KEY_8; _glfw.ns.keycodes[0x19] = GLFW_KEY_9; _glfw.ns.keycodes[0x00] = GLFW_KEY_A; _glfw.ns.keycodes[0x0B] = GLFW_KEY_B; _glfw.ns.keycodes[0x08] = GLFW_KEY_C; _glfw.ns.keycodes[0x02] = GLFW_KEY_D; _glfw.ns.keycodes[0x0E] = GLFW_KEY_E; _glfw.ns.keycodes[0x03] = GLFW_KEY_F; _glfw.ns.keycodes[0x05] = GLFW_KEY_G; _glfw.ns.keycodes[0x04] = GLFW_KEY_H; _glfw.ns.keycodes[0x22] = GLFW_KEY_I; _glfw.ns.keycodes[0x26] = GLFW_KEY_J; _glfw.ns.keycodes[0x28] = GLFW_KEY_K; _glfw.ns.keycodes[0x25] = GLFW_KEY_L; _glfw.ns.keycodes[0x2E] = GLFW_KEY_M; _glfw.ns.keycodes[0x2D] = GLFW_KEY_N; _glfw.ns.keycodes[0x1F] = GLFW_KEY_O; _glfw.ns.keycodes[0x23] = GLFW_KEY_P; _glfw.ns.keycodes[0x0C] = GLFW_KEY_Q; _glfw.ns.keycodes[0x0F] = GLFW_KEY_R; _glfw.ns.keycodes[0x01] = GLFW_KEY_S; _glfw.ns.keycodes[0x11] = GLFW_KEY_T; _glfw.ns.keycodes[0x20] = GLFW_KEY_U; _glfw.ns.keycodes[0x09] = GLFW_KEY_V; _glfw.ns.keycodes[0x0D] = GLFW_KEY_W; _glfw.ns.keycodes[0x07] = GLFW_KEY_X; _glfw.ns.keycodes[0x10] = GLFW_KEY_Y; _glfw.ns.keycodes[0x06] = GLFW_KEY_Z; _glfw.ns.keycodes[0x27] = GLFW_KEY_APOSTROPHE; _glfw.ns.keycodes[0x2A] = GLFW_KEY_BACKSLASH; _glfw.ns.keycodes[0x2B] = GLFW_KEY_COMMA; _glfw.ns.keycodes[0x18] = GLFW_KEY_EQUAL; _glfw.ns.keycodes[0x32] = GLFW_KEY_GRAVE_ACCENT; _glfw.ns.keycodes[0x21] = GLFW_KEY_LEFT_BRACKET; _glfw.ns.keycodes[0x1B] = GLFW_KEY_MINUS; _glfw.ns.keycodes[0x2F] = GLFW_KEY_PERIOD; _glfw.ns.keycodes[0x1E] = GLFW_KEY_RIGHT_BRACKET; _glfw.ns.keycodes[0x29] = GLFW_KEY_SEMICOLON; _glfw.ns.keycodes[0x2C] = GLFW_KEY_SLASH; _glfw.ns.keycodes[0x0A] = GLFW_KEY_WORLD_1; _glfw.ns.keycodes[0x33] = GLFW_KEY_BACKSPACE; _glfw.ns.keycodes[0x39] = GLFW_KEY_CAPS_LOCK; _glfw.ns.keycodes[0x75] = GLFW_KEY_DELETE; _glfw.ns.keycodes[0x7D] = GLFW_KEY_DOWN; _glfw.ns.keycodes[0x77] = GLFW_KEY_END; _glfw.ns.keycodes[0x24] = GLFW_KEY_ENTER; _glfw.ns.keycodes[0x35] = GLFW_KEY_ESCAPE; _glfw.ns.keycodes[0x7A] = GLFW_KEY_F1; _glfw.ns.keycodes[0x78] = GLFW_KEY_F2; _glfw.ns.keycodes[0x63] = GLFW_KEY_F3; _glfw.ns.keycodes[0x76] = GLFW_KEY_F4; _glfw.ns.keycodes[0x60] = GLFW_KEY_F5; _glfw.ns.keycodes[0x61] = GLFW_KEY_F6; _glfw.ns.keycodes[0x62] = GLFW_KEY_F7; _glfw.ns.keycodes[0x64] = GLFW_KEY_F8; _glfw.ns.keycodes[0x65] = GLFW_KEY_F9; _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[0x6B] = GLFW_KEY_F14; _glfw.ns.keycodes[0x71] = GLFW_KEY_F15; _glfw.ns.keycodes[0x6A] = GLFW_KEY_F16; _glfw.ns.keycodes[0x40] = GLFW_KEY_F17; _glfw.ns.keycodes[0x4F] = GLFW_KEY_F18; _glfw.ns.keycodes[0x50] = GLFW_KEY_F19; _glfw.ns.keycodes[0x5A] = GLFW_KEY_F20; _glfw.ns.keycodes[0x73] = GLFW_KEY_HOME; _glfw.ns.keycodes[0x72] = GLFW_KEY_INSERT; _glfw.ns.keycodes[0x7B] = GLFW_KEY_LEFT; _glfw.ns.keycodes[0x3A] = GLFW_KEY_LEFT_ALT; _glfw.ns.keycodes[0x3B] = GLFW_KEY_LEFT_CONTROL; _glfw.ns.keycodes[0x38] = GLFW_KEY_LEFT_SHIFT; _glfw.ns.keycodes[0x37] = GLFW_KEY_LEFT_SUPER; _glfw.ns.keycodes[0x6E] = GLFW_KEY_MENU; _glfw.ns.keycodes[0x47] = GLFW_KEY_NUM_LOCK; _glfw.ns.keycodes[0x79] = GLFW_KEY_PAGE_DOWN; _glfw.ns.keycodes[0x74] = GLFW_KEY_PAGE_UP; _glfw.ns.keycodes[0x7C] = GLFW_KEY_RIGHT; _glfw.ns.keycodes[0x3D] = GLFW_KEY_RIGHT_ALT; _glfw.ns.keycodes[0x3E] = GLFW_KEY_RIGHT_CONTROL; _glfw.ns.keycodes[0x3C] = GLFW_KEY_RIGHT_SHIFT; _glfw.ns.keycodes[0x36] = GLFW_KEY_RIGHT_SUPER; _glfw.ns.keycodes[0x31] = GLFW_KEY_SPACE; _glfw.ns.keycodes[0x30] = GLFW_KEY_TAB; _glfw.ns.keycodes[0x7E] = GLFW_KEY_UP; _glfw.ns.keycodes[0x52] = GLFW_KEY_KP_0; _glfw.ns.keycodes[0x53] = GLFW_KEY_KP_1; _glfw.ns.keycodes[0x54] = GLFW_KEY_KP_2; _glfw.ns.keycodes[0x55] = GLFW_KEY_KP_3; _glfw.ns.keycodes[0x56] = GLFW_KEY_KP_4; _glfw.ns.keycodes[0x57] = GLFW_KEY_KP_5; _glfw.ns.keycodes[0x58] = GLFW_KEY_KP_6; _glfw.ns.keycodes[0x59] = GLFW_KEY_KP_7; _glfw.ns.keycodes[0x5B] = GLFW_KEY_KP_8; _glfw.ns.keycodes[0x5C] = GLFW_KEY_KP_9; _glfw.ns.keycodes[0x45] = GLFW_KEY_KP_ADD; _glfw.ns.keycodes[0x41] = GLFW_KEY_KP_DECIMAL; _glfw.ns.keycodes[0x4B] = GLFW_KEY_KP_DIVIDE; _glfw.ns.keycodes[0x4C] = GLFW_KEY_KP_ENTER; _glfw.ns.keycodes[0x51] = GLFW_KEY_KP_EQUAL; _glfw.ns.keycodes[0x43] = GLFW_KEY_KP_MULTIPLY; _glfw.ns.keycodes[0x4E] = GLFW_KEY_KP_SUBTRACT; for (scancode = 0; scancode < 256; scancode++) { // Store the reverse translation for faster key name lookup if (_glfw.ns.keycodes[scancode] >= 0) _glfw.ns.scancodes[_glfw.ns.keycodes[scancode]] = scancode; } } // Retrieve Unicode data for the current keyboard layout // static GLFWbool updateUnicodeDataNS(void) { if (_glfw.ns.inputSource) { CFRelease(_glfw.ns.inputSource); _glfw.ns.inputSource = NULL; _glfw.ns.unicodeData = nil; } _glfw.ns.inputSource = TISCopyCurrentKeyboardLayoutInputSource(); if (!_glfw.ns.inputSource) { _glfwInputError(GLFW_PLATFORM_ERROR, "Cocoa: Failed to retrieve keyboard layout input source"); return GLFW_FALSE; } _glfw.ns.unicodeData = TISGetInputSourceProperty(_glfw.ns.inputSource, kTISPropertyUnicodeKeyLayoutData); if (!_glfw.ns.unicodeData) { _glfwInputError(GLFW_PLATFORM_ERROR, "Cocoa: Failed to retrieve keyboard layout Unicode data"); return GLFW_FALSE; } return GLFW_TRUE; } // Load HIToolbox.framework and the TIS symbols we need from it // static GLFWbool initializeTIS(void) { // This works only because Cocoa has already loaded it properly _glfw.ns.tis.bundle = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.HIToolbox")); if (!_glfw.ns.tis.bundle) { _glfwInputError(GLFW_PLATFORM_ERROR, "Cocoa: Failed to load HIToolbox.framework"); return GLFW_FALSE; } CFStringRef* kPropertyUnicodeKeyLayoutData = CFBundleGetDataPointerForName(_glfw.ns.tis.bundle, CFSTR("kTISPropertyUnicodeKeyLayoutData")); _glfw.ns.tis.CopyCurrentKeyboardLayoutInputSource = CFBundleGetFunctionPointerForName(_glfw.ns.tis.bundle, CFSTR("TISCopyCurrentKeyboardLayoutInputSource")); _glfw.ns.tis.GetInputSourceProperty = CFBundleGetFunctionPointerForName(_glfw.ns.tis.bundle, CFSTR("TISGetInputSourceProperty")); _glfw.ns.tis.GetKbdType = CFBundleGetFunctionPointerForName(_glfw.ns.tis.bundle, CFSTR("LMGetKbdType")); if (!kPropertyUnicodeKeyLayoutData || !TISCopyCurrentKeyboardLayoutInputSource || !TISGetInputSourceProperty || !LMGetKbdType) { _glfwInputError(GLFW_PLATFORM_ERROR, "Cocoa: Failed to load TIS API symbols"); return GLFW_FALSE; } _glfw.ns.tis.kPropertyUnicodeKeyLayoutData = *kPropertyUnicodeKeyLayoutData; return updateUnicodeDataNS(); } @interface GLFWHelper : NSObject @end @implementation GLFWHelper - (void)selectedKeyboardInputSourceChanged:(NSObject* )object { updateUnicodeDataNS(); } - (void)doNothing:(id)object { } @end // GLFWHelper @interface GLFWApplicationDelegate : NSObject @end @implementation GLFWApplicationDelegate - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender { _GLFWwindow* window; for (window = _glfw.windowListHead; window; window = window->next) _glfwInputWindowCloseRequest(window); return NSTerminateCancel; } - (void)applicationDidChangeScreenParameters:(NSNotification *) notification { _GLFWwindow* window; for (window = _glfw.windowListHead; window; window = window->next) { if (window->context.client != GLFW_NO_API) [window->context.nsgl.object update]; } _glfwPollMonitorsNS(); } - (void)applicationWillFinishLaunching:(NSNotification *)notification { if (_glfw.hints.init.ns.menubar) { // Menu bar setup must go between sharedApplication and finishLaunching // in order to properly emulate the behavior of NSApplicationMain if ([[NSBundle mainBundle] pathForResource:@"MainMenu" ofType:@"nib"]) { [[NSBundle mainBundle] loadNibNamed:@"MainMenu" owner:NSApp topLevelObjects:&_glfw.ns.nibObjects]; } else createMenuBar(); } } - (void)applicationDidFinishLaunching:(NSNotification *)notification { _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]; } - (void)applicationDidHide:(NSNotification *)notification { int i; for (i = 0; i < _glfw.monitorCount; i++) _glfwRestoreVideoModeNS(_glfw.monitors[i]); } @end // GLFWApplicationDelegate ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// void* _glfwLoadLocalVulkanLoaderNS(void) { CFBundleRef bundle = CFBundleGetMainBundle(); if (!bundle) return NULL; CFURLRef url = CFBundleCopyAuxiliaryExecutableURL(bundle, CFSTR("libvulkan.1.dylib")); if (!url) return NULL; char path[PATH_MAX]; void* handle = NULL; if (CFURLGetFileSystemRepresentation(url, true, (UInt8*) path, sizeof(path) - 1)) handle = _glfw_dlopen(path); CFRelease(url); return handle; } ////////////////////////////////////////////////////////////////////////// ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// int _glfwPlatformInit(void) { @autoreleasepool { _glfw.ns.helper = [[GLFWHelper alloc] init]; [NSThread detachNewThreadSelector:@selector(doNothing:) toTarget:_glfw.ns.helper withObject:nil]; if (NSApp) _glfw.ns.finishedLaunching = GLFW_TRUE; [NSApplication sharedApplication]; _glfw.ns.delegate = [[GLFWApplicationDelegate alloc] init]; if (_glfw.ns.delegate == nil) { _glfwInputError(GLFW_PLATFORM_ERROR, "Cocoa: Failed to create application delegate"); return GLFW_FALSE; } [NSApp setDelegate:_glfw.ns.delegate]; NSEvent* (^block)(NSEvent*) = ^ NSEvent* (NSEvent* event) { if ([event modifierFlags] & NSEventModifierFlagCommand) [[NSApp keyWindow] sendEvent:event]; return event; }; _glfw.ns.keyUpMonitor = [NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskKeyUp handler:block]; if (_glfw.hints.init.ns.chdir) changeToResourcesDirectory(); // Press and Hold prevents some keys from emitting repeated characters NSDictionary* defaults = @{@"ApplePressAndHoldEnabled":@NO}; [[NSUserDefaults standardUserDefaults] registerDefaults:defaults]; [[NSNotificationCenter defaultCenter] addObserver:_glfw.ns.helper selector:@selector(selectedKeyboardInputSourceChanged:) name:NSTextInputContextKeyboardSelectionDidChangeNotification object:nil]; createKeyTables(); _glfw.ns.eventSource = CGEventSourceCreate(kCGEventSourceStateHIDSystemState); if (!_glfw.ns.eventSource) return GLFW_FALSE; CGEventSourceSetLocalEventsSuppressionInterval(_glfw.ns.eventSource, 0.0); if (!initializeTIS()) return GLFW_FALSE; _glfwInitTimerNS(); _glfwInitJoysticksNS(); _glfwPollMonitorsNS(); return GLFW_TRUE; } // autoreleasepool } void _glfwPlatformTerminate(void) { @autoreleasepool { if (_glfw.ns.inputSource) { CFRelease(_glfw.ns.inputSource); _glfw.ns.inputSource = NULL; _glfw.ns.unicodeData = nil; } if (_glfw.ns.eventSource) { CFRelease(_glfw.ns.eventSource); _glfw.ns.eventSource = NULL; } if (_glfw.ns.delegate) { [NSApp setDelegate:nil]; [_glfw.ns.delegate release]; _glfw.ns.delegate = nil; } if (_glfw.ns.helper) { [[NSNotificationCenter defaultCenter] removeObserver:_glfw.ns.helper name:NSTextInputContextKeyboardSelectionDidChangeNotification object:nil]; [[NSNotificationCenter defaultCenter] removeObserver:_glfw.ns.helper]; [_glfw.ns.helper release]; _glfw.ns.helper = nil; } if (_glfw.ns.keyUpMonitor) [NSEvent removeMonitor:_glfw.ns.keyUpMonitor]; free(_glfw.ns.clipboardString); _glfwTerminateNSGL(); _glfwTerminateJoysticksNS(); } // autoreleasepool } const char* _glfwPlatformGetVersionString(void) { return _GLFW_VERSION_NUMBER " Cocoa NSGL EGL OSMesa" #if defined(_GLFW_BUILD_DLL) " dynamic" #endif ; } #endif #ifndef HEADER_GUARD_NSGL_CONTEXT_M #define HEADER_GUARD_NSGL_CONTEXT_M //======================================================================== // GLFW 3.3.7 macOS - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2009-2019 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== // It is fine to use C99 in this file because it will not be built with VS //======================================================================== #include #include static void makeContextCurrentNSGL(_GLFWwindow* window) { @autoreleasepool { if (window) [window->context.nsgl.object makeCurrentContext]; else [NSOpenGLContext clearCurrentContext]; _glfwPlatformSetTls(&_glfw.contextSlot, window); } // autoreleasepool } static void swapBuffersNSGL(_GLFWwindow* window) { @autoreleasepool { // HACK: Simulate vsync with usleep as NSGL swap interval does not apply to // windows with a non-visible occlusion state if (window->ns.occluded) { int interval = 0; [window->context.nsgl.object getValues:&interval forParameter:NSOpenGLContextParameterSwapInterval]; if (interval > 0) { const double framerate = 60.0; const uint64_t frequency = _glfwPlatformGetTimerFrequency(); const uint64_t value = _glfwPlatformGetTimerValue(); const double elapsed = value / (double) frequency; const double period = 1.0 / framerate; const double delay = period - fmod(elapsed, period); usleep(floorl(delay * 1e6)); } } [window->context.nsgl.object flushBuffer]; } // autoreleasepool } static void swapIntervalNSGL(int interval) { @autoreleasepool { _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot); if (window) { [window->context.nsgl.object setValues:&interval forParameter:NSOpenGLContextParameterSwapInterval]; } } // autoreleasepool } static int extensionSupportedNSGL(const char* extension) { // There are no NSGL extensions return GLFW_FALSE; } static GLFWglproc getProcAddressNSGL(const char* procname) { CFStringRef symbolName = CFStringCreateWithCString(kCFAllocatorDefault, procname, kCFStringEncodingASCII); GLFWglproc symbol = CFBundleGetFunctionPointerForName(_glfw.nsgl.framework, symbolName); CFRelease(symbolName); return symbol; } static void destroyContextNSGL(_GLFWwindow* window) { @autoreleasepool { [window->context.nsgl.pixelFormat release]; window->context.nsgl.pixelFormat = nil; [window->context.nsgl.object release]; window->context.nsgl.object = nil; } // autoreleasepool } ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// // Initialize OpenGL support // GLFWbool _glfwInitNSGL(void) { if (_glfw.nsgl.framework) return GLFW_TRUE; _glfw.nsgl.framework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl")); if (_glfw.nsgl.framework == NULL) { _glfwInputError(GLFW_API_UNAVAILABLE, "NSGL: Failed to locate OpenGL framework"); return GLFW_FALSE; } return GLFW_TRUE; } // Terminate OpenGL support // void _glfwTerminateNSGL(void) { } // Create the OpenGL context // GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig) { if (ctxconfig->client == GLFW_OPENGL_ES_API) { _glfwInputError(GLFW_API_UNAVAILABLE, "NSGL: OpenGL ES is not available on macOS"); return GLFW_FALSE; } if (ctxconfig->major > 2) { if (ctxconfig->major == 3 && ctxconfig->minor < 2) { _glfwInputError(GLFW_VERSION_UNAVAILABLE, "NSGL: The targeted version of macOS does not support OpenGL 3.0 or 3.1 but may support 3.2 and above"); return GLFW_FALSE; } if (!ctxconfig->forward || ctxconfig->profile != GLFW_OPENGL_CORE_PROFILE) { _glfwInputError(GLFW_VERSION_UNAVAILABLE, "NSGL: The targeted version of macOS only supports forward-compatible core profile contexts for OpenGL 3.2 and above"); return GLFW_FALSE; } } // Context robustness modes (GL_KHR_robustness) are not yet supported by // macOS but are not a hard constraint, so ignore and continue // Context release behaviors (GL_KHR_context_flush_control) are not yet // supported by macOS but are not a hard constraint, so ignore and continue // Debug contexts (GL_KHR_debug) are not yet supported by macOS but are not // a hard constraint, so ignore and continue // No-error contexts (GL_KHR_no_error) are not yet supported by macOS but // are not a hard constraint, so ignore and continue #define addAttrib(a) \ { \ assert((size_t) index < sizeof(attribs) / sizeof(attribs[0])); \ attribs[index++] = a; \ } #define setAttrib(a, v) { addAttrib(a); addAttrib(v); } NSOpenGLPixelFormatAttribute attribs[40]; int index = 0; addAttrib(NSOpenGLPFAAccelerated); addAttrib(NSOpenGLPFAClosestPolicy); if (ctxconfig->nsgl.offline) { addAttrib(NSOpenGLPFAAllowOfflineRenderers); // NOTE: This replaces the NSSupportsAutomaticGraphicsSwitching key in // Info.plist for unbundled applications // HACK: This assumes that NSOpenGLPixelFormat will remain // a straightforward wrapper of its CGL counterpart addAttrib(kCGLPFASupportsAutomaticGraphicsSwitching); } #if MAC_OS_X_VERSION_MAX_ALLOWED >= 101000 if (ctxconfig->major >= 4) { setAttrib(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion4_1Core); } else #endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/ if (ctxconfig->major >= 3) { setAttrib(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core); } if (ctxconfig->major <= 2) { if (fbconfig->auxBuffers != GLFW_DONT_CARE) setAttrib(NSOpenGLPFAAuxBuffers, fbconfig->auxBuffers); if (fbconfig->accumRedBits != GLFW_DONT_CARE && fbconfig->accumGreenBits != GLFW_DONT_CARE && fbconfig->accumBlueBits != GLFW_DONT_CARE && fbconfig->accumAlphaBits != GLFW_DONT_CARE) { const int accumBits = fbconfig->accumRedBits + fbconfig->accumGreenBits + fbconfig->accumBlueBits + fbconfig->accumAlphaBits; setAttrib(NSOpenGLPFAAccumSize, accumBits); } } if (fbconfig->redBits != GLFW_DONT_CARE && fbconfig->greenBits != GLFW_DONT_CARE && fbconfig->blueBits != GLFW_DONT_CARE) { int colorBits = fbconfig->redBits + fbconfig->greenBits + fbconfig->blueBits; // macOS needs non-zero color size, so set reasonable values if (colorBits == 0) colorBits = 24; else if (colorBits < 15) colorBits = 15; setAttrib(NSOpenGLPFAColorSize, colorBits); } if (fbconfig->alphaBits != GLFW_DONT_CARE) setAttrib(NSOpenGLPFAAlphaSize, fbconfig->alphaBits); if (fbconfig->depthBits != GLFW_DONT_CARE) setAttrib(NSOpenGLPFADepthSize, fbconfig->depthBits); if (fbconfig->stencilBits != GLFW_DONT_CARE) setAttrib(NSOpenGLPFAStencilSize, fbconfig->stencilBits); if (fbconfig->stereo) { #if MAC_OS_X_VERSION_MAX_ALLOWED >= 101200 _glfwInputError(GLFW_FORMAT_UNAVAILABLE, "NSGL: Stereo rendering is deprecated"); return GLFW_FALSE; #else addAttrib(NSOpenGLPFAStereo); #endif } if (fbconfig->doublebuffer) addAttrib(NSOpenGLPFADoubleBuffer); if (fbconfig->samples != GLFW_DONT_CARE) { if (fbconfig->samples == 0) { setAttrib(NSOpenGLPFASampleBuffers, 0); } else { setAttrib(NSOpenGLPFASampleBuffers, 1); setAttrib(NSOpenGLPFASamples, fbconfig->samples); } } // NOTE: All NSOpenGLPixelFormats on the relevant cards support sRGB // framebuffer, so there's no need (and no way) to request it addAttrib(0); #undef addAttrib #undef setAttrib window->context.nsgl.pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs]; if (window->context.nsgl.pixelFormat == nil) { _glfwInputError(GLFW_FORMAT_UNAVAILABLE, "NSGL: Failed to find a suitable pixel format"); return GLFW_FALSE; } NSOpenGLContext* share = nil; if (ctxconfig->share) share = ctxconfig->share->context.nsgl.object; window->context.nsgl.object = [[NSOpenGLContext alloc] initWithFormat:window->context.nsgl.pixelFormat shareContext:share]; if (window->context.nsgl.object == nil) { _glfwInputError(GLFW_VERSION_UNAVAILABLE, "NSGL: Failed to create OpenGL context"); return GLFW_FALSE; } if (fbconfig->transparent) { GLint opaque = 0; [window->context.nsgl.object setValues:&opaque forParameter:NSOpenGLContextParameterSurfaceOpacity]; } [window->ns.view setWantsBestResolutionOpenGLSurface:window->ns.retina]; [window->context.nsgl.object setView:window->ns.view]; window->context.makeCurrent = makeContextCurrentNSGL; window->context.swapBuffers = swapBuffersNSGL; window->context.swapInterval = swapIntervalNSGL; window->context.extensionSupported = extensionSupportedNSGL; window->context.getProcAddress = getProcAddressNSGL; window->context.destroy = destroyContextNSGL; return GLFW_TRUE; } ////////////////////////////////////////////////////////////////////////// ////// GLFW native API ////// ////////////////////////////////////////////////////////////////////////// GLFWAPI id glfwGetNSGLContext(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(nil); if (window->context.source != GLFW_NATIVE_CONTEXT_API) { _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); return nil; } return window->context.nsgl.object; } #endif #ifndef HEADER_GUARD_COCOA_JOYSTICK_M #define HEADER_GUARD_COCOA_JOYSTICK_M //======================================================================== // GLFW 3.3.7 Cocoa - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2009-2019 Camilla Löwy // Copyright (c) 2012 Torsten Walluhn // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== // It is fine to use C99 in this file because it will not be built with VS //======================================================================== #include #include #include #include #include #include #include // Joystick element information // typedef struct _GLFWjoyelementNS { IOHIDElementRef native; uint32_t usage; int index; long minimum; long maximum; } _GLFWjoyelementNS; // Returns the value of the specified element of the specified joystick // static long getElementValue(_GLFWjoystick* js, _GLFWjoyelementNS* element) { IOHIDValueRef valueRef; long value = 0; if (js->ns.device) { if (IOHIDDeviceGetValue(js->ns.device, element->native, &valueRef) == kIOReturnSuccess) { value = IOHIDValueGetIntegerValue(valueRef); } } return value; } // Comparison function for matching the SDL element order // static CFComparisonResult compareElements(const void* fp, const void* sp, void* user) { const _GLFWjoyelementNS* fe = fp; const _GLFWjoyelementNS* se = sp; if (fe->usage < se->usage) return kCFCompareLessThan; if (fe->usage > se->usage) return kCFCompareGreaterThan; if (fe->index < se->index) return kCFCompareLessThan; if (fe->index > se->index) return kCFCompareGreaterThan; return kCFCompareEqualTo; } // Removes the specified joystick // static void closeJoystick(_GLFWjoystick* js) { int i; if (!js->present) return; for (i = 0; i < CFArrayGetCount(js->ns.axes); i++) free((void*) CFArrayGetValueAtIndex(js->ns.axes, i)); CFRelease(js->ns.axes); for (i = 0; i < CFArrayGetCount(js->ns.buttons); i++) free((void*) CFArrayGetValueAtIndex(js->ns.buttons, i)); CFRelease(js->ns.buttons); for (i = 0; i < CFArrayGetCount(js->ns.hats); i++) free((void*) CFArrayGetValueAtIndex(js->ns.hats, i)); CFRelease(js->ns.hats); _glfwFreeJoystick(js); _glfwInputJoystick(js, GLFW_DISCONNECTED); } // Callback for user-initiated joystick addition // static void matchCallback(void* context, IOReturn result, void* sender, IOHIDDeviceRef device) { int jid; char name[256]; char guid[33]; CFIndex i; CFTypeRef property; uint32_t vendor = 0, product = 0, version = 0; _GLFWjoystick* js; CFMutableArrayRef axes, buttons, hats; for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) { if (_glfw.joysticks[jid].ns.device == device) return; } axes = CFArrayCreateMutable(NULL, 0, NULL); buttons = CFArrayCreateMutable(NULL, 0, NULL); hats = CFArrayCreateMutable(NULL, 0, NULL); property = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey)); if (property) { CFStringGetCString(property, name, sizeof(name), kCFStringEncodingUTF8); } else strncpy(name, "Unknown", sizeof(name)); property = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDVendorIDKey)); if (property) CFNumberGetValue(property, kCFNumberSInt32Type, &vendor); property = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductIDKey)); if (property) CFNumberGetValue(property, kCFNumberSInt32Type, &product); property = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDVersionNumberKey)); if (property) CFNumberGetValue(property, kCFNumberSInt32Type, &version); // Generate a joystick GUID that matches the SDL 2.0.5+ one if (vendor && product) { sprintf(guid, "03000000%02x%02x0000%02x%02x0000%02x%02x0000", (uint8_t) vendor, (uint8_t) (vendor >> 8), (uint8_t) product, (uint8_t) (product >> 8), (uint8_t) version, (uint8_t) (version >> 8)); } else { sprintf(guid, "05000000%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x00", name[0], name[1], name[2], name[3], name[4], name[5], name[6], name[7], name[8], name[9], name[10]); } CFArrayRef elements = IOHIDDeviceCopyMatchingElements(device, NULL, kIOHIDOptionsTypeNone); for (i = 0; i < CFArrayGetCount(elements); i++) { IOHIDElementRef native = (IOHIDElementRef) CFArrayGetValueAtIndex(elements, i); if (CFGetTypeID(native) != IOHIDElementGetTypeID()) continue; const IOHIDElementType type = IOHIDElementGetType(native); if ((type != kIOHIDElementTypeInput_Axis) && (type != kIOHIDElementTypeInput_Button) && (type != kIOHIDElementTypeInput_Misc)) { continue; } CFMutableArrayRef target = NULL; const uint32_t usage = IOHIDElementGetUsage(native); const uint32_t page = IOHIDElementGetUsagePage(native); if (page == kHIDPage_GenericDesktop) { switch (usage) { case kHIDUsage_GD_X: case kHIDUsage_GD_Y: case kHIDUsage_GD_Z: case kHIDUsage_GD_Rx: case kHIDUsage_GD_Ry: case kHIDUsage_GD_Rz: case kHIDUsage_GD_Slider: case kHIDUsage_GD_Dial: case kHIDUsage_GD_Wheel: target = axes; break; case kHIDUsage_GD_Hatswitch: target = hats; break; case kHIDUsage_GD_DPadUp: case kHIDUsage_GD_DPadRight: case kHIDUsage_GD_DPadDown: case kHIDUsage_GD_DPadLeft: case kHIDUsage_GD_SystemMainMenu: case kHIDUsage_GD_Select: case kHIDUsage_GD_Start: target = buttons; break; } } else if (page == kHIDPage_Simulation) { switch (usage) { case kHIDUsage_Sim_Accelerator: case kHIDUsage_Sim_Brake: case kHIDUsage_Sim_Throttle: case kHIDUsage_Sim_Rudder: case kHIDUsage_Sim_Steering: target = axes; break; } } else if (page == kHIDPage_Button || page == kHIDPage_Consumer) target = buttons; if (target) { _GLFWjoyelementNS* element = calloc(1, sizeof(_GLFWjoyelementNS)); element->native = native; element->usage = usage; element->index = (int) CFArrayGetCount(target); element->minimum = IOHIDElementGetLogicalMin(native); element->maximum = IOHIDElementGetLogicalMax(native); CFArrayAppendValue(target, element); } } CFRelease(elements); CFArraySortValues(axes, CFRangeMake(0, CFArrayGetCount(axes)), compareElements, NULL); CFArraySortValues(buttons, CFRangeMake(0, CFArrayGetCount(buttons)), compareElements, NULL); CFArraySortValues(hats, CFRangeMake(0, CFArrayGetCount(hats)), compareElements, NULL); js = _glfwAllocJoystick(name, guid, (int) CFArrayGetCount(axes), (int) CFArrayGetCount(buttons), (int) CFArrayGetCount(hats)); js->ns.device = device; js->ns.axes = axes; js->ns.buttons = buttons; js->ns.hats = hats; _glfwInputJoystick(js, GLFW_CONNECTED); } // Callback for user-initiated joystick removal // static void removeCallback(void* context, IOReturn result, void* sender, IOHIDDeviceRef device) { int jid; for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) { if (_glfw.joysticks[jid].ns.device == device) { closeJoystick(_glfw.joysticks + jid); break; } } } ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// // Initialize joystick interface // void _glfwInitJoysticksNS(void) { CFMutableArrayRef matching; const long usages[] = { kHIDUsage_GD_Joystick, kHIDUsage_GD_GamePad, kHIDUsage_GD_MultiAxisController }; _glfw.ns.hidManager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone); matching = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); if (!matching) { _glfwInputError(GLFW_PLATFORM_ERROR, "Cocoa: Failed to create array"); return; } for (size_t i = 0; i < sizeof(usages) / sizeof(long); i++) { const long page = kHIDPage_GenericDesktop; CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); if (!dict) continue; CFNumberRef pageRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberLongType, &page); CFNumberRef usageRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberLongType, &usages[i]); if (pageRef && usageRef) { CFDictionarySetValue(dict, CFSTR(kIOHIDDeviceUsagePageKey), pageRef); CFDictionarySetValue(dict, CFSTR(kIOHIDDeviceUsageKey), usageRef); CFArrayAppendValue(matching, dict); } if (pageRef) CFRelease(pageRef); if (usageRef) CFRelease(usageRef); CFRelease(dict); } IOHIDManagerSetDeviceMatchingMultiple(_glfw.ns.hidManager, matching); CFRelease(matching); IOHIDManagerRegisterDeviceMatchingCallback(_glfw.ns.hidManager, &matchCallback, NULL); IOHIDManagerRegisterDeviceRemovalCallback(_glfw.ns.hidManager, &removeCallback, NULL); IOHIDManagerScheduleWithRunLoop(_glfw.ns.hidManager, CFRunLoopGetMain(), kCFRunLoopDefaultMode); IOHIDManagerOpen(_glfw.ns.hidManager, kIOHIDOptionsTypeNone); // Execute the run loop once in order to register any initially-attached // joysticks CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, false); } // Close all opened joystick handles // void _glfwTerminateJoysticksNS(void) { int jid; for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) closeJoystick(_glfw.joysticks + jid); CFRelease(_glfw.ns.hidManager); _glfw.ns.hidManager = NULL; } ////////////////////////////////////////////////////////////////////////// ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode) { if (mode & _GLFW_POLL_AXES) { CFIndex i; for (i = 0; i < CFArrayGetCount(js->ns.axes); i++) { _GLFWjoyelementNS* axis = (_GLFWjoyelementNS*) CFArrayGetValueAtIndex(js->ns.axes, i); const long raw = getElementValue(js, axis); // Perform auto calibration if (raw < axis->minimum) axis->minimum = raw; if (raw > axis->maximum) axis->maximum = raw; const long size = axis->maximum - axis->minimum; if (size == 0) _glfwInputJoystickAxis(js, (int) i, 0.f); else { const float value = (2.f * (raw - axis->minimum) / size) - 1.f; _glfwInputJoystickAxis(js, (int) i, value); } } } if (mode & _GLFW_POLL_BUTTONS) { CFIndex i; for (i = 0; i < CFArrayGetCount(js->ns.buttons); i++) { _GLFWjoyelementNS* button = (_GLFWjoyelementNS*) CFArrayGetValueAtIndex(js->ns.buttons, i); const char value = getElementValue(js, button) - button->minimum; const int state = (value > 0) ? GLFW_PRESS : GLFW_RELEASE; _glfwInputJoystickButton(js, (int) i, state); } for (i = 0; i < CFArrayGetCount(js->ns.hats); i++) { const int states[9] = { GLFW_HAT_UP, GLFW_HAT_RIGHT_UP, GLFW_HAT_RIGHT, GLFW_HAT_RIGHT_DOWN, GLFW_HAT_DOWN, GLFW_HAT_LEFT_DOWN, GLFW_HAT_LEFT, GLFW_HAT_LEFT_UP, GLFW_HAT_CENTERED }; _GLFWjoyelementNS* hat = (_GLFWjoyelementNS*) CFArrayGetValueAtIndex(js->ns.hats, i); long state = getElementValue(js, hat) - hat->minimum; if (state < 0 || state > 8) state = 8; _glfwInputJoystickHat(js, (int) i, states[state]); } } return js->present; } void _glfwPlatformUpdateGamepadGUID(char* guid) { if ((strncmp(guid + 4, "000000000000", 12) == 0) && (strncmp(guid + 20, "000000000000", 12) == 0)) { char original[33]; strncpy(original, guid, sizeof(original) - 1); sprintf(guid, "03000000%.4s0000%.4s000000000000", original, original + 16); } } #endif #ifndef HEADER_GUARD_COCOA_MONITOR_M #define HEADER_GUARD_COCOA_MONITOR_M //======================================================================== // GLFW 3.3.7 macOS - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2019 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== // It is fine to use C99 in this file because it will not be built with VS //======================================================================== #include #include #include #include #include // Get the name of the specified display, or NULL // 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(MACH_PORT_NULL, IOServiceMatching("IODisplayConnect"), &it) != 0) { // This may happen if a desktop Mac is running headless return _glfw_strdup("Display"); } while ((service = IOIteratorNext(it)) != 0) { info = IODisplayCreateInfoDictionary(service, kIODisplayOnlyPreferredName); CFNumberRef vendorIDRef = CFDictionaryGetValue(info, CFSTR(kDisplayVendorID)); CFNumberRef productIDRef = CFDictionaryGetValue(info, CFSTR(kDisplayProductID)); if (!vendorIDRef || !productIDRef) { CFRelease(info); continue; } unsigned int vendorID, productID; CFNumberGetValue(vendorIDRef, kCFNumberIntType, &vendorID); CFNumberGetValue(productIDRef, kCFNumberIntType, &productID); if (CGDisplayVendorNumber(displayID) == vendorID && CGDisplayModelNumber(displayID) == productID) { // Info dictionary is used and freed below break; } CFRelease(info); } IOObjectRelease(it); if (!service) { _glfwInputError(GLFW_PLATFORM_ERROR, "Cocoa: Failed to find service port for display"); return _glfw_strdup("Display"); } CFDictionaryRef names = CFDictionaryGetValue(info, CFSTR(kDisplayProductName)); CFStringRef nameRef; if (!names || !CFDictionaryGetValueIfPresent(names, CFSTR("en_US"), (const void**) &nameRef)) { // This may happen if a desktop Mac is running headless CFRelease(info); return _glfw_strdup("Display"); } const CFIndex size = CFStringGetMaximumSizeForEncoding(CFStringGetLength(nameRef), kCFStringEncodingUTF8); char* name = calloc(size + 1, 1); CFStringGetCString(nameRef, name, size, kCFStringEncodingUTF8); CFRelease(info); return name; } // Check whether the display mode should be included in enumeration // static GLFWbool modeIsGood(CGDisplayModeRef mode) { uint32_t flags = CGDisplayModeGetIOFlags(mode); if (!(flags & kDisplayModeValidFlag) || !(flags & kDisplayModeSafeFlag)) return GLFW_FALSE; if (flags & kDisplayModeInterlacedFlag) return GLFW_FALSE; if (flags & kDisplayModeStretchedFlag) return GLFW_FALSE; #if MAC_OS_X_VERSION_MAX_ALLOWED <= 101100 CFStringRef format = CGDisplayModeCopyPixelEncoding(mode); if (CFStringCompare(format, CFSTR(IO16BitDirectPixels), 0) && CFStringCompare(format, CFSTR(IO32BitDirectPixels), 0)) { CFRelease(format); return GLFW_FALSE; } CFRelease(format); #endif /* MAC_OS_X_VERSION_MAX_ALLOWED */ return GLFW_TRUE; } // Convert Core Graphics display mode to GLFW video mode // static GLFWvidmode vidmodeFromCGDisplayMode(CGDisplayModeRef mode, double fallbackRefreshRate) { GLFWvidmode result; result.width = (int) CGDisplayModeGetWidth(mode); result.height = (int) CGDisplayModeGetHeight(mode); result.refreshRate = (int) round(CGDisplayModeGetRefreshRate(mode)); if (result.refreshRate == 0) result.refreshRate = (int) round(fallbackRefreshRate); #if MAC_OS_X_VERSION_MAX_ALLOWED <= 101100 CFStringRef format = CGDisplayModeCopyPixelEncoding(mode); if (CFStringCompare(format, CFSTR(IO16BitDirectPixels), 0) == 0) { result.redBits = 5; result.greenBits = 5; result.blueBits = 5; } else #endif /* MAC_OS_X_VERSION_MAX_ALLOWED */ { result.redBits = 8; result.greenBits = 8; result.blueBits = 8; } #if MAC_OS_X_VERSION_MAX_ALLOWED <= 101100 CFRelease(format); #endif /* MAC_OS_X_VERSION_MAX_ALLOWED */ return result; } // Starts reservation for display fading // static CGDisplayFadeReservationToken beginFadeReservation(void) { CGDisplayFadeReservationToken token = kCGDisplayFadeReservationInvalidToken; if (CGAcquireDisplayFadeReservation(5, &token) == kCGErrorSuccess) { CGDisplayFade(token, 0.3, kCGDisplayBlendNormal, kCGDisplayBlendSolidColor, 0.0, 0.0, 0.0, TRUE); } return token; } // Ends reservation for display fading // static void endFadeReservation(CGDisplayFadeReservationToken token) { if (token != kCGDisplayFadeReservationInvalidToken) { CGDisplayFade(token, 0.5, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0.0, 0.0, 0.0, FALSE); CGReleaseDisplayFadeReservation(token); } } // Returns the display refresh rate queried from the I/O registry // static double getFallbackRefreshRate(CGDirectDisplayID displayID) { double refreshRate = 60.0; io_iterator_t it; io_service_t service; if (IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceMatching("IOFramebuffer"), &it) != 0) { return refreshRate; } while ((service = IOIteratorNext(it)) != 0) { const CFNumberRef indexRef = IORegistryEntryCreateCFProperty(service, CFSTR("IOFramebufferOpenGLIndex"), kCFAllocatorDefault, kNilOptions); if (!indexRef) continue; uint32_t index = 0; CFNumberGetValue(indexRef, kCFNumberIntType, &index); CFRelease(indexRef); if (CGOpenGLDisplayMaskToDisplayID(1 << index) != displayID) continue; const CFNumberRef clockRef = IORegistryEntryCreateCFProperty(service, CFSTR("IOFBCurrentPixelClock"), kCFAllocatorDefault, kNilOptions); const CFNumberRef countRef = IORegistryEntryCreateCFProperty(service, CFSTR("IOFBCurrentPixelCount"), kCFAllocatorDefault, kNilOptions); uint32_t clock = 0, count = 0; 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; break; } IOObjectRelease(it); return refreshRate; } ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// // Poll for changes in the set of connected monitors // void _glfwPollMonitorsNS(void) { uint32_t displayCount; CGGetOnlineDisplayList(0, NULL, &displayCount); CGDirectDisplayID* displays = calloc(displayCount, sizeof(CGDirectDisplayID)); CGGetOnlineDisplayList(displayCount, displays, &displayCount); for (int i = 0; i < _glfw.monitorCount; i++) _glfw.monitors[i]->ns.screen = nil; _GLFWmonitor** disconnected = NULL; uint32_t disconnectedCount = _glfw.monitorCount; if (disconnectedCount) { disconnected = calloc(_glfw.monitorCount, sizeof(_GLFWmonitor*)); memcpy(disconnected, _glfw.monitors, _glfw.monitorCount * sizeof(_GLFWmonitor*)); } for (uint32_t i = 0; i < displayCount; i++) { 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 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 = getMonitorName(displays[i], screen); if (!name) continue; _GLFWmonitor* monitor = _glfwAllocMonitor(name, size.width, size.height); monitor->ns.displayID = displays[i]; monitor->ns.unitNumber = unitNumber; monitor->ns.screen = screen; free(name); CGDisplayModeRef mode = CGDisplayCopyDisplayMode(displays[i]); if (CGDisplayModeGetRefreshRate(mode) == 0.0) monitor->ns.fallbackRefreshRate = getFallbackRefreshRate(displays[i]); CGDisplayModeRelease(mode); _glfwInputMonitor(monitor, GLFW_CONNECTED, _GLFW_INSERT_LAST); } for (uint32_t i = 0; i < disconnectedCount; i++) { if (disconnected[i]) _glfwInputMonitor(disconnected[i], GLFW_DISCONNECTED, 0); } free(disconnected); free(displays); } // Change the current video mode // void _glfwSetVideoModeNS(_GLFWmonitor* monitor, const GLFWvidmode* desired) { GLFWvidmode current; _glfwPlatformGetVideoMode(monitor, ¤t); const GLFWvidmode* best = _glfwChooseVideoMode(monitor, desired); if (_glfwCompareVideoModes(¤t, best) == 0) return; CFArrayRef modes = CGDisplayCopyAllDisplayModes(monitor->ns.displayID, NULL); const CFIndex count = CFArrayGetCount(modes); CGDisplayModeRef native = NULL; for (CFIndex i = 0; i < count; i++) { CGDisplayModeRef dm = (CGDisplayModeRef) CFArrayGetValueAtIndex(modes, i); if (!modeIsGood(dm)) continue; const GLFWvidmode mode = vidmodeFromCGDisplayMode(dm, monitor->ns.fallbackRefreshRate); if (_glfwCompareVideoModes(best, &mode) == 0) { native = dm; break; } } if (native) { if (monitor->ns.previousMode == NULL) monitor->ns.previousMode = CGDisplayCopyDisplayMode(monitor->ns.displayID); CGDisplayFadeReservationToken token = beginFadeReservation(); CGDisplaySetDisplayMode(monitor->ns.displayID, native, NULL); endFadeReservation(token); } CFRelease(modes); } // Restore the previously saved (original) video mode // void _glfwRestoreVideoModeNS(_GLFWmonitor* monitor) { if (monitor->ns.previousMode) { CGDisplayFadeReservationToken token = beginFadeReservation(); CGDisplaySetDisplayMode(monitor->ns.displayID, monitor->ns.previousMode, NULL); endFadeReservation(token); CGDisplayModeRelease(monitor->ns.previousMode); monitor->ns.previousMode = NULL; } } ////////////////////////////////////////////////////////////////////////// ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor) { } void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) { @autoreleasepool { const CGRect bounds = CGDisplayBounds(monitor->ns.displayID); if (xpos) *xpos = (int) bounds.origin.x; if (ypos) *ypos = (int) bounds.origin.y; } // autoreleasepool } void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor, float* xscale, float* yscale) { @autoreleasepool { 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]; if (xscale) *xscale = (float) (pixels.size.width / points.size.width); if (yscale) *yscale = (float) (pixels.size.height / points.size.height); } // autoreleasepool } void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor, int* xpos, int* ypos, int* width, int* height) { @autoreleasepool { if (!monitor->ns.screen) { _glfwInputError(GLFW_PLATFORM_ERROR, "Cocoa: Cannot query workarea without screen"); } const NSRect frameRect = [monitor->ns.screen visibleFrame]; if (xpos) *xpos = frameRect.origin.x; if (ypos) *ypos = _glfwTransformYNS(frameRect.origin.y + frameRect.size.height - 1); if (width) *width = frameRect.size.width; if (height) *height = frameRect.size.height; } // autoreleasepool } GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count) { @autoreleasepool { *count = 0; CFArrayRef modes = CGDisplayCopyAllDisplayModes(monitor->ns.displayID, NULL); const CFIndex found = CFArrayGetCount(modes); GLFWvidmode* result = calloc(found, sizeof(GLFWvidmode)); for (CFIndex i = 0; i < found; i++) { CGDisplayModeRef dm = (CGDisplayModeRef) CFArrayGetValueAtIndex(modes, i); if (!modeIsGood(dm)) continue; const GLFWvidmode mode = vidmodeFromCGDisplayMode(dm, monitor->ns.fallbackRefreshRate); CFIndex j; for (j = 0; j < *count; j++) { if (_glfwCompareVideoModes(result + j, &mode) == 0) break; } // Skip duplicate modes if (j < *count) continue; (*count)++; result[*count - 1] = mode; } CFRelease(modes); return result; } // autoreleasepool } void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode *mode) { @autoreleasepool { CGDisplayModeRef native = CGDisplayCopyDisplayMode(monitor->ns.displayID); *mode = vidmodeFromCGDisplayMode(native, monitor->ns.fallbackRefreshRate); CGDisplayModeRelease(native); } // autoreleasepool } GLFWbool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) { @autoreleasepool { uint32_t size = CGDisplayGammaTableCapacity(monitor->ns.displayID); CGGammaValue* values = calloc(size * 3, sizeof(CGGammaValue)); CGGetDisplayTransferByTable(monitor->ns.displayID, size, values, values + size, values + size * 2, &size); _glfwAllocGammaArrays(ramp, size); for (uint32_t i = 0; i < size; i++) { ramp->red[i] = (unsigned short) (values[i] * 65535); ramp->green[i] = (unsigned short) (values[i + size] * 65535); ramp->blue[i] = (unsigned short) (values[i + size * 2] * 65535); } free(values); return GLFW_TRUE; } // autoreleasepool } void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) { @autoreleasepool { CGGammaValue* values = calloc(ramp->size * 3, sizeof(CGGammaValue)); for (unsigned int i = 0; i < ramp->size; i++) { values[i] = ramp->red[i] / 65535.f; values[i + ramp->size] = ramp->green[i] / 65535.f; values[i + ramp->size * 2] = ramp->blue[i] / 65535.f; } CGSetDisplayTransferByTable(monitor->ns.displayID, ramp->size, values, values + ramp->size, values + ramp->size * 2); free(values); } // autoreleasepool } ////////////////////////////////////////////////////////////////////////// ////// GLFW native API ////// ////////////////////////////////////////////////////////////////////////// GLFWAPI CGDirectDisplayID glfwGetCocoaMonitor(GLFWmonitor* handle) { _GLFWmonitor* monitor = (_GLFWmonitor*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(kCGNullDirectDisplay); return monitor->ns.displayID; } #endif #ifndef HEADER_GUARD_COCOA_WINDOW_M #define HEADER_GUARD_COCOA_WINDOW_M //======================================================================== // GLFW 3.3.7 macOS - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2009-2019 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== // It is fine to use C99 in this file because it will not be built with VS //======================================================================== #include #include // 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; } // Returns whether the cursor is in the content area of the specified window // static GLFWbool cursorInContentArea(_GLFWwindow* window) { const NSPoint pos = [window->ns.object mouseLocationOutsideOfEventStream]; return [window->ns.view mouse:pos inRect:[window->ns.view frame]]; } // Hides the cursor if not already hidden // static void hideCursor(_GLFWwindow* window) { if (!_glfw.ns.cursorHidden) { [NSCursor hide]; _glfw.ns.cursorHidden = GLFW_TRUE; } } // Shows the cursor if not already shown // static void showCursor(_GLFWwindow* window) { if (_glfw.ns.cursorHidden) { [NSCursor unhide]; _glfw.ns.cursorHidden = GLFW_FALSE; } } // Updates the cursor image according to its cursor mode // static void updateCursorImage(_GLFWwindow* window) { if (window->cursorMode == GLFW_CURSOR_NORMAL) { showCursor(window); if (window->cursor) [(NSCursor*) window->cursor->ns.object set]; else [[NSCursor arrowCursor] set]; } else hideCursor(window); } // Apply chosen cursor mode to a focused window // static void updateCursorMode(_GLFWwindow* window) { if (window->cursorMode == GLFW_CURSOR_DISABLED) { _glfw.ns.disabledCursorWindow = window; _glfwPlatformGetCursorPos(window, &_glfw.ns.restoreCursorPosX, &_glfw.ns.restoreCursorPosY); _glfwCenterCursorInContentArea(window); CGAssociateMouseAndMouseCursorPosition(false); } else if (_glfw.ns.disabledCursorWindow == window) { _glfw.ns.disabledCursorWindow = NULL; _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)) updateCursorImage(window); } // Make the specified window and its video mode active on its monitor // static void acquireMonitor(_GLFWwindow* window) { _glfwSetVideoModeNS(window->monitor, &window->videoMode); const CGRect bounds = CGDisplayBounds(window->monitor->ns.displayID); const NSRect frame = NSMakeRect(bounds.origin.x, _glfwTransformYNS(bounds.origin.y + bounds.size.height - 1), bounds.size.width, bounds.size.height); [window->ns.object setFrame:frame display:YES]; _glfwInputMonitorWindow(window->monitor, window); } // Remove the window and restore the original video mode // static void releaseMonitor(_GLFWwindow* window) { if (window->monitor->window != window) return; _glfwInputMonitorWindow(window->monitor, NULL); _glfwRestoreVideoModeNS(window->monitor); } // Translates macOS key modifiers into GLFW ones // static int translateFlags(NSUInteger flags) { int mods = 0; if (flags & NSEventModifierFlagShift) mods |= GLFW_MOD_SHIFT; if (flags & NSEventModifierFlagControl) mods |= GLFW_MOD_CONTROL; if (flags & NSEventModifierFlagOption) mods |= GLFW_MOD_ALT; if (flags & NSEventModifierFlagCommand) mods |= GLFW_MOD_SUPER; if (flags & NSEventModifierFlagCapsLock) mods |= GLFW_MOD_CAPS_LOCK; return mods; } // Translates a macOS keycode to a GLFW keycode // static int translateKey(unsigned int key) { if (key >= sizeof(_glfw.ns.keycodes) / sizeof(_glfw.ns.keycodes[0])) return GLFW_KEY_UNKNOWN; return _glfw.ns.keycodes[key]; } // Translate a GLFW keycode to a Cocoa modifier flag // static NSUInteger translateKeyToModifierFlag(int key) { switch (key) { case GLFW_KEY_LEFT_SHIFT: case GLFW_KEY_RIGHT_SHIFT: return NSEventModifierFlagShift; case GLFW_KEY_LEFT_CONTROL: case GLFW_KEY_RIGHT_CONTROL: return NSEventModifierFlagControl; case GLFW_KEY_LEFT_ALT: case GLFW_KEY_RIGHT_ALT: return NSEventModifierFlagOption; case GLFW_KEY_LEFT_SUPER: case GLFW_KEY_RIGHT_SUPER: return NSEventModifierFlagCommand; case GLFW_KEY_CAPS_LOCK: return NSEventModifierFlagCapsLock; } return 0; } // Defines a constant for empty ranges in NSTextInputClient // static const NSRange kEmptyRange = { NSNotFound, 0 }; //------------------------------------------------------------------------ // Delegate for window related notifications //------------------------------------------------------------------------ @interface GLFWWindowDelegate : NSObject { _GLFWwindow* window; } - (instancetype)initWithGlfwWindow:(_GLFWwindow *)initWindow; @end @implementation GLFWWindowDelegate - (instancetype)initWithGlfwWindow:(_GLFWwindow *)initWindow { self = [super init]; if (self != nil) window = initWindow; return self; } - (BOOL)windowShouldClose:(id)sender { _glfwInputWindowCloseRequest(window); return NO; } - (void)windowDidResize:(NSNotification *)notification { if (window->context.source == GLFW_NATIVE_CONTEXT_API) [window->context.nsgl.object update]; if (_glfw.ns.disabledCursorWindow == window) _glfwCenterCursorInContentArea(window); const int maximized = [window->ns.object isZoomed]; if (window->ns.maximized != maximized) { window->ns.maximized = maximized; _glfwInputWindowMaximize(window, maximized); } 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); } if (contentRect.size.width != window->ns.width || contentRect.size.height != window->ns.height) { window->ns.width = contentRect.size.width; window->ns.height = contentRect.size.height; _glfwInputWindowSize(window, contentRect.size.width, contentRect.size.height); } } - (void)windowDidMove:(NSNotification *)notification { if (window->context.source == GLFW_NATIVE_CONTEXT_API) [window->context.nsgl.object update]; if (_glfw.ns.disabledCursorWindow == window) _glfwCenterCursorInContentArea(window); int x, y; _glfwPlatformGetWindowPos(window, &x, &y); _glfwInputWindowPos(window, x, y); } - (void)windowDidMiniaturize:(NSNotification *)notification { if (window->monitor) releaseMonitor(window); _glfwInputWindowIconify(window, GLFW_TRUE); } - (void)windowDidDeminiaturize:(NSNotification *)notification { if (window->monitor) acquireMonitor(window); _glfwInputWindowIconify(window, GLFW_FALSE); } - (void)windowDidBecomeKey:(NSNotification *)notification { if (_glfw.ns.disabledCursorWindow == window) _glfwCenterCursorInContentArea(window); _glfwInputWindowFocus(window, GLFW_TRUE); updateCursorMode(window); } - (void)windowDidResignKey:(NSNotification *)notification { if (window->monitor && window->autoIconify) _glfwPlatformIconifyWindow(window); _glfwInputWindowFocus(window, GLFW_FALSE); } - (void)windowDidChangeOcclusionState:(NSNotification* )notification { if ([window->ns.object occlusionState] & NSWindowOcclusionStateVisible) window->ns.occluded = GLFW_FALSE; else window->ns.occluded = GLFW_TRUE; } @end //------------------------------------------------------------------------ // Content view class for the GLFW window //------------------------------------------------------------------------ @interface GLFWContentView : NSView { _GLFWwindow* window; NSTrackingArea* trackingArea; NSMutableAttributedString* markedText; } - (instancetype)initWithGlfwWindow:(_GLFWwindow *)initWindow; @end @implementation GLFWContentView - (instancetype)initWithGlfwWindow:(_GLFWwindow *)initWindow { self = [super init]; if (self != nil) { window = initWindow; trackingArea = nil; markedText = [[NSMutableAttributedString alloc] init]; [self updateTrackingAreas]; [self registerForDraggedTypes:@[NSPasteboardTypeURL]]; } return self; } - (void)dealloc { [trackingArea release]; [markedText release]; [super dealloc]; } - (BOOL)isOpaque { return [window->ns.object isOpaque]; } - (BOOL)canBecomeKeyView { return YES; } - (BOOL)acceptsFirstResponder { return YES; } - (BOOL)wantsUpdateLayer { return YES; } - (void)updateLayer { if (window->context.source == GLFW_NATIVE_CONTEXT_API) [window->context.nsgl.object update]; _glfwInputWindowDamage(window); } - (void)cursorUpdate:(NSEvent *)event { updateCursorImage(window); } - (BOOL)acceptsFirstMouse:(NSEvent *)event { return YES; } - (void)mouseDown:(NSEvent *)event { _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_LEFT, GLFW_PRESS, translateFlags([event modifierFlags])); } - (void)mouseDragged:(NSEvent *)event { [self mouseMoved:event]; } - (void)mouseUp:(NSEvent *)event { _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_LEFT, GLFW_RELEASE, translateFlags([event modifierFlags])); } - (void)mouseMoved:(NSEvent *)event { if (window->cursorMode == GLFW_CURSOR_DISABLED) { const double dx = [event deltaX] - window->ns.cursorWarpDeltaX; const double dy = [event deltaY] - window->ns.cursorWarpDeltaY; _glfwInputCursorPos(window, window->virtualCursorPosX + dx, window->virtualCursorPosY + dy); } else { const NSRect contentRect = [window->ns.view frame]; // NOTE: The returned location uses base 0,1 not 0,0 const NSPoint pos = [event locationInWindow]; _glfwInputCursorPos(window, pos.x, contentRect.size.height - pos.y); } window->ns.cursorWarpDeltaX = 0; window->ns.cursorWarpDeltaY = 0; } - (void)rightMouseDown:(NSEvent *)event { _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_RIGHT, GLFW_PRESS, translateFlags([event modifierFlags])); } - (void)rightMouseDragged:(NSEvent *)event { [self mouseMoved:event]; } - (void)rightMouseUp:(NSEvent *)event { _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_RIGHT, GLFW_RELEASE, translateFlags([event modifierFlags])); } - (void)otherMouseDown:(NSEvent *)event { _glfwInputMouseClick(window, (int) [event buttonNumber], GLFW_PRESS, translateFlags([event modifierFlags])); } - (void)otherMouseDragged:(NSEvent *)event { [self mouseMoved:event]; } - (void)otherMouseUp:(NSEvent *)event { _glfwInputMouseClick(window, (int) [event buttonNumber], GLFW_RELEASE, translateFlags([event modifierFlags])); } - (void)mouseExited:(NSEvent *)event { if (window->cursorMode == GLFW_CURSOR_HIDDEN) showCursor(window); _glfwInputCursorEnter(window, GLFW_FALSE); } - (void)mouseEntered:(NSEvent *)event { if (window->cursorMode == GLFW_CURSOR_HIDDEN) hideCursor(window); _glfwInputCursorEnter(window, GLFW_TRUE); } - (void)viewDidChangeBackingProperties { const NSRect contentRect = [window->ns.view frame]; const NSRect fbRect = [window->ns.view convertRectToBacking:contentRect]; 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 (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); } } - (void)drawRect:(NSRect)rect { _glfwInputWindowDamage(window); } - (void)updateTrackingAreas { if (trackingArea != nil) { [self removeTrackingArea:trackingArea]; [trackingArea release]; } const NSTrackingAreaOptions options = NSTrackingMouseEnteredAndExited | NSTrackingActiveInKeyWindow | NSTrackingEnabledDuringMouseDrag | NSTrackingCursorUpdate | NSTrackingInVisibleRect | NSTrackingAssumeInside; trackingArea = [[NSTrackingArea alloc] initWithRect:[self bounds] options:options owner:self userInfo:nil]; [self addTrackingArea:trackingArea]; [super updateTrackingAreas]; } - (void)keyDown:(NSEvent *)event { const int key = translateKey([event keyCode]); const int mods = translateFlags([event modifierFlags]); _glfwInputKey(window, key, [event keyCode], GLFW_PRESS, mods); [self interpretKeyEvents:@[event]]; } - (void)flagsChanged:(NSEvent *)event { int action; const unsigned int modifierFlags = [event modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask; const int key = translateKey([event keyCode]); const int mods = translateFlags(modifierFlags); const NSUInteger keyFlag = translateKeyToModifierFlag(key); if (keyFlag & modifierFlags) { if (window->keys[key] == GLFW_PRESS) action = GLFW_RELEASE; else action = GLFW_PRESS; } else action = GLFW_RELEASE; _glfwInputKey(window, key, [event keyCode], action, mods); } - (void)keyUp:(NSEvent *)event { const int key = translateKey([event keyCode]); const int mods = translateFlags([event modifierFlags]); _glfwInputKey(window, key, [event keyCode], GLFW_RELEASE, mods); } - (void)scrollWheel:(NSEvent *)event { double deltaX = [event scrollingDeltaX]; double deltaY = [event scrollingDeltaY]; if ([event hasPreciseScrollingDeltas]) { deltaX *= 0.1; deltaY *= 0.1; } if (fabs(deltaX) > 0.0 || fabs(deltaY) > 0.0) _glfwInputScroll(window, deltaX, deltaY); } - (NSDragOperation)draggingEntered:(id )sender { // HACK: We don't know what to say here because we don't know what the // application wants to do with the paths return NSDragOperationGeneric; } - (BOOL)performDragOperation:(id )sender { const NSRect contentRect = [window->ns.view frame]; // NOTE: The returned location uses base 0,1 not 0,0 const NSPoint pos = [sender draggingLocation]; _glfwInputCursorPos(window, pos.x, contentRect.size.height - pos.y); NSPasteboard* pasteboard = [sender draggingPasteboard]; NSDictionary* options = @{NSPasteboardURLReadingFileURLsOnlyKey:@YES}; NSArray* urls = [pasteboard readObjectsForClasses:@[[NSURL class]] options:options]; const NSUInteger count = [urls count]; if (count) { char** paths = calloc(count, sizeof(char*)); for (NSUInteger i = 0; i < count; i++) paths[i] = _glfw_strdup([urls[i] fileSystemRepresentation]); _glfwInputDrop(window, (int) count, (const char**) paths); for (NSUInteger i = 0; i < count; i++) free(paths[i]); free(paths); } return YES; } - (BOOL)hasMarkedText { return [markedText length] > 0; } - (NSRange)markedRange { if ([markedText length] > 0) return NSMakeRange(0, [markedText length] - 1); else return kEmptyRange; } - (NSRange)selectedRange { return kEmptyRange; } - (void)setMarkedText:(id)string selectedRange:(NSRange)selectedRange replacementRange:(NSRange)replacementRange { [markedText release]; if ([string isKindOfClass:[NSAttributedString class]]) markedText = [[NSMutableAttributedString alloc] initWithAttributedString:string]; else markedText = [[NSMutableAttributedString alloc] initWithString:string]; } - (void)unmarkText { [[markedText mutableString] setString:@""]; } - (NSArray*)validAttributesForMarkedText { return [NSArray array]; } - (NSAttributedString*)attributedSubstringForProposedRange:(NSRange)range actualRange:(NSRangePointer)actualRange { return nil; } - (NSUInteger)characterIndexForPoint:(NSPoint)point { return 0; } - (NSRect)firstRectForCharacterRange:(NSRange)range actualRange:(NSRangePointer)actualRange { const NSRect frame = [window->ns.view frame]; return NSMakeRect(frame.origin.x, frame.origin.y, 0.0, 0.0); } - (void)insertText:(id)string replacementRange:(NSRange)replacementRange { NSString* characters; NSEvent* event = [NSApp currentEvent]; const int mods = translateFlags([event modifierFlags]); const int plain = !(mods & GLFW_MOD_SUPER); if ([string isKindOfClass:[NSAttributedString class]]) characters = [string string]; else characters = (NSString*) string; NSRange range = NSMakeRange(0, [characters length]); while (range.length) { uint32_t codepoint = 0; 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); } } } - (void)doCommandBySelector:(SEL)selector { } @end //------------------------------------------------------------------------ // GLFW window class //------------------------------------------------------------------------ @interface GLFWWindow : NSWindow {} @end @implementation GLFWWindow - (BOOL)canBecomeKeyWindow { // Required for NSWindowStyleMaskBorderless windows return YES; } - (BOOL)canBecomeMainWindow { return YES; } @end // Create the Cocoa window // static GLFWbool createNativeWindow(_GLFWwindow* window, const _GLFWwndconfig* wndconfig, const _GLFWfbconfig* fbconfig) { window->ns.delegate = [[GLFWWindowDelegate alloc] initWithGlfwWindow:window]; if (window->ns.delegate == nil) { _glfwInputError(GLFW_PLATFORM_ERROR, "Cocoa: Failed to create window delegate"); return GLFW_FALSE; } NSRect contentRect; if (window->monitor) { GLFWvidmode mode; int xpos, ypos; _glfwPlatformGetVideoMode(window->monitor, &mode); _glfwPlatformGetMonitorPos(window->monitor, &xpos, &ypos); contentRect = NSMakeRect(xpos, ypos, mode.width, mode.height); } else contentRect = NSMakeRect(0, 0, wndconfig->width, wndconfig->height); window->ns.object = [[GLFWWindow alloc] initWithContentRect:contentRect styleMask:getStyleMask(window) backing:NSBackingStoreBuffered defer:NO]; if (window->ns.object == nil) { _glfwInputError(GLFW_PLATFORM_ERROR, "Cocoa: Failed to create window"); return GLFW_FALSE; } if (window->monitor) [window->ns.object setLevel:NSMainMenuWindowLevel + 1]; else { [(NSWindow*) window->ns.object center]; _glfw.ns.cascadePoint = NSPointToCGPoint([window->ns.object cascadeTopLeftFromPoint: NSPointFromCGPoint(_glfw.ns.cascadePoint)]); if (wndconfig->resizable) { const NSWindowCollectionBehavior behavior = NSWindowCollectionBehaviorFullScreenPrimary | NSWindowCollectionBehaviorManaged; [window->ns.object setCollectionBehavior:behavior]; } if (wndconfig->floating) [window->ns.object setLevel:NSFloatingWindowLevel]; if (wndconfig->maximized) [window->ns.object zoom:nil]; } if (strlen(wndconfig->ns.frameName)) [window->ns.object setFrameAutosaveName:@(wndconfig->ns.frameName)]; window->ns.view = [[GLFWContentView alloc] initWithGlfwWindow:window]; window->ns.retina = wndconfig->ns.retina; if (fbconfig->transparent) { [window->ns.object setOpaque:NO]; [window->ns.object setHasShadow:NO]; [window->ns.object setBackgroundColor:[NSColor clearColor]]; } [window->ns.object setContentView:window->ns.view]; [window->ns.object makeFirstResponder:window->ns.view]; [window->ns.object setTitle:@(wndconfig->title)]; [window->ns.object setDelegate:window->ns.delegate]; [window->ns.object setAcceptsMouseMovedEvents:YES]; [window->ns.object setRestorable:NO]; #if MAC_OS_X_VERSION_MAX_ALLOWED >= 101200 if ([window->ns.object respondsToSelector:@selector(setTabbingMode:)]) [window->ns.object setTabbingMode:NSWindowTabbingModeDisallowed]; #endif _glfwPlatformGetWindowSize(window, &window->ns.width, &window->ns.height); _glfwPlatformGetFramebufferSize(window, &window->ns.fbWidth, &window->ns.fbHeight); return GLFW_TRUE; } ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// // Transforms a y-coordinate between the CG display and NS screen spaces // float _glfwTransformYNS(float y) { return CGDisplayBounds(CGMainDisplayID()).size.height - y - 1; } ////////////////////////////////////////////////////////////////////////// ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// int _glfwPlatformCreateWindow(_GLFWwindow* window, const _GLFWwndconfig* wndconfig, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig) { @autoreleasepool { if (!_glfw.ns.finishedLaunching) [NSApp run]; if (!createNativeWindow(window, wndconfig, fbconfig)) return GLFW_FALSE; if (ctxconfig->client != GLFW_NO_API) { if (ctxconfig->source == GLFW_NATIVE_CONTEXT_API) { if (!_glfwInitNSGL()) return GLFW_FALSE; if (!_glfwCreateContextNSGL(window, ctxconfig, fbconfig)) return GLFW_FALSE; } 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)) 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 (window->monitor) { _glfwPlatformShowWindow(window); _glfwPlatformFocusWindow(window); acquireMonitor(window); } return GLFW_TRUE; } // autoreleasepool } void _glfwPlatformDestroyWindow(_GLFWwindow* window) { @autoreleasepool { if (_glfw.ns.disabledCursorWindow == window) _glfw.ns.disabledCursorWindow = NULL; [window->ns.object orderOut:nil]; if (window->monitor) releaseMonitor(window); if (window->context.destroy) window->context.destroy(window); [window->ns.object setDelegate:nil]; [window->ns.delegate release]; window->ns.delegate = nil; [window->ns.view release]; window->ns.view = nil; [window->ns.object close]; window->ns.object = nil; // HACK: Allow Cocoa to catch up before returning _glfwPlatformPollEvents(); } // autoreleasepool } void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title) { @autoreleasepool { NSString* string = @(title); [window->ns.object setTitle:string]; // HACK: Set the miniwindow title explicitly as setTitle: doesn't update it // if the window lacks NSWindowStyleMaskTitled [window->ns.object setMiniwindowTitle:string]; } // autoreleasepool } void _glfwPlatformSetWindowIcon(_GLFWwindow* window, int count, const GLFWimage* images) { // Regular windows do not have icons } void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos) { @autoreleasepool { const NSRect contentRect = [window->ns.object contentRectForFrameRect:[window->ns.object frame]]; if (xpos) *xpos = contentRect.origin.x; if (ypos) *ypos = _glfwTransformYNS(contentRect.origin.y + contentRect.size.height - 1); } // autoreleasepool } void _glfwPlatformSetWindowPos(_GLFWwindow* window, int x, int y) { @autoreleasepool { const NSRect contentRect = [window->ns.view frame]; const NSRect dummyRect = NSMakeRect(x, _glfwTransformYNS(y + contentRect.size.height - 1), 0, 0); const NSRect frameRect = [window->ns.object frameRectForContentRect:dummyRect]; [window->ns.object setFrameOrigin:frameRect.origin]; } // autoreleasepool } void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height) { @autoreleasepool { const NSRect contentRect = [window->ns.view frame]; if (width) *width = contentRect.size.width; if (height) *height = contentRect.size.height; } // autoreleasepool } void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) { @autoreleasepool { if (window->monitor) { if (window->monitor->window == window) acquireMonitor(window); } else { NSRect contentRect = [window->ns.object contentRectForFrameRect:[window->ns.object frame]]; contentRect.origin.y += contentRect.size.height - height; contentRect.size = NSMakeSize(width, height); [window->ns.object setFrame:[window->ns.object frameRectForContentRect:contentRect] display:YES]; } } // autoreleasepool } void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window, int minwidth, int minheight, int maxwidth, int maxheight) { @autoreleasepool { if (minwidth == GLFW_DONT_CARE || minheight == GLFW_DONT_CARE) [window->ns.object setContentMinSize:NSMakeSize(0, 0)]; else [window->ns.object setContentMinSize:NSMakeSize(minwidth, minheight)]; if (maxwidth == GLFW_DONT_CARE || maxheight == GLFW_DONT_CARE) [window->ns.object setContentMaxSize:NSMakeSize(DBL_MAX, DBL_MAX)]; else [window->ns.object setContentMaxSize:NSMakeSize(maxwidth, maxheight)]; } // autoreleasepool } void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom) { @autoreleasepool { if (numer == GLFW_DONT_CARE || denom == GLFW_DONT_CARE) [window->ns.object setResizeIncrements:NSMakeSize(1.0, 1.0)]; else [window->ns.object setContentAspectRatio:NSMakeSize(numer, denom)]; } // autoreleasepool } void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height) { @autoreleasepool { const NSRect contentRect = [window->ns.view frame]; const NSRect fbRect = [window->ns.view convertRectToBacking:contentRect]; if (width) *width = (int) fbRect.size.width; if (height) *height = (int) fbRect.size.height; } // autoreleasepool } void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, int* left, int* top, int* right, int* bottom) { @autoreleasepool { const NSRect contentRect = [window->ns.view frame]; const NSRect frameRect = [window->ns.object frameRectForContentRect:contentRect]; if (left) *left = contentRect.origin.x - frameRect.origin.x; if (top) *top = frameRect.origin.y + frameRect.size.height - contentRect.origin.y - contentRect.size.height; if (right) *right = frameRect.origin.x + frameRect.size.width - contentRect.origin.x - contentRect.size.width; if (bottom) *bottom = contentRect.origin.y - frameRect.origin.y; } // autoreleasepool } void _glfwPlatformGetWindowContentScale(_GLFWwindow* window, float* xscale, float* yscale) { @autoreleasepool { const NSRect points = [window->ns.view frame]; const NSRect pixels = [window->ns.view convertRectToBacking:points]; if (xscale) *xscale = (float) (pixels.size.width / points.size.width); if (yscale) *yscale = (float) (pixels.size.height / points.size.height); } // autoreleasepool } void _glfwPlatformIconifyWindow(_GLFWwindow* window) { @autoreleasepool { [window->ns.object miniaturize:nil]; } // autoreleasepool } void _glfwPlatformRestoreWindow(_GLFWwindow* window) { @autoreleasepool { if ([window->ns.object isMiniaturized]) [window->ns.object deminiaturize:nil]; else if ([window->ns.object isZoomed]) [window->ns.object zoom:nil]; } // autoreleasepool } void _glfwPlatformMaximizeWindow(_GLFWwindow* window) { @autoreleasepool { if (![window->ns.object isZoomed]) [window->ns.object zoom:nil]; } // autoreleasepool } void _glfwPlatformShowWindow(_GLFWwindow* window) { @autoreleasepool { [window->ns.object orderFront:nil]; } // autoreleasepool } void _glfwPlatformHideWindow(_GLFWwindow* window) { @autoreleasepool { [window->ns.object orderOut:nil]; } // autoreleasepool } void _glfwPlatformRequestWindowAttention(_GLFWwindow* window) { @autoreleasepool { [NSApp requestUserAttention:NSInformationalRequest]; } // autoreleasepool } void _glfwPlatformFocusWindow(_GLFWwindow* window) { @autoreleasepool { // Make us the active application // HACK: This is here to prevent applications using only hidden windows from // being activated, but should probably not be done every time any // window is shown [NSApp activateIgnoringOtherApps:YES]; [window->ns.object makeKeyAndOrderFront:nil]; } // autoreleasepool } void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor, int xpos, int ypos, int width, int height, int refreshRate) { @autoreleasepool { if (window->monitor == monitor) { if (monitor) { if (monitor->window == window) acquireMonitor(window); } else { const NSRect contentRect = NSMakeRect(xpos, _glfwTransformYNS(ypos + height - 1), width, height); const NSRect frameRect = [window->ns.object frameRectForContentRect:contentRect styleMask:getStyleMask(window)]; [window->ns.object setFrame:frameRect display:YES]; } return; } if (window->monitor) releaseMonitor(window); _glfwInputWindowMonitor(window, monitor); // HACK: Allow the state cached in Cocoa to catch up to reality // TODO: Solve this in a less terrible way _glfwPlatformPollEvents(); const NSUInteger styleMask = getStyleMask(window); [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]; if (window->monitor) { [window->ns.object setLevel:NSMainMenuWindowLevel + 1]; [window->ns.object setHasShadow:NO]; acquireMonitor(window); } else { NSRect contentRect = NSMakeRect(xpos, _glfwTransformYNS(ypos + height - 1), width, height); NSRect frameRect = [window->ns.object frameRectForContentRect:contentRect styleMask:styleMask]; [window->ns.object setFrame:frameRect display:YES]; if (window->numer != GLFW_DONT_CARE && window->denom != GLFW_DONT_CARE) { [window->ns.object setContentAspectRatio:NSMakeSize(window->numer, window->denom)]; } if (window->minwidth != GLFW_DONT_CARE && window->minheight != GLFW_DONT_CARE) { [window->ns.object setContentMinSize:NSMakeSize(window->minwidth, window->minheight)]; } if (window->maxwidth != GLFW_DONT_CARE && window->maxheight != GLFW_DONT_CARE) { [window->ns.object setContentMaxSize:NSMakeSize(window->maxwidth, window->maxheight)]; } if (window->floating) [window->ns.object setLevel:NSFloatingWindowLevel]; else [window->ns.object setLevel:NSNormalWindowLevel]; [window->ns.object setHasShadow:YES]; // HACK: Clearing NSWindowStyleMaskTitled resets and disables the window // title property but the miniwindow title property is unaffected [window->ns.object setTitle:[window->ns.object miniwindowTitle]]; } } // autoreleasepool } int _glfwPlatformWindowFocused(_GLFWwindow* window) { @autoreleasepool { return [window->ns.object isKeyWindow]; } // autoreleasepool } int _glfwPlatformWindowIconified(_GLFWwindow* window) { @autoreleasepool { return [window->ns.object isMiniaturized]; } // autoreleasepool } int _glfwPlatformWindowVisible(_GLFWwindow* window) { @autoreleasepool { return [window->ns.object isVisible]; } // autoreleasepool } int _glfwPlatformWindowMaximized(_GLFWwindow* window) { @autoreleasepool { return [window->ns.object isZoomed]; } // autoreleasepool } int _glfwPlatformWindowHovered(_GLFWwindow* window) { @autoreleasepool { const NSPoint point = [NSEvent mouseLocation]; if ([NSWindow windowNumberAtPoint:point belowWindowWithWindowNumber:0] != [window->ns.object windowNumber]) { return GLFW_FALSE; } return NSMouseInRect(point, [window->ns.object convertRectToScreen:[window->ns.view frame]], NO); } // autoreleasepool } int _glfwPlatformFramebufferTransparent(_GLFWwindow* window) { @autoreleasepool { return ![window->ns.object isOpaque] && ![window->ns.view isOpaque]; } // autoreleasepool } void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled) { @autoreleasepool { [window->ns.object setStyleMask:getStyleMask(window)]; } // autoreleasepool } void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled) { @autoreleasepool { [window->ns.object setStyleMask:getStyleMask(window)]; [window->ns.object makeFirstResponder:window->ns.view]; } // autoreleasepool } void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled) { @autoreleasepool { if (enabled) [window->ns.object setLevel:NSFloatingWindowLevel]; else [window->ns.object setLevel:NSNormalWindowLevel]; } // autoreleasepool } float _glfwPlatformGetWindowOpacity(_GLFWwindow* window) { @autoreleasepool { return (float) [window->ns.object alphaValue]; } // autoreleasepool } void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity) { @autoreleasepool { [window->ns.object setAlphaValue:opacity]; } // autoreleasepool } void _glfwPlatformSetRawMouseMotion(_GLFWwindow *window, GLFWbool enabled) { } GLFWbool _glfwPlatformRawMouseMotionSupported(void) { return GLFW_FALSE; } void _glfwPlatformPollEvents(void) { @autoreleasepool { if (!_glfw.ns.finishedLaunching) [NSApp run]; for (;;) { NSEvent* event = [NSApp nextEventMatchingMask:NSEventMaskAny untilDate:[NSDate distantPast] inMode:NSDefaultRunLoopMode dequeue:YES]; if (event == nil) break; [NSApp sendEvent:event]; } } // autoreleasepool } void _glfwPlatformWaitEvents(void) { @autoreleasepool { if (!_glfw.ns.finishedLaunching) [NSApp run]; // I wanted to pass NO to dequeue:, and rely on PollEvents to // dequeue and send. For reasons not at all clear to me, passing // NO to dequeue: causes this method never to return. NSEvent *event = [NSApp nextEventMatchingMask:NSEventMaskAny untilDate:[NSDate distantFuture] inMode:NSDefaultRunLoopMode dequeue:YES]; [NSApp sendEvent:event]; _glfwPlatformPollEvents(); } // autoreleasepool } void _glfwPlatformWaitEventsTimeout(double timeout) { @autoreleasepool { if (!_glfw.ns.finishedLaunching) [NSApp run]; NSDate* date = [NSDate dateWithTimeIntervalSinceNow:timeout]; NSEvent* event = [NSApp nextEventMatchingMask:NSEventMaskAny untilDate:date inMode:NSDefaultRunLoopMode dequeue:YES]; if (event) [NSApp sendEvent:event]; _glfwPlatformPollEvents(); } // autoreleasepool } void _glfwPlatformPostEmptyEvent(void) { @autoreleasepool { if (!_glfw.ns.finishedLaunching) [NSApp run]; NSEvent* event = [NSEvent otherEventWithType:NSEventTypeApplicationDefined location:NSMakePoint(0, 0) modifierFlags:0 timestamp:0 windowNumber:0 context:nil subtype:0 data1:0 data2:0]; [NSApp postEvent:event atStart:YES]; } // autoreleasepool } void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos) { @autoreleasepool { const NSRect contentRect = [window->ns.view frame]; // NOTE: The returned location uses base 0,1 not 0,0 const NSPoint pos = [window->ns.object mouseLocationOutsideOfEventStream]; if (xpos) *xpos = pos.x; if (ypos) *ypos = contentRect.size.height - pos.y; } // autoreleasepool } void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y) { @autoreleasepool { updateCursorImage(window); const NSRect contentRect = [window->ns.view frame]; // NOTE: The returned location uses base 0,1 not 0,0 const NSPoint pos = [window->ns.object mouseLocationOutsideOfEventStream]; window->ns.cursorWarpDeltaX += x - pos.x; window->ns.cursorWarpDeltaY += y - contentRect.size.height + pos.y; if (window->monitor) { CGDisplayMoveCursorToPoint(window->monitor->ns.displayID, CGPointMake(x, y)); } else { const NSRect localRect = NSMakeRect(x, contentRect.size.height - y - 1, 0, 0); const NSRect globalRect = [window->ns.object convertRectToScreen:localRect]; const NSPoint globalPoint = globalRect.origin; CGWarpMouseCursorPosition(CGPointMake(globalPoint.x, _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 } void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) { @autoreleasepool { if (_glfwPlatformWindowFocused(window)) updateCursorMode(window); } // autoreleasepool } const char* _glfwPlatformGetScancodeName(int scancode) { @autoreleasepool { if (scancode < 0 || scancode > 0xff || _glfw.ns.keycodes[scancode] == GLFW_KEY_UNKNOWN) { _glfwInputError(GLFW_INVALID_VALUE, "Invalid scancode %i", scancode); return NULL; } const int key = _glfw.ns.keycodes[scancode]; UInt32 deadKeyState = 0; UniChar characters[4]; UniCharCount characterCount = 0; if (UCKeyTranslate([(NSData*) _glfw.ns.unicodeData bytes], scancode, kUCKeyActionDisplay, 0, LMGetKbdType(), kUCKeyTranslateNoDeadKeysBit, &deadKeyState, sizeof(characters) / sizeof(characters[0]), &characterCount, characters) != noErr) { return NULL; } if (!characterCount) return NULL; CFStringRef string = CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, characters, characterCount, kCFAllocatorNull); CFStringGetCString(string, _glfw.ns.keynames[key], sizeof(_glfw.ns.keynames[key]), kCFStringEncodingUTF8); CFRelease(string); return _glfw.ns.keynames[key]; } // autoreleasepool } int _glfwPlatformGetKeyScancode(int key) { return _glfw.ns.scancodes[key]; } int _glfwPlatformCreateCursor(_GLFWcursor* cursor, const GLFWimage* image, int xhot, int yhot) { @autoreleasepool { NSImage* native; NSBitmapImageRep* rep; rep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL pixelsWide:image->width pixelsHigh:image->height bitsPerSample:8 samplesPerPixel:4 hasAlpha:YES isPlanar:NO colorSpaceName:NSCalibratedRGBColorSpace bitmapFormat:NSBitmapFormatAlphaNonpremultiplied bytesPerRow:image->width * 4 bitsPerPixel:32]; if (rep == nil) return GLFW_FALSE; memcpy([rep bitmapData], image->pixels, image->width * image->height * 4); native = [[NSImage alloc] initWithSize:NSMakeSize(image->width, image->height)]; [native addRepresentation:rep]; cursor->ns.object = [[NSCursor alloc] initWithImage:native hotSpot:NSMakePoint(xhot, yhot)]; [native release]; [rep release]; if (cursor->ns.object == nil) return GLFW_FALSE; return GLFW_TRUE; } // autoreleasepool } int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape) { @autoreleasepool { if (shape == GLFW_ARROW_CURSOR) cursor->ns.object = [NSCursor arrowCursor]; else if (shape == GLFW_IBEAM_CURSOR) cursor->ns.object = [NSCursor IBeamCursor]; else if (shape == GLFW_CROSSHAIR_CURSOR) cursor->ns.object = [NSCursor crosshairCursor]; else if (shape == GLFW_HAND_CURSOR) cursor->ns.object = [NSCursor pointingHandCursor]; else if (shape == GLFW_HRESIZE_CURSOR) cursor->ns.object = [NSCursor resizeLeftRightCursor]; else if (shape == GLFW_VRESIZE_CURSOR) cursor->ns.object = [NSCursor resizeUpDownCursor]; if (!cursor->ns.object) { _glfwInputError(GLFW_PLATFORM_ERROR, "Cocoa: Failed to retrieve standard cursor"); return GLFW_FALSE; } [cursor->ns.object retain]; return GLFW_TRUE; } // autoreleasepool } void _glfwPlatformDestroyCursor(_GLFWcursor* cursor) { @autoreleasepool { if (cursor->ns.object) [(NSCursor*) cursor->ns.object release]; } // autoreleasepool } void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) { @autoreleasepool { if (cursorInContentArea(window)) updateCursorImage(window); } // autoreleasepool } void _glfwPlatformSetClipboardString(const char* string) { @autoreleasepool { NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; [pasteboard declareTypes:@[NSPasteboardTypeString] owner:nil]; [pasteboard setString:@(string) forType:NSPasteboardTypeString]; } // autoreleasepool } const char* _glfwPlatformGetClipboardString(void) { @autoreleasepool { NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; if (![[pasteboard types] containsObject:NSPasteboardTypeString]) { _glfwInputError(GLFW_FORMAT_UNAVAILABLE, "Cocoa: Failed to retrieve string from pasteboard"); return NULL; } NSString* object = [pasteboard stringForType:NSPasteboardTypeString]; if (!object) { _glfwInputError(GLFW_PLATFORM_ERROR, "Cocoa: Failed to retrieve object from pasteboard"); return NULL; } free(_glfw.ns.clipboardString); _glfw.ns.clipboardString = _glfw_strdup([object UTF8String]); return _glfw.ns.clipboardString; } // autoreleasepool } void _glfwPlatformGetRequiredInstanceExtensions(char** extensions) { if (_glfw.vk.KHR_surface && _glfw.vk.EXT_metal_surface) { extensions[0] = "VK_KHR_surface"; extensions[1] = "VK_EXT_metal_surface"; } else if (_glfw.vk.KHR_surface && _glfw.vk.MVK_macos_surface) { extensions[0] = "VK_KHR_surface"; extensions[1] = "VK_MVK_macos_surface"; } } int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, VkPhysicalDevice device, uint32_t queuefamily) { return GLFW_TRUE; } VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, _GLFWwindow* window, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface) { @autoreleasepool { #if MAC_OS_X_VERSION_MAX_ALLOWED >= 101100 // HACK: Dynamically load Core Animation to avoid adding an extra // dependency for the majority who don't use MoltenVK NSBundle* bundle = [NSBundle bundleWithPath:@"/System/Library/Frameworks/QuartzCore.framework"]; if (!bundle) { _glfwInputError(GLFW_PLATFORM_ERROR, "Cocoa: Failed to find QuartzCore.framework"); return VK_ERROR_EXTENSION_NOT_PRESENT; } // NOTE: Create the layer here as makeBackingLayer should not return nil window->ns.layer = [[bundle classNamed:@"CAMetalLayer"] layer]; if (!window->ns.layer) { _glfwInputError(GLFW_PLATFORM_ERROR, "Cocoa: Failed to create layer for view"); return VK_ERROR_EXTENSION_NOT_PRESENT; } if (window->ns.retina) [window->ns.layer setContentsScale:[window->ns.object backingScaleFactor]]; [window->ns.view setLayer:window->ns.layer]; [window->ns.view setWantsLayer:YES]; VkResult err; if (_glfw.vk.EXT_metal_surface) { VkMetalSurfaceCreateInfoEXT sci; PFN_vkCreateMetalSurfaceEXT vkCreateMetalSurfaceEXT; vkCreateMetalSurfaceEXT = (PFN_vkCreateMetalSurfaceEXT) vkGetInstanceProcAddr(instance, "vkCreateMetalSurfaceEXT"); if (!vkCreateMetalSurfaceEXT) { _glfwInputError(GLFW_API_UNAVAILABLE, "Cocoa: Vulkan instance missing VK_EXT_metal_surface extension"); return VK_ERROR_EXTENSION_NOT_PRESENT; } memset(&sci, 0, sizeof(sci)); sci.sType = VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT; sci.pLayer = window->ns.layer; err = vkCreateMetalSurfaceEXT(instance, &sci, allocator, surface); } else { VkMacOSSurfaceCreateInfoMVK sci; PFN_vkCreateMacOSSurfaceMVK vkCreateMacOSSurfaceMVK; vkCreateMacOSSurfaceMVK = (PFN_vkCreateMacOSSurfaceMVK) vkGetInstanceProcAddr(instance, "vkCreateMacOSSurfaceMVK"); if (!vkCreateMacOSSurfaceMVK) { _glfwInputError(GLFW_API_UNAVAILABLE, "Cocoa: Vulkan instance missing VK_MVK_macos_surface extension"); return VK_ERROR_EXTENSION_NOT_PRESENT; } memset(&sci, 0, sizeof(sci)); sci.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK; sci.pView = window->ns.view; err = vkCreateMacOSSurfaceMVK(instance, &sci, allocator, surface); } if (err) { _glfwInputError(GLFW_PLATFORM_ERROR, "Cocoa: Failed to create Vulkan surface: %s", _glfwGetVulkanResultString(err)); } return err; #else return VK_ERROR_EXTENSION_NOT_PRESENT; #endif } // autoreleasepool } ////////////////////////////////////////////////////////////////////////// ////// GLFW native API ////// ////////////////////////////////////////////////////////////////////////// GLFWAPI id glfwGetCocoaWindow(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(nil); return window->ns.object; } #endif #ifndef HEADER_GUARD_COCOA_TIME_C #define HEADER_GUARD_COCOA_TIME_C //======================================================================== // GLFW 3.3.7 macOS - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2009-2016 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== // It is fine to use C99 in this file because it will not be built with VS //======================================================================== #include ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// // Initialise timer // void _glfwInitTimerNS(void) { mach_timebase_info_data_t info; mach_timebase_info(&info); _glfw.timer.ns.frequency = (info.denom * 1e9) / info.numer; } ////////////////////////////////////////////////////////////////////////// ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// uint64_t _glfwPlatformGetTimerValue(void) { return mach_absolute_time(); } uint64_t _glfwPlatformGetTimerFrequency(void) { return _glfw.timer.ns.frequency; } #endif #endif #if !defined _GLFW_COCOA && !defined _GLFW_WIN32 #ifndef HEADER_GUARD_POSIX_TIME_C #define HEADER_GUARD_POSIX_TIME_C //======================================================================== // GLFW 3.3.7 POSIX - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2017 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== // It is fine to use C99 in this file because it will not be built with VS //======================================================================== #include #include ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// // Initialise timer // void _glfwInitTimerPOSIX(void) { #if defined(CLOCK_MONOTONIC) struct timespec ts; if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) { _glfw.timer.posix.monotonic = GLFW_TRUE; _glfw.timer.posix.frequency = 1000000000; } else #endif { _glfw.timer.posix.monotonic = GLFW_FALSE; _glfw.timer.posix.frequency = 1000000; } } ////////////////////////////////////////////////////////////////////////// ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// uint64_t _glfwPlatformGetTimerValue(void) { #if defined(CLOCK_MONOTONIC) if (_glfw.timer.posix.monotonic) { struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); return (uint64_t) ts.tv_sec * (uint64_t) 1000000000 + (uint64_t) ts.tv_nsec; } else #endif { struct timeval tv; gettimeofday(&tv, NULL); return (uint64_t) tv.tv_sec * (uint64_t) 1000000 + (uint64_t) tv.tv_usec; } } uint64_t _glfwPlatformGetTimerFrequency(void) { return _glfw.timer.posix.frequency; } #endif #endif #if !defined _GLFW_WIN32 #ifndef HEADER_GUARD_POSIX_THREAD_C #define HEADER_GUARD_POSIX_THREAD_C //======================================================================== // GLFW 3.3.7 POSIX - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2017 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== // It is fine to use C99 in this file because it will not be built with VS //======================================================================== #include #include ////////////////////////////////////////////////////////////////////////// ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// GLFWbool _glfwPlatformCreateTls(_GLFWtls* tls) { assert(tls->posix.allocated == GLFW_FALSE); if (pthread_key_create(&tls->posix.key, NULL) != 0) { _glfwInputError(GLFW_PLATFORM_ERROR, "POSIX: Failed to create context TLS"); return GLFW_FALSE; } tls->posix.allocated = GLFW_TRUE; return GLFW_TRUE; } void _glfwPlatformDestroyTls(_GLFWtls* tls) { if (tls->posix.allocated) pthread_key_delete(tls->posix.key); memset(tls, 0, sizeof(_GLFWtls)); } void* _glfwPlatformGetTls(_GLFWtls* tls) { assert(tls->posix.allocated == GLFW_TRUE); return pthread_getspecific(tls->posix.key); } void _glfwPlatformSetTls(_GLFWtls* tls, void* value) { assert(tls->posix.allocated == GLFW_TRUE); pthread_setspecific(tls->posix.key, value); } GLFWbool _glfwPlatformCreateMutex(_GLFWmutex* mutex) { assert(mutex->posix.allocated == GLFW_FALSE); if (pthread_mutex_init(&mutex->posix.handle, NULL) != 0) { _glfwInputError(GLFW_PLATFORM_ERROR, "POSIX: Failed to create mutex"); return GLFW_FALSE; } return mutex->posix.allocated = GLFW_TRUE; } void _glfwPlatformDestroyMutex(_GLFWmutex* mutex) { if (mutex->posix.allocated) pthread_mutex_destroy(&mutex->posix.handle); memset(mutex, 0, sizeof(_GLFWmutex)); } void _glfwPlatformLockMutex(_GLFWmutex* mutex) { assert(mutex->posix.allocated == GLFW_TRUE); pthread_mutex_lock(&mutex->posix.handle); } void _glfwPlatformUnlockMutex(_GLFWmutex* mutex) { assert(mutex->posix.allocated == GLFW_TRUE); pthread_mutex_unlock(&mutex->posix.handle); } #endif #endif #if !defined _GLFW_COCOA && !defined _GLFW_WIN32 && !defined _GLFW_OSMESA #ifndef HEADER_GUARD_LINUX_JOYSTICK_C #define HEADER_GUARD_LINUX_JOYSTICK_C //======================================================================== // GLFW 3.3.7 Linux - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2017 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== // It is fine to use C99 in this file because it will not be built with VS //======================================================================== #include #include #include #include #include #include #include #include #include #include #ifndef SYN_DROPPED // < v2.6.39 kernel headers // Workaround for CentOS-6, which is supported till 2020-11-30, but still on v2.6.32 #define SYN_DROPPED 3 #endif // Apply an EV_KEY event to the specified joystick // static void handleKeyEvent(_GLFWjoystick* js, int code, int value) { _glfwInputJoystickButton(js, js->linjs.keyMap[code - BTN_MISC], value ? GLFW_PRESS : GLFW_RELEASE); } // Apply an EV_ABS event to the specified joystick // static void handleAbsEvent(_GLFWjoystick* js, int code, int value) { const int index = js->linjs.absMap[code]; if (code >= ABS_HAT0X && code <= ABS_HAT3Y) { static const char stateMap[3][3] = { { GLFW_HAT_CENTERED, GLFW_HAT_UP, GLFW_HAT_DOWN }, { GLFW_HAT_LEFT, GLFW_HAT_LEFT_UP, GLFW_HAT_LEFT_DOWN }, { GLFW_HAT_RIGHT, GLFW_HAT_RIGHT_UP, GLFW_HAT_RIGHT_DOWN }, }; const int hat = (code - ABS_HAT0X) / 2; const int axis = (code - ABS_HAT0X) % 2; int* state = js->linjs.hats[hat]; // NOTE: Looking at several input drivers, it seems all hat events use // -1 for left / up, 0 for centered and 1 for right / down if (value == 0) state[axis] = 0; else if (value < 0) state[axis] = 1; else if (value > 0) state[axis] = 2; _glfwInputJoystickHat(js, index, stateMap[state[0]][state[1]]); } else { const struct input_absinfo* info = &js->linjs.absInfo[code]; float normalized = value; const int range = info->maximum - info->minimum; if (range) { // Normalize to 0.0 -> 1.0 normalized = (normalized - info->minimum) / range; // Normalize to -1.0 -> 1.0 normalized = normalized * 2.0f - 1.0f; } _glfwInputJoystickAxis(js, index, normalized); } } // Poll state of absolute axes // static void pollAbsState(_GLFWjoystick* js) { for (int code = 0; code < ABS_CNT; code++) { if (js->linjs.absMap[code] < 0) continue; struct input_absinfo* info = &js->linjs.absInfo[code]; if (ioctl(js->linjs.fd, EVIOCGABS(code), info) < 0) continue; handleAbsEvent(js, code, info->value); } } #define isBitSet(bit, arr) (arr[(bit) / 8] & (1 << ((bit) % 8))) // Attempt to open the specified joystick device // static GLFWbool openJoystickDevice(const char* path) { for (int jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) { if (!_glfw.joysticks[jid].present) continue; if (strcmp(_glfw.joysticks[jid].linjs.path, path) == 0) return GLFW_FALSE; } _GLFWjoystickLinux linjs = {0}; linjs.fd = open(path, O_RDONLY | O_NONBLOCK); if (linjs.fd == -1) return GLFW_FALSE; char evBits[(EV_CNT + 7) / 8] = {0}; char keyBits[(KEY_CNT + 7) / 8] = {0}; char absBits[(ABS_CNT + 7) / 8] = {0}; struct input_id id; if (ioctl(linjs.fd, EVIOCGBIT(0, sizeof(evBits)), evBits) < 0 || ioctl(linjs.fd, EVIOCGBIT(EV_KEY, sizeof(keyBits)), keyBits) < 0 || ioctl(linjs.fd, EVIOCGBIT(EV_ABS, sizeof(absBits)), absBits) < 0 || ioctl(linjs.fd, EVIOCGID, &id) < 0) { _glfwInputError(GLFW_PLATFORM_ERROR, "Linux: Failed to query input device: %s", strerror(errno)); close(linjs.fd); return GLFW_FALSE; } // Ensure this device supports the events expected of a joystick if (!isBitSet(EV_KEY, evBits) || !isBitSet(EV_ABS, evBits)) { close(linjs.fd); return GLFW_FALSE; } char name[256] = ""; if (ioctl(linjs.fd, EVIOCGNAME(sizeof(name)), name) < 0) strncpy(name, "Unknown", sizeof(name)); char guid[33] = ""; // Generate a joystick GUID that matches the SDL 2.0.5+ one if (id.vendor && id.product && id.version) { sprintf(guid, "%02x%02x0000%02x%02x0000%02x%02x0000%02x%02x0000", id.bustype & 0xff, id.bustype >> 8, id.vendor & 0xff, id.vendor >> 8, id.product & 0xff, id.product >> 8, id.version & 0xff, id.version >> 8); } else { sprintf(guid, "%02x%02x0000%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x00", id.bustype & 0xff, id.bustype >> 8, name[0], name[1], name[2], name[3], name[4], name[5], name[6], name[7], name[8], name[9], name[10]); } int axisCount = 0, buttonCount = 0, hatCount = 0; for (int code = BTN_MISC; code < KEY_CNT; code++) { if (!isBitSet(code, keyBits)) continue; linjs.keyMap[code - BTN_MISC] = buttonCount; buttonCount++; } for (int code = 0; code < ABS_CNT; code++) { linjs.absMap[code] = -1; if (!isBitSet(code, absBits)) continue; if (code >= ABS_HAT0X && code <= ABS_HAT3Y) { linjs.absMap[code] = hatCount; hatCount++; // Skip the Y axis code++; } else { if (ioctl(linjs.fd, EVIOCGABS(code), &linjs.absInfo[code]) < 0) continue; linjs.absMap[code] = axisCount; axisCount++; } } _GLFWjoystick* js = _glfwAllocJoystick(name, guid, axisCount, buttonCount, hatCount); if (!js) { close(linjs.fd); return GLFW_FALSE; } strncpy(linjs.path, path, sizeof(linjs.path) - 1); memcpy(&js->linjs, &linjs, sizeof(linjs)); pollAbsState(js); _glfwInputJoystick(js, GLFW_CONNECTED); return GLFW_TRUE; } #undef isBitSet // Frees all resources associated with the specified joystick // static void closeJoystick(_GLFWjoystick* js) { close(js->linjs.fd); _glfwFreeJoystick(js); _glfwInputJoystick(js, GLFW_DISCONNECTED); } // Lexically compare joysticks by name; used by qsort // static int compareJoysticks(const void* fp, const void* sp) { const _GLFWjoystick* fj = fp; const _GLFWjoystick* sj = sp; return strcmp(fj->linjs.path, sj->linjs.path); } ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// // Initialize joystick interface // GLFWbool _glfwInitJoysticksLinux(void) { const char* dirname = "/dev/input"; _glfw.linjs.inotify = inotify_init1(IN_NONBLOCK | IN_CLOEXEC); if (_glfw.linjs.inotify > 0) { // HACK: Register for IN_ATTRIB to get notified when udev is done // This works well in practice but the true way is libudev _glfw.linjs.watch = inotify_add_watch(_glfw.linjs.inotify, dirname, IN_CREATE | IN_ATTRIB | IN_DELETE); } // Continue without device connection notifications if inotify fails if (regcomp(&_glfw.linjs.regex, "^event[0-9]\\+$", 0) != 0) { _glfwInputError(GLFW_PLATFORM_ERROR, "Linux: Failed to compile regex"); return GLFW_FALSE; } int count = 0; DIR* dir = opendir(dirname); if (dir) { struct dirent* entry; while ((entry = readdir(dir))) { regmatch_t match; if (regexec(&_glfw.linjs.regex, entry->d_name, 1, &match, 0) != 0) continue; char path[PATH_MAX]; snprintf(path, sizeof(path), "%s/%s", dirname, entry->d_name); if (openJoystickDevice(path)) count++; } closedir(dir); } // Continue with no joysticks if enumeration fails qsort(_glfw.joysticks, count, sizeof(_GLFWjoystick), compareJoysticks); return GLFW_TRUE; } // Close all opened joystick handles // void _glfwTerminateJoysticksLinux(void) { int jid; for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) { _GLFWjoystick* js = _glfw.joysticks + jid; if (js->present) closeJoystick(js); } regfree(&_glfw.linjs.regex); if (_glfw.linjs.inotify > 0) { if (_glfw.linjs.watch > 0) inotify_rm_watch(_glfw.linjs.inotify, _glfw.linjs.watch); close(_glfw.linjs.inotify); } } void _glfwDetectJoystickConnectionLinux(void) { if (_glfw.linjs.inotify <= 0) return; ssize_t offset = 0; char buffer[16384]; const ssize_t size = read(_glfw.linjs.inotify, buffer, sizeof(buffer)); while (size > offset) { regmatch_t match; const struct inotify_event* e = (struct inotify_event*) (buffer + offset); offset += sizeof(struct inotify_event) + e->len; if (regexec(&_glfw.linjs.regex, e->name, 1, &match, 0) != 0) continue; char path[PATH_MAX]; snprintf(path, sizeof(path), "/dev/input/%s", e->name); if (e->mask & (IN_CREATE | IN_ATTRIB)) openJoystickDevice(path); else if (e->mask & IN_DELETE) { for (int jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) { if (strcmp(_glfw.joysticks[jid].linjs.path, path) == 0) { closeJoystick(_glfw.joysticks + jid); break; } } } } } ////////////////////////////////////////////////////////////////////////// ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode) { // Read all queued events (non-blocking) for (;;) { struct input_event e; errno = 0; if (read(js->linjs.fd, &e, sizeof(e)) < 0) { // Reset the joystick slot if the device was disconnected if (errno == ENODEV) closeJoystick(js); break; } if (e.type == EV_SYN) { if (e.code == SYN_DROPPED) _glfw.linjs.dropped = GLFW_TRUE; else if (e.code == SYN_REPORT) { _glfw.linjs.dropped = GLFW_FALSE; pollAbsState(js); } } if (_glfw.linjs.dropped) continue; if (e.type == EV_KEY) handleKeyEvent(js, e.code, e.value); else if (e.type == EV_ABS) handleAbsEvent(js, e.code, e.value); } return js->present; } void _glfwPlatformUpdateGamepadGUID(char* guid) { } #endif #ifndef HEADER_GUARD_XKB_UNICODE_C #define HEADER_GUARD_XKB_UNICODE_C //======================================================================== // GLFW 3.3.7 X11 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2017 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== // It is fine to use C99 in this file because it will not be built with VS //======================================================================== /* * Marcus: This code was originally written by Markus G. Kuhn. * I have made some slight changes (trimmed it down a bit from >60 KB to * 20 KB), but the functionality is the same. */ /* * This module converts keysym values into the corresponding ISO 10646 * (UCS, Unicode) values. * * The array keysymtab[] contains pairs of X11 keysym values for graphical * characters and the corresponding Unicode value. The function * _glfwKeySym2Unicode() maps a keysym onto a Unicode value using a binary * search, therefore keysymtab[] must remain SORTED by keysym value. * * We allow to represent any UCS character in the range U-00000000 to * U-00FFFFFF by a keysym value in the range 0x01000000 to 0x01ffffff. * This admittedly does not cover the entire 31-bit space of UCS, but * it does cover all of the characters up to U-10FFFF, which can be * represented by UTF-16, and more, and it is very unlikely that higher * UCS codes will ever be assigned by ISO. So to get Unicode character * U+ABCD you can directly use keysym 0x0100abcd. * * Original author: Markus G. Kuhn , University of * Cambridge, April 2001 * * Special thanks to Richard Verhoeven for preparing * an initial draft of the mapping table. * */ //************************************************************************ //**** KeySym to Unicode mapping table **** //************************************************************************ static const struct codepair { unsigned short keysym; unsigned short ucs; } keysymtab[] = { { 0x01a1, 0x0104 }, { 0x01a2, 0x02d8 }, { 0x01a3, 0x0141 }, { 0x01a5, 0x013d }, { 0x01a6, 0x015a }, { 0x01a9, 0x0160 }, { 0x01aa, 0x015e }, { 0x01ab, 0x0164 }, { 0x01ac, 0x0179 }, { 0x01ae, 0x017d }, { 0x01af, 0x017b }, { 0x01b1, 0x0105 }, { 0x01b2, 0x02db }, { 0x01b3, 0x0142 }, { 0x01b5, 0x013e }, { 0x01b6, 0x015b }, { 0x01b7, 0x02c7 }, { 0x01b9, 0x0161 }, { 0x01ba, 0x015f }, { 0x01bb, 0x0165 }, { 0x01bc, 0x017a }, { 0x01bd, 0x02dd }, { 0x01be, 0x017e }, { 0x01bf, 0x017c }, { 0x01c0, 0x0154 }, { 0x01c3, 0x0102 }, { 0x01c5, 0x0139 }, { 0x01c6, 0x0106 }, { 0x01c8, 0x010c }, { 0x01ca, 0x0118 }, { 0x01cc, 0x011a }, { 0x01cf, 0x010e }, { 0x01d0, 0x0110 }, { 0x01d1, 0x0143 }, { 0x01d2, 0x0147 }, { 0x01d5, 0x0150 }, { 0x01d8, 0x0158 }, { 0x01d9, 0x016e }, { 0x01db, 0x0170 }, { 0x01de, 0x0162 }, { 0x01e0, 0x0155 }, { 0x01e3, 0x0103 }, { 0x01e5, 0x013a }, { 0x01e6, 0x0107 }, { 0x01e8, 0x010d }, { 0x01ea, 0x0119 }, { 0x01ec, 0x011b }, { 0x01ef, 0x010f }, { 0x01f0, 0x0111 }, { 0x01f1, 0x0144 }, { 0x01f2, 0x0148 }, { 0x01f5, 0x0151 }, { 0x01f8, 0x0159 }, { 0x01f9, 0x016f }, { 0x01fb, 0x0171 }, { 0x01fe, 0x0163 }, { 0x01ff, 0x02d9 }, { 0x02a1, 0x0126 }, { 0x02a6, 0x0124 }, { 0x02a9, 0x0130 }, { 0x02ab, 0x011e }, { 0x02ac, 0x0134 }, { 0x02b1, 0x0127 }, { 0x02b6, 0x0125 }, { 0x02b9, 0x0131 }, { 0x02bb, 0x011f }, { 0x02bc, 0x0135 }, { 0x02c5, 0x010a }, { 0x02c6, 0x0108 }, { 0x02d5, 0x0120 }, { 0x02d8, 0x011c }, { 0x02dd, 0x016c }, { 0x02de, 0x015c }, { 0x02e5, 0x010b }, { 0x02e6, 0x0109 }, { 0x02f5, 0x0121 }, { 0x02f8, 0x011d }, { 0x02fd, 0x016d }, { 0x02fe, 0x015d }, { 0x03a2, 0x0138 }, { 0x03a3, 0x0156 }, { 0x03a5, 0x0128 }, { 0x03a6, 0x013b }, { 0x03aa, 0x0112 }, { 0x03ab, 0x0122 }, { 0x03ac, 0x0166 }, { 0x03b3, 0x0157 }, { 0x03b5, 0x0129 }, { 0x03b6, 0x013c }, { 0x03ba, 0x0113 }, { 0x03bb, 0x0123 }, { 0x03bc, 0x0167 }, { 0x03bd, 0x014a }, { 0x03bf, 0x014b }, { 0x03c0, 0x0100 }, { 0x03c7, 0x012e }, { 0x03cc, 0x0116 }, { 0x03cf, 0x012a }, { 0x03d1, 0x0145 }, { 0x03d2, 0x014c }, { 0x03d3, 0x0136 }, { 0x03d9, 0x0172 }, { 0x03dd, 0x0168 }, { 0x03de, 0x016a }, { 0x03e0, 0x0101 }, { 0x03e7, 0x012f }, { 0x03ec, 0x0117 }, { 0x03ef, 0x012b }, { 0x03f1, 0x0146 }, { 0x03f2, 0x014d }, { 0x03f3, 0x0137 }, { 0x03f9, 0x0173 }, { 0x03fd, 0x0169 }, { 0x03fe, 0x016b }, { 0x047e, 0x203e }, { 0x04a1, 0x3002 }, { 0x04a2, 0x300c }, { 0x04a3, 0x300d }, { 0x04a4, 0x3001 }, { 0x04a5, 0x30fb }, { 0x04a6, 0x30f2 }, { 0x04a7, 0x30a1 }, { 0x04a8, 0x30a3 }, { 0x04a9, 0x30a5 }, { 0x04aa, 0x30a7 }, { 0x04ab, 0x30a9 }, { 0x04ac, 0x30e3 }, { 0x04ad, 0x30e5 }, { 0x04ae, 0x30e7 }, { 0x04af, 0x30c3 }, { 0x04b0, 0x30fc }, { 0x04b1, 0x30a2 }, { 0x04b2, 0x30a4 }, { 0x04b3, 0x30a6 }, { 0x04b4, 0x30a8 }, { 0x04b5, 0x30aa }, { 0x04b6, 0x30ab }, { 0x04b7, 0x30ad }, { 0x04b8, 0x30af }, { 0x04b9, 0x30b1 }, { 0x04ba, 0x30b3 }, { 0x04bb, 0x30b5 }, { 0x04bc, 0x30b7 }, { 0x04bd, 0x30b9 }, { 0x04be, 0x30bb }, { 0x04bf, 0x30bd }, { 0x04c0, 0x30bf }, { 0x04c1, 0x30c1 }, { 0x04c2, 0x30c4 }, { 0x04c3, 0x30c6 }, { 0x04c4, 0x30c8 }, { 0x04c5, 0x30ca }, { 0x04c6, 0x30cb }, { 0x04c7, 0x30cc }, { 0x04c8, 0x30cd }, { 0x04c9, 0x30ce }, { 0x04ca, 0x30cf }, { 0x04cb, 0x30d2 }, { 0x04cc, 0x30d5 }, { 0x04cd, 0x30d8 }, { 0x04ce, 0x30db }, { 0x04cf, 0x30de }, { 0x04d0, 0x30df }, { 0x04d1, 0x30e0 }, { 0x04d2, 0x30e1 }, { 0x04d3, 0x30e2 }, { 0x04d4, 0x30e4 }, { 0x04d5, 0x30e6 }, { 0x04d6, 0x30e8 }, { 0x04d7, 0x30e9 }, { 0x04d8, 0x30ea }, { 0x04d9, 0x30eb }, { 0x04da, 0x30ec }, { 0x04db, 0x30ed }, { 0x04dc, 0x30ef }, { 0x04dd, 0x30f3 }, { 0x04de, 0x309b }, { 0x04df, 0x309c }, { 0x05ac, 0x060c }, { 0x05bb, 0x061b }, { 0x05bf, 0x061f }, { 0x05c1, 0x0621 }, { 0x05c2, 0x0622 }, { 0x05c3, 0x0623 }, { 0x05c4, 0x0624 }, { 0x05c5, 0x0625 }, { 0x05c6, 0x0626 }, { 0x05c7, 0x0627 }, { 0x05c8, 0x0628 }, { 0x05c9, 0x0629 }, { 0x05ca, 0x062a }, { 0x05cb, 0x062b }, { 0x05cc, 0x062c }, { 0x05cd, 0x062d }, { 0x05ce, 0x062e }, { 0x05cf, 0x062f }, { 0x05d0, 0x0630 }, { 0x05d1, 0x0631 }, { 0x05d2, 0x0632 }, { 0x05d3, 0x0633 }, { 0x05d4, 0x0634 }, { 0x05d5, 0x0635 }, { 0x05d6, 0x0636 }, { 0x05d7, 0x0637 }, { 0x05d8, 0x0638 }, { 0x05d9, 0x0639 }, { 0x05da, 0x063a }, { 0x05e0, 0x0640 }, { 0x05e1, 0x0641 }, { 0x05e2, 0x0642 }, { 0x05e3, 0x0643 }, { 0x05e4, 0x0644 }, { 0x05e5, 0x0645 }, { 0x05e6, 0x0646 }, { 0x05e7, 0x0647 }, { 0x05e8, 0x0648 }, { 0x05e9, 0x0649 }, { 0x05ea, 0x064a }, { 0x05eb, 0x064b }, { 0x05ec, 0x064c }, { 0x05ed, 0x064d }, { 0x05ee, 0x064e }, { 0x05ef, 0x064f }, { 0x05f0, 0x0650 }, { 0x05f1, 0x0651 }, { 0x05f2, 0x0652 }, { 0x06a1, 0x0452 }, { 0x06a2, 0x0453 }, { 0x06a3, 0x0451 }, { 0x06a4, 0x0454 }, { 0x06a5, 0x0455 }, { 0x06a6, 0x0456 }, { 0x06a7, 0x0457 }, { 0x06a8, 0x0458 }, { 0x06a9, 0x0459 }, { 0x06aa, 0x045a }, { 0x06ab, 0x045b }, { 0x06ac, 0x045c }, { 0x06ae, 0x045e }, { 0x06af, 0x045f }, { 0x06b0, 0x2116 }, { 0x06b1, 0x0402 }, { 0x06b2, 0x0403 }, { 0x06b3, 0x0401 }, { 0x06b4, 0x0404 }, { 0x06b5, 0x0405 }, { 0x06b6, 0x0406 }, { 0x06b7, 0x0407 }, { 0x06b8, 0x0408 }, { 0x06b9, 0x0409 }, { 0x06ba, 0x040a }, { 0x06bb, 0x040b }, { 0x06bc, 0x040c }, { 0x06be, 0x040e }, { 0x06bf, 0x040f }, { 0x06c0, 0x044e }, { 0x06c1, 0x0430 }, { 0x06c2, 0x0431 }, { 0x06c3, 0x0446 }, { 0x06c4, 0x0434 }, { 0x06c5, 0x0435 }, { 0x06c6, 0x0444 }, { 0x06c7, 0x0433 }, { 0x06c8, 0x0445 }, { 0x06c9, 0x0438 }, { 0x06ca, 0x0439 }, { 0x06cb, 0x043a }, { 0x06cc, 0x043b }, { 0x06cd, 0x043c }, { 0x06ce, 0x043d }, { 0x06cf, 0x043e }, { 0x06d0, 0x043f }, { 0x06d1, 0x044f }, { 0x06d2, 0x0440 }, { 0x06d3, 0x0441 }, { 0x06d4, 0x0442 }, { 0x06d5, 0x0443 }, { 0x06d6, 0x0436 }, { 0x06d7, 0x0432 }, { 0x06d8, 0x044c }, { 0x06d9, 0x044b }, { 0x06da, 0x0437 }, { 0x06db, 0x0448 }, { 0x06dc, 0x044d }, { 0x06dd, 0x0449 }, { 0x06de, 0x0447 }, { 0x06df, 0x044a }, { 0x06e0, 0x042e }, { 0x06e1, 0x0410 }, { 0x06e2, 0x0411 }, { 0x06e3, 0x0426 }, { 0x06e4, 0x0414 }, { 0x06e5, 0x0415 }, { 0x06e6, 0x0424 }, { 0x06e7, 0x0413 }, { 0x06e8, 0x0425 }, { 0x06e9, 0x0418 }, { 0x06ea, 0x0419 }, { 0x06eb, 0x041a }, { 0x06ec, 0x041b }, { 0x06ed, 0x041c }, { 0x06ee, 0x041d }, { 0x06ef, 0x041e }, { 0x06f0, 0x041f }, { 0x06f1, 0x042f }, { 0x06f2, 0x0420 }, { 0x06f3, 0x0421 }, { 0x06f4, 0x0422 }, { 0x06f5, 0x0423 }, { 0x06f6, 0x0416 }, { 0x06f7, 0x0412 }, { 0x06f8, 0x042c }, { 0x06f9, 0x042b }, { 0x06fa, 0x0417 }, { 0x06fb, 0x0428 }, { 0x06fc, 0x042d }, { 0x06fd, 0x0429 }, { 0x06fe, 0x0427 }, { 0x06ff, 0x042a }, { 0x07a1, 0x0386 }, { 0x07a2, 0x0388 }, { 0x07a3, 0x0389 }, { 0x07a4, 0x038a }, { 0x07a5, 0x03aa }, { 0x07a7, 0x038c }, { 0x07a8, 0x038e }, { 0x07a9, 0x03ab }, { 0x07ab, 0x038f }, { 0x07ae, 0x0385 }, { 0x07af, 0x2015 }, { 0x07b1, 0x03ac }, { 0x07b2, 0x03ad }, { 0x07b3, 0x03ae }, { 0x07b4, 0x03af }, { 0x07b5, 0x03ca }, { 0x07b6, 0x0390 }, { 0x07b7, 0x03cc }, { 0x07b8, 0x03cd }, { 0x07b9, 0x03cb }, { 0x07ba, 0x03b0 }, { 0x07bb, 0x03ce }, { 0x07c1, 0x0391 }, { 0x07c2, 0x0392 }, { 0x07c3, 0x0393 }, { 0x07c4, 0x0394 }, { 0x07c5, 0x0395 }, { 0x07c6, 0x0396 }, { 0x07c7, 0x0397 }, { 0x07c8, 0x0398 }, { 0x07c9, 0x0399 }, { 0x07ca, 0x039a }, { 0x07cb, 0x039b }, { 0x07cc, 0x039c }, { 0x07cd, 0x039d }, { 0x07ce, 0x039e }, { 0x07cf, 0x039f }, { 0x07d0, 0x03a0 }, { 0x07d1, 0x03a1 }, { 0x07d2, 0x03a3 }, { 0x07d4, 0x03a4 }, { 0x07d5, 0x03a5 }, { 0x07d6, 0x03a6 }, { 0x07d7, 0x03a7 }, { 0x07d8, 0x03a8 }, { 0x07d9, 0x03a9 }, { 0x07e1, 0x03b1 }, { 0x07e2, 0x03b2 }, { 0x07e3, 0x03b3 }, { 0x07e4, 0x03b4 }, { 0x07e5, 0x03b5 }, { 0x07e6, 0x03b6 }, { 0x07e7, 0x03b7 }, { 0x07e8, 0x03b8 }, { 0x07e9, 0x03b9 }, { 0x07ea, 0x03ba }, { 0x07eb, 0x03bb }, { 0x07ec, 0x03bc }, { 0x07ed, 0x03bd }, { 0x07ee, 0x03be }, { 0x07ef, 0x03bf }, { 0x07f0, 0x03c0 }, { 0x07f1, 0x03c1 }, { 0x07f2, 0x03c3 }, { 0x07f3, 0x03c2 }, { 0x07f4, 0x03c4 }, { 0x07f5, 0x03c5 }, { 0x07f6, 0x03c6 }, { 0x07f7, 0x03c7 }, { 0x07f8, 0x03c8 }, { 0x07f9, 0x03c9 }, { 0x08a1, 0x23b7 }, { 0x08a2, 0x250c }, { 0x08a3, 0x2500 }, { 0x08a4, 0x2320 }, { 0x08a5, 0x2321 }, { 0x08a6, 0x2502 }, { 0x08a7, 0x23a1 }, { 0x08a8, 0x23a3 }, { 0x08a9, 0x23a4 }, { 0x08aa, 0x23a6 }, { 0x08ab, 0x239b }, { 0x08ac, 0x239d }, { 0x08ad, 0x239e }, { 0x08ae, 0x23a0 }, { 0x08af, 0x23a8 }, { 0x08b0, 0x23ac }, { 0x08bc, 0x2264 }, { 0x08bd, 0x2260 }, { 0x08be, 0x2265 }, { 0x08bf, 0x222b }, { 0x08c0, 0x2234 }, { 0x08c1, 0x221d }, { 0x08c2, 0x221e }, { 0x08c5, 0x2207 }, { 0x08c8, 0x223c }, { 0x08c9, 0x2243 }, { 0x08cd, 0x21d4 }, { 0x08ce, 0x21d2 }, { 0x08cf, 0x2261 }, { 0x08d6, 0x221a }, { 0x08da, 0x2282 }, { 0x08db, 0x2283 }, { 0x08dc, 0x2229 }, { 0x08dd, 0x222a }, { 0x08de, 0x2227 }, { 0x08df, 0x2228 }, { 0x08ef, 0x2202 }, { 0x08f6, 0x0192 }, { 0x08fb, 0x2190 }, { 0x08fc, 0x2191 }, { 0x08fd, 0x2192 }, { 0x08fe, 0x2193 }, { 0x09e0, 0x25c6 }, { 0x09e1, 0x2592 }, { 0x09e2, 0x2409 }, { 0x09e3, 0x240c }, { 0x09e4, 0x240d }, { 0x09e5, 0x240a }, { 0x09e8, 0x2424 }, { 0x09e9, 0x240b }, { 0x09ea, 0x2518 }, { 0x09eb, 0x2510 }, { 0x09ec, 0x250c }, { 0x09ed, 0x2514 }, { 0x09ee, 0x253c }, { 0x09ef, 0x23ba }, { 0x09f0, 0x23bb }, { 0x09f1, 0x2500 }, { 0x09f2, 0x23bc }, { 0x09f3, 0x23bd }, { 0x09f4, 0x251c }, { 0x09f5, 0x2524 }, { 0x09f6, 0x2534 }, { 0x09f7, 0x252c }, { 0x09f8, 0x2502 }, { 0x0aa1, 0x2003 }, { 0x0aa2, 0x2002 }, { 0x0aa3, 0x2004 }, { 0x0aa4, 0x2005 }, { 0x0aa5, 0x2007 }, { 0x0aa6, 0x2008 }, { 0x0aa7, 0x2009 }, { 0x0aa8, 0x200a }, { 0x0aa9, 0x2014 }, { 0x0aaa, 0x2013 }, { 0x0aae, 0x2026 }, { 0x0aaf, 0x2025 }, { 0x0ab0, 0x2153 }, { 0x0ab1, 0x2154 }, { 0x0ab2, 0x2155 }, { 0x0ab3, 0x2156 }, { 0x0ab4, 0x2157 }, { 0x0ab5, 0x2158 }, { 0x0ab6, 0x2159 }, { 0x0ab7, 0x215a }, { 0x0ab8, 0x2105 }, { 0x0abb, 0x2012 }, { 0x0abc, 0x2329 }, { 0x0abe, 0x232a }, { 0x0ac3, 0x215b }, { 0x0ac4, 0x215c }, { 0x0ac5, 0x215d }, { 0x0ac6, 0x215e }, { 0x0ac9, 0x2122 }, { 0x0aca, 0x2613 }, { 0x0acc, 0x25c1 }, { 0x0acd, 0x25b7 }, { 0x0ace, 0x25cb }, { 0x0acf, 0x25af }, { 0x0ad0, 0x2018 }, { 0x0ad1, 0x2019 }, { 0x0ad2, 0x201c }, { 0x0ad3, 0x201d }, { 0x0ad4, 0x211e }, { 0x0ad6, 0x2032 }, { 0x0ad7, 0x2033 }, { 0x0ad9, 0x271d }, { 0x0adb, 0x25ac }, { 0x0adc, 0x25c0 }, { 0x0add, 0x25b6 }, { 0x0ade, 0x25cf }, { 0x0adf, 0x25ae }, { 0x0ae0, 0x25e6 }, { 0x0ae1, 0x25ab }, { 0x0ae2, 0x25ad }, { 0x0ae3, 0x25b3 }, { 0x0ae4, 0x25bd }, { 0x0ae5, 0x2606 }, { 0x0ae6, 0x2022 }, { 0x0ae7, 0x25aa }, { 0x0ae8, 0x25b2 }, { 0x0ae9, 0x25bc }, { 0x0aea, 0x261c }, { 0x0aeb, 0x261e }, { 0x0aec, 0x2663 }, { 0x0aed, 0x2666 }, { 0x0aee, 0x2665 }, { 0x0af0, 0x2720 }, { 0x0af1, 0x2020 }, { 0x0af2, 0x2021 }, { 0x0af3, 0x2713 }, { 0x0af4, 0x2717 }, { 0x0af5, 0x266f }, { 0x0af6, 0x266d }, { 0x0af7, 0x2642 }, { 0x0af8, 0x2640 }, { 0x0af9, 0x260e }, { 0x0afa, 0x2315 }, { 0x0afb, 0x2117 }, { 0x0afc, 0x2038 }, { 0x0afd, 0x201a }, { 0x0afe, 0x201e }, { 0x0ba3, 0x003c }, { 0x0ba6, 0x003e }, { 0x0ba8, 0x2228 }, { 0x0ba9, 0x2227 }, { 0x0bc0, 0x00af }, { 0x0bc2, 0x22a5 }, { 0x0bc3, 0x2229 }, { 0x0bc4, 0x230a }, { 0x0bc6, 0x005f }, { 0x0bca, 0x2218 }, { 0x0bcc, 0x2395 }, { 0x0bce, 0x22a4 }, { 0x0bcf, 0x25cb }, { 0x0bd3, 0x2308 }, { 0x0bd6, 0x222a }, { 0x0bd8, 0x2283 }, { 0x0bda, 0x2282 }, { 0x0bdc, 0x22a2 }, { 0x0bfc, 0x22a3 }, { 0x0cdf, 0x2017 }, { 0x0ce0, 0x05d0 }, { 0x0ce1, 0x05d1 }, { 0x0ce2, 0x05d2 }, { 0x0ce3, 0x05d3 }, { 0x0ce4, 0x05d4 }, { 0x0ce5, 0x05d5 }, { 0x0ce6, 0x05d6 }, { 0x0ce7, 0x05d7 }, { 0x0ce8, 0x05d8 }, { 0x0ce9, 0x05d9 }, { 0x0cea, 0x05da }, { 0x0ceb, 0x05db }, { 0x0cec, 0x05dc }, { 0x0ced, 0x05dd }, { 0x0cee, 0x05de }, { 0x0cef, 0x05df }, { 0x0cf0, 0x05e0 }, { 0x0cf1, 0x05e1 }, { 0x0cf2, 0x05e2 }, { 0x0cf3, 0x05e3 }, { 0x0cf4, 0x05e4 }, { 0x0cf5, 0x05e5 }, { 0x0cf6, 0x05e6 }, { 0x0cf7, 0x05e7 }, { 0x0cf8, 0x05e8 }, { 0x0cf9, 0x05e9 }, { 0x0cfa, 0x05ea }, { 0x0da1, 0x0e01 }, { 0x0da2, 0x0e02 }, { 0x0da3, 0x0e03 }, { 0x0da4, 0x0e04 }, { 0x0da5, 0x0e05 }, { 0x0da6, 0x0e06 }, { 0x0da7, 0x0e07 }, { 0x0da8, 0x0e08 }, { 0x0da9, 0x0e09 }, { 0x0daa, 0x0e0a }, { 0x0dab, 0x0e0b }, { 0x0dac, 0x0e0c }, { 0x0dad, 0x0e0d }, { 0x0dae, 0x0e0e }, { 0x0daf, 0x0e0f }, { 0x0db0, 0x0e10 }, { 0x0db1, 0x0e11 }, { 0x0db2, 0x0e12 }, { 0x0db3, 0x0e13 }, { 0x0db4, 0x0e14 }, { 0x0db5, 0x0e15 }, { 0x0db6, 0x0e16 }, { 0x0db7, 0x0e17 }, { 0x0db8, 0x0e18 }, { 0x0db9, 0x0e19 }, { 0x0dba, 0x0e1a }, { 0x0dbb, 0x0e1b }, { 0x0dbc, 0x0e1c }, { 0x0dbd, 0x0e1d }, { 0x0dbe, 0x0e1e }, { 0x0dbf, 0x0e1f }, { 0x0dc0, 0x0e20 }, { 0x0dc1, 0x0e21 }, { 0x0dc2, 0x0e22 }, { 0x0dc3, 0x0e23 }, { 0x0dc4, 0x0e24 }, { 0x0dc5, 0x0e25 }, { 0x0dc6, 0x0e26 }, { 0x0dc7, 0x0e27 }, { 0x0dc8, 0x0e28 }, { 0x0dc9, 0x0e29 }, { 0x0dca, 0x0e2a }, { 0x0dcb, 0x0e2b }, { 0x0dcc, 0x0e2c }, { 0x0dcd, 0x0e2d }, { 0x0dce, 0x0e2e }, { 0x0dcf, 0x0e2f }, { 0x0dd0, 0x0e30 }, { 0x0dd1, 0x0e31 }, { 0x0dd2, 0x0e32 }, { 0x0dd3, 0x0e33 }, { 0x0dd4, 0x0e34 }, { 0x0dd5, 0x0e35 }, { 0x0dd6, 0x0e36 }, { 0x0dd7, 0x0e37 }, { 0x0dd8, 0x0e38 }, { 0x0dd9, 0x0e39 }, { 0x0dda, 0x0e3a }, { 0x0ddf, 0x0e3f }, { 0x0de0, 0x0e40 }, { 0x0de1, 0x0e41 }, { 0x0de2, 0x0e42 }, { 0x0de3, 0x0e43 }, { 0x0de4, 0x0e44 }, { 0x0de5, 0x0e45 }, { 0x0de6, 0x0e46 }, { 0x0de7, 0x0e47 }, { 0x0de8, 0x0e48 }, { 0x0de9, 0x0e49 }, { 0x0dea, 0x0e4a }, { 0x0deb, 0x0e4b }, { 0x0dec, 0x0e4c }, { 0x0ded, 0x0e4d }, { 0x0df0, 0x0e50 }, { 0x0df1, 0x0e51 }, { 0x0df2, 0x0e52 }, { 0x0df3, 0x0e53 }, { 0x0df4, 0x0e54 }, { 0x0df5, 0x0e55 }, { 0x0df6, 0x0e56 }, { 0x0df7, 0x0e57 }, { 0x0df8, 0x0e58 }, { 0x0df9, 0x0e59 }, { 0x0ea1, 0x3131 }, { 0x0ea2, 0x3132 }, { 0x0ea3, 0x3133 }, { 0x0ea4, 0x3134 }, { 0x0ea5, 0x3135 }, { 0x0ea6, 0x3136 }, { 0x0ea7, 0x3137 }, { 0x0ea8, 0x3138 }, { 0x0ea9, 0x3139 }, { 0x0eaa, 0x313a }, { 0x0eab, 0x313b }, { 0x0eac, 0x313c }, { 0x0ead, 0x313d }, { 0x0eae, 0x313e }, { 0x0eaf, 0x313f }, { 0x0eb0, 0x3140 }, { 0x0eb1, 0x3141 }, { 0x0eb2, 0x3142 }, { 0x0eb3, 0x3143 }, { 0x0eb4, 0x3144 }, { 0x0eb5, 0x3145 }, { 0x0eb6, 0x3146 }, { 0x0eb7, 0x3147 }, { 0x0eb8, 0x3148 }, { 0x0eb9, 0x3149 }, { 0x0eba, 0x314a }, { 0x0ebb, 0x314b }, { 0x0ebc, 0x314c }, { 0x0ebd, 0x314d }, { 0x0ebe, 0x314e }, { 0x0ebf, 0x314f }, { 0x0ec0, 0x3150 }, { 0x0ec1, 0x3151 }, { 0x0ec2, 0x3152 }, { 0x0ec3, 0x3153 }, { 0x0ec4, 0x3154 }, { 0x0ec5, 0x3155 }, { 0x0ec6, 0x3156 }, { 0x0ec7, 0x3157 }, { 0x0ec8, 0x3158 }, { 0x0ec9, 0x3159 }, { 0x0eca, 0x315a }, { 0x0ecb, 0x315b }, { 0x0ecc, 0x315c }, { 0x0ecd, 0x315d }, { 0x0ece, 0x315e }, { 0x0ecf, 0x315f }, { 0x0ed0, 0x3160 }, { 0x0ed1, 0x3161 }, { 0x0ed2, 0x3162 }, { 0x0ed3, 0x3163 }, { 0x0ed4, 0x11a8 }, { 0x0ed5, 0x11a9 }, { 0x0ed6, 0x11aa }, { 0x0ed7, 0x11ab }, { 0x0ed8, 0x11ac }, { 0x0ed9, 0x11ad }, { 0x0eda, 0x11ae }, { 0x0edb, 0x11af }, { 0x0edc, 0x11b0 }, { 0x0edd, 0x11b1 }, { 0x0ede, 0x11b2 }, { 0x0edf, 0x11b3 }, { 0x0ee0, 0x11b4 }, { 0x0ee1, 0x11b5 }, { 0x0ee2, 0x11b6 }, { 0x0ee3, 0x11b7 }, { 0x0ee4, 0x11b8 }, { 0x0ee5, 0x11b9 }, { 0x0ee6, 0x11ba }, { 0x0ee7, 0x11bb }, { 0x0ee8, 0x11bc }, { 0x0ee9, 0x11bd }, { 0x0eea, 0x11be }, { 0x0eeb, 0x11bf }, { 0x0eec, 0x11c0 }, { 0x0eed, 0x11c1 }, { 0x0eee, 0x11c2 }, { 0x0eef, 0x316d }, { 0x0ef0, 0x3171 }, { 0x0ef1, 0x3178 }, { 0x0ef2, 0x317f }, { 0x0ef3, 0x3181 }, { 0x0ef4, 0x3184 }, { 0x0ef5, 0x3186 }, { 0x0ef6, 0x318d }, { 0x0ef7, 0x318e }, { 0x0ef8, 0x11eb }, { 0x0ef9, 0x11f0 }, { 0x0efa, 0x11f9 }, { 0x0eff, 0x20a9 }, { 0x13a4, 0x20ac }, { 0x13bc, 0x0152 }, { 0x13bd, 0x0153 }, { 0x13be, 0x0178 }, { 0x20ac, 0x20ac }, { 0xfe50, '`' }, { 0xfe51, 0x00b4 }, { 0xfe52, '^' }, { 0xfe53, '~' }, { 0xfe54, 0x00af }, { 0xfe55, 0x02d8 }, { 0xfe56, 0x02d9 }, { 0xfe57, 0x00a8 }, { 0xfe58, 0x02da }, { 0xfe59, 0x02dd }, { 0xfe5a, 0x02c7 }, { 0xfe5b, 0x00b8 }, { 0xfe5c, 0x02db }, { 0xfe5d, 0x037a }, { 0xfe5e, 0x309b }, { 0xfe5f, 0x309c }, { 0xfe63, '/' }, { 0xfe64, 0x02bc }, { 0xfe65, 0x02bd }, { 0xfe66, 0x02f5 }, { 0xfe67, 0x02f3 }, { 0xfe68, 0x02cd }, { 0xfe69, 0xa788 }, { 0xfe6a, 0x02f7 }, { 0xfe6e, ',' }, { 0xfe6f, 0x00a4 }, { 0xfe80, 'a' }, // XK_dead_a { 0xfe81, 'A' }, // XK_dead_A { 0xfe82, 'e' }, // XK_dead_e { 0xfe83, 'E' }, // XK_dead_E { 0xfe84, 'i' }, // XK_dead_i { 0xfe85, 'I' }, // XK_dead_I { 0xfe86, 'o' }, // XK_dead_o { 0xfe87, 'O' }, // XK_dead_O { 0xfe88, 'u' }, // XK_dead_u { 0xfe89, 'U' }, // XK_dead_U { 0xfe8a, 0x0259 }, { 0xfe8b, 0x018f }, { 0xfe8c, 0x00b5 }, { 0xfe90, '_' }, { 0xfe91, 0x02c8 }, { 0xfe92, 0x02cc }, { 0xff80 /*XKB_KEY_KP_Space*/, ' ' }, { 0xff95 /*XKB_KEY_KP_7*/, 0x0037 }, { 0xff96 /*XKB_KEY_KP_4*/, 0x0034 }, { 0xff97 /*XKB_KEY_KP_8*/, 0x0038 }, { 0xff98 /*XKB_KEY_KP_6*/, 0x0036 }, { 0xff99 /*XKB_KEY_KP_2*/, 0x0032 }, { 0xff9a /*XKB_KEY_KP_9*/, 0x0039 }, { 0xff9b /*XKB_KEY_KP_3*/, 0x0033 }, { 0xff9c /*XKB_KEY_KP_1*/, 0x0031 }, { 0xff9d /*XKB_KEY_KP_5*/, 0x0035 }, { 0xff9e /*XKB_KEY_KP_0*/, 0x0030 }, { 0xffaa /*XKB_KEY_KP_Multiply*/, '*' }, { 0xffab /*XKB_KEY_KP_Add*/, '+' }, { 0xffac /*XKB_KEY_KP_Separator*/, ',' }, { 0xffad /*XKB_KEY_KP_Subtract*/, '-' }, { 0xffae /*XKB_KEY_KP_Decimal*/, '.' }, { 0xffaf /*XKB_KEY_KP_Divide*/, '/' }, { 0xffb0 /*XKB_KEY_KP_0*/, 0x0030 }, { 0xffb1 /*XKB_KEY_KP_1*/, 0x0031 }, { 0xffb2 /*XKB_KEY_KP_2*/, 0x0032 }, { 0xffb3 /*XKB_KEY_KP_3*/, 0x0033 }, { 0xffb4 /*XKB_KEY_KP_4*/, 0x0034 }, { 0xffb5 /*XKB_KEY_KP_5*/, 0x0035 }, { 0xffb6 /*XKB_KEY_KP_6*/, 0x0036 }, { 0xffb7 /*XKB_KEY_KP_7*/, 0x0037 }, { 0xffb8 /*XKB_KEY_KP_8*/, 0x0038 }, { 0xffb9 /*XKB_KEY_KP_9*/, 0x0039 }, { 0xffbd /*XKB_KEY_KP_Equal*/, '=' } }; ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// // Convert XKB KeySym to Unicode // uint32_t _glfwKeySym2Unicode(unsigned int keysym) { int min = 0; int max = sizeof(keysymtab) / sizeof(struct codepair) - 1; int mid; // First check for Latin-1 characters (1:1 mapping) if ((keysym >= 0x0020 && keysym <= 0x007e) || (keysym >= 0x00a0 && keysym <= 0x00ff)) { return keysym; } // Also check for directly encoded 24-bit UCS characters if ((keysym & 0xff000000) == 0x01000000) return keysym & 0x00ffffff; // Binary search in table while (max >= min) { mid = (min + max) / 2; if (keysymtab[mid].keysym < keysym) min = mid + 1; else if (keysymtab[mid].keysym > keysym) max = mid - 1; else return keysymtab[mid].ucs; } // No matching Unicode value found return GLFW_INVALID_CODEPOINT; } #endif #endif #endif #endif /* __EMSCRIPTEN__ */