39194 lines
1.4 MiB
39194 lines
1.4 MiB
#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 <glfw.h> 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 <elmindreda@glfw.org>
|
||
*
|
||
* 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 <stddef.h>
|
||
|
||
/* Include because it is needed by Vulkan and related functions.
|
||
* Include it unconditionally to avoid surprising side-effects.
|
||
*/
|
||
#include <stdint.h>
|
||
|
||
#if defined(GLFW_INCLUDE_VULKAN)
|
||
#include <vulkan/vulkan.h>
|
||
#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 <GLES/gl.h>
|
||
#if defined(GLFW_INCLUDE_GLEXT)
|
||
#include <GLES/glext.h>
|
||
#endif
|
||
|
||
#elif defined(GLFW_INCLUDE_ES2)
|
||
|
||
#include <GLES2/gl2.h>
|
||
#if defined(GLFW_INCLUDE_GLEXT)
|
||
#include <GLES2/gl2ext.h>
|
||
#endif
|
||
|
||
#elif defined(GLFW_INCLUDE_ES3)
|
||
|
||
#include <GLES3/gl3.h>
|
||
#if defined(GLFW_INCLUDE_GLEXT)
|
||
#include <GLES2/gl2ext.h>
|
||
#endif
|
||
|
||
#elif defined(GLFW_INCLUDE_ES31)
|
||
|
||
#include <GLES3/gl31.h>
|
||
#if defined(GLFW_INCLUDE_GLEXT)
|
||
#include <GLES2/gl2ext.h>
|
||
#endif
|
||
|
||
#elif defined(GLFW_INCLUDE_ES32)
|
||
|
||
#include <GLES3/gl32.h>
|
||
#if defined(GLFW_INCLUDE_GLEXT)
|
||
#include <GLES2/gl2ext.h>
|
||
#endif
|
||
|
||
#elif defined(GLFW_INCLUDE_GLCOREARB)
|
||
|
||
#if defined(__APPLE__)
|
||
|
||
#include <OpenGL/gl3.h>
|
||
#if defined(GLFW_INCLUDE_GLEXT)
|
||
#include <OpenGL/gl3ext.h>
|
||
#endif /*GLFW_INCLUDE_GLEXT*/
|
||
|
||
#else /*__APPLE__*/
|
||
|
||
#include <GL/glcorearb.h>
|
||
#if defined(GLFW_INCLUDE_GLEXT)
|
||
#include <GL/glext.h>
|
||
#endif
|
||
|
||
#endif /*__APPLE__*/
|
||
|
||
#elif defined(GLFW_INCLUDE_GLU)
|
||
|
||
#if defined(__APPLE__)
|
||
|
||
#if defined(GLFW_INCLUDE_GLU)
|
||
#include <OpenGL/glu.h>
|
||
#endif
|
||
|
||
#else /*__APPLE__*/
|
||
|
||
#if defined(GLFW_INCLUDE_GLU)
|
||
#include <GL/glu.h>
|
||
#endif
|
||
|
||
#endif /*__APPLE__*/
|
||
|
||
#elif !defined(GLFW_INCLUDE_NONE) && \
|
||
!defined(__gl_h_) && \
|
||
!defined(__gles1_gl_h_) && \
|
||
!defined(__gles2_gl2_h_) && \
|
||
!defined(__gles2_gl3_h_) && \
|
||
!defined(__gles2_gl31_h_) && \
|
||
!defined(__gles2_gl32_h_) && \
|
||
!defined(__gl_glcorearb_h_) && \
|
||
!defined(__gl2_h_) /*legacy*/ && \
|
||
!defined(__gl3_h_) /*legacy*/ && \
|
||
!defined(__gl31_h_) /*legacy*/ && \
|
||
!defined(__gl32_h_) /*legacy*/ && \
|
||
!defined(__glcorearb_h_) /*legacy*/ && \
|
||
!defined(__GL_H__) /*non-standard*/ && \
|
||
!defined(__gltypes_h_) /*non-standard*/ && \
|
||
!defined(__glee_h_) /*non-standard*/
|
||
|
||
#if defined(__APPLE__)
|
||
|
||
#if !defined(GLFW_INCLUDE_GLEXT)
|
||
#define GL_GLEXT_LEGACY
|
||
#endif
|
||
#include <OpenGL/gl.h>
|
||
|
||
#else /*__APPLE__*/
|
||
|
||
#include <GL/gl.h>
|
||
#if defined(GLFW_INCLUDE_GLEXT)
|
||
#include <GL/glext.h>
|
||
#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((2<sup>64</sup> - 1) / 10<sup>9</sup>) 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 <elmindreda@glfw.org>
|
||
*
|
||
* 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 <windows.h>
|
||
#elif defined(GLFW_EXPOSE_NATIVE_COCOA) || defined(GLFW_EXPOSE_NATIVE_NSGL)
|
||
#if defined(__OBJC__)
|
||
#import <Cocoa/Cocoa.h>
|
||
#else
|
||
#include <ApplicationServices/ApplicationServices.h>
|
||
typedef void* id;
|
||
#endif
|
||
#elif defined(GLFW_EXPOSE_NATIVE_X11) || defined(GLFW_EXPOSE_NATIVE_GLX)
|
||
#include <X11/Xlib.h>
|
||
#include <X11/extensions/Xrandr.h>
|
||
#elif defined(GLFW_EXPOSE_NATIVE_WAYLAND)
|
||
#include <wayland-client.h>
|
||
#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 <GL/glx.h>
|
||
#endif
|
||
#if defined(GLFW_EXPOSE_NATIVE_EGL)
|
||
#include <EGL/egl.h>
|
||
#endif
|
||
#if defined(GLFW_EXPOSE_NATIVE_OSMESA)
|
||
#include <GL/osmesa.h>
|
||
#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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <stdint.h>
|
||
#include <dlfcn.h>
|
||
|
||
#include <Carbon/Carbon.h>
|
||
|
||
// NOTE: All of NSGL was deprecated in the 10.14 SDK
|
||
// This disables the pointless warnings for every symbol we use
|
||
#ifndef GL_SILENCE_DEPRECATION
|
||
#define GL_SILENCE_DEPRECATION
|
||
#endif
|
||
|
||
#if defined(__OBJC__)
|
||
#import <Cocoa/Cocoa.h>
|
||
#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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <pthread.h>
|
||
|
||
#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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <IOKit/IOKitLib.h>
|
||
#include <IOKit/IOCFPlugIn.h>
|
||
#include <IOKit/hid/IOHIDLib.h>
|
||
#include <IOKit/hid/IOHIDKeys.h>
|
||
|
||
#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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <stdatomic.h>
|
||
|
||
|
||
// 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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <EGL/eglplatform.h>
|
||
#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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <wctype.h>
|
||
#include <windows.h>
|
||
#include <dinput.h>
|
||
#include <xinput.h>
|
||
#include <dbt.h>
|
||
|
||
// 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 <dwmapi.h>
|
||
#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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <EGL/eglplatform.h>
|
||
#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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <unistd.h>
|
||
#include <signal.h>
|
||
#include <stdint.h>
|
||
#include <dlfcn.h>
|
||
|
||
#include <X11/Xlib.h>
|
||
#include <X11/keysym.h>
|
||
#include <X11/Xatom.h>
|
||
#include <X11/Xcursor/Xcursor.h>
|
||
|
||
// The XRandR extension provides mode setting and gamma control
|
||
#include <X11/extensions/Xrandr.h>
|
||
|
||
// The Xkb extension provides improved keyboard support
|
||
#include <X11/XKBlib.h>
|
||
|
||
// The Xinerama extension provides legacy monitor indices
|
||
#include <X11/extensions/Xinerama.h>
|
||
|
||
// The XInput extension provides raw mouse motion input
|
||
#include <X11/extensions/XInput2.h>
|
||
|
||
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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <pthread.h>
|
||
|
||
#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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <stdint.h>
|
||
|
||
|
||
// 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 <jadahl@gmail.com>
|
||
//
|
||
// 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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <EGL/eglplatform.h>
|
||
#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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <jadahl@gmail.com>
|
||
//
|
||
// 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 <linux/input.h>
|
||
#include <linux/limits.h>
|
||
#include <regex.h>
|
||
|
||
#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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <jadahl@gmail.com>
|
||
//
|
||
// 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 <wayland-client.h>
|
||
#include <xkbcommon/xkbcommon.h>
|
||
#include <xkbcommon/xkbcommon-compose.h>
|
||
#include <dlfcn.h>
|
||
|
||
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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <pthread.h>
|
||
|
||
#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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <stdint.h>
|
||
|
||
|
||
// 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 <jadahl@gmail.com>
|
||
//
|
||
// 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 <linux/input.h>
|
||
#include <linux/limits.h>
|
||
#include <regex.h>
|
||
|
||
#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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <jadahl@gmail.com>
|
||
//
|
||
// 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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <EGL/eglplatform.h>
|
||
#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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <dlfcn.h>
|
||
|
||
#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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <stdint.h>
|
||
|
||
|
||
// 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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <pthread.h>
|
||
|
||
#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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <stdlib.h>
|
||
#include <string.h>
|
||
#include <assert.h>
|
||
|
||
|
||
|
||
|
||
|
||
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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <stdio.h>
|
||
#include <string.h>
|
||
#include <stdlib.h>
|
||
#include <assert.h>
|
||
|
||
|
||
// 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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <assert.h>
|
||
#include <stdio.h>
|
||
#include <string.h>
|
||
#include <limits.h>
|
||
#include <stdio.h>
|
||
|
||
|
||
//////////////////////////////////////////////////////////////////////////
|
||
////// 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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <string.h>
|
||
#include <stdlib.h>
|
||
#include <stdio.h>
|
||
#include <stdarg.h>
|
||
#include <assert.h>
|
||
|
||
|
||
// 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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <slouken@libsdl.org>
|
||
//
|
||
// 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 <assert.h>
|
||
#include <float.h>
|
||
#include <math.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
|
||
// 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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <assert.h>
|
||
#include <math.h>
|
||
#include <float.h>
|
||
#include <string.h>
|
||
#include <stdlib.h>
|
||
#include <limits.h>
|
||
|
||
|
||
// 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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <assert.h>
|
||
#include <string.h>
|
||
#include <stdlib.h>
|
||
|
||
#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 <elmindreda@glfw.org>
|
||
// Copyright (c) 2012 Torsten Walluhn <tw@mad-cad.net>
|
||
//
|
||
// 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 <assert.h>
|
||
#include <string.h>
|
||
#include <stdlib.h>
|
||
#include <float.h>
|
||
|
||
|
||
//////////////////////////////////////////////////////////////////////////
|
||
////// 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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <stdlib.h>
|
||
#include <malloc.h>
|
||
|
||
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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <stdio.h>
|
||
#include <math.h>
|
||
|
||
#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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <stdlib.h>
|
||
#include <string.h>
|
||
#include <limits.h>
|
||
#include <malloc.h>
|
||
#include <wchar.h>
|
||
|
||
|
||
// 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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <assert.h>
|
||
|
||
|
||
//////////////////////////////////////////////////////////////////////////
|
||
////// 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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <limits.h>
|
||
#include <stdlib.h>
|
||
#include <malloc.h>
|
||
#include <string.h>
|
||
#include <windowsx.h>
|
||
#include <shellapi.h>
|
||
|
||
// 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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <stdlib.h>
|
||
#include <malloc.h>
|
||
#include <assert.h>
|
||
|
||
// 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)
|
||
{
|
||
if (IsWindowsVistaOrGreater())
|
||
{
|
||
// DWM Composition is always enabled on Win8+
|
||
BOOL enabled = IsWindows8OrGreater();
|
||
|
||
// HACK: Use DwmFlush when desktop composition is enabled
|
||
if (enabled ||
|
||
(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);
|
||
|
||
window->context.wgl.interval = interval;
|
||
|
||
if (!window->monitor)
|
||
{
|
||
if (IsWindowsVistaOrGreater())
|
||
{
|
||
// DWM Composition is always enabled on Win8+
|
||
BOOL enabled = IsWindows8OrGreater();
|
||
|
||
// HACK: Disable WGL swap interval when desktop composition is enabled to
|
||
// avoid interfering with DWM vsync
|
||
if (enabled ||
|
||
(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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <X11/Xresource.h>
|
||
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
#include <limits.h>
|
||
#include <stdio.h>
|
||
#include <locale.h>
|
||
#include <unistd.h>
|
||
#include <fcntl.h>
|
||
#include <errno.h>
|
||
|
||
|
||
// 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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <limits.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
#include <math.h>
|
||
|
||
|
||
// 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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <X11/cursorfont.h>
|
||
#include <X11/Xmd.h>
|
||
|
||
#include <poll.h>
|
||
#include <signal.h>
|
||
#include <time.h>
|
||
|
||
#include <string.h>
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <limits.h>
|
||
#include <errno.h>
|
||
#include <assert.h>
|
||
|
||
// 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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <string.h>
|
||
#include <stdlib.h>
|
||
#include <assert.h>
|
||
|
||
#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 <jadahl@gmail.com>
|
||
//
|
||
// 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 <assert.h>
|
||
#include <errno.h>
|
||
#include <limits.h>
|
||
#include <linux/input.h>
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
#include <sys/mman.h>
|
||
#include <sys/timerfd.h>
|
||
#include <unistd.h>
|
||
#include <wayland-client.h>
|
||
|
||
|
||
static inline int min(int n1, int n2)
|
||
{
|
||
return n1 < n2 ? n1 : n2;
|
||
}
|
||
|
||
static _GLFWwindow* findWindowFromDecorationSurface(struct wl_surface* surface,
|
||
int* which)
|
||
{
|
||
int focus;
|
||
_GLFWwindow* window = _glfw.windowListHead;
|
||
if (!which)
|
||
which = &focus;
|
||
while (window)
|
||
{
|
||
if (surface == window->wl.decorations.top.surface)
|
||
{
|
||
*which = topDecoration;
|
||
break;
|
||
}
|
||
if (surface == window->wl.decorations.left.surface)
|
||
{
|
||
*which = leftDecoration;
|
||
break;
|
||
}
|
||
if (surface == window->wl.decorations.right.surface)
|
||
{
|
||
*which = rightDecoration;
|
||
break;
|
||
}
|
||
if (surface == window->wl.decorations.bottom.surface)
|
||
{
|
||
*which = bottomDecoration;
|
||
break;
|
||
}
|
||
window = window->next;
|
||
}
|
||
return window;
|
||
}
|
||
|
||
static void pointerHandleEnter(void* data,
|
||
struct wl_pointer* pointer,
|
||
uint32_t serial,
|
||
struct wl_surface* surface,
|
||
wl_fixed_t sx,
|
||
wl_fixed_t sy)
|
||
{
|
||
// Happens in the case we just destroyed the surface.
|
||
if (!surface)
|
||
return;
|
||
|
||
int focus = 0;
|
||
_GLFWwindow* window = wl_surface_get_user_data(surface);
|
||
if (!window)
|
||
{
|
||
window = findWindowFromDecorationSurface(surface, &focus);
|
||
if (!window)
|
||
return;
|
||
}
|
||
|
||
window->wl.decorations.focus = focus;
|
||
_glfw.wl.serial = serial;
|
||
_glfw.wl.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 <jadahl@gmail.com>
|
||
//
|
||
// 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 <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
#include <errno.h>
|
||
#include <math.h>
|
||
|
||
|
||
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 <jadahl@gmail.com>
|
||
//
|
||
// 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 <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <errno.h>
|
||
#include <unistd.h>
|
||
#include <string.h>
|
||
#include <fcntl.h>
|
||
#include <sys/mman.h>
|
||
#include <sys/timerfd.h>
|
||
#include <poll.h>
|
||
#include <signal.h>
|
||
#include <time.h>
|
||
|
||
static void shellSurfaceHandlePing(void* data,
|
||
struct wl_shell_surface* shellSurface,
|
||
uint32_t serial)
|
||
{
|
||
wl_shell_surface_pong(shellSurface, serial);
|
||
}
|
||
|
||
static void shellSurfaceHandleConfigure(void* data,
|
||
struct wl_shell_surface* shellSurface,
|
||
uint32_t edges,
|
||
int32_t width,
|
||
int32_t height)
|
||
{
|
||
_GLFWwindow* window = data;
|
||
float aspectRatio;
|
||
float targetRatio;
|
||
|
||
if (!window->monitor)
|
||
{
|
||
if (_glfw.wl.viewporter && window->decorated)
|
||
{
|
||
width -= _GLFW_DECORATION_HORIZONTAL;
|
||
height -= _GLFW_DECORATION_VERTICAL;
|
||
}
|
||
if (width < 1)
|
||
width = 1;
|
||
if (height < 1)
|
||
height = 1;
|
||
|
||
if (window->numer != GLFW_DONT_CARE && window->denom != GLFW_DONT_CARE)
|
||
{
|
||
aspectRatio = (float)width / (float)height;
|
||
targetRatio = (float)window->numer / (float)window->denom;
|
||
if (aspectRatio < targetRatio)
|
||
height = width / targetRatio;
|
||
else if (aspectRatio > targetRatio)
|
||
width = height * targetRatio;
|
||
}
|
||
|
||
if (window->minwidth != GLFW_DONT_CARE && width < window->minwidth)
|
||
width = window->minwidth;
|
||
else if (window->maxwidth != GLFW_DONT_CARE && width > window->maxwidth)
|
||
width = window->maxwidth;
|
||
|
||
if (window->minheight != GLFW_DONT_CARE && height < window->minheight)
|
||
height = window->minheight;
|
||
else if (window->maxheight != GLFW_DONT_CARE && height > window->maxheight)
|
||
height = window->maxheight;
|
||
}
|
||
|
||
_glfwInputWindowSize(window, width, height);
|
||
_glfwPlatformSetWindowSize(window, width, height);
|
||
_glfwInputWindowDamage(window);
|
||
}
|
||
|
||
static void shellSurfaceHandlePopupDone(void* data,
|
||
struct wl_shell_surface* shellSurface)
|
||
{
|
||
}
|
||
|
||
static const struct wl_shell_surface_listener shellSurfaceListener = {
|
||
shellSurfaceHandlePing,
|
||
shellSurfaceHandleConfigure,
|
||
shellSurfaceHandlePopupDone
|
||
};
|
||
|
||
static int createTmpfileCloexec(char* tmpname)
|
||
{
|
||
int fd;
|
||
|
||
fd = mkostemp(tmpname, O_CLOEXEC);
|
||
if (fd >= 0)
|
||
unlink(tmpname);
|
||
|
||
return fd;
|
||
}
|
||
|
||
/*
|
||
* Create a new, unique, anonymous file of the given size, and
|
||
* return the file descriptor for it. The file descriptor is set
|
||
* CLOEXEC. The file is immediately suitable for mmap()'ing
|
||
* the given size at offset zero.
|
||
*
|
||
* The file should not have a permanent backing store like a disk,
|
||
* but may have if XDG_RUNTIME_DIR is not properly implemented in OS.
|
||
*
|
||
* The file name is deleted from the file system.
|
||
*
|
||
* The file is suitable for buffer sharing between processes by
|
||
* transmitting the file descriptor over Unix sockets using the
|
||
* SCM_RIGHTS methods.
|
||
*
|
||
* posix_fallocate() is used to guarantee that disk space is available
|
||
* for the file at the given size. If disk space is insufficient, errno
|
||
* is set to ENOSPC. If posix_fallocate() is not supported, program may
|
||
* receive SIGBUS on accessing mmap()'ed file contents instead.
|
||
*/
|
||
static int createAnonymousFile(off_t size)
|
||
{
|
||
static const char template[] = "/glfw-shared-XXXXXX";
|
||
const char* path;
|
||
char* name;
|
||
int fd;
|
||
int ret;
|
||
|
||
#ifdef HAVE_MEMFD_CREATE
|
||
fd = memfd_create("glfw-shared", MFD_CLOEXEC | MFD_ALLOW_SEALING);
|
||
if (fd >= 0)
|
||
{
|
||
// We can add this seal before calling posix_fallocate(), as the file
|
||
// is currently zero-sized anyway.
|
||
//
|
||
// There is also no need to check for the return value, we couldn’t do
|
||
// anything with it anyway.
|
||
fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_SEAL);
|
||
}
|
||
else
|
||
#elif defined(SHM_ANON)
|
||
fd = shm_open(SHM_ANON, O_RDWR | O_CLOEXEC, 0600);
|
||
if (fd < 0)
|
||
#endif
|
||
{
|
||
path = getenv("XDG_RUNTIME_DIR");
|
||
if (!path)
|
||
{
|
||
errno = ENOENT;
|
||
return -1;
|
||
}
|
||
|
||
name = calloc(strlen(path) + sizeof(template), 1);
|
||
strcpy(name, path);
|
||
strcat(name, template);
|
||
|
||
fd = createTmpfileCloexec(name);
|
||
free(name);
|
||
if (fd < 0)
|
||
return -1;
|
||
}
|
||
|
||
#if defined(SHM_ANON)
|
||
// posix_fallocate does not work on SHM descriptors
|
||
ret = ftruncate(fd, size);
|
||
#else
|
||
ret = posix_fallocate(fd, 0, size);
|
||
#endif
|
||
if (ret != 0)
|
||
{
|
||
close(fd);
|
||
errno = ret;
|
||
return -1;
|
||
}
|
||
return fd;
|
||
}
|
||
|
||
static struct wl_buffer* createShmBuffer(const GLFWimage* image)
|
||
{
|
||
struct wl_shm_pool* pool;
|
||
struct wl_buffer* buffer;
|
||
int stride = image->width * 4;
|
||
int length = image->width * image->height * 4;
|
||
void* data;
|
||
int fd, i;
|
||
|
||
fd = createAnonymousFile(length);
|
||
if (fd < 0)
|
||
{
|
||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||
"Wayland: Creating a buffer file for %d B failed: %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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <sys/param.h> // For MAXPATHLEN
|
||
|
||
// Needed for _NSGetProgname
|
||
#include <crt_externs.h>
|
||
|
||
// 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 <NSApplicationDelegate>
|
||
@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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <unistd.h>
|
||
#include <math.h>
|
||
|
||
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 <elmindreda@glfw.org>
|
||
// Copyright (c) 2012 Torsten Walluhn <tw@mad-cad.net>
|
||
//
|
||
// 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 <unistd.h>
|
||
#include <ctype.h>
|
||
#include <string.h>
|
||
|
||
#include <mach/mach.h>
|
||
#include <mach/mach_error.h>
|
||
|
||
#include <CoreFoundation/CoreFoundation.h>
|
||
#include <Kernel/IOKit/hidsystem/IOHIDUsageTables.h>
|
||
|
||
|
||
// 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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <stdlib.h>
|
||
#include <limits.h>
|
||
#include <math.h>
|
||
|
||
#include <IOKit/graphics/IOGraphicsLib.h>
|
||
#include <ApplicationServices/ApplicationServices.h>
|
||
|
||
|
||
// 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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <float.h>
|
||
#include <string.h>
|
||
|
||
// Returns the style mask corresponding to the window settings
|
||
//
|
||
static NSUInteger getStyleMask(_GLFWwindow* window)
|
||
{
|
||
NSUInteger styleMask = NSWindowStyleMaskMiniaturizable;
|
||
|
||
if (window->monitor || !window->decorated)
|
||
styleMask |= NSWindowStyleMaskBorderless;
|
||
else
|
||
{
|
||
styleMask |= NSWindowStyleMaskTitled |
|
||
NSWindowStyleMaskClosable;
|
||
|
||
if (window->resizable)
|
||
styleMask |= NSWindowStyleMaskResizable;
|
||
}
|
||
|
||
return styleMask;
|
||
}
|
||
|
||
// 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 <NSTextInputClient>
|
||
{
|
||
_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 <NSDraggingInfo>)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 <NSDraggingInfo>)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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <mach/mach_time.h>
|
||
|
||
|
||
//////////////////////////////////////////////////////////////////////////
|
||
////// 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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <sys/time.h>
|
||
#include <time.h>
|
||
|
||
|
||
//////////////////////////////////////////////////////////////////////////
|
||
////// 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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <assert.h>
|
||
#include <string.h>
|
||
|
||
|
||
//////////////////////////////////////////////////////////////////////////
|
||
////// 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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <sys/types.h>
|
||
#include <sys/stat.h>
|
||
#include <sys/inotify.h>
|
||
#include <fcntl.h>
|
||
#include <errno.h>
|
||
#include <dirent.h>
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
#include <unistd.h>
|
||
|
||
#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 <elmindreda@glfw.org>
|
||
//
|
||
// 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 <mkuhn@acm.org>, University of
|
||
* Cambridge, April 2001
|
||
*
|
||
* Special thanks to Richard Verhoeven <river@win.tue.nl> 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__ */
|