1
0
Fork 0
mirror of https://github.com/gwm17/glfw.git synced 2024-11-23 02:38:52 -05:00

Mir: Add cursor mode support

Implements a few other missing functions. Cleaning up naming convention
as well.

Fix FindMir.cmake was not finding the correct mirclient.so when
you wanted something other then the system library.

Closes #839.
This commit is contained in:
Brandon Schaefer 2016-08-16 15:26:07 -07:00 committed by Camilla Berglund
parent fbb2d5e10d
commit acce7ec9cf
5 changed files with 167 additions and 77 deletions

View File

@ -2,17 +2,36 @@
# #
# This will define: # This will define:
# #
# MIR_LIBRARIES - Link these to use Wayland # MIR_FOUND - System has Mir
# MIR_INCLUDE_DIR - Include directory for Wayland # MIR_LIBRARIES - Link these to use Mir
# # MIR_INCLUDE_DIR - Include directory for Mir
# Copyright (c) 2014 Brandon Schaefer <brandon.schaefer@canonical.com> # MIR_DEFINITIONS - Compiler switches required for using Mir
if (NOT WIN32) if (NOT WIN32)
find_package (PkgConfig) find_package (PkgConfig)
pkg_check_modules (PKG_MIR QUIET mirclient) pkg_check_modules (PKG_MIR QUIET mirclient)
set(MIR_DEFINITIONS ${PKG_MIR_CFLAGS_OTHER})
find_path(MIR_INCLUDE_DIR
NAMES xkbcommon/xkbcommon.h
HINTS ${PC_XKBCOMMON_INCLUDE_DIR} ${PC_XKBCOMMON_INCLUDE_DIRS}
)
find_library(MIR_LIBRARY
NAMES mirclient
HINTS ${PKG_MIR_LIBRARIES} ${MIR_LIBRARY_DIRS}
)
set (MIR_INCLUDE_DIR ${PKG_MIR_INCLUDE_DIRS}) set (MIR_INCLUDE_DIR ${PKG_MIR_INCLUDE_DIRS})
set (MIR_LIBRARIES ${PKG_MIR_LIBRARIES}) set (MIR_LIBRARIES ${MIR_LIBRARY})
include (FindPackageHandleStandardArgs)
find_package_handle_standard_args (MIR DEFAULT_MSG
MIR_LIBRARIES
MIR_INCLUDE_DIR
)
mark_as_advanced (MIR_LIBRARIES MIR_INCLUDE_DIR)
endif () endif ()

View File

