mirror of
https://github.com/glfw/glfw.git
synced 2024-11-10 00:51:47 +00:00
Add keyboard layout support
This adds a keyboard layout switch callback and a query for the human-readable name of the current layout. Fixes #1201.
This commit is contained in:
parent
d7ae90a790
commit
761d7e7c4e
@ -119,6 +119,10 @@ information on what to include when reporting a bug.
|
|||||||
|
|
||||||
## Changelog
|
## Changelog
|
||||||
|
|
||||||
|
- Added `glfwGetKeyboardLayoutName` for querying the name of the current
|
||||||
|
keyboard layout (#1201)
|
||||||
|
- Added `glfwSetKeyboardLayoutCallback` and `GLFWkeyboardlayoutfun` for
|
||||||
|
receiving keyboard layout events (#1201)
|
||||||
- Added `GLFW_RESIZE_NWSE_CURSOR`, `GLFW_RESIZE_NESW_CURSOR`,
|
- Added `GLFW_RESIZE_NWSE_CURSOR`, `GLFW_RESIZE_NESW_CURSOR`,
|
||||||
`GLFW_RESIZE_ALL_CURSOR` and `GLFW_NOT_ALLOWED_CURSOR` cursor shapes (#427)
|
`GLFW_RESIZE_ALL_CURSOR` and `GLFW_NOT_ALLOWED_CURSOR` cursor shapes (#427)
|
||||||
- Added `GLFW_RESIZE_EW_CURSOR` alias for `GLFW_HRESIZE_CURSOR` (#427)
|
- Added `GLFW_RESIZE_EW_CURSOR` alias for `GLFW_HRESIZE_CURSOR` (#427)
|
||||||
|
@ -230,6 +230,32 @@ specified key is `GLFW_KEY_UNKNOWN` then the scancode is used, otherwise it is
|
|||||||
ignored. This matches the behavior of the key callback, meaning the callback
|
ignored. This matches the behavior of the key callback, meaning the callback
|
||||||
arguments can always be passed unmodified to this function.
|
arguments can always be passed unmodified to this function.
|
||||||
|
|
||||||
|
The name of a key will not change unless the keyboard layout changes.
|
||||||
|
|
||||||
|
|
||||||
|
@subsection keyboard_layout Keyboard layout
|
||||||
|
|
||||||
|
The human-readable name of the current keyboard layout is returned by @ref
|
||||||
|
glfwGetKeyboardLayoutName.
|
||||||
|
|
||||||
|
If you wish to be notified when the keyboard layout changes, set a keyboard
|
||||||
|
layout callback.
|
||||||
|
|
||||||
|
@code
|
||||||
|
glfwSetKeyboardLayoutCallback(keyboard_layout_callback);
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
The callback is called when the new layout takes effect for the application,
|
||||||
|
which on some platforms may not happen until one of its windows gets input
|
||||||
|
focus.
|
||||||
|
|
||||||
|
@code
|
||||||
|
void keyboard_layout_callback(void)
|
||||||
|
{
|
||||||
|
update_keyboard_layout_name(glfwGetKeyboardLayoutName());
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
|
||||||
@section input_mouse Mouse input
|
@section input_mouse Mouse input
|
||||||
|
|
||||||
|
@ -9,6 +9,15 @@
|
|||||||
|
|
||||||
@subsection features_34 New features in version 3.4
|
@subsection features_34 New features in version 3.4
|
||||||
|
|
||||||
|
@subsubsection keyboard_layout_34 Keyboard layouts
|
||||||
|
|
||||||
|
GLFW can now notify when the keyboard layout has changed with @ref
|
||||||
|
glfwSetKeyboardLayoutCallback and provides the human-readable name of the
|
||||||
|
current layout with @ref glfwGetKeyboardLayoutName.
|
||||||
|
|
||||||
|
For more information, see @ref keyboard_layout.
|
||||||
|
|
||||||
|
|
||||||
@subsubsection standard_cursors_34 More standard cursors
|
@subsubsection standard_cursors_34 More standard cursors
|
||||||
|
|
||||||
GLFW now provides the standard cursor shapes @ref GLFW_RESIZE_NWSE_CURSOR and
|
GLFW now provides the standard cursor shapes @ref GLFW_RESIZE_NWSE_CURSOR and
|
||||||
|
@ -1270,6 +1270,23 @@ typedef struct GLFWcursor GLFWcursor;
|
|||||||
*/
|
*/
|
||||||
typedef void (* GLFWerrorfun)(int,const char*);
|
typedef void (* GLFWerrorfun)(int,const char*);
|
||||||
|
|
||||||
|
/*! @brief The function pointer type for keyboard layout callbacks.
|
||||||
|
*
|
||||||
|
* This is the function pointer type for keyboard layout callbacks. A keyboard
|
||||||
|
* layout callback function has the following signature:
|
||||||
|
* @code
|
||||||
|
* void callback_name(void);
|
||||||
|
* @endcode
|
||||||
|
*
|
||||||
|
* @sa @ref keyboard_layout
|
||||||
|
* @sa @ref glfwSetKeyboardLayoutCallback
|
||||||
|
*
|
||||||
|
* @since Added in version 3.4.
|
||||||
|
*
|
||||||
|
* @ingroup input
|
||||||
|
*/
|
||||||
|
typedef void (* GLFWkeyboardlayoutfun)(void);
|
||||||
|
|
||||||
/*! @brief The function pointer type for window position callbacks.
|
/*! @brief The function pointer type for window position callbacks.
|
||||||
*
|
*
|
||||||
* This is the function pointer type for window position callbacks. A window
|
* This is the function pointer type for window position callbacks. A window
|
||||||
@ -4265,6 +4282,11 @@ GLFWAPI int glfwRawMouseMotionSupported(void);
|
|||||||
* non-printable keys are the same across layouts but depend on the application
|
* non-printable keys are the same across layouts but depend on the application
|
||||||
* language and should be localized along with other user interface text.
|
* language and should be localized along with other user interface text.
|
||||||
*
|
*
|
||||||
|
* The contents of the returned string may change when a keyboard
|
||||||
|
* layout change event is received. Set a
|
||||||
|
* [keyboard layout](@ref keyboard_layout) callback to be notified when the
|
||||||
|
* layout changes.
|
||||||
|
*
|
||||||
* @param[in] key The key to query, or `GLFW_KEY_UNKNOWN`.
|
* @param[in] key The key to query, or `GLFW_KEY_UNKNOWN`.
|
||||||
* @param[in] scancode The scancode of the key to query.
|
* @param[in] scancode The scancode of the key to query.
|
||||||
* @return The UTF-8 encoded, layout-specific name of the key, or `NULL`.
|
* @return The UTF-8 encoded, layout-specific name of the key, or `NULL`.
|
||||||
@ -4272,9 +4294,6 @@ GLFWAPI int glfwRawMouseMotionSupported(void);
|
|||||||
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
|
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
|
||||||
* GLFW_PLATFORM_ERROR.
|
* 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
|
* @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.
|
* should not free it yourself. It is valid until the library is terminated.
|
||||||
*
|
*
|
||||||
@ -4312,6 +4331,73 @@ GLFWAPI const char* glfwGetKeyName(int key, int scancode);
|
|||||||
*/
|
*/
|
||||||
GLFWAPI int glfwGetKeyScancode(int key);
|
GLFWAPI int glfwGetKeyScancode(int key);
|
||||||
|
|
||||||
|
/*! @brief Returns the human-readable name of the current keyboard layout.
|
||||||
|
*
|
||||||
|
* This function returns the human-readable name, encoded as UTF-8, of the
|
||||||
|
* current keyboard layout. On some platforms this may not be updated until
|
||||||
|
* one of the application's windows gets input focus.
|
||||||
|
*
|
||||||
|
* The keyboard layout name is intended to be shown to the user during text
|
||||||
|
* input, especially in full screen applications.
|
||||||
|
*
|
||||||
|
* The name may be localized into the current operating system UI language. It
|
||||||
|
* is provided by the operating system and may not be identical for a given
|
||||||
|
* layout across platforms.
|
||||||
|
*
|
||||||
|
* @return The UTF-8 encoded name of the current keyboard layout, or `NULL` if
|
||||||
|
* an [error](@ref error_handling) occurred.
|
||||||
|
*
|
||||||
|
* @errors Possible errors include @ref GLFW_PLATFORM_ERROR and @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 next call to this
|
||||||
|
* function or the library is terminated.
|
||||||
|
*
|
||||||
|
* @thread_safety This function must only be called from the main thread.
|
||||||
|
*
|
||||||
|
* @sa @ref keyboard_layout
|
||||||
|
* @sa @ref glfwSetKeyboardLayoutCallback
|
||||||
|
*
|
||||||
|
* @since Added in version 3.4.
|
||||||
|
*
|
||||||
|
* @ingroup input
|
||||||
|
*/
|
||||||
|
GLFWAPI const char* glfwGetKeyboardLayoutName(void);
|
||||||
|
|
||||||
|
/*! @brief Sets the keyboard layout callback.
|
||||||
|
*
|
||||||
|
* This function sets the keyboard layout callback, which is called when the
|
||||||
|
* keyboard layout is changed. The name of the current layout is returned by
|
||||||
|
* @ref glfwGetKeyboardLayoutName.
|
||||||
|
*
|
||||||
|
* On some platforms the keyboard layout event may not arrive until one of the
|
||||||
|
* application's windows get input focus. Layout changes may not be reported
|
||||||
|
* while other applications have input focus.
|
||||||
|
*
|
||||||
|
* @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(void)
|
||||||
|
* @endcode
|
||||||
|
*
|
||||||
|
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
|
||||||
|
*
|
||||||
|
* @thread_safety This function must only be called from the main thread.
|
||||||
|
*
|
||||||
|
* @sa @ref keyboard_layout
|
||||||
|
* @sa @ref glfwGetKeyboardLayoutName
|
||||||
|
*
|
||||||
|
* @since Added in version 3.4.
|
||||||
|
*
|
||||||
|
* @ingroup input
|
||||||
|
*/
|
||||||
|
GLFWAPI GLFWkeyboardlayoutfun glfwSetKeyboardLayoutCallback(GLFWkeyboardlayoutfun callback);
|
||||||
|
|
||||||
/*! @brief Returns the last reported state of a keyboard key for the specified
|
/*! @brief Returns the last reported state of a keyboard key for the specified
|
||||||
* window.
|
* window.
|
||||||
*
|
*
|
||||||
|
@ -305,38 +305,6 @@ static void createKeyTables(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
// Load HIToolbox.framework and the TIS symbols we need from it
|
||||||
//
|
//
|
||||||
static GLFWbool initializeTIS(void)
|
static GLFWbool initializeTIS(void)
|
||||||
@ -354,6 +322,15 @@ static GLFWbool initializeTIS(void)
|
|||||||
CFStringRef* kPropertyUnicodeKeyLayoutData =
|
CFStringRef* kPropertyUnicodeKeyLayoutData =
|
||||||
CFBundleGetDataPointerForName(_glfw.ns.tis.bundle,
|
CFBundleGetDataPointerForName(_glfw.ns.tis.bundle,
|
||||||
CFSTR("kTISPropertyUnicodeKeyLayoutData"));
|
CFSTR("kTISPropertyUnicodeKeyLayoutData"));
|
||||||
|
CFStringRef* kPropertyInputSourceID =
|
||||||
|
CFBundleGetDataPointerForName(_glfw.ns.tis.bundle,
|
||||||
|
CFSTR("kTISPropertyInputSourceID"));
|
||||||
|
CFStringRef* kPropertyLocalizedName =
|
||||||
|
CFBundleGetDataPointerForName(_glfw.ns.tis.bundle,
|
||||||
|
CFSTR("kTISPropertyLocalizedName"));
|
||||||
|
_glfw.ns.tis.CopyCurrentKeyboardInputSource =
|
||||||
|
CFBundleGetFunctionPointerForName(_glfw.ns.tis.bundle,
|
||||||
|
CFSTR("TISCopyCurrentKeyboardInputSource"));
|
||||||
_glfw.ns.tis.CopyCurrentKeyboardLayoutInputSource =
|
_glfw.ns.tis.CopyCurrentKeyboardLayoutInputSource =
|
||||||
CFBundleGetFunctionPointerForName(_glfw.ns.tis.bundle,
|
CFBundleGetFunctionPointerForName(_glfw.ns.tis.bundle,
|
||||||
CFSTR("TISCopyCurrentKeyboardLayoutInputSource"));
|
CFSTR("TISCopyCurrentKeyboardLayoutInputSource"));
|
||||||
@ -365,6 +342,9 @@ static GLFWbool initializeTIS(void)
|
|||||||
CFSTR("LMGetKbdType"));
|
CFSTR("LMGetKbdType"));
|
||||||
|
|
||||||
if (!kPropertyUnicodeKeyLayoutData ||
|
if (!kPropertyUnicodeKeyLayoutData ||
|
||||||
|
!kPropertyInputSourceID ||
|
||||||
|
!kPropertyLocalizedName ||
|
||||||
|
!TISCopyCurrentKeyboardInputSource ||
|
||||||
!TISCopyCurrentKeyboardLayoutInputSource ||
|
!TISCopyCurrentKeyboardLayoutInputSource ||
|
||||||
!TISGetInputSourceProperty ||
|
!TISGetInputSourceProperty ||
|
||||||
!LMGetKbdType)
|
!LMGetKbdType)
|
||||||
@ -376,8 +356,18 @@ static GLFWbool initializeTIS(void)
|
|||||||
|
|
||||||
_glfw.ns.tis.kPropertyUnicodeKeyLayoutData =
|
_glfw.ns.tis.kPropertyUnicodeKeyLayoutData =
|
||||||
*kPropertyUnicodeKeyLayoutData;
|
*kPropertyUnicodeKeyLayoutData;
|
||||||
|
_glfw.ns.tis.kPropertyInputSourceID =
|
||||||
|
*kPropertyInputSourceID;
|
||||||
|
_glfw.ns.tis.kPropertyLocalizedName =
|
||||||
|
*kPropertyLocalizedName;
|
||||||
|
|
||||||
return updateUnicodeDataNS();
|
_glfw.ns.inputSource = TISCopyCurrentKeyboardInputSource();
|
||||||
|
_glfw.ns.keyboardLayout = TISCopyCurrentKeyboardLayoutInputSource();
|
||||||
|
_glfw.ns.unicodeData =
|
||||||
|
TISGetInputSourceProperty(_glfw.ns.keyboardLayout,
|
||||||
|
kTISPropertyUnicodeKeyLayoutData);
|
||||||
|
|
||||||
|
return GLFW_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@interface GLFWHelper : NSObject
|
@interface GLFWHelper : NSObject
|
||||||
@ -387,7 +377,28 @@ static GLFWbool initializeTIS(void)
|
|||||||
|
|
||||||
- (void)selectedKeyboardInputSourceChanged:(NSObject* )object
|
- (void)selectedKeyboardInputSourceChanged:(NSObject* )object
|
||||||
{
|
{
|
||||||
updateUnicodeDataNS();
|
// The keyboard layout is needed for Unicode data which is the source of
|
||||||
|
// GLFW key names on Cocoa (the generic input source may not have this)
|
||||||
|
CFRelease(_glfw.ns.keyboardLayout);
|
||||||
|
_glfw.ns.keyboardLayout = TISCopyCurrentKeyboardLayoutInputSource();
|
||||||
|
_glfw.ns.unicodeData =
|
||||||
|
TISGetInputSourceProperty(_glfw.ns.keyboardLayout,
|
||||||
|
kTISPropertyUnicodeKeyLayoutData);
|
||||||
|
|
||||||
|
// The generic input source may be something higher level than a keyboard
|
||||||
|
// layout and if so will provide a better layout name than the layout source
|
||||||
|
const TISInputSourceRef source = TISCopyCurrentKeyboardInputSource();
|
||||||
|
const CFStringRef newID =
|
||||||
|
TISGetInputSourceProperty(source, kTISPropertyInputSourceID);
|
||||||
|
const CFStringRef oldID =
|
||||||
|
TISGetInputSourceProperty(_glfw.ns.inputSource, kTISPropertyInputSourceID);
|
||||||
|
const CFComparisonResult result = CFStringCompare(oldID, newID, 0);
|
||||||
|
CFRelease(_glfw.ns.inputSource);
|
||||||
|
_glfw.ns.inputSource = source;
|
||||||
|
|
||||||
|
// Filter events as we may receive more than one per input source switch
|
||||||
|
if (result != kCFCompareEqualTo)
|
||||||
|
_glfwInputKeyboardLayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)doNothing:(id)object
|
- (void)doNothing:(id)object
|
||||||
@ -567,11 +578,17 @@ void _glfwPlatformTerminate(void)
|
|||||||
{
|
{
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
|
|
||||||
|
if (_glfw.ns.keyboardLayout)
|
||||||
|
{
|
||||||
|
CFRelease(_glfw.ns.keyboardLayout);
|
||||||
|
_glfw.ns.keyboardLayout = NULL;
|
||||||
|
_glfw.ns.unicodeData = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (_glfw.ns.inputSource)
|
if (_glfw.ns.inputSource)
|
||||||
{
|
{
|
||||||
CFRelease(_glfw.ns.inputSource);
|
CFRelease(_glfw.ns.inputSource);
|
||||||
_glfw.ns.inputSource = NULL;
|
_glfw.ns.inputSource = NULL;
|
||||||
_glfw.ns.unicodeData = nil;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_glfw.ns.eventSource)
|
if (_glfw.ns.eventSource)
|
||||||
@ -603,6 +620,7 @@ void _glfwPlatformTerminate(void)
|
|||||||
[NSEvent removeMonitor:_glfw.ns.keyUpMonitor];
|
[NSEvent removeMonitor:_glfw.ns.keyUpMonitor];
|
||||||
|
|
||||||
free(_glfw.ns.clipboardString);
|
free(_glfw.ns.clipboardString);
|
||||||
|
free(_glfw.ns.keyboardLayoutName);
|
||||||
|
|
||||||
_glfwTerminateNSGL();
|
_glfwTerminateNSGL();
|
||||||
_glfwTerminateJoysticksNS();
|
_glfwTerminateJoysticksNS();
|
||||||
|
@ -103,6 +103,10 @@ typedef VkResult (APIENTRY *PFN_vkCreateMetalSurfaceEXT)(VkInstance,const VkMeta
|
|||||||
|
|
||||||
// HIToolbox.framework pointer typedefs
|
// HIToolbox.framework pointer typedefs
|
||||||
#define kTISPropertyUnicodeKeyLayoutData _glfw.ns.tis.kPropertyUnicodeKeyLayoutData
|
#define kTISPropertyUnicodeKeyLayoutData _glfw.ns.tis.kPropertyUnicodeKeyLayoutData
|
||||||
|
#define kTISPropertyInputSourceID _glfw.ns.tis.kPropertyInputSourceID
|
||||||
|
#define kTISPropertyLocalizedName _glfw.ns.tis.kPropertyLocalizedName
|
||||||
|
typedef TISInputSourceRef (*PFN_TISCopyCurrentKeyboardInputSource)(void);
|
||||||
|
#define TISCopyCurrentKeyboardInputSource _glfw.ns.tis.CopyCurrentKeyboardInputSource
|
||||||
typedef TISInputSourceRef (*PFN_TISCopyCurrentKeyboardLayoutInputSource)(void);
|
typedef TISInputSourceRef (*PFN_TISCopyCurrentKeyboardLayoutInputSource)(void);
|
||||||
#define TISCopyCurrentKeyboardLayoutInputSource _glfw.ns.tis.CopyCurrentKeyboardLayoutInputSource
|
#define TISCopyCurrentKeyboardLayoutInputSource _glfw.ns.tis.CopyCurrentKeyboardLayoutInputSource
|
||||||
typedef void* (*PFN_TISGetInputSourceProperty)(TISInputSourceRef,CFStringRef);
|
typedef void* (*PFN_TISGetInputSourceProperty)(TISInputSourceRef,CFStringRef);
|
||||||
@ -144,8 +148,9 @@ typedef struct _GLFWlibraryNS
|
|||||||
id delegate;
|
id delegate;
|
||||||
GLFWbool cursorHidden;
|
GLFWbool cursorHidden;
|
||||||
TISInputSourceRef inputSource;
|
TISInputSourceRef inputSource;
|
||||||
|
TISInputSourceRef keyboardLayout;
|
||||||
IOHIDManagerRef hidManager;
|
IOHIDManagerRef hidManager;
|
||||||
id unicodeData;
|
void* unicodeData;
|
||||||
id helper;
|
id helper;
|
||||||
id keyUpMonitor;
|
id keyUpMonitor;
|
||||||
id nibObjects;
|
id nibObjects;
|
||||||
@ -154,6 +159,7 @@ typedef struct _GLFWlibraryNS
|
|||||||
short int keycodes[256];
|
short int keycodes[256];
|
||||||
short int scancodes[GLFW_KEY_LAST + 1];
|
short int scancodes[GLFW_KEY_LAST + 1];
|
||||||
char* clipboardString;
|
char* clipboardString;
|
||||||
|
char* keyboardLayoutName;
|
||||||
CGPoint cascadePoint;
|
CGPoint cascadePoint;
|
||||||
// Where to place the cursor when re-enabled
|
// Where to place the cursor when re-enabled
|
||||||
double restoreCursorPosX, restoreCursorPosY;
|
double restoreCursorPosX, restoreCursorPosY;
|
||||||
@ -162,10 +168,13 @@ typedef struct _GLFWlibraryNS
|
|||||||
|
|
||||||
struct {
|
struct {
|
||||||
CFBundleRef bundle;
|
CFBundleRef bundle;
|
||||||
|
PFN_TISCopyCurrentKeyboardInputSource CopyCurrentKeyboardInputSource;
|
||||||
PFN_TISCopyCurrentKeyboardLayoutInputSource CopyCurrentKeyboardLayoutInputSource;
|
PFN_TISCopyCurrentKeyboardLayoutInputSource CopyCurrentKeyboardLayoutInputSource;
|
||||||
PFN_TISGetInputSourceProperty GetInputSourceProperty;
|
PFN_TISGetInputSourceProperty GetInputSourceProperty;
|
||||||
PFN_LMGetKbdType GetKbdType;
|
PFN_LMGetKbdType GetKbdType;
|
||||||
CFStringRef kPropertyUnicodeKeyLayoutData;
|
CFStringRef kPropertyUnicodeKeyLayoutData;
|
||||||
|
CFStringRef kPropertyInputSourceID;
|
||||||
|
CFStringRef kPropertyLocalizedName;
|
||||||
} tis;
|
} tis;
|
||||||
|
|
||||||
} _GLFWlibraryNS;
|
} _GLFWlibraryNS;
|
||||||
|
@ -1516,6 +1516,12 @@ const char* _glfwPlatformGetScancodeName(int scancode)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!_glfw.ns.unicodeData)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR, "Cocoa: Keyboard Unicode data missing");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
const int key = _glfw.ns.keycodes[scancode];
|
const int key = _glfw.ns.keycodes[scancode];
|
||||||
|
|
||||||
UInt32 deadKeyState = 0;
|
UInt32 deadKeyState = 0;
|
||||||
@ -1559,6 +1565,26 @@ int _glfwPlatformGetKeyScancode(int key)
|
|||||||
return _glfw.ns.scancodes[key];
|
return _glfw.ns.scancodes[key];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* _glfwPlatformGetKeyboardLayoutName(void)
|
||||||
|
{
|
||||||
|
TISInputSourceRef source = TISCopyCurrentKeyboardInputSource();
|
||||||
|
NSString* name = (__bridge NSString*)
|
||||||
|
TISGetInputSourceProperty(source, kTISPropertyLocalizedName);
|
||||||
|
if (!name)
|
||||||
|
{
|
||||||
|
CFRelease(source);
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Cocoa: Failed to retrieve keyboard layout name");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(_glfw.ns.keyboardLayoutName);
|
||||||
|
_glfw.ns.keyboardLayoutName = _glfw_strdup([name UTF8String]);
|
||||||
|
|
||||||
|
CFRelease(source);
|
||||||
|
return _glfw.ns.keyboardLayoutName;
|
||||||
|
}
|
||||||
|
|
||||||
int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
|
int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
|
||||||
const GLFWimage* image,
|
const GLFWimage* image,
|
||||||
int xhot, int yhot)
|
int xhot, int yhot)
|
||||||
|
21
src/input.c
21
src/input.c
@ -256,6 +256,14 @@ static GLFWbool parseMapping(_GLFWmapping* mapping, const char* string)
|
|||||||
////// GLFW event API //////
|
////// GLFW event API //////
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Notifies shared code of a keyboard layout change event
|
||||||
|
//
|
||||||
|
void _glfwInputKeyboardLayout(void)
|
||||||
|
{
|
||||||
|
if (_glfw.callbacks.layout)
|
||||||
|
_glfw.callbacks.layout();
|
||||||
|
}
|
||||||
|
|
||||||
// Notifies shared code of a physical key event
|
// Notifies shared code of a physical key event
|
||||||
//
|
//
|
||||||
void _glfwInputKey(_GLFWwindow* window, int key, int scancode, int action, int mods)
|
void _glfwInputKey(_GLFWwindow* window, int key, int scancode, int action, int mods)
|
||||||
@ -626,6 +634,19 @@ GLFWAPI int glfwGetKeyScancode(int key)
|
|||||||
return _glfwPlatformGetKeyScancode(key);
|
return _glfwPlatformGetKeyScancode(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GLFWAPI const char* glfwGetKeyboardLayoutName(void)
|
||||||
|
{
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||||
|
return _glfwPlatformGetKeyboardLayoutName();
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI GLFWkeyboardlayoutfun glfwSetKeyboardLayoutCallback(GLFWkeyboardlayoutfun cbfun)
|
||||||
|
{
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||||
|
_GLFW_SWAP_POINTERS(_glfw.callbacks.layout, cbfun);
|
||||||
|
return cbfun;
|
||||||
|
}
|
||||||
|
|
||||||
GLFWAPI int glfwGetKey(GLFWwindow* handle, int key)
|
GLFWAPI int glfwGetKey(GLFWwindow* handle, int key)
|
||||||
{
|
{
|
||||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
@ -572,6 +572,7 @@ struct _GLFWlibrary
|
|||||||
struct {
|
struct {
|
||||||
GLFWmonitorfun monitor;
|
GLFWmonitorfun monitor;
|
||||||
GLFWjoystickfun joystick;
|
GLFWjoystickfun joystick;
|
||||||
|
GLFWkeyboardlayoutfun layout;
|
||||||
} callbacks;
|
} callbacks;
|
||||||
|
|
||||||
// This is defined in the window API's platform.h
|
// This is defined in the window API's platform.h
|
||||||
@ -612,6 +613,7 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor);
|
|||||||
|
|
||||||
const char* _glfwPlatformGetScancodeName(int scancode);
|
const char* _glfwPlatformGetScancodeName(int scancode);
|
||||||
int _glfwPlatformGetKeyScancode(int key);
|
int _glfwPlatformGetKeyScancode(int key);
|
||||||
|
const char* _glfwPlatformGetKeyboardLayoutName(void);
|
||||||
|
|
||||||
void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor);
|
void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor);
|
||||||
void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos);
|
void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos);
|
||||||
@ -717,6 +719,7 @@ void _glfwInputWindowDamage(_GLFWwindow* window);
|
|||||||
void _glfwInputWindowCloseRequest(_GLFWwindow* window);
|
void _glfwInputWindowCloseRequest(_GLFWwindow* window);
|
||||||
void _glfwInputWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor);
|
void _glfwInputWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor);
|
||||||
|
|
||||||
|
void _glfwInputKeyboardLayout(void);
|
||||||
void _glfwInputKey(_GLFWwindow* window,
|
void _glfwInputKey(_GLFWwindow* window,
|
||||||
int key, int scancode, int action, int mods);
|
int key, int scancode, int action, int mods);
|
||||||
void _glfwInputChar(_GLFWwindow* window,
|
void _glfwInputChar(_GLFWwindow* window,
|
||||||
|
@ -310,6 +310,11 @@ int _glfwPlatformGetKeyScancode(int key)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* _glfwPlatformGetKeyboardLayoutName(void)
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
void _glfwPlatformGetRequiredInstanceExtensions(char** extensions)
|
void _glfwPlatformGetRequiredInstanceExtensions(char** extensions)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -602,6 +602,7 @@ void _glfwPlatformTerminate(void)
|
|||||||
SPIF_SENDCHANGE);
|
SPIF_SENDCHANGE);
|
||||||
|
|
||||||
free(_glfw.win32.clipboardString);
|
free(_glfw.win32.clipboardString);
|
||||||
|
free(_glfw.win32.keyboardLayoutName);
|
||||||
free(_glfw.win32.rawInput);
|
free(_glfw.win32.rawInput);
|
||||||
|
|
||||||
_glfwTerminateWGL();
|
_glfwTerminateWGL();
|
||||||
|
@ -331,6 +331,7 @@ typedef struct _GLFWlibraryWin32
|
|||||||
DWORD foregroundLockTimeout;
|
DWORD foregroundLockTimeout;
|
||||||
int acquiredMonitorCount;
|
int acquiredMonitorCount;
|
||||||
char* clipboardString;
|
char* clipboardString;
|
||||||
|
char* keyboardLayoutName;
|
||||||
short int keycodes[512];
|
short int keycodes[512];
|
||||||
short int scancodes[GLFW_KEY_LAST + 1];
|
short int scancodes[GLFW_KEY_LAST + 1];
|
||||||
char keynames[GLFW_KEY_LAST + 1][5];
|
char keynames[GLFW_KEY_LAST + 1][5];
|
||||||
|
@ -645,6 +645,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
|
|||||||
case WM_INPUTLANGCHANGE:
|
case WM_INPUTLANGCHANGE:
|
||||||
{
|
{
|
||||||
_glfwUpdateKeyNamesWin32();
|
_glfwUpdateKeyNamesWin32();
|
||||||
|
_glfwInputKeyboardLayout();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2042,6 +2043,48 @@ int _glfwPlatformGetKeyScancode(int key)
|
|||||||
return _glfw.win32.scancodes[key];
|
return _glfw.win32.scancodes[key];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* _glfwPlatformGetKeyboardLayoutName(void)
|
||||||
|
{
|
||||||
|
WCHAR klid[KL_NAMELENGTH];
|
||||||
|
int size;
|
||||||
|
LCID lcid;
|
||||||
|
WCHAR* language;
|
||||||
|
|
||||||
|
if (!GetKeyboardLayoutNameW(klid))
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Win32: Failed to retrieve keyboard layout name");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: We only care about the language part of the keyboard layout ID
|
||||||
|
lcid = MAKELCID(LANGIDFROMLCID(wcstoul(klid, NULL, 16)), 0);
|
||||||
|
|
||||||
|
size = GetLocaleInfoW(lcid, LOCALE_SLANGUAGE, NULL, 0);
|
||||||
|
if (!size)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Win32: Failed to retrieve keyboard layout name length");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
language = calloc(size, sizeof(WCHAR));
|
||||||
|
|
||||||
|
if (!GetLocaleInfoW(lcid, LOCALE_SLANGUAGE, language, size))
|
||||||
|
{
|
||||||
|
free(language);
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Win32: Failed to translate keyboard layout name");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(_glfw.win32.keyboardLayoutName);
|
||||||
|
_glfw.win32.keyboardLayoutName = _glfwCreateUTF8FromWideStringWin32(language);
|
||||||
|
free(language);
|
||||||
|
|
||||||
|
return _glfw.win32.keyboardLayoutName;
|
||||||
|
}
|
||||||
|
|
||||||
int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
|
int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
|
||||||
const GLFWimage* image,
|
const GLFWimage* image,
|
||||||
int xhot, int yhot)
|
int xhot, int yhot)
|
||||||
|
@ -640,6 +640,12 @@ static void keyboardHandleModifiers(void* data,
|
|||||||
if (mask & _glfw.wl.xkb.numLockMask)
|
if (mask & _glfw.wl.xkb.numLockMask)
|
||||||
modifiers |= GLFW_MOD_NUM_LOCK;
|
modifiers |= GLFW_MOD_NUM_LOCK;
|
||||||
_glfw.wl.xkb.modifiers = modifiers;
|
_glfw.wl.xkb.modifiers = modifiers;
|
||||||
|
|
||||||
|
if (_glfw.wl.xkb.group != group)
|
||||||
|
{
|
||||||
|
_glfw.wl.xkb.group = group;
|
||||||
|
_glfwInputKeyboardLayout();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION
|
#ifdef WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION
|
||||||
@ -1101,6 +1107,8 @@ int _glfwPlatformInit(void)
|
|||||||
_glfw_dlsym(_glfw.wl.xkb.handle, "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.wl.xkb.state_serialize_mods = (PFN_xkb_state_serialize_mods)
|
||||||
_glfw_dlsym(_glfw.wl.xkb.handle, "xkb_state_serialize_mods");
|
_glfw_dlsym(_glfw.wl.xkb.handle, "xkb_state_serialize_mods");
|
||||||
|
_glfw.wl.xkb.keymap_layout_get_name = (PFN_xkb_keymap_layout_get_name)
|
||||||
|
_glfw_dlsym(_glfw.wl.xkb.handle, "xkb_keymap_layout_get_name");
|
||||||
|
|
||||||
#ifdef HAVE_XKBCOMMON_COMPOSE_H
|
#ifdef HAVE_XKBCOMMON_COMPOSE_H
|
||||||
_glfw.wl.xkb.compose_table_new_from_locale = (PFN_xkb_compose_table_new_from_locale)
|
_glfw.wl.xkb.compose_table_new_from_locale = (PFN_xkb_compose_table_new_from_locale)
|
||||||
@ -1300,6 +1308,8 @@ void _glfwPlatformTerminate(void)
|
|||||||
free(_glfw.wl.clipboardString);
|
free(_glfw.wl.clipboardString);
|
||||||
if (_glfw.wl.clipboardSendString)
|
if (_glfw.wl.clipboardSendString)
|
||||||
free(_glfw.wl.clipboardSendString);
|
free(_glfw.wl.clipboardSendString);
|
||||||
|
if (_glfw.wl.keyboardLayoutName)
|
||||||
|
free(_glfw.wl.keyboardLayoutName);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* _glfwPlatformGetVersionString(void)
|
const char* _glfwPlatformGetVersionString(void)
|
||||||
|
@ -117,6 +117,7 @@ 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 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 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_mod_mask_t (* PFN_xkb_state_serialize_mods)(struct xkb_state*, enum xkb_state_component);
|
||||||
|
typedef const char * (* PFN_xkb_keymap_layout_get_name)(struct xkb_keymap*,xkb_layout_index_t);
|
||||||
#define xkb_context_new _glfw.wl.xkb.context_new
|
#define xkb_context_new _glfw.wl.xkb.context_new
|
||||||
#define xkb_context_unref _glfw.wl.xkb.context_unref
|
#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_new_from_string _glfw.wl.xkb.keymap_new_from_string
|
||||||
@ -128,6 +129,7 @@ typedef xkb_mod_mask_t (* PFN_xkb_state_serialize_mods)(struct xkb_state*, enum
|
|||||||
#define xkb_state_key_get_syms _glfw.wl.xkb.state_key_get_syms
|
#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_update_mask _glfw.wl.xkb.state_update_mask
|
||||||
#define xkb_state_serialize_mods _glfw.wl.xkb.state_serialize_mods
|
#define xkb_state_serialize_mods _glfw.wl.xkb.state_serialize_mods
|
||||||
|
#define xkb_keymap_layout_get_name _glfw.wl.xkb.keymap_layout_get_name
|
||||||
|
|
||||||
#ifdef HAVE_XKBCOMMON_COMPOSE_H
|
#ifdef HAVE_XKBCOMMON_COMPOSE_H
|
||||||
typedef struct xkb_compose_table* (* PFN_xkb_compose_table_new_from_locale)(struct xkb_context*, const char*, enum xkb_compose_compile_flags);
|
typedef struct xkb_compose_table* (* PFN_xkb_compose_table_new_from_locale)(struct xkb_context*, const char*, enum xkb_compose_compile_flags);
|
||||||
@ -259,6 +261,7 @@ typedef struct _GLFWlibraryWayland
|
|||||||
size_t clipboardSize;
|
size_t clipboardSize;
|
||||||
char* clipboardSendString;
|
char* clipboardSendString;
|
||||||
size_t clipboardSendSize;
|
size_t clipboardSendSize;
|
||||||
|
char* keyboardLayoutName;
|
||||||
int timerfd;
|
int timerfd;
|
||||||
short int keycodes[256];
|
short int keycodes[256];
|
||||||
short int scancodes[GLFW_KEY_LAST + 1];
|
short int scancodes[GLFW_KEY_LAST + 1];
|
||||||
@ -280,6 +283,7 @@ typedef struct _GLFWlibraryWayland
|
|||||||
xkb_mod_mask_t capsLockMask;
|
xkb_mod_mask_t capsLockMask;
|
||||||
xkb_mod_mask_t numLockMask;
|
xkb_mod_mask_t numLockMask;
|
||||||
unsigned int modifiers;
|
unsigned int modifiers;
|
||||||
|
xkb_layout_index_t group;
|
||||||
|
|
||||||
PFN_xkb_context_new context_new;
|
PFN_xkb_context_new context_new;
|
||||||
PFN_xkb_context_unref context_unref;
|
PFN_xkb_context_unref context_unref;
|
||||||
@ -292,6 +296,7 @@ typedef struct _GLFWlibraryWayland
|
|||||||
PFN_xkb_state_key_get_syms state_key_get_syms;
|
PFN_xkb_state_key_get_syms state_key_get_syms;
|
||||||
PFN_xkb_state_update_mask state_update_mask;
|
PFN_xkb_state_update_mask state_update_mask;
|
||||||
PFN_xkb_state_serialize_mods state_serialize_mods;
|
PFN_xkb_state_serialize_mods state_serialize_mods;
|
||||||
|
PFN_xkb_keymap_layout_get_name keymap_layout_get_name;
|
||||||
|
|
||||||
#ifdef HAVE_XKBCOMMON_COMPOSE_H
|
#ifdef HAVE_XKBCOMMON_COMPOSE_H
|
||||||
PFN_xkb_compose_table_new_from_locale compose_table_new_from_locale;
|
PFN_xkb_compose_table_new_from_locale compose_table_new_from_locale;
|
||||||
|
@ -1194,6 +1194,29 @@ int _glfwPlatformGetKeyScancode(int key)
|
|||||||
return _glfw.wl.scancodes[key];
|
return _glfw.wl.scancodes[key];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* _glfwPlatformGetKeyboardLayoutName(void)
|
||||||
|
{
|
||||||
|
if (!_glfw.wl.xkb.keymap)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Wayland: Keymap missing");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* name = xkb_keymap_layout_get_name(_glfw.wl.xkb.keymap,
|
||||||
|
_glfw.wl.xkb.group);
|
||||||
|
if (!name)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Wayland: Failed to query keyboard layout name");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(_glfw.wl.keyboardLayoutName);
|
||||||
|
_glfw.wl.keyboardLayoutName = _glfw_strdup(name);
|
||||||
|
return _glfw.wl.keyboardLayoutName;
|
||||||
|
}
|
||||||
|
|
||||||
int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
|
int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
|
||||||
const GLFWimage* image,
|
const GLFWimage* image,
|
||||||
int xhot, int yhot)
|
int xhot, int yhot)
|
||||||
|
@ -1153,6 +1153,8 @@ int _glfwPlatformInit(void)
|
|||||||
_glfw_dlsym(_glfw.x11.xlib.handle, "XFreeCursor");
|
_glfw_dlsym(_glfw.x11.xlib.handle, "XFreeCursor");
|
||||||
_glfw.x11.xlib.FreeEventData = (PFN_XFreeEventData)
|
_glfw.x11.xlib.FreeEventData = (PFN_XFreeEventData)
|
||||||
_glfw_dlsym(_glfw.x11.xlib.handle, "XFreeEventData");
|
_glfw_dlsym(_glfw.x11.xlib.handle, "XFreeEventData");
|
||||||
|
_glfw.x11.xlib.GetAtomName = (PFN_XGetAtomName)
|
||||||
|
_glfw_dlsym(_glfw.x11.xlib.handle, "XGetAtomName");
|
||||||
_glfw.x11.xlib.GetErrorText = (PFN_XGetErrorText)
|
_glfw.x11.xlib.GetErrorText = (PFN_XGetErrorText)
|
||||||
_glfw_dlsym(_glfw.x11.xlib.handle, "XGetErrorText");
|
_glfw_dlsym(_glfw.x11.xlib.handle, "XGetErrorText");
|
||||||
_glfw.x11.xlib.GetEventData = (PFN_XGetEventData)
|
_glfw.x11.xlib.GetEventData = (PFN_XGetEventData)
|
||||||
@ -1263,6 +1265,8 @@ int _glfwPlatformInit(void)
|
|||||||
_glfw_dlsym(_glfw.x11.xlib.handle, "XVisualIDFromVisual");
|
_glfw_dlsym(_glfw.x11.xlib.handle, "XVisualIDFromVisual");
|
||||||
_glfw.x11.xlib.WarpPointer = (PFN_XWarpPointer)
|
_glfw.x11.xlib.WarpPointer = (PFN_XWarpPointer)
|
||||||
_glfw_dlsym(_glfw.x11.xlib.handle, "XWarpPointer");
|
_glfw_dlsym(_glfw.x11.xlib.handle, "XWarpPointer");
|
||||||
|
_glfw.x11.xkb.AllocKeyboard = (PFN_XkbAllocKeyboard)
|
||||||
|
_glfw_dlsym(_glfw.x11.xlib.handle, "XkbAllocKeyboard");
|
||||||
_glfw.x11.xkb.FreeKeyboard = (PFN_XkbFreeKeyboard)
|
_glfw.x11.xkb.FreeKeyboard = (PFN_XkbFreeKeyboard)
|
||||||
_glfw_dlsym(_glfw.x11.xlib.handle, "XkbFreeKeyboard");
|
_glfw_dlsym(_glfw.x11.xlib.handle, "XkbFreeKeyboard");
|
||||||
_glfw.x11.xkb.FreeNames = (PFN_XkbFreeNames)
|
_glfw.x11.xkb.FreeNames = (PFN_XkbFreeNames)
|
||||||
@ -1376,6 +1380,9 @@ void _glfwPlatformTerminate(void)
|
|||||||
free(_glfw.x11.primarySelectionString);
|
free(_glfw.x11.primarySelectionString);
|
||||||
free(_glfw.x11.clipboardString);
|
free(_glfw.x11.clipboardString);
|
||||||
|
|
||||||
|
if (_glfw.x11.keyboardLayoutName)
|
||||||
|
XFree(_glfw.x11.keyboardLayoutName);
|
||||||
|
|
||||||
XUnregisterIMInstantiateCallback(_glfw.x11.display,
|
XUnregisterIMInstantiateCallback(_glfw.x11.display,
|
||||||
NULL, NULL, NULL,
|
NULL, NULL, NULL,
|
||||||
inputMethodInstantiateCallback,
|
inputMethodInstantiateCallback,
|
||||||
|
@ -76,6 +76,7 @@ typedef int (* PFN_XFree)(void*);
|
|||||||
typedef int (* PFN_XFreeColormap)(Display*,Colormap);
|
typedef int (* PFN_XFreeColormap)(Display*,Colormap);
|
||||||
typedef int (* PFN_XFreeCursor)(Display*,Cursor);
|
typedef int (* PFN_XFreeCursor)(Display*,Cursor);
|
||||||
typedef void (* PFN_XFreeEventData)(Display*,XGenericEventCookie*);
|
typedef void (* PFN_XFreeEventData)(Display*,XGenericEventCookie*);
|
||||||
|
typedef char* (* PFN_XGetAtomName)(Display*,Atom);
|
||||||
typedef int (* PFN_XGetErrorText)(Display*,int,char*,int);
|
typedef int (* PFN_XGetErrorText)(Display*,int,char*,int);
|
||||||
typedef Bool (* PFN_XGetEventData)(Display*,XGenericEventCookie*);
|
typedef Bool (* PFN_XGetEventData)(Display*,XGenericEventCookie*);
|
||||||
typedef char* (* PFN_XGetICValues)(XIC,...);
|
typedef char* (* PFN_XGetICValues)(XIC,...);
|
||||||
@ -133,6 +134,7 @@ typedef VisualID (* PFN_XVisualIDFromVisual)(Visual*);
|
|||||||
typedef int (* PFN_XWarpPointer)(Display*,Window,Window,int,int,unsigned int,unsigned int,int,int);
|
typedef int (* PFN_XWarpPointer)(Display*,Window,Window,int,int,unsigned int,unsigned int,int,int);
|
||||||
typedef void (* PFN_XkbFreeKeyboard)(XkbDescPtr,unsigned int,Bool);
|
typedef void (* PFN_XkbFreeKeyboard)(XkbDescPtr,unsigned int,Bool);
|
||||||
typedef void (* PFN_XkbFreeNames)(XkbDescPtr,unsigned int,Bool);
|
typedef void (* PFN_XkbFreeNames)(XkbDescPtr,unsigned int,Bool);
|
||||||
|
typedef XkbDescPtr (* PFN_XkbAllocKeyboard)(void);
|
||||||
typedef XkbDescPtr (* PFN_XkbGetMap)(Display*,unsigned int,unsigned int);
|
typedef XkbDescPtr (* PFN_XkbGetMap)(Display*,unsigned int,unsigned int);
|
||||||
typedef Status (* PFN_XkbGetNames)(Display*,unsigned int,XkbDescPtr);
|
typedef Status (* PFN_XkbGetNames)(Display*,unsigned int,XkbDescPtr);
|
||||||
typedef Status (* PFN_XkbGetState)(Display*,unsigned int,XkbStatePtr);
|
typedef Status (* PFN_XkbGetState)(Display*,unsigned int,XkbStatePtr);
|
||||||
@ -176,6 +178,7 @@ typedef void (* PFN_Xutf8SetWMProperties)(Display*,Window,const char*,const char
|
|||||||
#define XFreeColormap _glfw.x11.xlib.FreeColormap
|
#define XFreeColormap _glfw.x11.xlib.FreeColormap
|
||||||
#define XFreeCursor _glfw.x11.xlib.FreeCursor
|
#define XFreeCursor _glfw.x11.xlib.FreeCursor
|
||||||
#define XFreeEventData _glfw.x11.xlib.FreeEventData
|
#define XFreeEventData _glfw.x11.xlib.FreeEventData
|
||||||
|
#define XGetAtomName _glfw.x11.xlib.GetAtomName
|
||||||
#define XGetErrorText _glfw.x11.xlib.GetErrorText
|
#define XGetErrorText _glfw.x11.xlib.GetErrorText
|
||||||
#define XGetEventData _glfw.x11.xlib.GetEventData
|
#define XGetEventData _glfw.x11.xlib.GetEventData
|
||||||
#define XGetICValues _glfw.x11.xlib.GetICValues
|
#define XGetICValues _glfw.x11.xlib.GetICValues
|
||||||
@ -231,6 +234,7 @@ typedef void (* PFN_Xutf8SetWMProperties)(Display*,Window,const char*,const char
|
|||||||
#define XUnsetICFocus _glfw.x11.xlib.UnsetICFocus
|
#define XUnsetICFocus _glfw.x11.xlib.UnsetICFocus
|
||||||
#define XVisualIDFromVisual _glfw.x11.xlib.VisualIDFromVisual
|
#define XVisualIDFromVisual _glfw.x11.xlib.VisualIDFromVisual
|
||||||
#define XWarpPointer _glfw.x11.xlib.WarpPointer
|
#define XWarpPointer _glfw.x11.xlib.WarpPointer
|
||||||
|
#define XkbAllocKeyboard _glfw.x11.xkb.AllocKeyboard
|
||||||
#define XkbFreeKeyboard _glfw.x11.xkb.FreeKeyboard
|
#define XkbFreeKeyboard _glfw.x11.xkb.FreeKeyboard
|
||||||
#define XkbFreeNames _glfw.x11.xkb.FreeNames
|
#define XkbFreeNames _glfw.x11.xkb.FreeNames
|
||||||
#define XkbGetMap _glfw.x11.xkb.GetMap
|
#define XkbGetMap _glfw.x11.xkb.GetMap
|
||||||
@ -442,6 +446,7 @@ typedef struct _GLFWlibraryX11
|
|||||||
short int keycodes[256];
|
short int keycodes[256];
|
||||||
// GLFW key to X11 keycode LUT
|
// GLFW key to X11 keycode LUT
|
||||||
short int scancodes[GLFW_KEY_LAST + 1];
|
short int scancodes[GLFW_KEY_LAST + 1];
|
||||||
|
char* keyboardLayoutName;
|
||||||
// Where to place the cursor when re-enabled
|
// Where to place the cursor when re-enabled
|
||||||
double restoreCursorPosX, restoreCursorPosY;
|
double restoreCursorPosX, restoreCursorPosY;
|
||||||
// The window whose disabled cursor mode is active
|
// The window whose disabled cursor mode is active
|
||||||
@ -533,6 +538,7 @@ typedef struct _GLFWlibraryX11
|
|||||||
PFN_XFreeColormap FreeColormap;
|
PFN_XFreeColormap FreeColormap;
|
||||||
PFN_XFreeCursor FreeCursor;
|
PFN_XFreeCursor FreeCursor;
|
||||||
PFN_XFreeEventData FreeEventData;
|
PFN_XFreeEventData FreeEventData;
|
||||||
|
PFN_XGetAtomName GetAtomName;
|
||||||
PFN_XGetErrorText GetErrorText;
|
PFN_XGetErrorText GetErrorText;
|
||||||
PFN_XGetEventData GetEventData;
|
PFN_XGetEventData GetEventData;
|
||||||
PFN_XGetICValues GetICValues;
|
PFN_XGetICValues GetICValues;
|
||||||
@ -638,6 +644,7 @@ typedef struct _GLFWlibraryX11
|
|||||||
int major;
|
int major;
|
||||||
int minor;
|
int minor;
|
||||||
unsigned int group;
|
unsigned int group;
|
||||||
|
PFN_XkbAllocKeyboard AllocKeyboard;
|
||||||
PFN_XkbFreeKeyboard FreeKeyboard;
|
PFN_XkbFreeKeyboard FreeKeyboard;
|
||||||
PFN_XkbFreeNames FreeNames;
|
PFN_XkbFreeNames FreeNames;
|
||||||
PFN_XkbGetMap GetMap;
|
PFN_XkbGetMap GetMap;
|
||||||
|
@ -1184,6 +1184,7 @@ static void processEvent(XEvent *event)
|
|||||||
(((XkbEvent*) event)->state.changed & XkbGroupStateMask))
|
(((XkbEvent*) event)->state.changed & XkbGroupStateMask))
|
||||||
{
|
{
|
||||||
_glfw.x11.xkb.group = ((XkbEvent*) event)->state.group;
|
_glfw.x11.xkb.group = ((XkbEvent*) event)->state.group;
|
||||||
|
_glfwInputKeyboardLayout();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2920,6 +2921,42 @@ int _glfwPlatformGetKeyScancode(int key)
|
|||||||
return _glfw.x11.scancodes[key];
|
return _glfw.x11.scancodes[key];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* _glfwPlatformGetKeyboardLayoutName(void)
|
||||||
|
{
|
||||||
|
if (!_glfw.x11.xkb.available)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"X11: XKB extension required for keyboard layout names");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
XkbStateRec state = {0};
|
||||||
|
XkbGetState(_glfw.x11.display, XkbUseCoreKbd, &state);
|
||||||
|
|
||||||
|
XkbDescPtr desc = XkbAllocKeyboard();
|
||||||
|
if (XkbGetNames(_glfw.x11.display, XkbGroupNamesMask, desc) != Success)
|
||||||
|
{
|
||||||
|
XkbFreeKeyboard(desc, 0, True);
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"X11: Failed to retrieve keyboard layout names");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Atom atom = desc->names->groups[state.group];
|
||||||
|
XkbFreeKeyboard(desc, 0, True);
|
||||||
|
|
||||||
|
if (atom == None)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"X11: Name missing for current keyboard layout");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(_glfw.x11.keyboardLayoutName);
|
||||||
|
_glfw.x11.keyboardLayoutName = XGetAtomName(_glfw.x11.display, atom);
|
||||||
|
return _glfw.x11.keyboardLayoutName;
|
||||||
|
}
|
||||||
|
|
||||||
int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
|
int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
|
||||||
const GLFWimage* image,
|
const GLFWimage* image,
|
||||||
int xhot, int yhot)
|
int xhot, int yhot)
|
||||||
|
@ -465,6 +465,12 @@ static void drop_callback(GLFWwindow* window, int count, const char* paths[])
|
|||||||
printf(" %i: \"%s\"\n", i, paths[i]);
|
printf(" %i: \"%s\"\n", i, paths[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void keyboard_layout_callback(void)
|
||||||
|
{
|
||||||
|
printf("%08x at %0.3f: Keyboard layout changed to \'%s\'\n",
|
||||||
|
counter++, glfwGetTime(), glfwGetKeyboardLayoutName());
|
||||||
|
}
|
||||||
|
|
||||||
static void monitor_callback(GLFWmonitor* monitor, int event)
|
static void monitor_callback(GLFWmonitor* monitor, int event)
|
||||||
{
|
{
|
||||||
if (event == GLFW_CONNECTED)
|
if (event == GLFW_CONNECTED)
|
||||||
@ -546,6 +552,7 @@ int main(int argc, char** argv)
|
|||||||
|
|
||||||
glfwSetMonitorCallback(monitor_callback);
|
glfwSetMonitorCallback(monitor_callback);
|
||||||
glfwSetJoystickCallback(joystick_callback);
|
glfwSetJoystickCallback(joystick_callback);
|
||||||
|
glfwSetKeyboardLayoutCallback(keyboard_layout_callback);
|
||||||
|
|
||||||
while ((ch = getopt(argc, argv, "hfn:")) != -1)
|
while ((ch = getopt(argc, argv, "hfn:")) != -1)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user