@ -198,12 +198,13 @@ int _glfwPlatformInit(void)
_glfwInitTimerPOSIX(); _glfwInitTimerPOSIX();
// Need the default conf for when we set a NULL cursor // Need the default conf for when we set a NULL cursor
_glfw.mir.default_conf = mir_cursor_configuration_from_name(mir_arrow_cursor_name); _glfw.mir.defaultConf = mir_cursor_configuration_from_name(mir_default_cursor_name);
_glfw.mir.disabledConf = mir_cursor_configuration_from_name(mir_disabled_cursor_name);
_glfw.mir.event_queue = calloc(1, sizeof(EventQueue)); _glfw.mir.eventQueue = calloc(1, sizeof(EventQueue));
_glfwInitEventQueueMir(_glfw.mir.event_queue); _glfwInitEventQueueMir(_glfw.mir.eventQueue);
error = pthread_mutex_init(&_glfw.mir.event_mutex, NULL); error = pthread_mutex_init(&_glfw.mir.eventMutex, NULL);
if (error) if (error)
{ {
_glfwInputError(GLFW_PLATFORM_ERROR, _glfwInputError(GLFW_PLATFORM_ERROR,
@ -221,9 +222,9 @@ void _glfwPlatformTerminate(void)
_glfwTerminateJoysticksLinux(); _glfwTerminateJoysticksLinux();
_glfwTerminateThreadLocalStoragePOSIX(); _glfwTerminateThreadLocalStoragePOSIX();
_glfwDeleteEventQueueMir(_glfw.mir.event_queue); _glfwDeleteEventQueueMir(_glfw.mir.eventQueue);
pthread_mutex_destroy(&_glfw.mir.event_mutex); pthread_mutex_destroy(&_glfw.mir.eventMutex);
mir_connection_release(_glfw.mir.connection); mir_connection_release(_glfw.mir.connection);
} }

View File

@ -59,8 +59,8 @@ _GLFWmonitor** _glfwPlatformGetMonitors(int* count)
monitors[i]->mir.x = out->position_x; monitors[i]->mir.x = out->position_x;
monitors[i]->mir.y = out->position_y; monitors[i]->mir.y = out->position_y;
monitors[i]->mir.output_id = out->output_id; monitors[i]->mir.outputId = out->output_id;
monitors[i]->mir.cur_mode = out->current_mode; monitors[i]->mir.curMode = out->current_mode;
monitors[i]->modes = _glfwPlatformGetVideoModes(monitors[i], monitors[i]->modes = _glfwPlatformGetVideoModes(monitors[i],
&monitors[i]->modeCount); &monitors[i]->modeCount);
@ -75,7 +75,7 @@ _GLFWmonitor** _glfwPlatformGetMonitors(int* count)
GLFWbool _glfwPlatformIsSameMonitor(_GLFWmonitor* first, _GLFWmonitor* second) GLFWbool _glfwPlatformIsSameMonitor(_GLFWmonitor* first, _GLFWmonitor* second)
{ {
return first->mir.output_id == second->mir.output_id; return first->mir.outputId == second->mir.outputId;
} }
void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
@ -129,7 +129,7 @@ GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found)
for (i = 0; i < displayConfig->num_outputs; i++) for (i = 0; i < displayConfig->num_outputs; i++)
{ {
const MirDisplayOutput* out = displayConfig->outputs + i; const MirDisplayOutput* out = displayConfig->outputs + i;
if (out->output_id != monitor->mir.output_id) if (out->output_id != monitor->mir.outputId)
continue; continue;
modes = calloc(out->num_modes, sizeof(GLFWvidmode)); modes = calloc(out->num_modes, sizeof(GLFWvidmode));
@ -153,7 +153,7 @@ GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found)
void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode) void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode)
{ {
*mode = monitor->modes[monitor->mir.cur_mode]; *mode = monitor->modes[monitor->mir.curMode];
} }
void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
@ -177,6 +177,6 @@ GLFWAPI int glfwGetMirMonitor(GLFWmonitor* handle)
{ {
_GLFWmonitor* monitor = (_GLFWmonitor*) handle; _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
_GLFW_REQUIRE_INIT_OR_RETURN(0); _GLFW_REQUIRE_INIT_OR_RETURN(0);
return monitor->mir.output_id; return monitor->mir.outputId;
} }

View File

@ -84,6 +84,7 @@ typedef struct _GLFWwindowMir
int width; int width;
int height; int height;
MirEGLNativeWindowType window; MirEGLNativeWindowType window;
_GLFWcursor* currentCursor;
} _GLFWwindowMir; } _GLFWwindowMir;
@ -91,8 +92,8 @@ typedef struct _GLFWwindowMir
// //
typedef struct _GLFWmonitorMir typedef struct _GLFWmonitorMir
{ {
int cur_mode; int curMode;
int output_id; int outputId;
int x; int x;
int y; int y;
@ -104,14 +105,18 @@ typedef struct _GLFWlibraryMir
{ {
MirConnection* connection; MirConnection* connection;
MirEGLNativeDisplayType display; MirEGLNativeDisplayType display;
MirCursorConfiguration* default_conf; MirCursorConfiguration* defaultConf;
EventQueue* event_queue; MirCursorConfiguration* disabledConf;
EventQueue* eventQueue;
short int publicKeys[256]; short int publicKeys[256];
short int nativeKeys[GLFW_KEY_LAST + 1]; short int nativeKeys[GLFW_KEY_LAST + 1];
pthread_mutex_t event_mutex; pthread_mutex_t eventMutex;
pthread_cond_t event_cond; pthread_cond_t eventCond;
// The window whose disabled cursor mode is active
_GLFWwindow* disabledCursorWindow;
} _GLFWlibraryMir; } _GLFWlibraryMir;
@ -121,7 +126,7 @@ typedef struct _GLFWlibraryMir
typedef struct _GLFWcursorMir typedef struct _GLFWcursorMir
{ {
MirCursorConfiguration* conf; MirCursorConfiguration* conf;
MirBufferStream* custom_cursor; MirBufferStream* customCursor;
} _GLFWcursorMir; } _GLFWcursorMir;

View File

@ -54,37 +54,37 @@ static GLFWbool emptyEventQueue(EventQueue* queue)
// for single threaded event handling. // for single threaded event handling.
static EventNode* newEventNode(const MirEvent* event, _GLFWwindow* context) static EventNode* newEventNode(const MirEvent* event, _GLFWwindow* context)
{ {
EventNode* new_node = calloc(1, sizeof(EventNode)); EventNode* newNode = calloc(1, sizeof(EventNode));
new_node->event = mir_event_ref(event); newNode->event = mir_event_ref(event);
new_node->window = context; newNode->window = context;
return new_node; return newNode;
} }
static void enqueueEvent(const MirEvent* event, _GLFWwindow* context) static void enqueueEvent(const MirEvent* event, _GLFWwindow* context)
{ {
pthread_mutex_lock(&_glfw.mir.event_mutex); pthread_mutex_lock(&_glfw.mir.eventMutex);
EventNode* new_node = newEventNode(event, context); EventNode* newNode = newEventNode(event, context);
TAILQ_INSERT_TAIL(&_glfw.mir.event_queue->head, new_node, entries); TAILQ_INSERT_TAIL(&_glfw.mir.eventQueue->head, newNode, entries);
pthread_cond_signal(&_glfw.mir.event_cond); pthread_cond_signal(&_glfw.mir.eventCond);
pthread_mutex_unlock(&_glfw.mir.event_mutex); pthread_mutex_unlock(&_glfw.mir.eventMutex);
} }
static EventNode* dequeueEvent(EventQueue* queue) static EventNode* dequeueEvent(EventQueue* queue)
{ {
EventNode* node = NULL; EventNode* node = NULL;
pthread_mutex_lock(&_glfw.mir.event_mutex); pthread_mutex_lock(&_glfw.mir.eventMutex);
node = queue->head.tqh_first; node = queue->head.tqh_first;
if (node) if (node)
TAILQ_REMOVE(&queue->head, node, entries); TAILQ_REMOVE(&queue->head, node, entries);
pthread_mutex_unlock(&_glfw.mir.event_mutex); pthread_mutex_unlock(&_glfw.mir.eventMutex);
return node; return node;
} }
@ -201,16 +201,31 @@ static void handlePointerButton(_GLFWwindow* window,
static void handlePointerMotion(_GLFWwindow* window, static void handlePointerMotion(_GLFWwindow* window,
const MirPointerEvent* pointer_event) const MirPointerEvent* pointer_event)
{ {
int current_x = window->virtualCursorPosX; const int hscroll = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_hscroll);
int current_y = window->virtualCursorPosY; const int vscroll = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_vscroll);
int x = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_x);
int y = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_y); if (window->cursorMode == GLFW_CURSOR_DISABLED)
int dx = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_hscroll); {
int dy = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_vscroll); if (_glfw.mir.disabledCursorWindow != window)
return;
const int dx = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_relative_x);
const int dy = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_relative_y);
const int current_x = window->virtualCursorPosX;
const int current_y = window->virtualCursorPosY;
_glfwInputCursorPos(window, dx + current_x, dy + current_y);
}
else
{
const int x = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_x);
const int y = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_y);
_glfwInputCursorPos(window, x, y); _glfwInputCursorPos(window, x, y);
if (dx != 0 || dy != 0) }
_glfwInputScroll(window, dx, dy);
if (hscroll != 0 || vscroll != 0)
_glfwInputScroll(window, hscroll, vscroll);
} }
static void handlePointerEvent(const MirPointerEvent* pointer_event, static void handlePointerEvent(const MirPointerEvent* pointer_event,
@ -234,7 +249,6 @@ static void handlePointerEvent(const MirPointerEvent* pointer_event,
break; break;
default: default:
break; break;
} }
} }
@ -312,6 +326,17 @@ static GLFWbool createSurface(_GLFWwindow* window)
return GLFW_TRUE; return GLFW_TRUE;
} }
static void setSurfaceConfinement(_GLFWwindow* window, MirPointerConfinementState state)
{
MirSurfaceSpec* spec;
spec = mir_connection_create_spec_for_changes(_glfw.mir.connection);
mir_surface_spec_set_pointer_confinement(spec, state);
mir_surface_apply_spec(window->mir.surface, spec);
mir_surface_spec_release(spec);
}
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
////// GLFW internal API ////// ////// GLFW internal API //////
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@ -370,6 +395,7 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
window->mir.width = wndconfig->width; window->mir.width = wndconfig->width;
window->mir.height = wndconfig->height; window->mir.height = wndconfig->height;
window->mir.currentCursor = NULL;
if (!createSurface(window)) if (!createSurface(window))
return GLFW_FALSE; return GLFW_FALSE;
@ -390,6 +416,9 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
void _glfwPlatformDestroyWindow(_GLFWwindow* window) void _glfwPlatformDestroyWindow(_GLFWwindow* window)
{ {
if (_glfw.mir.disabledCursorWindow == window)
_glfw.mir.disabledCursorWindow = NULL;
if (mir_surface_is_valid(window->mir.surface)) if (mir_surface_is_valid(window->mir.surface))
{ {
mir_surface_release_sync(window->mir.surface); mir_surface_release_sync(window->mir.surface);
@ -475,18 +504,35 @@ void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height)
void _glfwPlatformIconifyWindow(_GLFWwindow* window) void _glfwPlatformIconifyWindow(_GLFWwindow* window)
{ {
mir_surface_set_state(window->mir.surface, mir_surface_state_minimized); MirSurfaceSpec* spec;
spec = mir_connection_create_spec_for_changes(_glfw.mir.connection);
mir_surface_spec_set_state(spec, mir_surface_state_minimized);
mir_surface_apply_spec(window->mir.surface, spec);
mir_surface_spec_release(spec);
} }
void _glfwPlatformRestoreWindow(_GLFWwindow* window) void _glfwPlatformRestoreWindow(_GLFWwindow* window)
{ {
mir_surface_set_state(window->mir.surface, mir_surface_state_restored); MirSurfaceSpec* spec;
spec = mir_connection_create_spec_for_changes(_glfw.mir.connection);
mir_surface_spec_set_state(spec, mir_surface_state_restored);
mir_surface_apply_spec(window->mir.surface, spec);
mir_surface_spec_release(spec);
} }
void _glfwPlatformMaximizeWindow(_GLFWwindow* window) void _glfwPlatformMaximizeWindow(_GLFWwindow* window)
{ {
_glfwInputError(GLFW_PLATFORM_ERROR, MirSurfaceSpec* spec;
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
spec = mir_connection_create_spec_for_changes(_glfw.mir.connection);
mir_surface_spec_set_state(spec, mir_surface_state_maximized);
mir_surface_apply_spec(window->mir.surface, spec);
mir_surface_spec_release(spec);
} }
void _glfwPlatformHideWindow(_GLFWwindow* window) void _glfwPlatformHideWindow(_GLFWwindow* window)
@ -529,9 +575,7 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
int _glfwPlatformWindowFocused(_GLFWwindow* window) int _glfwPlatformWindowFocused(_GLFWwindow* window)
{ {
_glfwInputError(GLFW_PLATFORM_ERROR, return mir_surface_get_focus(window->mir.surface) == mir_surface_focused;
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
return GLFW_FALSE;
} }
int _glfwPlatformWindowIconified(_GLFWwindow* window) int _glfwPlatformWindowIconified(_GLFWwindow* window)
@ -548,48 +592,46 @@ int _glfwPlatformWindowVisible(_GLFWwindow* window)
int _glfwPlatformWindowMaximized(_GLFWwindow* window) int _glfwPlatformWindowMaximized(_GLFWwindow* window)
{ {
_glfwInputError(GLFW_PLATFORM_ERROR, return mir_surface_get_state(window->mir.surface) == mir_surface_state_maximized;
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
return GLFW_FALSE;
} }
void _glfwPlatformPollEvents(void) void _glfwPlatformPollEvents(void)
{ {
EventNode* node = NULL; EventNode* node = NULL;
while ((node = dequeueEvent(_glfw.mir.event_queue))) while ((node = dequeueEvent(_glfw.mir.eventQueue)))
{ {
handleEvent(node->event, node->window); handleEvent(node->event, node->window);
deleteNode(_glfw.mir.event_queue, node); deleteNode(_glfw.mir.eventQueue, node);
} }
} }
void _glfwPlatformWaitEvents(void) void _glfwPlatformWaitEvents(void)
{ {
pthread_mutex_lock(&_glfw.mir.event_mutex); pthread_mutex_lock(&_glfw.mir.eventMutex);
if (emptyEventQueue(_glfw.mir.event_queue)) if (emptyEventQueue(_glfw.mir.eventQueue))
pthread_cond_wait(&_glfw.mir.event_cond, &_glfw.mir.event_mutex); pthread_cond_wait(&_glfw.mir.eventCond, &_glfw.mir.eventMutex);
pthread_mutex_unlock(&_glfw.mir.event_mutex); pthread_mutex_unlock(&_glfw.mir.eventMutex);
_glfwPlatformPollEvents(); _glfwPlatformPollEvents();
} }
void _glfwPlatformWaitEventsTimeout(double timeout) void _glfwPlatformWaitEventsTimeout(double timeout)
{ {
pthread_mutex_lock(&_glfw.mir.event_mutex); pthread_mutex_lock(&_glfw.mir.eventMutex);
if (emptyEventQueue(_glfw.mir.event_queue)) if (emptyEventQueue(_glfw.mir.eventQueue))
{ {
struct timespec time; struct timespec time;
clock_gettime(CLOCK_REALTIME, &time); clock_gettime(CLOCK_REALTIME, &time);
time.tv_sec += (long) timeout; time.tv_sec += (long) timeout;
time.tv_nsec += (long) ((timeout - (long) timeout) * 1e9); time.tv_nsec += (long) ((timeout - (long) timeout) * 1e9);
pthread_cond_timedwait(&_glfw.mir.event_cond, &_glfw.mir.event_mutex, &time); pthread_cond_timedwait(&_glfw.mir.eventCond, &_glfw.mir.eventMutex, &time);
} }
pthread_mutex_unlock(&_glfw.mir.event_mutex); pthread_mutex_unlock(&_glfw.mir.eventMutex);
_glfwPlatformPollEvents(); _glfwPlatformPollEvents();
} }
@ -606,7 +648,6 @@ void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* heigh
*height = window->mir.height; *height = window->mir.height;
} }
// FIXME implement
int _glfwPlatformCreateCursor(_GLFWcursor* cursor, int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
const GLFWimage* image, const GLFWimage* image,
int xhot, int yhot) int xhot, int yhot)
@ -654,7 +695,7 @@ int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
pixels += r_stride; pixels += r_stride;
} }
cursor->mir.custom_cursor = stream; cursor->mir.customCursor = stream;
return GLFW_TRUE; return GLFW_TRUE;
} }
@ -687,7 +728,7 @@ int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape)
if (cursor_name) if (cursor_name)
{ {
cursor->mir.conf = mir_cursor_configuration_from_name(cursor_name); cursor->mir.conf = mir_cursor_configuration_from_name(cursor_name);
cursor->mir.custom_cursor = NULL; cursor->mir.customCursor = NULL;
return GLFW_TRUE; return GLFW_TRUE;
} }
@ -699,23 +740,25 @@ void _glfwPlatformDestroyCursor(_GLFWcursor* cursor)
{ {
if (cursor->mir.conf) if (cursor->mir.conf)
mir_cursor_configuration_destroy(cursor->mir.conf); mir_cursor_configuration_destroy(cursor->mir.conf);
if (cursor->mir.custom_cursor) if (cursor->mir.customCursor)
mir_buffer_stream_release_sync(cursor->mir.custom_cursor); mir_buffer_stream_release_sync(cursor->mir.customCursor);
} }
void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
{ {
if (cursor && cursor->mir.conf) if (cursor && cursor->mir.conf)
{ {
window->mir.currentCursor = cursor;
mir_wait_for(mir_surface_configure_cursor(window->mir.surface, cursor->mir.conf)); mir_wait_for(mir_surface_configure_cursor(window->mir.surface, cursor->mir.conf));
if (cursor->mir.custom_cursor) if (cursor->mir.customCursor)
{ {
mir_buffer_stream_swap_buffers_sync(cursor->mir.custom_cursor); mir_buffer_stream_swap_buffers_sync(cursor->mir.customCursor);
} }
} }
else else
{ {
mir_wait_for(mir_surface_configure_cursor(window->mir.surface, _glfw.mir.default_conf)); mir_wait_for(mir_surface_configure_cursor(window->mir.surface, _glfw.mir.defaultConf));
} }
} }
@ -733,8 +776,30 @@ void _glfwPlatformSetCursorPos(_GLFWwindow* window, double xpos, double ypos)
void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode)
{ {
_glfwInputError(GLFW_PLATFORM_ERROR, if (mode == GLFW_CURSOR_DISABLED)
"Mir: Unsupported function %s", __PRETTY_FUNCTION__); {
_glfw.mir.disabledCursorWindow = window;
setSurfaceConfinement(window, mir_pointer_confined_to_surface);
mir_wait_for(mir_surface_configure_cursor(window->mir.surface, _glfw.mir.disabledConf));
}
else
{
// If we were disabled before lets undo that!
if (_glfw.mir.disabledCursorWindow == window)
{
_glfw.mir.disabledCursorWindow = NULL;
setSurfaceConfinement(window, mir_pointer_unconfined);
}
if (window->cursorMode == GLFW_CURSOR_NORMAL)
{
_glfwPlatformSetCursor(window, window->mir.currentCursor);
}
else if (window->cursorMode == GLFW_CURSOR_HIDDEN)
{
mir_wait_for(mir_surface_configure_cursor(window->mir.surface, _glfw.mir.disabledConf));
}
}
} }
const char* _glfwPlatformGetKeyName(int key, int scancode) const char* _glfwPlatformGetKeyName(int key, int scancode)