Merge branch '2.6.x' into master

This commit is contained in:
Lukas Dürrenberger 2023-01-20 21:43:12 +01:00
commit d9f8df9ca0
31 changed files with 5353 additions and 1126 deletions

View File

@ -60,11 +60,12 @@ public:
////////////////////////////////////////////////////////////
struct KeyEvent
{
Keyboard::Key code; //!< Code of the key that has been pressed
bool alt; //!< Is the Alt key pressed?
bool control; //!< Is the Control key pressed?
bool shift; //!< Is the Shift key pressed?
bool system; //!< Is the System key pressed?
Keyboard::Key code; //!< Code of the key that has been pressed
Keyboard::Scancode scancode; //!< Physical code of the key that has been pressed
bool alt; //!< Is the Alt key pressed?
bool control; //!< Is the Control key pressed?
bool shift; //!< Is the Shift key pressed?
bool system; //!< Is the System key pressed?
};
////////////////////////////////////////////////////////////

View File

@ -30,15 +30,23 @@
#include <SFML/Window/Export.hpp>
namespace sf
{
class String;
////////////////////////////////////////////////////////////
/// \brief Give access to the real-time state of the keyboard
///
////////////////////////////////////////////////////////////
namespace sf::Keyboard
namespace Keyboard
{
////////////////////////////////////////////////////////////
/// \brief Key codes
///
/// The enumerators refer to the "localized" key; i.e. depending
/// on the layout set by the operating system, a key can be mapped
/// to `Y` or `Z`.
///
////////////////////////////////////////////////////////////
enum Key
{
@ -83,21 +91,21 @@ enum Key
LControl, //!< The left Control key
LShift, //!< The left Shift key
LAlt, //!< The left Alt key
LSystem, //!< The left OS specific key: window (Windows and Linux), apple (MacOS X), ...
LSystem, //!< The left OS specific key: window (Windows and Linux), apple (macOS), ...
RControl, //!< The right Control key
RShift, //!< The right Shift key
RAlt, //!< The right Alt key
RSystem, //!< The right OS specific key: window (Windows and Linux), apple (MacOS X), ...
RSystem, //!< The right OS specific key: window (Windows and Linux), apple (macOS), ...
Menu, //!< The Menu key
LBracket, //!< The [ key
RBracket, //!< The ] key
Semicolon, //!< The ; key
Comma, //!< The , key
Period, //!< The . key
Quote, //!< The ' key
Apostrophe, //!< The ' key
Slash, //!< The / key
Backslash, //!< The \ key
Tilde, //!< The ~ key
Grave, //!< The ` key
Equal, //!< The = key
Hyphen, //!< The - key (hyphen)
Space, //!< The Space key
@ -145,9 +153,205 @@ enum Key
F15, //!< The F15 key
Pause, //!< The Pause key
KeyCount //!< Keep last -- the total number of keyboard keys
KeyCount, //!< Keep last -- the total number of keyboard keys
// Deprecated values:
Tilde = Grave, //!< \deprecated Use Grave instead
Dash = Hyphen, //!< \deprecated Use Hyphen instead
BackSpace = Backspace, //!< \deprecated Use Backspace instead
BackSlash = Backslash, //!< \deprecated Use Backslash instead
SemiColon = Semicolon, //!< \deprecated Use Semicolon instead
Return = Enter, //!< \deprecated Use Enter instead
Quote = Apostrophe //!< \deprecated Use Apostrophe instead
};
////////////////////////////////////////////////////////////
/// \brief Scancodes
///
/// The enumerators are bound to a physical key and do not depend on
/// the keyboard layout used by the operating system. Usually, the AT-101
/// keyboard can be used as reference for the physical position of the keys.
///
////////////////////////////////////////////////////////////
struct Scan
{
// TODO: replace with enum class in SFML 3.
// Clang warns us rightfully that Scancode names shadow Key names.
// A safer solution would be to use a C++11 scoped enumeration (enum class),
// but it is not possible in SFML 2 which uses C++03.
// For now, we just ignore those warnings.
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wshadow"
#endif
enum Scancode
{
Unknown = -1, //!< Represents any scancode not present in this enum
A = 0, //!< Keyboard a and A key
B, //!< Keyboard b and B key
C, //!< Keyboard c and C key
D, //!< Keyboard d and D key
E, //!< Keyboard e and E key
F, //!< Keyboard f and F key
G, //!< Keyboard g and G key
H, //!< Keyboard h and H key
I, //!< Keyboard i and I key
J, //!< Keyboard j and J key
K, //!< Keyboard k and K key
L, //!< Keyboard l and L key
M, //!< Keyboard m and M key
N, //!< Keyboard n and N key
O, //!< Keyboard o and O key
P, //!< Keyboard p and P key
Q, //!< Keyboard q and Q key
R, //!< Keyboard r and R key
S, //!< Keyboard s and S key
T, //!< Keyboard t and T key
U, //!< Keyboard u and U key
V, //!< Keyboard v and V key
W, //!< Keyboard w and W key
X, //!< Keyboard x and X key
Y, //!< Keyboard y and Y key
Z, //!< Keyboard z and Z key
Num1, //!< Keyboard 1 and ! key
Num2, //!< Keyboard 2 and @ key
Num3, //!< Keyboard 3 and # key
Num4, //!< Keyboard 4 and $ key
Num5, //!< Keyboard 5 and % key
Num6, //!< Keyboard 6 and ^ key
Num7, //!< Keyboard 7 and & key
Num8, //!< Keyboard 8 and * key
Num9, //!< Keyboard 9 and ) key
Num0, //!< Keyboard 0 and ) key
Enter, //!< Keyboard Enter/Return key
Escape, //!< Keyboard Escape key
Backspace, //!< Keyboard Backspace key
Tab, //!< Keyboard Tab key
Space, //!< Keyboard Space key
Hyphen, //!< Keyboard - and _ key
Equal, //!< Keyboard = and +
LBracket, //!< Keyboard [ and { key
RBracket, //!< Keyboard ] and } key
// For US keyboards mapped to key 29 (Microsoft Keyboard Scan Code Specification)
// For Non-US keyboards mapped to key 42 (Microsoft Keyboard Scan Code Specification)
// Typical language mappings: Belg:£µ` FrCa:<>} Dan:*' Dutch:`´ Fren:µ* Ger:'# Ital:§ù LatAm:[}` Nor:*@ Span:ç} Swed:*' Swiss:$£} UK:~# Brazil:}]
Backslash, //!< Keyboard \ and | key OR various keys for Non-US keyboards
Semicolon, //!< Keyboard ; and : key
Apostrophe, //!< Keyboard ' and " key
Grave, //!< Keyboard ` and ~ key
Comma, //!< Keyboard , and < key
Period, //!< Keyboard . and > key
Slash, //!< Keyboard / and ? key
F1, //!< Keyboard F1 key
F2, //!< Keyboard F2 key
F3, //!< Keyboard F3 key
F4, //!< Keyboard F4 key
F5, //!< Keyboard F5 key
F6, //!< Keyboard F6 key
F7, //!< Keyboard F7 key
F8, //!< Keyboard F8 key
F9, //!< Keyboard F9 key
F10, //!< Keyboard F10 key
F11, //!< Keyboard F11 key
F12, //!< Keyboard F12 key
F13, //!< Keyboard F13 key
F14, //!< Keyboard F14 key
F15, //!< Keyboard F15 key
F16, //!< Keyboard F16 key
F17, //!< Keyboard F17 key
F18, //!< Keyboard F18 key
F19, //!< Keyboard F19 key
F20, //!< Keyboard F20 key
F21, //!< Keyboard F21 key
F22, //!< Keyboard F22 key
F23, //!< Keyboard F23 key
F24, //!< Keyboard F24 key
CapsLock, //!< Keyboard Caps %Lock key
PrintScreen, //!< Keyboard Print Screen key
ScrollLock, //!< Keyboard Scroll %Lock key
Pause, //!< Keyboard Pause key
Insert, //!< Keyboard Insert key
Home, //!< Keyboard Home key
PageUp, //!< Keyboard Page Up key
Delete, //!< Keyboard Delete Forward key
End, //!< Keyboard End key
PageDown, //!< Keyboard Page Down key
Right, //!< Keyboard Right Arrow key
Left, //!< Keyboard Left Arrow key
Down, //!< Keyboard Down Arrow key
Up, //!< Keyboard Up Arrow key
NumLock, //!< Keypad Num %Lock and Clear key
NumpadDivide, //!< Keypad / key
NumpadMultiply, //!< Keypad * key
NumpadMinus, //!< Keypad - key
NumpadPlus, //!< Keypad + key
NumpadEqual, //!< keypad = key
NumpadEnter, //!< Keypad Enter/Return key
NumpadDecimal, //!< Keypad . and Delete key
Numpad1, //!< Keypad 1 and End key
Numpad2, //!< Keypad 2 and Down Arrow key
Numpad3, //!< Keypad 3 and Page Down key
Numpad4, //!< Keypad 4 and Left Arrow key
Numpad5, //!< Keypad 5 key
Numpad6, //!< Keypad 6 and Right Arrow key
Numpad7, //!< Keypad 7 and Home key
Numpad8, //!< Keypad 8 and Up Arrow key
Numpad9, //!< Keypad 9 and Page Up key
Numpad0, //!< Keypad 0 and Insert key
// For US keyboards doesn't exist
// For Non-US keyboards mapped to key 45 (Microsoft Keyboard Scan Code Specification)
// Typical language mappings: Belg:<\> FrCa:«°» Dan:<\> Dutch:]|[ Fren:<> Ger:<|> Ital:<> LatAm:<> Nor:<> Span:<> Swed:<|> Swiss:<\> UK:\| Brazil: \|.
NonUsBackslash, //!< Keyboard Non-US \ and | key
Application, //!< Keyboard Application key
Execute, //!< Keyboard Execute key
ModeChange, //!< Keyboard Mode Change key
Help, //!< Keyboard Help key
Menu, //!< Keyboard Menu key
Select, //!< Keyboard Select key
Redo, //!< Keyboard Redo key
Undo, //!< Keyboard Undo key
Cut, //!< Keyboard Cut key
Copy, //!< Keyboard Copy key
Paste, //!< Keyboard Paste key
VolumeMute, //!< Keyboard Volume Mute key
VolumeUp, //!< Keyboard Volume Up key
VolumeDown, //!< Keyboard Volume Down key
MediaPlayPause, //!< Keyboard Media Play Pause key
MediaStop, //!< Keyboard Media Stop key
MediaNextTrack, //!< Keyboard Media Next Track key
MediaPreviousTrack, //!< Keyboard Media Previous Track key
LControl, //!< Keyboard Left Control key
LShift, //!< Keyboard Left Shift key
LAlt, //!< Keyboard Left Alt key
LSystem, //!< Keyboard Left System key
RControl, //!< Keyboard Right Control key
RShift, //!< Keyboard Right Shift key
RAlt, //!< Keyboard Right Alt key
RSystem, //!< Keyboard Right System key
Back, //!< Keyboard Back key
Forward, //!< Keyboard Forward key
Refresh, //!< Keyboard Refresh key
Stop, //!< Keyboard Stop key
Search, //!< Keyboard Search key
Favorites, //!< Keyboard Favorites key
HomePage, //!< Keyboard Home Page key
LaunchApplication1, //!< Keyboard Launch Application 1 key
LaunchApplication2, //!< Keyboard Launch Application 2 key
LaunchMail, //!< Keyboard Launch Mail key
LaunchMediaSelect, //!< Keyboard Launch Media Select key
ScancodeCount //!< Keep last -- the total number of scancodes
};
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
};
using Scancode = Scan::Scancode;
////////////////////////////////////////////////////////////
/// \brief Check if a key is pressed
///
@ -158,12 +362,73 @@ enum Key
////////////////////////////////////////////////////////////
SFML_WINDOW_API bool isKeyPressed(Key key);
////////////////////////////////////////////////////////////
/// \brief Check if a key is pressed
///
/// \param code Scancode to check
///
/// \return True if the physical key is pressed, false otherwise
///
////////////////////////////////////////////////////////////
SFML_WINDOW_API bool isKeyPressed(Scancode code);
////////////////////////////////////////////////////////////
/// \brief Localize a physical key to a logical one
///
/// \param code Scancode to localize
///
/// \return The key corresponding to the scancode under the current
/// keyboard layout used by the operating system, or
/// sf::Keyboard::Unknown when the scancode cannot be mapped
/// to a Key.
///
/// \see delocalize
///
////////////////////////////////////////////////////////////
SFML_WINDOW_API Key localize(Scancode code);
////////////////////////////////////////////////////////////
/// \brief Identify the physical key corresponding to a logical one
///
/// \param key Key to "delocalize"
///
/// \return The scancode corresponding to the key under the current
/// keyboard layout used by the operating system, or
/// sf::Keyboard::Scan::Unknown when the key cannot be mapped
/// to a sf::Keyboard::Scancode.
///
/// \see localize
///
////////////////////////////////////////////////////////////
SFML_WINDOW_API Scancode delocalize(Key key);
////////////////////////////////////////////////////////////
/// \brief Provide a string representation for a given scancode
///
/// The returned string is a short, non-technical description of
/// the key represented with the given scancode. Most effectively
/// used in user interfaces, as the description for the key takes
/// the users keyboard layout into consideration.
///
/// \warning The result is OS-dependent: for example, sf::Keyboard::Scan::LSystem
/// is "Left Meta" on Linux, "Left Windows" on Windows and
/// "Left Command" on macOS.
///
/// The current keyboard layout set by the operating system is used to
/// interpret the scancode: for example, sf::Keyboard::Semicolon is
/// mapped to ";" for layout and to "é" for others.
///
/// \return The localized description of the code
///
////////////////////////////////////////////////////////////
SFML_WINDOW_API String getDescription(Scancode code);
////////////////////////////////////////////////////////////
/// \brief Show or hide the virtual keyboard
///
/// Warning: the virtual keyboard is not supported on all
/// systems. It will typically be implemented on mobile OSes
/// (Android, iOS) but not on desktop OSes (Windows, Linux, ...).
/// \warning The virtual keyboard is not supported on all
/// systems. It will typically be implemented on mobile OSes
/// (Android, iOS) but not on desktop OSes (Windows, Linux, ...).
///
/// If the virtual keyboard is not available, this function does
/// nothing.
@ -172,7 +437,9 @@ SFML_WINDOW_API bool isKeyPressed(Key key);
///
////////////////////////////////////////////////////////////
SFML_WINDOW_API void setVirtualKeyboardVisible(bool visible);
} // namespace sf::Keyboard
} // namespace Keyboard
} // namespace sf
////////////////////////////////////////////////////////////
@ -206,6 +473,10 @@ SFML_WINDOW_API void setVirtualKeyboardVisible(bool visible);
/// {
/// // quit...
/// }
/// else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Scan::Grave))
/// {
/// // open in-game command line (if it's not already open)
/// }
/// \endcode
///
/// \see sf::Joystick, sf::Mouse, sf::Touch

View File

@ -44,6 +44,30 @@ bool InputImpl::isKeyPressed(Keyboard::Key /* key */)
return false;
}
bool InputImpl::isKeyPressed(Keyboard::Scancode /* codes */)
{
// Not applicable
return false;
}
Keyboard::Key InputImpl::localize(Keyboard::Scancode /* code */)
{
// Not applicable
return Keyboard::Unknown;
}
Keyboard::Scancode InputImpl::delocalize(Keyboard::Key /* key */)
{
// Not applicable
return Keyboard::Scan::Unknown;
}
String InputImpl::getDescription(Keyboard::Scancode /* code */)
{
// Not applicable
return "";
}
////////////////////////////////////////////////////////////
void InputImpl::setVirtualKeyboardVisible(bool visible)
{

View File

@ -41,19 +41,37 @@ class InputImpl
{
public:
////////////////////////////////////////////////////////////
/// \brief Check if a key is pressed
///
/// \param key Key to check
///
/// \return True if the key is pressed, false otherwise
/// \copydoc sf::Keyboard::isKeyPressed(Key)
///
////////////////////////////////////////////////////////////
static bool isKeyPressed(Keyboard::Key key);
////////////////////////////////////////////////////////////
/// \brief Show or hide the virtual keyboard
/// \copydoc sf::Keyboard::isKeyPressed(Scancode)
///
/// \param visible True to show, false to hide
////////////////////////////////////////////////////////////
static bool isKeyPressed(Keyboard::Scancode code);
////////////////////////////////////////////////////////////
/// \copydoc sf::Keyboard::localize
///
////////////////////////////////////////////////////////////
static Keyboard::Key localize(Keyboard::Scancode code);
////////////////////////////////////////////////////////////
/// \copydoc sf::Keyboard::delocalize
///
////////////////////////////////////////////////////////////
static Keyboard::Scancode delocalize(Keyboard::Key key);
////////////////////////////////////////////////////////////
/// \copydoc sf::Keyboard::getDescription
///
////////////////////////////////////////////////////////////
static String getDescription(Keyboard::Scancode code);
////////////////////////////////////////////////////////////
/// \copydoc sf::Keyboard::setVirtualKeyboardVisible
///
////////////////////////////////////////////////////////////
static void setVirtualKeyboardVisible(bool visible);

View File

@ -640,7 +640,7 @@ Keyboard::Key WindowImplAndroid::androidKeyToSF(std::int32_t key)
case AKEYCODE_ENTER: return Keyboard::Enter;
case AKEYCODE_DEL: return Keyboard::Backspace;
case AKEYCODE_FORWARD_DEL: return Keyboard::Delete;
case AKEYCODE_GRAVE: return Keyboard::Tilde;
case AKEYCODE_GRAVE: return Keyboard::Grave;
case AKEYCODE_MINUS: return Keyboard::Subtract;
case AKEYCODE_EQUALS: return Keyboard::Equal;
case AKEYCODE_LEFT_BRACKET: return Keyboard::LBracket;

View File

@ -116,6 +116,12 @@ elseif(SFML_OS_LINUX OR SFML_OS_FREEBSD OR SFML_OS_OPENBSD OR SFML_OS_NETBSD)
${SRCROOT}/Unix/ClipboardImpl.cpp
${SRCROOT}/Unix/InputImpl.cpp
${SRCROOT}/Unix/InputImpl.hpp
${SRCROOT}/Unix/KeyboardImpl.hpp
${SRCROOT}/Unix/KeyboardImpl.cpp
${SRCROOT}/Unix/KeySymToKeyMapping.hpp
${SRCROOT}/Unix/KeySymToKeyMapping.cpp
${SRCROOT}/Unix/KeySymToUnicodeMapping.hpp
${SRCROOT}/Unix/KeySymToUnicodeMapping.cpp
${SRCROOT}/Unix/SensorImpl.cpp
${SRCROOT}/Unix/SensorImpl.hpp
${SRCROOT}/Unix/Display.cpp

View File

@ -227,7 +227,7 @@ sf::Keyboard::Key toKey(int code)
case KEY_L: return sf::Keyboard::L;
case KEY_SEMICOLON: return sf::Keyboard::Semicolon;
case KEY_APOSTROPHE: return sf::Keyboard::Quote;
case KEY_GRAVE: return sf::Keyboard::Tilde;
case KEY_GRAVE: return sf::Keyboard::Grave;
case KEY_LEFTSHIFT: return sf::Keyboard::LShift;
case KEY_BACKSLASH: return sf::Keyboard::Backslash;
case KEY_Z: return sf::Keyboard::Z;
@ -414,12 +414,13 @@ bool eventProcess(sf::Event& event)
{
// key down and key up events
//
event.type = inputEvent.value ? sf::Event::KeyPressed : sf::Event::KeyReleased;
event.key.code = kb;
event.key.alt = altDown();
event.key.control = controlDown();
event.key.shift = shiftDown();
event.key.system = systemDown();
event.type = inputEvent.value ? sf::Event::KeyPressed : sf::Event::KeyReleased;
event.key.code = kb;
event.key.scancode = sf::Keyboard::Scan::Unknown; // TODO: not implemented
event.key.alt = altDown();
event.key.control = controlDown();
event.key.shift = shiftDown();
event.key.system = systemDown();
keyMap[static_cast<std::size_t>(kb)] = inputEvent.value;
@ -575,6 +576,41 @@ bool InputImpl::isKeyPressed(Keyboard::Key key)
return keyMap[static_cast<std::size_t>(key)];
}
////////////////////////////////////////////////////////////
bool InputImpl::isKeyPressed(Keyboard::Scancode /* code */)
{
// TODO: not implemented
err() << "sf::Keyboard::isKeyPressed(Keyboard::Scancode) is not implemented for DRM." << std::endl;
return false;
}
////////////////////////////////////////////////////////////
Keyboard::Key InputImpl::localize(Keyboard::Scancode /* code */)
{
// TODO: not implemented
err() << "sf::Keyboard::localize is not implemented for DRM." << std::endl;
return Keyboard::Unknown;
}
////////////////////////////////////////////////////////////
Keyboard::Scancode InputImpl::delocalize(Keyboard::Key /* key */)
{
// TODO: not implemented
err() << "sf::Keyboard::delocalize is not implemented for DRM." << std::endl;
return Keyboard::Scan::Unknown;
}
////////////////////////////////////////////////////////////
String InputImpl::getDescription(Keyboard::Scancode /* code */)
{
// TODO: not implemented
err() << "sf::Keyboard::getDescription is not implemented for DRM." << std::endl;
return "";
}
////////////////////////////////////////////////////////////
void InputImpl::setVirtualKeyboardVisible(bool /*visible*/)

View File

@ -42,19 +42,37 @@ class InputImpl
{
public:
////////////////////////////////////////////////////////////
/// \brief Check if a key is pressed
///
/// \param key Key to check
///
/// \return True if the key is pressed, false otherwise
/// \copydoc sf::Keyboard::isKeyPressed(Key)
///
////////////////////////////////////////////////////////////
static bool isKeyPressed(Keyboard::Key key);
////////////////////////////////////////////////////////////
/// \brief Show or hide the virtual keyboard
/// \copydoc sf::Keyboard::isKeyPressed(Scancode)
///
/// \param visible True to show, false to hide
////////////////////////////////////////////////////////////
static bool isKeyPressed(Keyboard::Scancode code);
////////////////////////////////////////////////////////////
/// \copydoc sf::Keyboard::localize
///
////////////////////////////////////////////////////////////
static Keyboard::Key localize(Keyboard::Scancode code);
////////////////////////////////////////////////////////////
/// \copydoc sf::Keyboard::delocalize
///
////////////////////////////////////////////////////////////
static Keyboard::Scancode delocalize(Keyboard::Key key);
////////////////////////////////////////////////////////////
/// \copydoc sf::Keyboard::getDescription
///
////////////////////////////////////////////////////////////
static String getDescription(Keyboard::Scancode code);
////////////////////////////////////////////////////////////
/// \copydoc sf::Keyboard::setVirtualKeyboardVisible
///
////////////////////////////////////////////////////////////
static void setVirtualKeyboardVisible(bool visible);

View File

@ -25,6 +25,7 @@
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/System/String.hpp>
#include <SFML/Window/InputImpl.hpp>
#include <SFML/Window/Keyboard.hpp>
@ -37,6 +38,29 @@ bool Keyboard::isKeyPressed(Key key)
return priv::InputImpl::isKeyPressed(key);
}
////////////////////////////////////////////////////////////
bool Keyboard::isKeyPressed(Scancode code)
{
return priv::InputImpl::isKeyPressed(code);
}
////////////////////////////////////////////////////////////
Keyboard::Key Keyboard::localize(Scancode code)
{
return priv::InputImpl::localize(code);
}
////////////////////////////////////////////////////////////
Keyboard::Scancode Keyboard::delocalize(Key key)
{
return priv::InputImpl::delocalize(key);
}
////////////////////////////////////////////////////////////
String Keyboard::getDescription(Scancode code)
{
return priv::InputImpl::getDescription(code);
}
////////////////////////////////////////////////////////////
void Keyboard::setVirtualKeyboardVisible(bool visible)

View File

@ -73,16 +73,6 @@ public:
////////////////////////////////////////////////////////////
static HIDInputManager& getInstance();
////////////////////////////////////////////////////////////
/// \brief Check if a key is pressed
///
/// \param key Key to check
///
/// \return True if the key is pressed, false otherwise
///
////////////////////////////////////////////////////////////
bool isKeyPressed(Keyboard::Key key);
////////////////////////////////////////////////////////////
/// \brief Get the usb location ID of a given device
///
@ -102,28 +92,69 @@ public:
/// \return a retained CFDictionaryRef
///
////////////////////////////////////////////////////////////
static CFDictionaryRef copyDevicesMask(UInt32 page, UInt32 usage);
static CFDictionaryRef copyDevicesMask(std::uint32_t page, std::uint32_t usage);
////////////////////////////////////////////////////////////
/// Try to convert a character into a SFML key code.
/// \brief Try to convert a character into a SFML key code
///
/// Return sf::Keyboard::Unknown if it doesn't match any 'localized' keys.
///
/// By 'localized' I mean keys that depend on the keyboard layout
/// and might not be the same as the US keycode in some country
/// (e.g. the keys 'Y' and 'Z' are switched on QWERTZ keyboard and
/// By 'localized' we mean keys that depend on the keyboard layout
/// and might not be the same as the US keycode for some countries
/// (e.g. the keys 'Y' and 'Z' are swapped on QWERTZ keyboard and
/// US keyboard layouts.)
///
////////////////////////////////////////////////////////////
static Keyboard::Key localizedKeys(UniChar ch);
static Keyboard::Key localizedKey(UniChar ch);
////////////////////////////////////////////////////////////
/// Try to convert a virtual keycode into a SFML key code.
/// \brief Opposite transformation as localizedKeys
///
/// Return sf::Keyboard::Unknown if the keycode is unknown.
/// Return 0x00 (NULL) for non-convertible keys/numpad numbers.
/// For letters, uppercase codes are returned.
/// Some returned value are specific to macOS.
///
////////////////////////////////////////////////////////////
static Keyboard::Key nonLocalizedKeys(UniChar virtualKeycode);
static UniChar toUnicode(Keyboard::Key key);
////////////////////////////////////////////////////////////
/// \brief Try to convert a virtual keycode (HID level) into a
/// SFML scancode.
///
/// Return sf::Keyboard::Scan::Unknown if the keycode is unknown.
///
////////////////////////////////////////////////////////////
static Keyboard::Scancode nonLocalizedKey(UniChar virtualKeycode);
////////////////////////////////////////////////////////////
/// \copydoc sf::Keyboard::isKeyPressed(Key)
///
////////////////////////////////////////////////////////////
bool isKeyPressed(Keyboard::Key key);
////////////////////////////////////////////////////////////
/// \copydoc sf::Keyboard::isKeyPressed(Scancode)
///
////////////////////////////////////////////////////////////
bool isKeyPressed(Keyboard::Scancode code);
////////////////////////////////////////////////////////////
/// \copydoc sf::Keyboard::localize
///
////////////////////////////////////////////////////////////
Keyboard::Key localize(Keyboard::Scancode code);
////////////////////////////////////////////////////////////
/// \copydoc sf::Keyboard::delocalize
///
////////////////////////////////////////////////////////////
Keyboard::Scancode delocalize(Keyboard::Key key);
////////////////////////////////////////////////////////////
/// \copydoc sf::Keyboard::getDescription
///
////////////////////////////////////////////////////////////
String getDescription(Keyboard::Scancode code);
private:
////////////////////////////////////////////////////////////
@ -141,7 +172,13 @@ private:
////////////////////////////////////////////////////////////
/// \brief Initialize the keyboard part of this class
///
/// If something went wrong freeUp is called
/// If something went wrong freeUp is called.
///
/// In a nutshell, this function does this:
///
/// for each connected keyboard kb:
/// for each key k of kb:
/// memorize k -> scancode mapping
///
////////////////////////////////////////////////////////////
void initializeKeyboard();
@ -150,28 +187,50 @@ private:
/// \brief Load the given keyboard into m_keys
///
/// If the given keyboard has no key this function simply
/// returns. freeUp is _not_ called because this is not fatal.
/// returns without calling freeUp because this is not fatal.
///
/// \param keyboard Keyboard to load
///
/// \see initializeKeyboard
///
////////////////////////////////////////////////////////////
void loadKeyboard(IOHIDDeviceRef keyboard);
////////////////////////////////////////////////////////////
/// \brief Load the given key into m_keys
///
/// freeUp is _not_ called by this function.
/// On error, freeUp is _not_ called by this function.
///
/// \param key Key to load
///
/// \see initializeKeyboard
///
////////////////////////////////////////////////////////////
void loadKey(IOHIDElementRef key);
////////////////////////////////////////////////////////////
/// \brief Regenerate the mappings from/to Key and Scancode
///
////////////////////////////////////////////////////////////
void buildMappings();
////////////////////////////////////////////////////////////
/// \brief Callback to regenerate mappings from/to Key and
/// Scancode when there's a keyboard layout change
///
////////////////////////////////////////////////////////////
static void keyboardChanged(CFNotificationCenterRef /* center */,
void* observer,
CFStringRef /* name */,
const void* /* object */,
CFDictionaryRef /* userInfo */);
////////////////////////////////////////////////////////////
/// \brief Release all resources
///
/// Close all connections to any devices, if required
/// Set m_isValid to false
/// Close all connections to any devices.
///
/// \see initializeKeyboard
///
////////////////////////////////////////////////////////////
void freeUp();
@ -179,14 +238,14 @@ private:
////////////////////////////////////////////////////////////
/// \brief Filter the devices and return them
///
/// freeUp is _not_ called by this function.
/// On error, freeUp is _not_ called by this function.
///
/// \param page HID page like kHIDPage_GenericDesktop
/// \param usage HID usage page like kHIDUsage_GD_Keyboard or kHIDUsage_GD_Mouse
/// \return a retained CFSetRef of IOHIDDeviceRef or a null pointer
/// \return a retained, non-empty CFSetRef of IOHIDDeviceRef or a null pointer
///
////////////////////////////////////////////////////////////
CFSetRef copyDevices(UInt32 page, UInt32 usage);
CFSetRef copyDevices(std::uint32_t page, std::uint32_t usage);
////////////////////////////////////////////////////////////
/// \brief Check if a key is pressed
@ -201,34 +260,46 @@ private:
bool isPressed(IOHIDElements& elements);
////////////////////////////////////////////////////////////
/// \brief Convert a HID key usage to its corresponding virtual code
///
/// See IOHIDUsageTables.h
/// \brief Convert a HID key usage to its corresponding scancode
///
/// \param usage Any kHIDUsage_Keyboard* usage
/// \return the virtual code associate with the given HID key usage
/// or 0xff if it is associate with no virtual code
/// \return the scancode associated with the given HID key usage
/// or Scan::Unknown if it is associated with no scancode.
///
////////////////////////////////////////////////////////////
static UInt8 usageToVirtualCode(UInt32 usage);
static Keyboard::Scancode usageToScancode(std::uint32_t usage);
////////////////////////////////////////////////////////////
/// Convert the scancode to the expected virtual code.
///
////////////////////////////////////////////////////////////
static std::uint8_t scanToVirtualCode(Keyboard::Scancode code);
////////////////////////////////////////////////////////////
/// Fallback convertion for keys which aren't expected to be impacted
/// by the layout. Can return Unknown.
///
////////////////////////////////////////////////////////////
static Keyboard::Key localizedKeyFallback(Keyboard::Scancode code);
////////////////////////////////////////////////////////////
// Member data
////////////////////////////////////////////////////////////
bool m_isValid{true}; ///< If any error occurs this variable is false
CFDataRef m_layoutData{}; ///< CFData containing the layout
UCKeyboardLayout* m_layout{}; ///< Current Keyboard Layout
IOHIDManagerRef m_manager{}; ///< HID Manager
IOHIDElements m_keys[Keyboard::KeyCount]; ///< All the keys on any connected keyboard
IOHIDManagerRef m_manager{}; ///< Underlying HID Manager
IOHIDElements m_keys[Keyboard::Scan::ScancodeCount]; ///< All the keys on any connected keyboard
Keyboard::Scancode m_keyToScancodeMapping[Keyboard::KeyCount]; ///< Mapping from Key to Scancode
Keyboard::Key m_scancodeToKeyMapping[Keyboard::Scan::ScancodeCount]; ///< Mapping from Scancode to Key
////////////////////////////////////////////////////////////
/// m_keys' index corresponds to sf::Keyboard::Key enum.
/// if no key is assigned with key XYZ then m_keys[XYZ].size() == 0.
/// if there are several keyboards connected and several HID keys associate
/// m_keys' index corresponds to sf::Keyboard::Scancode enum.
/// If no key is assigned with key XYZ then m_keys[XYZ].size() == 0.
/// If there are several keyboards connected and several HID keys associated
/// with the same sf::Keyboard::Key then m_keys[XYZ] contains all these
/// HID keys.
///
/// The mappings (both directions) get invalidated when the
/// keyboard layout changes. They both default to (Scan::)Unknown.
///
////////////////////////////////////////////////////////////
};

File diff suppressed because it is too large Load Diff

View File

@ -42,19 +42,37 @@ class InputImpl
{
public:
////////////////////////////////////////////////////////////
/// \brief Check if a key is pressed
///
/// \param key Key to check
///
/// \return True if the key is pressed, false otherwise
/// \copydoc sf::Keyboard::isKeyPressed(Key)
///
////////////////////////////////////////////////////////////
static bool isKeyPressed(Keyboard::Key key);
////////////////////////////////////////////////////////////
/// \brief Show or hide the virtual keyboard
/// \copydoc sf::Keyboard::isKeyPressed(Scancode)
///
/// \param visible True to show, false to hide
////////////////////////////////////////////////////////////
static bool isKeyPressed(Keyboard::Scancode code);
////////////////////////////////////////////////////////////
/// \copydoc sf::Keyboard::localize
///
////////////////////////////////////////////////////////////
static Keyboard::Key localize(Keyboard::Scancode code);
////////////////////////////////////////////////////////////
/// \copydoc sf::Keyboard::delocalize
///
////////////////////////////////////////////////////////////
static Keyboard::Scancode delocalize(Keyboard::Key key);
////////////////////////////////////////////////////////////
/// \copydoc sf::Keyboard::getDescription
///
////////////////////////////////////////////////////////////
static String getDescription(Keyboard::Scancode code);
////////////////////////////////////////////////////////////
/// \copydoc sf::Keyboard::setVirtualKeyboardVisible
///
////////////////////////////////////////////////////////////
static void setVirtualKeyboardVisible(bool visible);

View File

@ -41,9 +41,6 @@
/// In order to keep track of the keyboard's state and mouse buttons' state
/// we use the HID manager. Mouse position is handled differently.
///
/// NB: we probably could use
/// NSEvent +addGlobalMonitorForEventsMatchingMask:handler: for mouse only.
///
////////////////////////////////////////////////////////////
namespace sf::priv
@ -118,6 +115,7 @@ SFOpenGLView* getSFOpenGLViewFromSFMLWindow(const WindowBase& window)
return view;
}
////////////////////////////////////////////////////////////
bool InputImpl::isKeyPressed(Keyboard::Key key)
{
@ -126,6 +124,34 @@ bool InputImpl::isKeyPressed(Keyboard::Key key)
}
////////////////////////////////////////////////////////////
bool InputImpl::isKeyPressed(Keyboard::Scancode code)
{
return HIDInputManager::getInstance().isKeyPressed(code);
}
////////////////////////////////////////////////////////////
Keyboard::Key InputImpl::localize(Keyboard::Scancode code)
{
return HIDInputManager::getInstance().localize(code);
}
////////////////////////////////////////////////////////////
Keyboard::Scancode InputImpl::delocalize(Keyboard::Key key)
{
return HIDInputManager::getInstance().delocalize(key);
}
////////////////////////////////////////////////////////////
String InputImpl::getDescription(Keyboard::Scancode code)
{
return HIDInputManager::getInstance().getDescription(code);
}
////////////////////////////////////////////////////////////
void InputImpl::setVirtualKeyboardVisible(bool /*visible*/)
{

View File

@ -57,7 +57,7 @@ void initialiseKeyboardHelper();
/// \brief Set up a SFML key event based on the given modifiers flags and key code
///
////////////////////////////////////////////////////////////
sf::Event::KeyEvent keyEventWithModifiers(NSUInteger modifiers, sf::Keyboard::Key key);
sf::Event::KeyEvent keyEventWithModifiers(NSUInteger modifiers, sf::Keyboard::Key key, sf::Keyboard::Scancode code);
////////////////////////////////////////////////////////////

View File

@ -62,6 +62,7 @@ struct ModifiersState
BOOL leftAlternateWasDown;
BOOL leftControlWasDown;
BOOL rightControlWasDown;
BOOL capsLockWasOn;
};
@ -95,6 +96,7 @@ void processOneModifier(NSUInteger modifiers,
NSUInteger mask,
BOOL& wasDown,
sf::Keyboard::Key key,
sf::Keyboard::Scancode code,
sf::priv::WindowImplCocoa& requester);
@ -112,6 +114,8 @@ void processLeftRightModifiers(
BOOL& rightWasDown,
sf::Keyboard::Key leftKey,
sf::Keyboard::Key rightKey,
sf::Keyboard::Scancode leftCode,
sf::Keyboard::Scancode rightCode,
sf::priv::WindowImplCocoa& requester);
@ -137,20 +141,22 @@ void initialiseKeyboardHelper()
state.rightAlternateWasDown = isKeyMaskActive(modifiers, NSRightAlternateKeyMask);
state.leftControlWasDown = isKeyMaskActive(modifiers, NSLeftControlKeyMask);
state.rightControlWasDown = isKeyMaskActive(modifiers, NSRightControlKeyMask);
state.capsLockWasOn = isKeyMaskActive(modifiers, NSEventModifierFlagCapsLock);
isStateInitialized = YES;
}
////////////////////////////////////////////////////////
sf::Event::KeyEvent keyEventWithModifiers(NSUInteger modifiers, sf::Keyboard::Key key)
sf::Event::KeyEvent keyEventWithModifiers(NSUInteger modifiers, sf::Keyboard::Key key, sf::Keyboard::Scancode code)
{
sf::Event::KeyEvent event;
event.code = key;
event.alt = modifiers & NSAlternateKeyMask;
event.control = modifiers & NSControlKeyMask;
event.shift = modifiers & NSShiftKeyMask;
event.system = modifiers & NSCommandKeyMask;
event.code = key;
event.scancode = code;
event.alt = modifiers & NSAlternateKeyMask;
event.control = modifiers & NSControlKeyMask;
event.shift = modifiers & NSShiftKeyMask;
event.system = modifiers & NSCommandKeyMask;
return event;
}
@ -167,6 +173,8 @@ void handleModifiersChanged(NSUInteger modifiers, sf::priv::WindowImplCocoa& req
state.rightShiftWasDown,
sf::Keyboard::LShift,
sf::Keyboard::RShift,
sf::Keyboard::Scan::LShift,
sf::Keyboard::Scan::RShift,
requester);
// Handle command
@ -177,6 +185,8 @@ void handleModifiersChanged(NSUInteger modifiers, sf::priv::WindowImplCocoa& req
state.rightCommandWasDown,
sf::Keyboard::LSystem,
sf::Keyboard::RSystem,
sf::Keyboard::Scan::LSystem,
sf::Keyboard::Scan::RSystem,
requester);
// Handle option (alt)
@ -187,6 +197,8 @@ void handleModifiersChanged(NSUInteger modifiers, sf::priv::WindowImplCocoa& req
state.rightAlternateWasDown,
sf::Keyboard::LAlt,
sf::Keyboard::RAlt,
sf::Keyboard::Scan::LAlt,
sf::Keyboard::Scan::RAlt,
requester);
// Handle control
@ -197,7 +209,17 @@ void handleModifiersChanged(NSUInteger modifiers, sf::priv::WindowImplCocoa& req
state.rightControlWasDown,
sf::Keyboard::LControl,
sf::Keyboard::RControl,
sf::Keyboard::Scan::LControl,
sf::Keyboard::Scan::RControl,
requester);
// Handle caps lock
processOneModifier(modifiers,
NSEventModifierFlagCapsLock,
state.capsLockWasOn,
sf::Keyboard::Unknown,
sf::Keyboard::Scan::CapsLock,
requester);
}
@ -212,10 +234,15 @@ BOOL isKeyMaskActive(NSUInteger modifiers, NSUInteger mask)
////////////////////////////////////////////////////////
void processOneModifier(NSUInteger modifiers, NSUInteger mask, BOOL& wasDown, sf::Keyboard::Key key, sf::priv::WindowImplCocoa& requester)
void processOneModifier(NSUInteger modifiers,
NSUInteger mask,
BOOL& wasDown,
sf::Keyboard::Key key,
sf::Keyboard::Scancode code,
sf::priv::WindowImplCocoa& requester)
{
// Setup a potential event key.
sf::Event::KeyEvent event = keyEventWithModifiers(modifiers, key);
sf::Event::KeyEvent event = keyEventWithModifiers(modifiers, key, code);
// State
BOOL isDown = isKeyMaskActive(modifiers, mask);
@ -244,8 +271,10 @@ void processLeftRightModifiers(
BOOL& rightWasDown,
sf::Keyboard::Key leftKey,
sf::Keyboard::Key rightKey,
sf::Keyboard::Scancode leftCode,
sf::Keyboard::Scancode rightCode,
sf::priv::WindowImplCocoa& requester)
{
processOneModifier(modifiers, leftMask, leftWasDown, leftKey, requester);
processOneModifier(modifiers, rightMask, rightWasDown, rightKey, requester);
processOneModifier(modifiers, leftMask, leftWasDown, leftKey, leftCode, requester);
processOneModifier(modifiers, rightMask, rightWasDown, rightKey, rightCode, requester);
}

View File

@ -86,7 +86,7 @@
{
sf::Event::KeyEvent key = [SFOpenGLView convertNSKeyEventToSFMLEvent:theEvent];
if (key.code != sf::Keyboard::Unknown) // The key is recognized.
if ((key.code != sf::Keyboard::Unknown) || (key.scancode != sf::Keyboard::Scan::Unknown))
m_requester->keyDown(key);
}
@ -158,7 +158,7 @@
sf::Event::KeyEvent key = [SFOpenGLView convertNSKeyEventToSFMLEvent:theEvent];
if (key.code != sf::Keyboard::Unknown) // The key is recognized.
if ((key.code != sf::Keyboard::Unknown) || (key.scancode != sf::Keyboard::Scan::Unknown))
m_requester->keyUp(key);
}
@ -180,21 +180,13 @@
////////////////////////////////////////////////////////
+ (sf::Event::KeyEvent)convertNSKeyEventToSFMLEvent:(NSEvent*)event
{
// Key code
sf::Keyboard::Key key = sf::Keyboard::Unknown;
// The scancode always depends on the hardware keyboard, not some OS setting.
sf::Keyboard::Scancode code = sf::priv::HIDInputManager::nonLocalizedKey([event keyCode]);
// First we look if the key down is from a list of characters
// that depend on keyboard localization.
NSString* string = [event charactersIgnoringModifiers];
if ([string length] > 0)
key = sf::priv::HIDInputManager::localizedKeys([string characterAtIndex:0]);
// Get the corresponding key under the current keyboard layout.
sf::Keyboard::Key key = sf::Keyboard::localize(code);
// If the key is not a localized one, we try to find a corresponding code
// through virtual key code.
if (key == sf::Keyboard::Unknown)
key = sf::priv::HIDInputManager::nonLocalizedKeys([event keyCode]);
return keyEventWithModifiers([event modifierFlags], key);
return keyEventWithModifiers([event modifierFlags], key, code);
}

View File

@ -25,9 +25,12 @@
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/System/String.hpp>
#include <SFML/Window/Unix/Display.hpp>
#include <SFML/Window/Unix/InputImpl.hpp>
#include <SFML/Window/Window.hpp>
#include <SFML/Window/Unix/KeyboardImpl.hpp>
#include <SFML/Window/WindowBase.hpp>
#include <SFML/Window/WindowHandle.hpp>
#include <X11/Xlib.h>
#include <X11/keysym.h>
@ -38,145 +41,35 @@ namespace sf::priv
////////////////////////////////////////////////////////////
bool InputImpl::isKeyPressed(Keyboard::Key key)
{
// Get the corresponding X11 keysym
KeySym keysym = 0;
return KeyboardImpl::isKeyPressed(key);
}
// clang-format off
switch (key)
{
case Keyboard::LShift: keysym = XK_Shift_L; break;
case Keyboard::RShift: keysym = XK_Shift_R; break;
case Keyboard::LControl: keysym = XK_Control_L; break;
case Keyboard::RControl: keysym = XK_Control_R; break;
case Keyboard::LAlt: keysym = XK_Alt_L; break;
case Keyboard::RAlt: keysym = XK_Alt_R; break;
case Keyboard::LSystem: keysym = XK_Super_L; break;
case Keyboard::RSystem: keysym = XK_Super_R; break;
case Keyboard::Menu: keysym = XK_Menu; break;
case Keyboard::Escape: keysym = XK_Escape; break;
case Keyboard::Semicolon: keysym = XK_semicolon; break;
case Keyboard::Slash: keysym = XK_slash; break;
case Keyboard::Equal: keysym = XK_equal; break;
case Keyboard::Hyphen: keysym = XK_minus; break;
case Keyboard::LBracket: keysym = XK_bracketleft; break;
case Keyboard::RBracket: keysym = XK_bracketright; break;
case Keyboard::Comma: keysym = XK_comma; break;
case Keyboard::Period: keysym = XK_period; break;
case Keyboard::Quote: keysym = XK_apostrophe; break;
case Keyboard::Backslash: keysym = XK_backslash; break;
case Keyboard::Tilde: keysym = XK_grave; break;
case Keyboard::Space: keysym = XK_space; break;
case Keyboard::Enter: keysym = XK_Return; break;
case Keyboard::Backspace: keysym = XK_BackSpace; break;
case Keyboard::Tab: keysym = XK_Tab; break;
case Keyboard::PageUp: keysym = XK_Prior; break;
case Keyboard::PageDown: keysym = XK_Next; break;
case Keyboard::End: keysym = XK_End; break;
case Keyboard::Home: keysym = XK_Home; break;
case Keyboard::Insert: keysym = XK_Insert; break;
case Keyboard::Delete: keysym = XK_Delete; break;
case Keyboard::Add: keysym = XK_KP_Add; break;
case Keyboard::Subtract: keysym = XK_KP_Subtract; break;
case Keyboard::Multiply: keysym = XK_KP_Multiply; break;
case Keyboard::Divide: keysym = XK_KP_Divide; break;
case Keyboard::Pause: keysym = XK_Pause; break;
case Keyboard::F1: keysym = XK_F1; break;
case Keyboard::F2: keysym = XK_F2; break;
case Keyboard::F3: keysym = XK_F3; break;
case Keyboard::F4: keysym = XK_F4; break;
case Keyboard::F5: keysym = XK_F5; break;
case Keyboard::F6: keysym = XK_F6; break;
case Keyboard::F7: keysym = XK_F7; break;
case Keyboard::F8: keysym = XK_F8; break;
case Keyboard::F9: keysym = XK_F9; break;
case Keyboard::F10: keysym = XK_F10; break;
case Keyboard::F11: keysym = XK_F11; break;
case Keyboard::F12: keysym = XK_F12; break;
case Keyboard::F13: keysym = XK_F13; break;
case Keyboard::F14: keysym = XK_F14; break;
case Keyboard::F15: keysym = XK_F15; break;
case Keyboard::Left: keysym = XK_Left; break;
case Keyboard::Right: keysym = XK_Right; break;
case Keyboard::Up: keysym = XK_Up; break;
case Keyboard::Down: keysym = XK_Down; break;
case Keyboard::Numpad0: keysym = XK_KP_Insert; break;
case Keyboard::Numpad1: keysym = XK_KP_End; break;
case Keyboard::Numpad2: keysym = XK_KP_Down; break;
case Keyboard::Numpad3: keysym = XK_KP_Page_Down; break;
case Keyboard::Numpad4: keysym = XK_KP_Left; break;
case Keyboard::Numpad5: keysym = XK_KP_Begin; break;
case Keyboard::Numpad6: keysym = XK_KP_Right; break;
case Keyboard::Numpad7: keysym = XK_KP_Home; break;
case Keyboard::Numpad8: keysym = XK_KP_Up; break;
case Keyboard::Numpad9: keysym = XK_KP_Page_Up; break;
case Keyboard::A: keysym = XK_a; break;
case Keyboard::B: keysym = XK_b; break;
case Keyboard::C: keysym = XK_c; break;
case Keyboard::D: keysym = XK_d; break;
case Keyboard::E: keysym = XK_e; break;
case Keyboard::F: keysym = XK_f; break;
case Keyboard::G: keysym = XK_g; break;
case Keyboard::H: keysym = XK_h; break;
case Keyboard::I: keysym = XK_i; break;
case Keyboard::J: keysym = XK_j; break;
case Keyboard::K: keysym = XK_k; break;
case Keyboard::L: keysym = XK_l; break;
case Keyboard::M: keysym = XK_m; break;
case Keyboard::N: keysym = XK_n; break;
case Keyboard::O: keysym = XK_o; break;
case Keyboard::P: keysym = XK_p; break;
case Keyboard::Q: keysym = XK_q; break;
case Keyboard::R: keysym = XK_r; break;
case Keyboard::S: keysym = XK_s; break;
case Keyboard::T: keysym = XK_t; break;
case Keyboard::U: keysym = XK_u; break;
case Keyboard::V: keysym = XK_v; break;
case Keyboard::W: keysym = XK_w; break;
case Keyboard::X: keysym = XK_x; break;
case Keyboard::Y: keysym = XK_y; break;
case Keyboard::Z: keysym = XK_z; break;
case Keyboard::Num0: keysym = XK_0; break;
case Keyboard::Num1: keysym = XK_1; break;
case Keyboard::Num2: keysym = XK_2; break;
case Keyboard::Num3: keysym = XK_3; break;
case Keyboard::Num4: keysym = XK_4; break;
case Keyboard::Num5: keysym = XK_5; break;
case Keyboard::Num6: keysym = XK_6; break;
case Keyboard::Num7: keysym = XK_7; break;
case Keyboard::Num8: keysym = XK_8; break;
case Keyboard::Num9: keysym = XK_9; break;
default: keysym = 0; break;
}
// clang-format on
// Sanity checks
if (key < 0 || key >= sf::Keyboard::KeyCount)
return false;
////////////////////////////////////////////////////////////
bool InputImpl::isKeyPressed(Keyboard::Scancode code)
{
return KeyboardImpl::isKeyPressed(code);
}
// Open a connection with the X server
Display* display = openDisplay();
// Convert to keycode
KeyCode keycode = XKeysymToKeycode(display, keysym);
if (keycode != 0)
{
// Get the whole keyboard state
char keys[32];
XQueryKeymap(display, keys);
////////////////////////////////////////////////////////////
Keyboard::Key InputImpl::localize(Keyboard::Scancode code)
{
return KeyboardImpl::localize(code);
}
// Close the connection with the X server
closeDisplay(display);
// Check our keycode
return (keys[keycode / 8] & (1 << (keycode % 8))) != 0;
}
else
{
// Close the connection with the X server
closeDisplay(display);
////////////////////////////////////////////////////////////
Keyboard::Scancode InputImpl::delocalize(Keyboard::Key key)
{
return KeyboardImpl::delocalize(key);
}
return false;
}
////////////////////////////////////////////////////////////
String InputImpl::getDescription(Keyboard::Scancode code)
{
return KeyboardImpl::getDescription(code);
}

View File

@ -41,19 +41,37 @@ class InputImpl
{
public:
////////////////////////////////////////////////////////////
/// \brief Check if a key is pressed
///
/// \param key Key to check
///
/// \return True if the key is pressed, false otherwise
/// \copydoc sf::Keyboard::isKeyPressed(Key)
///
////////////////////////////////////////////////////////////
static bool isKeyPressed(Keyboard::Key key);
////////////////////////////////////////////////////////////
/// \brief Show or hide the virtual keyboard
/// \copydoc sf::Keyboard::isKeyPressed(Scancode)
///
/// \param visible True to show, false to hide
////////////////////////////////////////////////////////////
static bool isKeyPressed(Keyboard::Scancode code);
////////////////////////////////////////////////////////////
/// \copydoc sf::Keyboard::localize
///
////////////////////////////////////////////////////////////
static Keyboard::Key localize(Keyboard::Scancode code);
////////////////////////////////////////////////////////////
/// \copydoc sf::Keyboard::delocalize
///
////////////////////////////////////////////////////////////
static Keyboard::Scancode delocalize(Keyboard::Key key);
////////////////////////////////////////////////////////////
/// \copydoc sf::Keyboard::getDescription
///
////////////////////////////////////////////////////////////
static String getDescription(Keyboard::Scancode code);
////////////////////////////////////////////////////////////
/// \copydoc sf::Keyboard::setVirtualKeyboardVisible
///
////////////////////////////////////////////////////////////
static void setVirtualKeyboardVisible(bool visible);

View File

@ -0,0 +1,262 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2023 Laurent Gomila (laurent@sfml-dev.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.
//
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Window/Unix/KeySymToKeyMapping.hpp>
#include <X11/keysym.h>
namespace sf::priv
{
////////////////////////////////////////////////////////////
Keyboard::Key keySymToKey(KeySym symbol)
{
// clang-format off
switch (symbol)
{
case XK_Shift_L: return Keyboard::LShift;
case XK_Shift_R: return Keyboard::RShift;
case XK_Control_L: return Keyboard::LControl;
case XK_Control_R: return Keyboard::RControl;
case XK_Alt_L: return Keyboard::LAlt;
case XK_ISO_Level3_Shift:
case XK_Alt_R: return Keyboard::RAlt;
case XK_Super_L: return Keyboard::LSystem;
case XK_Super_R: return Keyboard::RSystem;
case XK_Menu: return Keyboard::Menu;
case XK_Escape: return Keyboard::Escape;
case XK_semicolon: return Keyboard::SemiColon;
case XK_slash: return Keyboard::Slash;
case XK_equal: return Keyboard::Equal;
case XK_minus: return Keyboard::Dash;
case XK_bracketleft: return Keyboard::LBracket;
case XK_bracketright: return Keyboard::RBracket;
case XK_comma: return Keyboard::Comma;
case XK_period: return Keyboard::Period;
case XK_apostrophe: return Keyboard::Quote;
case XK_backslash: return Keyboard::BackSlash;
case XK_grave: return Keyboard::Grave;
case XK_space: return Keyboard::Space;
case XK_Return: return Keyboard::Return;
case XK_KP_Enter: return Keyboard::Return;
case XK_BackSpace: return Keyboard::BackSpace;
case XK_Tab: return Keyboard::Tab;
case XK_Prior: return Keyboard::PageUp;
case XK_Next: return Keyboard::PageDown;
case XK_End: return Keyboard::End;
case XK_Home: return Keyboard::Home;
case XK_Insert: return Keyboard::Insert;
case XK_Delete: return Keyboard::Delete;
case XK_KP_Add: return Keyboard::Add;
case XK_KP_Subtract: return Keyboard::Subtract;
case XK_KP_Multiply: return Keyboard::Multiply;
case XK_KP_Divide: return Keyboard::Divide;
case XK_KP_Delete: return Keyboard::Period;
case XK_Pause: return Keyboard::Pause;
case XK_F1: return Keyboard::F1;
case XK_F2: return Keyboard::F2;
case XK_F3: return Keyboard::F3;
case XK_F4: return Keyboard::F4;
case XK_F5: return Keyboard::F5;
case XK_F6: return Keyboard::F6;
case XK_F7: return Keyboard::F7;
case XK_F8: return Keyboard::F8;
case XK_F9: return Keyboard::F9;
case XK_F10: return Keyboard::F10;
case XK_F11: return Keyboard::F11;
case XK_F12: return Keyboard::F12;
case XK_F13: return Keyboard::F13;
case XK_F14: return Keyboard::F14;
case XK_F15: return Keyboard::F15;
case XK_Left: return Keyboard::Left;
case XK_Right: return Keyboard::Right;
case XK_Up: return Keyboard::Up;
case XK_Down: return Keyboard::Down;
case XK_KP_Insert: return Keyboard::Numpad0;
case XK_KP_End: return Keyboard::Numpad1;
case XK_KP_Down: return Keyboard::Numpad2;
case XK_KP_Page_Down: return Keyboard::Numpad3;
case XK_KP_Left: return Keyboard::Numpad4;
case XK_KP_Begin: return Keyboard::Numpad5;
case XK_KP_Right: return Keyboard::Numpad6;
case XK_KP_Home: return Keyboard::Numpad7;
case XK_KP_Up: return Keyboard::Numpad8;
case XK_KP_Page_Up: return Keyboard::Numpad9;
case XK_a: return Keyboard::A;
case XK_b: return Keyboard::B;
case XK_c: return Keyboard::C;
case XK_d: return Keyboard::D;
case XK_e: return Keyboard::E;
case XK_f: return Keyboard::F;
case XK_g: return Keyboard::G;
case XK_h: return Keyboard::H;
case XK_i: return Keyboard::I;
case XK_j: return Keyboard::J;
case XK_k: return Keyboard::K;
case XK_l: return Keyboard::L;
case XK_m: return Keyboard::M;
case XK_n: return Keyboard::N;
case XK_o: return Keyboard::O;
case XK_p: return Keyboard::P;
case XK_q: return Keyboard::Q;
case XK_r: return Keyboard::R;
case XK_s: return Keyboard::S;
case XK_t: return Keyboard::T;
case XK_u: return Keyboard::U;
case XK_v: return Keyboard::V;
case XK_w: return Keyboard::W;
case XK_x: return Keyboard::X;
case XK_y: return Keyboard::Y;
case XK_z: return Keyboard::Z;
case XK_0: return Keyboard::Num0;
case XK_1: return Keyboard::Num1;
case XK_2: return Keyboard::Num2;
case XK_3: return Keyboard::Num3;
case XK_4: return Keyboard::Num4;
case XK_5: return Keyboard::Num5;
case XK_6: return Keyboard::Num6;
case XK_7: return Keyboard::Num7;
case XK_8: return Keyboard::Num8;
case XK_9: return Keyboard::Num9;
default: return Keyboard::Unknown;
}
// clang-format on
}
////////////////////////////////////////////////////////////
KeySym keyToKeySym(Keyboard::Key key)
{
// clang-format off
switch (key)
{
case Keyboard::LShift: return XK_Shift_L;
case Keyboard::RShift: return XK_Shift_R;
case Keyboard::LControl: return XK_Control_L;
case Keyboard::RControl: return XK_Control_R;
case Keyboard::LAlt: return XK_Alt_L;
case Keyboard::RAlt: return XK_Alt_R;
case Keyboard::LSystem: return XK_Super_L;
case Keyboard::RSystem: return XK_Super_R;
case Keyboard::Menu: return XK_Menu;
case Keyboard::Escape: return XK_Escape;
case Keyboard::SemiColon: return XK_semicolon;
case Keyboard::Slash: return XK_slash;
case Keyboard::Equal: return XK_equal;
case Keyboard::Dash: return XK_minus;
case Keyboard::LBracket: return XK_bracketleft;
case Keyboard::RBracket: return XK_bracketright;
case Keyboard::Comma: return XK_comma;
case Keyboard::Period: return XK_period;
case Keyboard::Quote: return XK_apostrophe;
case Keyboard::BackSlash: return XK_backslash;
case Keyboard::Grave: return XK_grave;
case Keyboard::Space: return XK_space;
case Keyboard::Return: return XK_Return;
case Keyboard::BackSpace: return XK_BackSpace;
case Keyboard::Tab: return XK_Tab;
case Keyboard::PageUp: return XK_Prior;
case Keyboard::PageDown: return XK_Next;
case Keyboard::End: return XK_End;
case Keyboard::Home: return XK_Home;
case Keyboard::Insert: return XK_Insert;
case Keyboard::Delete: return XK_Delete;
case Keyboard::Add: return XK_KP_Add;
case Keyboard::Subtract: return XK_KP_Subtract;
case Keyboard::Multiply: return XK_KP_Multiply;
case Keyboard::Divide: return XK_KP_Divide;
case Keyboard::Pause: return XK_Pause;
case Keyboard::F1: return XK_F1;
case Keyboard::F2: return XK_F2;
case Keyboard::F3: return XK_F3;
case Keyboard::F4: return XK_F4;
case Keyboard::F5: return XK_F5;
case Keyboard::F6: return XK_F6;
case Keyboard::F7: return XK_F7;
case Keyboard::F8: return XK_F8;
case Keyboard::F9: return XK_F9;
case Keyboard::F10: return XK_F10;
case Keyboard::F11: return XK_F11;
case Keyboard::F12: return XK_F12;
case Keyboard::F13: return XK_F13;
case Keyboard::F14: return XK_F14;
case Keyboard::F15: return XK_F15;
case Keyboard::Left: return XK_Left;
case Keyboard::Right: return XK_Right;
case Keyboard::Up: return XK_Up;
case Keyboard::Down: return XK_Down;
case Keyboard::Numpad0: return XK_KP_Insert;
case Keyboard::Numpad1: return XK_KP_End;
case Keyboard::Numpad2: return XK_KP_Down;
case Keyboard::Numpad3: return XK_KP_Page_Down;
case Keyboard::Numpad4: return XK_KP_Left;
case Keyboard::Numpad5: return XK_KP_Begin;
case Keyboard::Numpad6: return XK_KP_Right;
case Keyboard::Numpad7: return XK_KP_Home;
case Keyboard::Numpad8: return XK_KP_Up;
case Keyboard::Numpad9: return XK_KP_Page_Up;
case Keyboard::A: return XK_a;
case Keyboard::B: return XK_b;
case Keyboard::C: return XK_c;
case Keyboard::D: return XK_d;
case Keyboard::E: return XK_e;
case Keyboard::F: return XK_f;
case Keyboard::G: return XK_g;
case Keyboard::H: return XK_h;
case Keyboard::I: return XK_i;
case Keyboard::J: return XK_j;
case Keyboard::K: return XK_k;
case Keyboard::L: return XK_l;
case Keyboard::M: return XK_m;
case Keyboard::N: return XK_n;
case Keyboard::O: return XK_o;
case Keyboard::P: return XK_p;
case Keyboard::Q: return XK_q;
case Keyboard::R: return XK_r;
case Keyboard::S: return XK_s;
case Keyboard::T: return XK_t;
case Keyboard::U: return XK_u;
case Keyboard::V: return XK_v;
case Keyboard::W: return XK_w;
case Keyboard::X: return XK_x;
case Keyboard::Y: return XK_y;
case Keyboard::Z: return XK_z;
case Keyboard::Num0: return XK_0;
case Keyboard::Num1: return XK_1;
case Keyboard::Num2: return XK_2;
case Keyboard::Num3: return XK_3;
case Keyboard::Num4: return XK_4;
case Keyboard::Num5: return XK_5;
case Keyboard::Num6: return XK_6;
case Keyboard::Num7: return XK_7;
case Keyboard::Num8: return XK_8;
case Keyboard::Num9: return XK_9;
default: return NoSymbol;
}
// clang-format on
}
} // namespace sf::priv

View File

@ -0,0 +1,57 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2021 Laurent Gomila (laurent@sfml-dev.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
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Window/Keyboard.hpp> // sf::Keyboard::Key
#include <X11/X.h> // KeySym
namespace sf::priv
{
////////////////////////////////////////////////////////////
/// \brief Convert X11 KeySym to sf::Keyboard::Key
///
/// \param symbol X11 KeySym
///
/// \return The corresponding sf::Keyboard::Key
///
////////////////////////////////////////////////////////////
Keyboard::Key keySymToKey(KeySym symbol);
////////////////////////////////////////////////////////////
/// \brief Convert sf::Keyboard::Key to X11 KeySym
///
/// \param key X11 sf::Keyboard::Key
///
/// \return The corresponding X11 KeySym
///
////////////////////////////////////////////////////////////
KeySym keyToKeySym(Keyboard::Key key);
} // namespace sf::priv

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,54 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2021 Laurent Gomila (laurent@sfml-dev.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
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <X11/X.h> // KeySym
#include <cstdint>
namespace sf::priv
{
////////////////////////////////////////////////////////////
/// \brief Converts a KeySym to UTF-32
///
/// This code was autogenerated from the following table:
/// https://www.cl.cam.ac.uk/~mgk25/ucs/keysyms.txt
///
/// The generated table was edited so that dead keys are mapped to
/// non-combining characters instead of combining diacritical marks
/// because is it more suitable to describe those keys in user interfaces.
///
/// \param keysym keysym to be converted
///
/// \return corresponding UTF-32
///
////////////////////////////////////////////////////////////
std::uint32_t keysymToUnicode(KeySym keysym);
} // namespace sf::priv

View File

@ -0,0 +1,810 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2021 Laurent Gomila (laurent@sfml-dev.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.
//
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/System/String.hpp>
#include <SFML/System/Utf.hpp>
#include <SFML/Window/Unix/Display.hpp>
#include <SFML/Window/Unix/KeySymToKeyMapping.hpp>
#include <SFML/Window/Unix/KeySymToUnicodeMapping.hpp>
#include <SFML/Window/Unix/KeyboardImpl.hpp>
#include <X11/XKBlib.h>
#include <X11/Xlib.h>
#include <X11/keysym.h>
#include <cstring>
#include <map>
#include <string>
#include <utility>
namespace
{
const KeyCode nullKeyCode = 0;
const int maxKeyCode = 256;
KeyCode scancodeToKeycode[sf::Keyboard::Scan::ScancodeCount]; ///< Mapping of SFML scancode to X11 KeyCode
sf::Keyboard::Scancode keycodeToScancode[maxKeyCode]; ///< Mapping of X11 KeyCode to SFML scancode
////////////////////////////////////////////////////////////
bool isValidKeycode(KeyCode keycode)
{
// Valid key code range is [8,255], according to the Xlib manual
return keycode >= 8;
}
////////////////////////////////////////////////////////////
sf::Keyboard::Scancode translateKeyCode(Display* display, KeyCode keycode)
{
if (!isValidKeycode(keycode))
return sf::Keyboard::Scan::Unknown;
// Try secondary keysym, for numeric keypad keys
// Note: This way we always force "NumLock = ON", which is intentional
// since the returned key code should correspond to a physical location.
KeySym keySym = XkbKeycodeToKeysym(display, keycode, 0, 1);
// clang-format off
switch (keySym)
{
case XK_KP_0: return sf::Keyboard::Scan::Numpad0;
case XK_KP_1: return sf::Keyboard::Scan::Numpad1;
case XK_KP_2: return sf::Keyboard::Scan::Numpad2;
case XK_KP_3: return sf::Keyboard::Scan::Numpad3;
case XK_KP_4: return sf::Keyboard::Scan::Numpad4;
case XK_KP_5: return sf::Keyboard::Scan::Numpad5;
case XK_KP_6: return sf::Keyboard::Scan::Numpad6;
case XK_KP_7: return sf::Keyboard::Scan::Numpad7;
case XK_KP_8: return sf::Keyboard::Scan::Numpad8;
case XK_KP_9: return sf::Keyboard::Scan::Numpad9;
case XK_KP_Separator: return sf::Keyboard::Scan::NumpadDecimal;
case XK_KP_Decimal: return sf::Keyboard::Scan::NumpadDecimal;
case XK_KP_Equal: return sf::Keyboard::Scan::NumpadEqual;
case XK_KP_Enter: return sf::Keyboard::Scan::NumpadEnter;
default: break;
}
// clang-format on
// Now try primary keysym for function keys (non-printable keys)
// These should not depend on the current keyboard layout
keySym = XkbKeycodeToKeysym(display, keycode, 0, 0);
// clang-format off
switch (keySym)
{
case XK_Return: return sf::Keyboard::Scan::Enter;
case XK_Escape: return sf::Keyboard::Scan::Escape;
case XK_BackSpace: return sf::Keyboard::Scan::Backspace;
case XK_Tab: return sf::Keyboard::Scan::Tab;
case XK_Shift_L: return sf::Keyboard::Scan::LShift;
case XK_Shift_R: return sf::Keyboard::Scan::RShift;
case XK_Control_L: return sf::Keyboard::Scan::LControl;
case XK_Control_R: return sf::Keyboard::Scan::RControl;
case XK_Alt_L: return sf::Keyboard::Scan::LAlt;
case XK_ISO_Level3_Shift: // AltGr on at least some machines
case XK_Alt_R: return sf::Keyboard::Scan::RAlt;
case XK_Meta_L:
case XK_Super_L: return sf::Keyboard::Scan::LSystem;
case XK_Meta_R:
case XK_Super_R: return sf::Keyboard::Scan::RSystem;
case XK_Menu: return sf::Keyboard::Scan::Menu;
case XK_Num_Lock: return sf::Keyboard::Scan::NumLock;
case XK_Caps_Lock: return sf::Keyboard::Scan::CapsLock;
case XK_Execute: return sf::Keyboard::Scan::Execute;
case XK_Hyper_R: return sf::Keyboard::Scan::Application;
case XK_Select: return sf::Keyboard::Scan::Select;
case XK_Cancel: return sf::Keyboard::Scan::Stop;
case XK_Redo: return sf::Keyboard::Scan::Redo;
case XK_Undo: return sf::Keyboard::Scan::Undo;
case XK_Find: return sf::Keyboard::Scan::Search;
case XK_Mode_switch: return sf::Keyboard::Scan::ModeChange;
case XK_Print: return sf::Keyboard::Scan::PrintScreen;
case XK_Scroll_Lock: return sf::Keyboard::Scan::ScrollLock;
case XK_Pause:
case XK_Break: return sf::Keyboard::Scan::Pause;
case XK_Delete:
case XK_Clear: return sf::Keyboard::Scan::Delete;
case XK_Home: return sf::Keyboard::Scan::Home;
case XK_End: return sf::Keyboard::Scan::End;
case XK_Page_Up: return sf::Keyboard::Scan::PageUp;
case XK_Page_Down: return sf::Keyboard::Scan::PageDown;
case XK_Insert: return sf::Keyboard::Scan::Insert;
case XK_Left: return sf::Keyboard::Scan::Left;
case XK_Right: return sf::Keyboard::Scan::Right;
case XK_Down: return sf::Keyboard::Scan::Down;
case XK_Up: return sf::Keyboard::Scan::Up;
case XK_F1: return sf::Keyboard::Scan::F1;
case XK_F2: return sf::Keyboard::Scan::F2;
case XK_F3: return sf::Keyboard::Scan::F3;
case XK_F4: return sf::Keyboard::Scan::F4;
case XK_F5: return sf::Keyboard::Scan::F5;
case XK_F6: return sf::Keyboard::Scan::F6;
case XK_F7: return sf::Keyboard::Scan::F7;
case XK_F8: return sf::Keyboard::Scan::F8;
case XK_F9: return sf::Keyboard::Scan::F9;
case XK_F10: return sf::Keyboard::Scan::F10;
case XK_F11: return sf::Keyboard::Scan::F11;
case XK_F12: return sf::Keyboard::Scan::F12;
case XK_F13: return sf::Keyboard::Scan::F13;
case XK_F14: return sf::Keyboard::Scan::F14;
case XK_F15: return sf::Keyboard::Scan::F15;
case XK_F16: return sf::Keyboard::Scan::F16;
case XK_F17: return sf::Keyboard::Scan::F17;
case XK_F18: return sf::Keyboard::Scan::F18;
case XK_F19: return sf::Keyboard::Scan::F19;
case XK_F20: return sf::Keyboard::Scan::F20;
case XK_F21: return sf::Keyboard::Scan::F21;
case XK_F22: return sf::Keyboard::Scan::F22;
case XK_F23: return sf::Keyboard::Scan::F23;
case XK_F24: return sf::Keyboard::Scan::F24;
// Numeric keypad
case XK_KP_Divide: return sf::Keyboard::Scan::NumpadDivide;
case XK_KP_Multiply: return sf::Keyboard::Scan::NumpadMultiply;
case XK_KP_Subtract: return sf::Keyboard::Scan::NumpadMinus;
case XK_KP_Add: return sf::Keyboard::Scan::NumpadPlus;
// These should have been detected in secondary keysym test above!
case XK_KP_Insert: return sf::Keyboard::Scan::Numpad0;
case XK_KP_End: return sf::Keyboard::Scan::Numpad1;
case XK_KP_Down: return sf::Keyboard::Scan::Numpad2;
case XK_KP_Page_Down: return sf::Keyboard::Scan::Numpad3;
case XK_KP_Left: return sf::Keyboard::Scan::Numpad4;
case XK_KP_Right: return sf::Keyboard::Scan::Numpad6;
case XK_KP_Home: return sf::Keyboard::Scan::Numpad7;
case XK_KP_Up: return sf::Keyboard::Scan::Numpad8;
case XK_KP_Page_Up: return sf::Keyboard::Scan::Numpad9;
case XK_KP_Delete: return sf::Keyboard::Scan::NumpadDecimal;
case XK_KP_Equal: return sf::Keyboard::Scan::NumpadEqual;
case XK_KP_Enter: return sf::Keyboard::Scan::NumpadEnter;
// 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:
case XK_A: return sf::Keyboard::Scan::A;
case XK_b:
case XK_B: return sf::Keyboard::Scan::B;
case XK_c:
case XK_C: return sf::Keyboard::Scan::C;
case XK_d:
case XK_D: return sf::Keyboard::Scan::D;
case XK_e:
case XK_E: return sf::Keyboard::Scan::E;
case XK_f:
case XK_F: return sf::Keyboard::Scan::F;
case XK_g:
case XK_G: return sf::Keyboard::Scan::G;
case XK_h:
case XK_H: return sf::Keyboard::Scan::H;
case XK_i:
case XK_I: return sf::Keyboard::Scan::I;
case XK_j:
case XK_J: return sf::Keyboard::Scan::J;
case XK_k:
case XK_K: return sf::Keyboard::Scan::K;
case XK_l:
case XK_L: return sf::Keyboard::Scan::L;
case XK_m:
case XK_M: return sf::Keyboard::Scan::M;
case XK_n:
case XK_N: return sf::Keyboard::Scan::N;
case XK_o:
case XK_O: return sf::Keyboard::Scan::O;
case XK_p:
case XK_P: return sf::Keyboard::Scan::P;
case XK_q:
case XK_Q: return sf::Keyboard::Scan::Q;
case XK_r:
case XK_R: return sf::Keyboard::Scan::R;
case XK_s:
case XK_S: return sf::Keyboard::Scan::S;
case XK_t:
case XK_T: return sf::Keyboard::Scan::T;
case XK_u:
case XK_U: return sf::Keyboard::Scan::U;
case XK_v:
case XK_V: return sf::Keyboard::Scan::V;
case XK_w:
case XK_W: return sf::Keyboard::Scan::W;
case XK_x:
case XK_X: return sf::Keyboard::Scan::X;
case XK_y:
case XK_Y: return sf::Keyboard::Scan::Y;
case XK_z:
case XK_Z: return sf::Keyboard::Scan::Z;
case XK_1: return sf::Keyboard::Scan::Num1;
case XK_2: return sf::Keyboard::Scan::Num2;
case XK_3: return sf::Keyboard::Scan::Num3;
case XK_4: return sf::Keyboard::Scan::Num4;
case XK_5: return sf::Keyboard::Scan::Num5;
case XK_6: return sf::Keyboard::Scan::Num6;
case XK_7: return sf::Keyboard::Scan::Num7;
case XK_8: return sf::Keyboard::Scan::Num8;
case XK_9: return sf::Keyboard::Scan::Num9;
case XK_0: return sf::Keyboard::Scan::Num0;
case XK_space: return sf::Keyboard::Scan::Space;
case XK_minus: return sf::Keyboard::Scan::Hyphen;
case XK_equal: return sf::Keyboard::Scan::Equal;
case XK_bracketleft: return sf::Keyboard::Scan::LBracket;
case XK_bracketright: return sf::Keyboard::Scan::RBracket;
case XK_backslash: return sf::Keyboard::Scan::Backslash;
case XK_semicolon: return sf::Keyboard::Scan::Semicolon;
case XK_apostrophe: return sf::Keyboard::Scan::Apostrophe;
case XK_grave: return sf::Keyboard::Scan::Grave;
case XK_comma: return sf::Keyboard::Scan::Comma;
case XK_period: return sf::Keyboard::Scan::Period;
case XK_slash: return sf::Keyboard::Scan::Slash;
case XK_less: return sf::Keyboard::Scan::NonUsBackslash;
default: return sf::Keyboard::Scan::Unknown;
}
// clang-format on
}
////////////////////////////////////////////////////////////
std::map<std::string, sf::Keyboard::Scancode> getNameScancodeMap()
{
std::map<std::string, sf::Keyboard::Scancode> mapping;
mapping.insert(std::make_pair("LSGT", sf::Keyboard::Scan::NonUsBackslash));
mapping.insert(std::make_pair("TLDE", sf::Keyboard::Scan::Grave));
mapping.insert(std::make_pair("AE01", sf::Keyboard::Scan::Num1));
mapping.insert(std::make_pair("AE02", sf::Keyboard::Scan::Num2));
mapping.insert(std::make_pair("AE03", sf::Keyboard::Scan::Num3));
mapping.insert(std::make_pair("AE04", sf::Keyboard::Scan::Num4));
mapping.insert(std::make_pair("AE05", sf::Keyboard::Scan::Num5));
mapping.insert(std::make_pair("AE06", sf::Keyboard::Scan::Num6));
mapping.insert(std::make_pair("AE07", sf::Keyboard::Scan::Num7));
mapping.insert(std::make_pair("AE08", sf::Keyboard::Scan::Num8));
mapping.insert(std::make_pair("AE09", sf::Keyboard::Scan::Num9));
mapping.insert(std::make_pair("AE10", sf::Keyboard::Scan::Num0));
mapping.insert(std::make_pair("AE11", sf::Keyboard::Scan::Hyphen));
mapping.insert(std::make_pair("AE12", sf::Keyboard::Scan::Equal));
mapping.insert(std::make_pair("BKSP", sf::Keyboard::Scan::Backspace));
mapping.insert(std::make_pair("TAB", sf::Keyboard::Scan::Tab));
mapping.insert(std::make_pair("AD01", sf::Keyboard::Scan::Q));
mapping.insert(std::make_pair("AD02", sf::Keyboard::Scan::W));
mapping.insert(std::make_pair("AD03", sf::Keyboard::Scan::E));
mapping.insert(std::make_pair("AD04", sf::Keyboard::Scan::R));
mapping.insert(std::make_pair("AD05", sf::Keyboard::Scan::T));
mapping.insert(std::make_pair("AD06", sf::Keyboard::Scan::Y));
mapping.insert(std::make_pair("AD07", sf::Keyboard::Scan::U));
mapping.insert(std::make_pair("AD08", sf::Keyboard::Scan::I));
mapping.insert(std::make_pair("AD09", sf::Keyboard::Scan::O));
mapping.insert(std::make_pair("AD10", sf::Keyboard::Scan::P));
mapping.insert(std::make_pair("AD11", sf::Keyboard::Scan::LBracket));
mapping.insert(std::make_pair("AD12", sf::Keyboard::Scan::RBracket));
mapping.insert(std::make_pair("BKSL", sf::Keyboard::Scan::Backslash));
mapping.insert(std::make_pair("RTRN", sf::Keyboard::Scan::Enter));
mapping.insert(std::make_pair("CAPS", sf::Keyboard::Scan::CapsLock));
mapping.insert(std::make_pair("AC01", sf::Keyboard::Scan::A));
mapping.insert(std::make_pair("AC02", sf::Keyboard::Scan::S));
mapping.insert(std::make_pair("AC03", sf::Keyboard::Scan::D));
mapping.insert(std::make_pair("AC04", sf::Keyboard::Scan::F));
mapping.insert(std::make_pair("AC05", sf::Keyboard::Scan::G));
mapping.insert(std::make_pair("AC06", sf::Keyboard::Scan::H));
mapping.insert(std::make_pair("AC07", sf::Keyboard::Scan::J));
mapping.insert(std::make_pair("AC08", sf::Keyboard::Scan::K));
mapping.insert(std::make_pair("AC09", sf::Keyboard::Scan::L));
mapping.insert(std::make_pair("AC10", sf::Keyboard::Scan::Semicolon));
mapping.insert(std::make_pair("AC11", sf::Keyboard::Scan::Apostrophe));
mapping.insert(std::make_pair("AC12", sf::Keyboard::Scan::Backslash));
mapping.insert(std::make_pair("LFSH", sf::Keyboard::Scan::LShift));
mapping.insert(std::make_pair("AB01", sf::Keyboard::Scan::Z));
mapping.insert(std::make_pair("AB02", sf::Keyboard::Scan::X));
mapping.insert(std::make_pair("AB03", sf::Keyboard::Scan::C));
mapping.insert(std::make_pair("AB04", sf::Keyboard::Scan::V));
mapping.insert(std::make_pair("AB05", sf::Keyboard::Scan::B));
mapping.insert(std::make_pair("AB06", sf::Keyboard::Scan::N));
mapping.insert(std::make_pair("AB07", sf::Keyboard::Scan::M));
mapping.insert(std::make_pair("AB08", sf::Keyboard::Scan::Comma));
mapping.insert(std::make_pair("AB09", sf::Keyboard::Scan::Period));
mapping.insert(std::make_pair("AB10", sf::Keyboard::Scan::Slash));
mapping.insert(std::make_pair("RTSH", sf::Keyboard::Scan::RShift));
mapping.insert(std::make_pair("LCTL", sf::Keyboard::Scan::LControl));
mapping.insert(std::make_pair("LALT", sf::Keyboard::Scan::LAlt));
mapping.insert(std::make_pair("SPCE", sf::Keyboard::Scan::Space));
mapping.insert(std::make_pair("RCTL", sf::Keyboard::Scan::RControl));
mapping.insert(std::make_pair("RALT", sf::Keyboard::Scan::RAlt));
mapping.insert(std::make_pair("LVL3", sf::Keyboard::Scan::RAlt));
mapping.insert(std::make_pair("ALGR", sf::Keyboard::Scan::RAlt));
mapping.insert(std::make_pair("LWIN", sf::Keyboard::Scan::LSystem));
mapping.insert(std::make_pair("RWIN", sf::Keyboard::Scan::RSystem));
mapping.insert(std::make_pair("HYPR", sf::Keyboard::Scan::Application));
mapping.insert(std::make_pair("EXEC", sf::Keyboard::Scan::Execute));
mapping.insert(std::make_pair("MDSW", sf::Keyboard::Scan::ModeChange));
mapping.insert(std::make_pair("MENU", sf::Keyboard::Scan::Menu));
mapping.insert(std::make_pair("COMP", sf::Keyboard::Scan::Menu));
mapping.insert(std::make_pair("SELE", sf::Keyboard::Scan::Select));
mapping.insert(std::make_pair("ESC", sf::Keyboard::Scan::Escape));
mapping.insert(std::make_pair("FK01", sf::Keyboard::Scan::F1));
mapping.insert(std::make_pair("FK02", sf::Keyboard::Scan::F2));
mapping.insert(std::make_pair("FK03", sf::Keyboard::Scan::F3));
mapping.insert(std::make_pair("FK04", sf::Keyboard::Scan::F4));
mapping.insert(std::make_pair("FK05", sf::Keyboard::Scan::F5));
mapping.insert(std::make_pair("FK06", sf::Keyboard::Scan::F6));
mapping.insert(std::make_pair("FK07", sf::Keyboard::Scan::F7));
mapping.insert(std::make_pair("FK08", sf::Keyboard::Scan::F8));
mapping.insert(std::make_pair("FK09", sf::Keyboard::Scan::F9));
mapping.insert(std::make_pair("FK10", sf::Keyboard::Scan::F10));
mapping.insert(std::make_pair("FK11", sf::Keyboard::Scan::F11));
mapping.insert(std::make_pair("FK12", sf::Keyboard::Scan::F12));
mapping.insert(std::make_pair("PRSC", sf::Keyboard::Scan::PrintScreen));
mapping.insert(std::make_pair("SCLK", sf::Keyboard::Scan::ScrollLock));
mapping.insert(std::make_pair("PAUS", sf::Keyboard::Scan::Pause));
mapping.insert(std::make_pair("INS", sf::Keyboard::Scan::Insert));
mapping.insert(std::make_pair("HOME", sf::Keyboard::Scan::Home));
mapping.insert(std::make_pair("PGUP", sf::Keyboard::Scan::PageUp));
mapping.insert(std::make_pair("DELE", sf::Keyboard::Scan::Delete));
mapping.insert(std::make_pair("END", sf::Keyboard::Scan::End));
mapping.insert(std::make_pair("PGDN", sf::Keyboard::Scan::PageDown));
mapping.insert(std::make_pair("UP", sf::Keyboard::Scan::Up));
mapping.insert(std::make_pair("RGHT", sf::Keyboard::Scan::Right));
mapping.insert(std::make_pair("DOWN", sf::Keyboard::Scan::Down));
mapping.insert(std::make_pair("LEFT", sf::Keyboard::Scan::Left));
mapping.insert(std::make_pair("NMLK", sf::Keyboard::Scan::NumLock));
mapping.insert(std::make_pair("KPDV", sf::Keyboard::Scan::NumpadDivide));
mapping.insert(std::make_pair("KPMU", sf::Keyboard::Scan::NumpadMultiply));
mapping.insert(std::make_pair("KPSU", sf::Keyboard::Scan::NumpadMinus));
mapping.insert(std::make_pair("KP7", sf::Keyboard::Scan::Numpad7));
mapping.insert(std::make_pair("KP8", sf::Keyboard::Scan::Numpad8));
mapping.insert(std::make_pair("KP9", sf::Keyboard::Scan::Numpad9));
mapping.insert(std::make_pair("KPAD", sf::Keyboard::Scan::NumpadPlus));
mapping.insert(std::make_pair("KP4", sf::Keyboard::Scan::Numpad4));
mapping.insert(std::make_pair("KP5", sf::Keyboard::Scan::Numpad5));
mapping.insert(std::make_pair("KP6", sf::Keyboard::Scan::Numpad6));
mapping.insert(std::make_pair("KP1", sf::Keyboard::Scan::Numpad1));
mapping.insert(std::make_pair("KP2", sf::Keyboard::Scan::Numpad2));
mapping.insert(std::make_pair("KP3", sf::Keyboard::Scan::Numpad3));
mapping.insert(std::make_pair("KPEN", sf::Keyboard::Scan::NumpadEnter));
mapping.insert(std::make_pair("KP0", sf::Keyboard::Scan::Numpad0));
mapping.insert(std::make_pair("KPDL", sf::Keyboard::Scan::NumpadDecimal));
mapping.insert(std::make_pair("KPEQ", sf::Keyboard::Scan::NumpadEqual));
mapping.insert(std::make_pair("FK13", sf::Keyboard::Scan::F13));
mapping.insert(std::make_pair("FK14", sf::Keyboard::Scan::F14));
mapping.insert(std::make_pair("FK15", sf::Keyboard::Scan::F15));
mapping.insert(std::make_pair("FK16", sf::Keyboard::Scan::F16));
mapping.insert(std::make_pair("FK17", sf::Keyboard::Scan::F17));
mapping.insert(std::make_pair("FK18", sf::Keyboard::Scan::F18));
mapping.insert(std::make_pair("FK19", sf::Keyboard::Scan::F19));
mapping.insert(std::make_pair("FK20", sf::Keyboard::Scan::F20));
mapping.insert(std::make_pair("FK21", sf::Keyboard::Scan::F21));
mapping.insert(std::make_pair("FK22", sf::Keyboard::Scan::F22));
mapping.insert(std::make_pair("FK23", sf::Keyboard::Scan::F23));
mapping.insert(std::make_pair("FK24", sf::Keyboard::Scan::F24));
mapping.insert(std::make_pair("LMTA", sf::Keyboard::Scan::LSystem));
mapping.insert(std::make_pair("RMTA", sf::Keyboard::Scan::RSystem));
mapping.insert(std::make_pair("MUTE", sf::Keyboard::Scan::VolumeMute));
mapping.insert(std::make_pair("VOL-", sf::Keyboard::Scan::VolumeDown));
mapping.insert(std::make_pair("VOL+", sf::Keyboard::Scan::VolumeUp));
mapping.insert(std::make_pair("STOP", sf::Keyboard::Scan::Stop));
mapping.insert(std::make_pair("REDO", sf::Keyboard::Scan::Redo));
mapping.insert(std::make_pair("AGAI", sf::Keyboard::Scan::Redo));
mapping.insert(std::make_pair("UNDO", sf::Keyboard::Scan::Undo));
mapping.insert(std::make_pair("COPY", sf::Keyboard::Scan::Copy));
mapping.insert(std::make_pair("PAST", sf::Keyboard::Scan::Paste));
mapping.insert(std::make_pair("FIND", sf::Keyboard::Scan::Search));
mapping.insert(std::make_pair("CUT", sf::Keyboard::Scan::Cut));
mapping.insert(std::make_pair("HELP", sf::Keyboard::Scan::Help));
mapping.insert(std::make_pair("I156", sf::Keyboard::Scan::LaunchApplication1));
mapping.insert(std::make_pair("I157", sf::Keyboard::Scan::LaunchApplication2));
mapping.insert(std::make_pair("I164", sf::Keyboard::Scan::Favorites));
mapping.insert(std::make_pair("I166", sf::Keyboard::Scan::Back));
mapping.insert(std::make_pair("I167", sf::Keyboard::Scan::Forward));
mapping.insert(std::make_pair("I171", sf::Keyboard::Scan::MediaNextTrack));
mapping.insert(std::make_pair("I172", sf::Keyboard::Scan::MediaPlayPause));
mapping.insert(std::make_pair("I173", sf::Keyboard::Scan::MediaPreviousTrack));
mapping.insert(std::make_pair("I174", sf::Keyboard::Scan::MediaStop));
mapping.insert(std::make_pair("I180", sf::Keyboard::Scan::HomePage));
mapping.insert(std::make_pair("I181", sf::Keyboard::Scan::Refresh));
mapping.insert(std::make_pair("I223", sf::Keyboard::Scan::LaunchMail));
mapping.insert(std::make_pair("I234", sf::Keyboard::Scan::LaunchMediaSelect));
return mapping;
}
////////////////////////////////////////////////////////////
void ensureMapping()
{
static bool isMappingInitialized = false;
if (isMappingInitialized)
return;
// Phase 1: Initialize mappings with default values
for (auto& keycode : scancodeToKeycode)
keycode = nullKeyCode;
for (auto& scancode : keycodeToScancode)
scancode = sf::Keyboard::Scan::Unknown;
// Phase 2: Get XKB names with key code
Display* display = sf::priv::openDisplay();
char name[XkbKeyNameLength + 1];
XkbDescPtr descriptor = XkbGetMap(display, 0, XkbUseCoreKbd);
XkbGetNames(display, XkbKeyNamesMask, descriptor);
std::map<std::string, sf::Keyboard::Scancode> nameScancodeMap = getNameScancodeMap();
sf::Keyboard::Scancode scancode = sf::Keyboard::Scan::Unknown;
for (int keycode = descriptor->min_key_code; keycode <= descriptor->max_key_code; ++keycode)
{
if (!isValidKeycode(static_cast<KeyCode>(keycode)))
{
continue;
}
std::memcpy(name, descriptor->names->keys[keycode].name, XkbKeyNameLength);
name[XkbKeyNameLength] = '\0';
std::map<std::string, sf::Keyboard::Scancode>::iterator mappedScancode = nameScancodeMap.find(std::string(name));
scancode = sf::Keyboard::Scan::Unknown;
if (mappedScancode != nameScancodeMap.end())
scancode = mappedScancode->second;
if (scancode != sf::Keyboard::Scan::Unknown)
scancodeToKeycode[scancode] = static_cast<KeyCode>(keycode);
keycodeToScancode[keycode] = scancode;
}
XkbFreeNames(descriptor, XkbKeyNamesMask, True);
XkbFreeKeyboard(descriptor, 0, True);
// Phase 3: Translate un-translated keycodes using traditional X11 KeySym lookups
for (int keycode = 8; keycode < maxKeyCode; ++keycode)
{
if (keycodeToScancode[static_cast<KeyCode>(keycode)] == sf::Keyboard::Scan::Unknown)
{
scancode = translateKeyCode(display, static_cast<KeyCode>(keycode));
if (scancode != sf::Keyboard::Scan::Unknown && scancodeToKeycode[scancode] == nullKeyCode)
scancodeToKeycode[scancode] = static_cast<KeyCode>(keycode);
keycodeToScancode[keycode] = scancode;
}
}
sf::priv::closeDisplay(display);
isMappingInitialized = true;
}
////////////////////////////////////////////////////////////
KeyCode scancodeToKeyCode(sf::Keyboard::Scancode code)
{
ensureMapping();
if (code != sf::Keyboard::Scan::Unknown)
return scancodeToKeycode[code];
return nullKeyCode;
}
////////////////////////////////////////////////////////////
sf::Keyboard::Scancode keyCodeToScancode(KeyCode code)
{
ensureMapping();
if (isValidKeycode(code))
return keycodeToScancode[code];
return sf::Keyboard::Scan::Unknown;
}
////////////////////////////////////////////////////////////
KeyCode keyToKeyCode(sf::Keyboard::Key key)
{
KeySym keysym = sf::priv::keyToKeySym(key);
if (keysym != NoSymbol)
{
Display* display = sf::priv::openDisplay();
KeyCode keycode = XKeysymToKeycode(display, keysym);
sf::priv::closeDisplay(display);
if (keycode != nullKeyCode)
return keycode;
}
// Fallback for when XKeysymToKeycode cannot tell the KeyCode for XK_Alt_R
if (key == sf::Keyboard::RAlt)
return scancodeToKeycode[sf::Keyboard::Scan::RAlt];
return nullKeyCode;
}
////////////////////////////////////////////////////////////
KeySym scancodeToKeySym(sf::Keyboard::Scancode code)
{
Display* display = sf::priv::openDisplay();
KeySym keysym = NoSymbol;
KeyCode keycode = scancodeToKeyCode(code);
if (keycode != nullKeyCode) // ensure that this Scancode is mapped to keycode
keysym = XkbKeycodeToKeysym(display, keycode, 0, 0);
sf::priv::closeDisplay(display);
return keysym;
}
////////////////////////////////////////////////////////////
bool isKeyPressedImpl(KeyCode keycode)
{
if (keycode != nullKeyCode)
{
Display* display = sf::priv::openDisplay();
// Get the whole keyboard state
char keys[32];
XQueryKeymap(display, keys);
sf::priv::closeDisplay(display);
// Check our keycode
return (keys[keycode / 8] & (1 << (keycode % 8))) != 0;
}
return false;
}
} // anonymous namespace
namespace sf::priv
{
////////////////////////////////////////////////////////////
bool KeyboardImpl::isKeyPressed(Keyboard::Key key)
{
KeyCode keycode = keyToKeyCode(key);
return isKeyPressedImpl(keycode);
}
////////////////////////////////////////////////////////////
bool KeyboardImpl::isKeyPressed(Keyboard::Scancode code)
{
KeyCode keycode = scancodeToKeyCode(code);
return isKeyPressedImpl(keycode);
}
////////////////////////////////////////////////////////////
Keyboard::Scancode KeyboardImpl::delocalize(Keyboard::Key key)
{
KeyCode keycode = keyToKeyCode(key);
return keyCodeToScancode(keycode);
}
////////////////////////////////////////////////////////////
Keyboard::Key KeyboardImpl::localize(Keyboard::Scancode code)
{
KeySym keysym = scancodeToKeySym(code);
return keySymToKey(keysym);
}
////////////////////////////////////////////////////////////
String KeyboardImpl::getDescription(Keyboard::Scancode code)
{
bool checkInput = true;
// these scancodes actually correspond to keys with input
// but we want to return their description, not their behaviour
if (code == Keyboard::Scan::Enter || code == Keyboard::Scan::Escape || code == Keyboard::Scan::Backspace ||
code == Keyboard::Scan::Tab || code == Keyboard::Scan::Space || code == Keyboard::Scan::ScrollLock ||
code == Keyboard::Scan::Pause || code == Keyboard::Scan::Delete || code == Keyboard::Scan::NumpadDivide ||
code == Keyboard::Scan::NumpadMultiply || code == Keyboard::Scan::NumpadMinus ||
code == Keyboard::Scan::NumpadPlus || code == Keyboard::Scan::NumpadEqual ||
code == Keyboard::Scan::NumpadEnter || code == Keyboard::Scan::NumpadDecimal)
{
checkInput = false;
}
if (checkInput)
{
KeySym keysym = scancodeToKeySym(code);
std::uint32_t unicode = keysymToUnicode(keysym);
if (unicode != 0)
return String(unicode);
}
// Fallback to our best guess for the keys that are known to be independent of the layout.
// clang-format off
switch (code)
{
case Keyboard::Scan::Enter: return "Enter";
case Keyboard::Scan::Escape: return "Escape";
case Keyboard::Scan::Backspace: return "Backspace";
case Keyboard::Scan::Tab: return "Tab";
case Keyboard::Scan::Space: return "Space";
case Keyboard::Scan::F1: return "F1";
case Keyboard::Scan::F2: return "F2";
case Keyboard::Scan::F3: return "F3";
case Keyboard::Scan::F4: return "F4";
case Keyboard::Scan::F5: return "F5";
case Keyboard::Scan::F6: return "F6";
case Keyboard::Scan::F7: return "F7";
case Keyboard::Scan::F8: return "F8";
case Keyboard::Scan::F9: return "F9";
case Keyboard::Scan::F10: return "F10";
case Keyboard::Scan::F11: return "F11";
case Keyboard::Scan::F12: return "F12";
case Keyboard::Scan::F13: return "F13";
case Keyboard::Scan::F14: return "F14";
case Keyboard::Scan::F15: return "F15";
case Keyboard::Scan::F16: return "F16";
case Keyboard::Scan::F17: return "F17";
case Keyboard::Scan::F18: return "F18";
case Keyboard::Scan::F19: return "F19";
case Keyboard::Scan::F20: return "F20";
case Keyboard::Scan::F21: return "F21";
case Keyboard::Scan::F22: return "F22";
case Keyboard::Scan::F23: return "F23";
case Keyboard::Scan::F24: return "F24";
case Keyboard::Scan::CapsLock: return "Caps Lock";
case Keyboard::Scan::PrintScreen: return "Print Screen";
case Keyboard::Scan::ScrollLock: return "Scroll Lock";
case Keyboard::Scan::Pause: return "Pause";
case Keyboard::Scan::Insert: return "Insert";
case Keyboard::Scan::Home: return "Home";
case Keyboard::Scan::PageUp: return "Page Up";
case Keyboard::Scan::Delete: return "Delete";
case Keyboard::Scan::End: return "End";
case Keyboard::Scan::PageDown: return "Page Down";
case Keyboard::Scan::Left: return "Left Arrow";
case Keyboard::Scan::Right: return "Right Arrow";
case Keyboard::Scan::Down: return "Down Arrow";
case Keyboard::Scan::Up: return "Up Arrow";
case Keyboard::Scan::NumLock: return "Num Lock";
case Keyboard::Scan::NumpadDivide: return "Divide (Numpad)";
case Keyboard::Scan::NumpadMultiply: return "Multiply (Numpad)";
case Keyboard::Scan::NumpadMinus: return "Minus (Numpad)";
case Keyboard::Scan::NumpadPlus: return "Plus (Numpad)";
case Keyboard::Scan::NumpadEqual: return "Equal (Numpad)";
case Keyboard::Scan::NumpadEnter: return "Enter (Numpad)";
case Keyboard::Scan::NumpadDecimal: return "Decimal (Numpad)";
case Keyboard::Scan::Numpad0: return "0 (Numpad)";
case Keyboard::Scan::Numpad1: return "1 (Numpad)";
case Keyboard::Scan::Numpad2: return "2 (Numpad)";
case Keyboard::Scan::Numpad3: return "3 (Numpad)";
case Keyboard::Scan::Numpad4: return "4 (Numpad)";
case Keyboard::Scan::Numpad5: return "5 (Numpad)";
case Keyboard::Scan::Numpad6: return "6 (Numpad)";
case Keyboard::Scan::Numpad7: return "7 (Numpad)";
case Keyboard::Scan::Numpad8: return "8 (Numpad)";
case Keyboard::Scan::Numpad9: return "9 (Numpad)";
case Keyboard::Scan::Application: return "Application";
case Keyboard::Scan::Execute: return "Execute";
case Keyboard::Scan::Help: return "Help";
case Keyboard::Scan::Menu: return "Menu";
case Keyboard::Scan::Select: return "Select";
case Keyboard::Scan::Stop: return "Stop";
case Keyboard::Scan::Redo: return "Redo";
case Keyboard::Scan::Undo: return "Undo";
case Keyboard::Scan::Cut: return "Cut";
case Keyboard::Scan::Copy: return "Copy";
case Keyboard::Scan::Paste: return "Paste";
case Keyboard::Scan::Search: return "Search";
case Keyboard::Scan::VolumeMute: return "Volume Mute";
case Keyboard::Scan::VolumeUp: return "Volume Up";
case Keyboard::Scan::VolumeDown: return "Volume Down";
case Keyboard::Scan::LControl: return "Left Control";
case Keyboard::Scan::LShift: return "Left Shift";
case Keyboard::Scan::LAlt: return "Left Alt";
case Keyboard::Scan::LSystem: return "Left System";
case Keyboard::Scan::RControl: return "Right Control";
case Keyboard::Scan::RShift: return "Right Shift";
case Keyboard::Scan::RAlt: return "Right Alt";
case Keyboard::Scan::RSystem: return "Right System";
case Keyboard::Scan::LaunchApplication1: return "Launch Application 1";
case Keyboard::Scan::LaunchApplication2: return "Launch Application 2";
case Keyboard::Scan::Favorites: return "Favorites";
case Keyboard::Scan::Back: return "Back";
case Keyboard::Scan::Forward: return "Forward";
case Keyboard::Scan::MediaNextTrack: return "Media Next Track";
case Keyboard::Scan::MediaPlayPause: return "Media Play Pause";
case Keyboard::Scan::MediaPreviousTrack: return "Media Previous Track";
case Keyboard::Scan::MediaStop: return "Media Stop";
case Keyboard::Scan::HomePage: return "Home Page";
case Keyboard::Scan::Refresh: return "Refresh";
case Keyboard::Scan::LaunchMail: return "Launch Mail";
case Keyboard::Scan::LaunchMediaSelect: return "Launch Media Select";
default: return "Unknown Scancode";
}
// clang-format on
}
////////////////////////////////////////////////////////////
Keyboard::Key KeyboardImpl::getKeyFromEvent(XKeyEvent& event)
{
// Try each KeySym index (modifier group) until we get a match
for (int i = 0; i < 4; ++i)
{
// Get the SFML keyboard code from the keysym of the key that has been pressed
KeySym keysym = XLookupKeysym(&event, i);
Keyboard::Key key = keySymToKey(keysym);
if (key != Keyboard::Unknown)
return key;
}
return Keyboard::Unknown;
}
////////////////////////////////////////////////////////////
Keyboard::Scancode KeyboardImpl::getScancodeFromEvent(XKeyEvent& event)
{
return keyCodeToScancode(static_cast<KeyCode>(event.keycode));
}
} // namespace sf::priv

View File

@ -0,0 +1,97 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2021 Laurent Gomila (laurent@sfml-dev.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
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Window/Keyboard.hpp>
#include <X11/Xlib.h> // XKeyEvent
namespace sf::priv
{
////////////////////////////////////////////////////////////
/// \brief sf::priv::KeyboardImpl helper
///
/// This class implements keyboard handling functions
/// to help sf::priv::InputImpl class.
////////////////////////////////////////////////////////////
class KeyboardImpl
{
public:
////////////////////////////////////////////////////////////
/// \copydoc sf::Keyboard::isKeyPressed(Key)
///
////////////////////////////////////////////////////////////
static bool isKeyPressed(Keyboard::Key key);
////////////////////////////////////////////////////////////
/// \copydoc sf::Keyboard::isKeyPressed(Scancode)
///
////////////////////////////////////////////////////////////
static bool isKeyPressed(Keyboard::Scancode code);
////////////////////////////////////////////////////////////
/// \copydoc sf::Keyboard::localize
///
////////////////////////////////////////////////////////////
static Keyboard::Scancode delocalize(Keyboard::Key key);
////////////////////////////////////////////////////////////
/// \copydoc sf::Keyboard::delocalize
///
////////////////////////////////////////////////////////////
static Keyboard::Key localize(Keyboard::Scancode code);
////////////////////////////////////////////////////////////
/// \copydoc sf::Keyboard::getDescription
///
////////////////////////////////////////////////////////////
static String getDescription(Keyboard::Scancode code);
////////////////////////////////////////////////////////////
/// \brief Get the sf::Keyboard::Key from XKeyEvent
///
/// \param event Event from which key is gotten
///
/// \return A key being pressed or released
///
////////////////////////////////////////////////////////////
static Keyboard::Key getKeyFromEvent(XKeyEvent& event);
////////////////////////////////////////////////////////////
/// \brief Get the sf::Keyboard::Scancode from XKeyEvent
///
/// \param event Event from which scancode is gotten
///
/// \return A scancode of a key being pressed or released
///
////////////////////////////////////////////////////////////
static Keyboard::Scancode getScancodeFromEvent(XKeyEvent& event);
};
} // namespace sf::priv

View File

@ -34,6 +34,7 @@
#include <SFML/Window/Unix/ClipboardImpl.hpp>
#include <SFML/Window/Unix/Display.hpp>
#include <SFML/Window/Unix/InputImpl.hpp>
#include <SFML/Window/Unix/KeyboardImpl.hpp>
#include <SFML/Window/Unix/WindowImplX11.hpp>
#include <X11/Xlibint.h>
@ -357,119 +358,6 @@ bool isWMAbsolutePositionGood()
return false;
}
sf::Keyboard::Key keysymToSF(KeySym symbol)
{
// clang-format off
switch (symbol)
{
case XK_Shift_L: return sf::Keyboard::LShift;
case XK_Shift_R: return sf::Keyboard::RShift;
case XK_Control_L: return sf::Keyboard::LControl;
case XK_Control_R: return sf::Keyboard::RControl;
case XK_Alt_L: return sf::Keyboard::LAlt;
case XK_Alt_R: return sf::Keyboard::RAlt;
case XK_Super_L: return sf::Keyboard::LSystem;
case XK_Super_R: return sf::Keyboard::RSystem;
case XK_Menu: return sf::Keyboard::Menu;
case XK_Escape: return sf::Keyboard::Escape;
case XK_semicolon: return sf::Keyboard::Semicolon;
case XK_slash: return sf::Keyboard::Slash;
case XK_equal: return sf::Keyboard::Equal;
case XK_minus: return sf::Keyboard::Hyphen;
case XK_bracketleft: return sf::Keyboard::LBracket;
case XK_bracketright: return sf::Keyboard::RBracket;
case XK_comma: return sf::Keyboard::Comma;
case XK_period: return sf::Keyboard::Period;
case XK_apostrophe: return sf::Keyboard::Quote;
case XK_backslash: return sf::Keyboard::Backslash;
case XK_grave: return sf::Keyboard::Tilde;
case XK_space: return sf::Keyboard::Space;
case XK_Return: return sf::Keyboard::Enter;
case XK_KP_Enter: return sf::Keyboard::Enter;
case XK_BackSpace: return sf::Keyboard::Backspace;
case XK_Tab: return sf::Keyboard::Tab;
case XK_Prior: return sf::Keyboard::PageUp;
case XK_Next: return sf::Keyboard::PageDown;
case XK_End: return sf::Keyboard::End;
case XK_Home: return sf::Keyboard::Home;
case XK_Insert: return sf::Keyboard::Insert;
case XK_Delete: return sf::Keyboard::Delete;
case XK_KP_Add: return sf::Keyboard::Add;
case XK_KP_Subtract: return sf::Keyboard::Subtract;
case XK_KP_Multiply: return sf::Keyboard::Multiply;
case XK_KP_Divide: return sf::Keyboard::Divide;
case XK_Pause: return sf::Keyboard::Pause;
case XK_F1: return sf::Keyboard::F1;
case XK_F2: return sf::Keyboard::F2;
case XK_F3: return sf::Keyboard::F3;
case XK_F4: return sf::Keyboard::F4;
case XK_F5: return sf::Keyboard::F5;
case XK_F6: return sf::Keyboard::F6;
case XK_F7: return sf::Keyboard::F7;
case XK_F8: return sf::Keyboard::F8;
case XK_F9: return sf::Keyboard::F9;
case XK_F10: return sf::Keyboard::F10;
case XK_F11: return sf::Keyboard::F11;
case XK_F12: return sf::Keyboard::F12;
case XK_F13: return sf::Keyboard::F13;
case XK_F14: return sf::Keyboard::F14;
case XK_F15: return sf::Keyboard::F15;
case XK_Left: return sf::Keyboard::Left;
case XK_Right: return sf::Keyboard::Right;
case XK_Up: return sf::Keyboard::Up;
case XK_Down: return sf::Keyboard::Down;
case XK_KP_Insert: return sf::Keyboard::Numpad0;
case XK_KP_End: return sf::Keyboard::Numpad1;
case XK_KP_Down: return sf::Keyboard::Numpad2;
case XK_KP_Page_Down: return sf::Keyboard::Numpad3;
case XK_KP_Left: return sf::Keyboard::Numpad4;
case XK_KP_Begin: return sf::Keyboard::Numpad5;
case XK_KP_Right: return sf::Keyboard::Numpad6;
case XK_KP_Home: return sf::Keyboard::Numpad7;
case XK_KP_Up: return sf::Keyboard::Numpad8;
case XK_KP_Page_Up: return sf::Keyboard::Numpad9;
case XK_a: return sf::Keyboard::A;
case XK_b: return sf::Keyboard::B;
case XK_c: return sf::Keyboard::C;
case XK_d: return sf::Keyboard::D;
case XK_e: return sf::Keyboard::E;
case XK_f: return sf::Keyboard::F;
case XK_g: return sf::Keyboard::G;
case XK_h: return sf::Keyboard::H;
case XK_i: return sf::Keyboard::I;
case XK_j: return sf::Keyboard::J;
case XK_k: return sf::Keyboard::K;
case XK_l: return sf::Keyboard::L;
case XK_m: return sf::Keyboard::M;
case XK_n: return sf::Keyboard::N;
case XK_o: return sf::Keyboard::O;
case XK_p: return sf::Keyboard::P;
case XK_q: return sf::Keyboard::Q;
case XK_r: return sf::Keyboard::R;
case XK_s: return sf::Keyboard::S;
case XK_t: return sf::Keyboard::T;
case XK_u: return sf::Keyboard::U;
case XK_v: return sf::Keyboard::V;
case XK_w: return sf::Keyboard::W;
case XK_x: return sf::Keyboard::X;
case XK_y: return sf::Keyboard::Y;
case XK_z: return sf::Keyboard::Z;
case XK_0: return sf::Keyboard::Num0;
case XK_1: return sf::Keyboard::Num1;
case XK_2: return sf::Keyboard::Num2;
case XK_3: return sf::Keyboard::Num3;
case XK_4: return sf::Keyboard::Num4;
case XK_5: return sf::Keyboard::Num5;
case XK_6: return sf::Keyboard::Num6;
case XK_7: return sf::Keyboard::Num7;
case XK_8: return sf::Keyboard::Num8;
case XK_9: return sf::Keyboard::Num9;
}
// clang-format on
return sf::Keyboard::Unknown;
}
} // namespace WindowsImplX11Impl
} // namespace
@ -1870,27 +1758,16 @@ bool WindowImplX11::processEvent(XEvent& windowEvent)
// Key down event
case KeyPress:
{
Keyboard::Key key = Keyboard::Unknown;
// Try each KeySym index (modifier group) until we get a match
for (int i = 0; i < 4; ++i)
{
// Get the SFML keyboard code from the keysym of the key that has been pressed
key = keysymToSF(XLookupKeysym(&windowEvent.xkey, i));
if (key != Keyboard::Unknown)
break;
}
// Fill the event parameters
// TODO: if modifiers are wrong, use XGetModifierMapping to retrieve the actual modifiers mapping
Event event;
event.type = Event::KeyPressed;
event.key.code = key;
event.key.alt = windowEvent.xkey.state & Mod1Mask;
event.key.control = windowEvent.xkey.state & ControlMask;
event.key.shift = windowEvent.xkey.state & ShiftMask;
event.key.system = windowEvent.xkey.state & Mod4Mask;
event.type = Event::KeyPressed;
event.key.code = KeyboardImpl::getKeyFromEvent(windowEvent.xkey);
event.key.scancode = KeyboardImpl::getScancodeFromEvent(windowEvent.xkey);
event.key.alt = windowEvent.xkey.state & Mod1Mask;
event.key.control = windowEvent.xkey.state & ControlMask;
event.key.shift = windowEvent.xkey.state & ShiftMask;
event.key.system = windowEvent.xkey.state & Mod4Mask;
const bool filtered = XFilterEvent(&windowEvent, None);
@ -1976,26 +1853,15 @@ bool WindowImplX11::processEvent(XEvent& windowEvent)
// Key up event
case KeyRelease:
{
Keyboard::Key key = Keyboard::Unknown;
// Try each KeySym index (modifier group) until we get a match
for (int i = 0; i < 4; ++i)
{
// Get the SFML keyboard code from the keysym of the key that has been released
key = keysymToSF(XLookupKeysym(&windowEvent.xkey, i));
if (key != Keyboard::Unknown)
break;
}
// Fill the event parameters
Event event;
event.type = Event::KeyReleased;
event.key.code = key;
event.key.alt = windowEvent.xkey.state & Mod1Mask;
event.key.control = windowEvent.xkey.state & ControlMask;
event.key.shift = windowEvent.xkey.state & ShiftMask;
event.key.system = windowEvent.xkey.state & Mod4Mask;
event.type = Event::KeyReleased;
event.key.code = KeyboardImpl::getKeyFromEvent(windowEvent.xkey);
event.key.scancode = KeyboardImpl::getScancodeFromEvent(windowEvent.xkey);
event.key.alt = windowEvent.xkey.state & Mod1Mask;
event.key.control = windowEvent.xkey.state & ControlMask;
event.key.shift = windowEvent.xkey.state & ShiftMask;
event.key.system = windowEvent.xkey.state & Mod4Mask;
pushEvent(event);
break;
@ -2121,6 +1987,15 @@ bool WindowImplX11::processEvent(XEvent& windowEvent)
break;
}
// Keyboard mapping changed
case MappingNotify:
{
if (windowEvent.xmapping.request == MappingKeyboard)
XRefreshKeyboardMapping(&windowEvent.xmapping);
break;
}
// Window unmapped
case UnmapNotify:
{

View File

@ -25,129 +25,584 @@
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/System/String.hpp>
#include <SFML/System/Win32/WindowsHeader.hpp>
#include <SFML/Window/Win32/InputImpl.hpp>
#include <SFML/Window/Window.hpp>
namespace sf::priv
{
////////////////////////////////////////////////////////////
bool InputImpl::isKeyPressed(Keyboard::Key key)
{
int vkey = 0;
Keyboard::Scancode InputImpl::m_keyToScancodeMapping[Keyboard::KeyCount]; ///< Mapping from Key to Scancode
Keyboard::Key InputImpl::m_scancodeToKeyMapping[Keyboard::Scan::ScancodeCount]; ///< Mapping from Scancode to Key
////////////////////////////////////////////////////////////
Keyboard::Key virtualKeyToSfKey(UINT virtualKey)
{
// clang-format off
switch (key)
switch (virtualKey)
{
default: vkey = 0; break;
case Keyboard::A: vkey = 'A'; break;
case Keyboard::B: vkey = 'B'; break;
case Keyboard::C: vkey = 'C'; break;
case Keyboard::D: vkey = 'D'; break;
case Keyboard::E: vkey = 'E'; break;
case Keyboard::F: vkey = 'F'; break;
case Keyboard::G: vkey = 'G'; break;
case Keyboard::H: vkey = 'H'; break;
case Keyboard::I: vkey = 'I'; break;
case Keyboard::J: vkey = 'J'; break;
case Keyboard::K: vkey = 'K'; break;
case Keyboard::L: vkey = 'L'; break;
case Keyboard::M: vkey = 'M'; break;
case Keyboard::N: vkey = 'N'; break;
case Keyboard::O: vkey = 'O'; break;
case Keyboard::P: vkey = 'P'; break;
case Keyboard::Q: vkey = 'Q'; break;
case Keyboard::R: vkey = 'R'; break;
case Keyboard::S: vkey = 'S'; break;
case Keyboard::T: vkey = 'T'; break;
case Keyboard::U: vkey = 'U'; break;
case Keyboard::V: vkey = 'V'; break;
case Keyboard::W: vkey = 'W'; break;
case Keyboard::X: vkey = 'X'; break;
case Keyboard::Y: vkey = 'Y'; break;
case Keyboard::Z: vkey = 'Z'; break;
case Keyboard::Num0: vkey = '0'; break;
case Keyboard::Num1: vkey = '1'; break;
case Keyboard::Num2: vkey = '2'; break;
case Keyboard::Num3: vkey = '3'; break;
case Keyboard::Num4: vkey = '4'; break;
case Keyboard::Num5: vkey = '5'; break;
case Keyboard::Num6: vkey = '6'; break;
case Keyboard::Num7: vkey = '7'; break;
case Keyboard::Num8: vkey = '8'; break;
case Keyboard::Num9: vkey = '9'; break;
case Keyboard::Escape: vkey = VK_ESCAPE; break;
case Keyboard::LControl: vkey = VK_LCONTROL; break;
case Keyboard::LShift: vkey = VK_LSHIFT; break;
case Keyboard::LAlt: vkey = VK_LMENU; break;
case Keyboard::LSystem: vkey = VK_LWIN; break;
case Keyboard::RControl: vkey = VK_RCONTROL; break;
case Keyboard::RShift: vkey = VK_RSHIFT; break;
case Keyboard::RAlt: vkey = VK_RMENU; break;
case Keyboard::RSystem: vkey = VK_RWIN; break;
case Keyboard::Menu: vkey = VK_APPS; break;
case Keyboard::LBracket: vkey = VK_OEM_4; break;
case Keyboard::RBracket: vkey = VK_OEM_6; break;
case Keyboard::Semicolon: vkey = VK_OEM_1; break;
case Keyboard::Comma: vkey = VK_OEM_COMMA; break;
case Keyboard::Period: vkey = VK_OEM_PERIOD; break;
case Keyboard::Quote: vkey = VK_OEM_7; break;
case Keyboard::Slash: vkey = VK_OEM_2; break;
case Keyboard::Backslash: vkey = VK_OEM_5; break;
case Keyboard::Tilde: vkey = VK_OEM_3; break;
case Keyboard::Equal: vkey = VK_OEM_PLUS; break;
case Keyboard::Hyphen: vkey = VK_OEM_MINUS; break;
case Keyboard::Space: vkey = VK_SPACE; break;
case Keyboard::Enter: vkey = VK_RETURN; break;
case Keyboard::Backspace: vkey = VK_BACK; break;
case Keyboard::Tab: vkey = VK_TAB; break;
case Keyboard::PageUp: vkey = VK_PRIOR; break;
case Keyboard::PageDown: vkey = VK_NEXT; break;
case Keyboard::End: vkey = VK_END; break;
case Keyboard::Home: vkey = VK_HOME; break;
case Keyboard::Insert: vkey = VK_INSERT; break;
case Keyboard::Delete: vkey = VK_DELETE; break;
case Keyboard::Add: vkey = VK_ADD; break;
case Keyboard::Subtract: vkey = VK_SUBTRACT; break;
case Keyboard::Multiply: vkey = VK_MULTIPLY; break;
case Keyboard::Divide: vkey = VK_DIVIDE; break;
case Keyboard::Left: vkey = VK_LEFT; break;
case Keyboard::Right: vkey = VK_RIGHT; break;
case Keyboard::Up: vkey = VK_UP; break;
case Keyboard::Down: vkey = VK_DOWN; break;
case Keyboard::Numpad0: vkey = VK_NUMPAD0; break;
case Keyboard::Numpad1: vkey = VK_NUMPAD1; break;
case Keyboard::Numpad2: vkey = VK_NUMPAD2; break;
case Keyboard::Numpad3: vkey = VK_NUMPAD3; break;
case Keyboard::Numpad4: vkey = VK_NUMPAD4; break;
case Keyboard::Numpad5: vkey = VK_NUMPAD5; break;
case Keyboard::Numpad6: vkey = VK_NUMPAD6; break;
case Keyboard::Numpad7: vkey = VK_NUMPAD7; break;
case Keyboard::Numpad8: vkey = VK_NUMPAD8; break;
case Keyboard::Numpad9: vkey = VK_NUMPAD9; break;
case Keyboard::F1: vkey = VK_F1; break;
case Keyboard::F2: vkey = VK_F2; break;
case Keyboard::F3: vkey = VK_F3; break;
case Keyboard::F4: vkey = VK_F4; break;
case Keyboard::F5: vkey = VK_F5; break;
case Keyboard::F6: vkey = VK_F6; break;
case Keyboard::F7: vkey = VK_F7; break;
case Keyboard::F8: vkey = VK_F8; break;
case Keyboard::F9: vkey = VK_F9; break;
case Keyboard::F10: vkey = VK_F10; break;
case Keyboard::F11: vkey = VK_F11; break;
case Keyboard::F12: vkey = VK_F12; break;
case Keyboard::F13: vkey = VK_F13; break;
case Keyboard::F14: vkey = VK_F14; break;
case Keyboard::F15: vkey = VK_F15; break;
case Keyboard::Pause: vkey = VK_PAUSE; break;
case 'A': return Keyboard::A;
case 'B': return Keyboard::B;
case 'C': return Keyboard::C;
case 'D': return Keyboard::D;
case 'E': return Keyboard::E;
case 'F': return Keyboard::F;
case 'G': return Keyboard::G;
case 'H': return Keyboard::H;
case 'I': return Keyboard::I;
case 'J': return Keyboard::J;
case 'K': return Keyboard::K;
case 'L': return Keyboard::L;
case 'M': return Keyboard::M;
case 'N': return Keyboard::N;
case 'O': return Keyboard::O;
case 'P': return Keyboard::P;
case 'Q': return Keyboard::Q;
case 'R': return Keyboard::R;
case 'S': return Keyboard::S;
case 'T': return Keyboard::T;
case 'U': return Keyboard::U;
case 'V': return Keyboard::V;
case 'W': return Keyboard::W;
case 'X': return Keyboard::X;
case 'Y': return Keyboard::Y;
case 'Z': return Keyboard::Z;
case '0': return Keyboard::Num0;
case '1': return Keyboard::Num1;
case '2': return Keyboard::Num2;
case '3': return Keyboard::Num3;
case '4': return Keyboard::Num4;
case '5': return Keyboard::Num5;
case '6': return Keyboard::Num6;
case '7': return Keyboard::Num7;
case '8': return Keyboard::Num8;
case '9': return Keyboard::Num9;
case VK_ESCAPE: return Keyboard::Escape;
case VK_LCONTROL: return Keyboard::LControl;
case VK_LSHIFT: return Keyboard::LShift;
case VK_LMENU: return Keyboard::LAlt;
case VK_LWIN: return Keyboard::LSystem;
case VK_RCONTROL: return Keyboard::RControl;
case VK_RSHIFT: return Keyboard::RShift;
case VK_RMENU: return Keyboard::RAlt;
case VK_RWIN: return Keyboard::RSystem;
case VK_APPS: return Keyboard::Menu;
case VK_OEM_4: return Keyboard::LBracket;
case VK_OEM_6: return Keyboard::RBracket;
case VK_OEM_1: return Keyboard::Semicolon;
case VK_OEM_COMMA: return Keyboard::Comma;
case VK_OEM_PERIOD: return Keyboard::Period;
case VK_OEM_7: return Keyboard::Apostrophe;
case VK_OEM_2: return Keyboard::Slash;
case VK_OEM_5: return Keyboard::Backslash;
case VK_OEM_3: return Keyboard::Grave;
case VK_OEM_PLUS: return Keyboard::Equal;
case VK_OEM_MINUS: return Keyboard::Hyphen;
case VK_SPACE: return Keyboard::Space;
case VK_RETURN: return Keyboard::Enter;
case VK_BACK: return Keyboard::Backspace;
case VK_TAB: return Keyboard::Tab;
case VK_PRIOR: return Keyboard::PageUp;
case VK_NEXT: return Keyboard::PageDown;
case VK_END: return Keyboard::End;
case VK_HOME: return Keyboard::Home;
case VK_INSERT: return Keyboard::Insert;
case VK_DELETE: return Keyboard::Delete;
case VK_ADD: return Keyboard::Add;
case VK_SUBTRACT: return Keyboard::Subtract;
case VK_MULTIPLY: return Keyboard::Multiply;
case VK_DIVIDE: return Keyboard::Divide;
case VK_LEFT: return Keyboard::Left;
case VK_RIGHT: return Keyboard::Right;
case VK_UP: return Keyboard::Up;
case VK_DOWN: return Keyboard::Down;
case VK_NUMPAD0: return Keyboard::Numpad0;
case VK_NUMPAD1: return Keyboard::Numpad1;
case VK_NUMPAD2: return Keyboard::Numpad2;
case VK_NUMPAD3: return Keyboard::Numpad3;
case VK_NUMPAD4: return Keyboard::Numpad4;
case VK_NUMPAD5: return Keyboard::Numpad5;
case VK_NUMPAD6: return Keyboard::Numpad6;
case VK_NUMPAD7: return Keyboard::Numpad7;
case VK_NUMPAD8: return Keyboard::Numpad8;
case VK_NUMPAD9: return Keyboard::Numpad9;
case VK_F1: return Keyboard::F1;
case VK_F2: return Keyboard::F2;
case VK_F3: return Keyboard::F3;
case VK_F4: return Keyboard::F4;
case VK_F5: return Keyboard::F5;
case VK_F6: return Keyboard::F6;
case VK_F7: return Keyboard::F7;
case VK_F8: return Keyboard::F8;
case VK_F9: return Keyboard::F9;
case VK_F10: return Keyboard::F10;
case VK_F11: return Keyboard::F11;
case VK_F12: return Keyboard::F12;
case VK_F13: return Keyboard::F13;
case VK_F14: return Keyboard::F14;
case VK_F15: return Keyboard::F15;
case VK_PAUSE: return Keyboard::Pause;
default: return Keyboard::Unknown;
}
// clang-format on
return (GetAsyncKeyState(vkey) & 0x8000) != 0;
}
////////////////////////////////////////////////////////////
int sfKeyToVirtualKey(Keyboard::Key key)
{
// clang-format off
switch (key)
{
case Keyboard::A: return 'A';
case Keyboard::B: return 'B';
case Keyboard::C: return 'C';
case Keyboard::D: return 'D';
case Keyboard::E: return 'E';
case Keyboard::F: return 'F';
case Keyboard::G: return 'G';
case Keyboard::H: return 'H';
case Keyboard::I: return 'I';
case Keyboard::J: return 'J';
case Keyboard::K: return 'K';
case Keyboard::L: return 'L';
case Keyboard::M: return 'M';
case Keyboard::N: return 'N';
case Keyboard::O: return 'O';
case Keyboard::P: return 'P';
case Keyboard::Q: return 'Q';
case Keyboard::R: return 'R';
case Keyboard::S: return 'S';
case Keyboard::T: return 'T';
case Keyboard::U: return 'U';
case Keyboard::V: return 'V';
case Keyboard::W: return 'W';
case Keyboard::X: return 'X';
case Keyboard::Y: return 'Y';
case Keyboard::Z: return 'Z';
case Keyboard::Num0: return '0';
case Keyboard::Num1: return '1';
case Keyboard::Num2: return '2';
case Keyboard::Num3: return '3';
case Keyboard::Num4: return '4';
case Keyboard::Num5: return '5';
case Keyboard::Num6: return '6';
case Keyboard::Num7: return '7';
case Keyboard::Num8: return '8';
case Keyboard::Num9: return '9';
case Keyboard::Escape: return VK_ESCAPE;
case Keyboard::LControl: return VK_LCONTROL;
case Keyboard::LShift: return VK_LSHIFT;
case Keyboard::LAlt: return VK_LMENU;
case Keyboard::LSystem: return VK_LWIN;
case Keyboard::RControl: return VK_RCONTROL;
case Keyboard::RShift: return VK_RSHIFT;
case Keyboard::RAlt: return VK_RMENU;
case Keyboard::RSystem: return VK_RWIN;
case Keyboard::Menu: return VK_APPS;
case Keyboard::LBracket: return VK_OEM_4;
case Keyboard::RBracket: return VK_OEM_6;
case Keyboard::Semicolon: return VK_OEM_1;
case Keyboard::Comma: return VK_OEM_COMMA;
case Keyboard::Period: return VK_OEM_PERIOD;
case Keyboard::Apostrophe: return VK_OEM_7;
case Keyboard::Slash: return VK_OEM_2;
case Keyboard::Backslash: return VK_OEM_5;
case Keyboard::Grave: return VK_OEM_3;
case Keyboard::Equal: return VK_OEM_PLUS;
case Keyboard::Hyphen: return VK_OEM_MINUS;
case Keyboard::Space: return VK_SPACE;
case Keyboard::Enter: return VK_RETURN;
case Keyboard::Backspace: return VK_BACK;
case Keyboard::Tab: return VK_TAB;
case Keyboard::PageUp: return VK_PRIOR;
case Keyboard::PageDown: return VK_NEXT;
case Keyboard::End: return VK_END;
case Keyboard::Home: return VK_HOME;
case Keyboard::Insert: return VK_INSERT;
case Keyboard::Delete: return VK_DELETE;
case Keyboard::Add: return VK_ADD;
case Keyboard::Subtract: return VK_SUBTRACT;
case Keyboard::Multiply: return VK_MULTIPLY;
case Keyboard::Divide: return VK_DIVIDE;
case Keyboard::Left: return VK_LEFT;
case Keyboard::Right: return VK_RIGHT;
case Keyboard::Up: return VK_UP;
case Keyboard::Down: return VK_DOWN;
case Keyboard::Numpad0: return VK_NUMPAD0;
case Keyboard::Numpad1: return VK_NUMPAD1;
case Keyboard::Numpad2: return VK_NUMPAD2;
case Keyboard::Numpad3: return VK_NUMPAD3;
case Keyboard::Numpad4: return VK_NUMPAD4;
case Keyboard::Numpad5: return VK_NUMPAD5;
case Keyboard::Numpad6: return VK_NUMPAD6;
case Keyboard::Numpad7: return VK_NUMPAD7;
case Keyboard::Numpad8: return VK_NUMPAD8;
case Keyboard::Numpad9: return VK_NUMPAD9;
case Keyboard::F1: return VK_F1;
case Keyboard::F2: return VK_F2;
case Keyboard::F3: return VK_F3;
case Keyboard::F4: return VK_F4;
case Keyboard::F5: return VK_F5;
case Keyboard::F6: return VK_F6;
case Keyboard::F7: return VK_F7;
case Keyboard::F8: return VK_F8;
case Keyboard::F9: return VK_F9;
case Keyboard::F10: return VK_F10;
case Keyboard::F11: return VK_F11;
case Keyboard::F12: return VK_F12;
case Keyboard::F13: return VK_F13;
case Keyboard::F14: return VK_F14;
case Keyboard::F15: return VK_F15;
case Keyboard::Pause: return VK_PAUSE;
default: return 0;
}
// clang-format on
}
////////////////////////////////////////////////////////////
WORD sfScanToWinScan(Keyboard::Scancode code)
{
// Convert an SFML scancode to a Windows scancode
// Reference: https://msdn.microsoft.com/en-us/library/aa299374(v=vs.60).aspx
// clang-format off
switch (code)
{
case Keyboard::Scan::A: return 0x1E;
case Keyboard::Scan::B: return 0x30;
case Keyboard::Scan::C: return 0x2E;
case Keyboard::Scan::D: return 0x20;
case Keyboard::Scan::E: return 0x12;
case Keyboard::Scan::F: return 0x21;
case Keyboard::Scan::G: return 0x22;
case Keyboard::Scan::H: return 0x23;
case Keyboard::Scan::I: return 0x17;
case Keyboard::Scan::J: return 0x24;
case Keyboard::Scan::K: return 0x25;
case Keyboard::Scan::L: return 0x26;
case Keyboard::Scan::M: return 0x32;
case Keyboard::Scan::N: return 0x31;
case Keyboard::Scan::O: return 0x18;
case Keyboard::Scan::P: return 0x19;
case Keyboard::Scan::Q: return 0x10;
case Keyboard::Scan::R: return 0x13;
case Keyboard::Scan::S: return 0x1F;
case Keyboard::Scan::T: return 0x14;
case Keyboard::Scan::U: return 0x16;
case Keyboard::Scan::V: return 0x2F;
case Keyboard::Scan::W: return 0x11;
case Keyboard::Scan::X: return 0x2D;
case Keyboard::Scan::Y: return 0x15;
case Keyboard::Scan::Z: return 0x2C;
case Keyboard::Scan::Num1: return 0x02;
case Keyboard::Scan::Num2: return 0x03;
case Keyboard::Scan::Num3: return 0x04;
case Keyboard::Scan::Num4: return 0x05;
case Keyboard::Scan::Num5: return 0x06;
case Keyboard::Scan::Num6: return 0x07;
case Keyboard::Scan::Num7: return 0x08;
case Keyboard::Scan::Num8: return 0x09;
case Keyboard::Scan::Num9: return 0x0A;
case Keyboard::Scan::Num0: return 0x0B;
case Keyboard::Scan::Enter: return 0x1C;
case Keyboard::Scan::Escape: return 0x01;
case Keyboard::Scan::Backspace: return 0x0E;
case Keyboard::Scan::Tab: return 0x0F;
case Keyboard::Scan::Space: return 0x39;
case Keyboard::Scan::Hyphen: return 0x0C;
case Keyboard::Scan::Equal: return 0x0D;
case Keyboard::Scan::LBracket: return 0x1A;
case Keyboard::Scan::RBracket: return 0x1B;
case Keyboard::Scan::Backslash: return 0x2B;
case Keyboard::Scan::Semicolon: return 0x27;
case Keyboard::Scan::Apostrophe: return 0x28;
case Keyboard::Scan::Grave: return 0x29;
case Keyboard::Scan::Comma: return 0x33;
case Keyboard::Scan::Period: return 0x34;
case Keyboard::Scan::Slash: return 0x35;
case Keyboard::Scan::F1: return 0x3B;
case Keyboard::Scan::F2: return 0x3C;
case Keyboard::Scan::F3: return 0x3D;
case Keyboard::Scan::F4: return 0x3E;
case Keyboard::Scan::F5: return 0x3F;
case Keyboard::Scan::F6: return 0x40;
case Keyboard::Scan::F7: return 0x41;
case Keyboard::Scan::F8: return 0x42;
case Keyboard::Scan::F9: return 0x43;
case Keyboard::Scan::F10: return 0x44;
case Keyboard::Scan::F11: return 0x57;
case Keyboard::Scan::F12: return 0x58;
case Keyboard::Scan::F13: return 0x64;
case Keyboard::Scan::F14: return 0x65;
case Keyboard::Scan::F15: return 0x66;
case Keyboard::Scan::F16: return 0x67;
case Keyboard::Scan::F17: return 0x68;
case Keyboard::Scan::F18: return 0x69;
case Keyboard::Scan::F19: return 0x6A;
case Keyboard::Scan::F20: return 0x6B;
case Keyboard::Scan::F21: return 0x6C;
case Keyboard::Scan::F22: return 0x6D;
case Keyboard::Scan::F23: return 0x6E;
case Keyboard::Scan::F24: return 0x76;
case Keyboard::Scan::CapsLock: return 0x3A;
case Keyboard::Scan::PrintScreen: return 0xE037;
case Keyboard::Scan::ScrollLock: return 0x46;
case Keyboard::Scan::Pause: return 0x45;
case Keyboard::Scan::Insert: return 0xE052;
case Keyboard::Scan::Home: return 0xE047;
case Keyboard::Scan::PageUp: return 0xE049;
case Keyboard::Scan::Delete: return 0xE053;
case Keyboard::Scan::End: return 0xE04F;
case Keyboard::Scan::PageDown: return 0xE051;
case Keyboard::Scan::Right: return 0xE04D;
case Keyboard::Scan::Left: return 0xE04B;
case Keyboard::Scan::Down: return 0xE050;
case Keyboard::Scan::Up: return 0xE048;
case Keyboard::Scan::NumLock: return 0xE045;
case Keyboard::Scan::NumpadDivide: return 0xE035;
case Keyboard::Scan::NumpadMultiply: return 0x37;
case Keyboard::Scan::NumpadMinus: return 0x4A;
case Keyboard::Scan::NumpadPlus: return 0x4E;
case Keyboard::Scan::NumpadEqual: return 0x7E;
case Keyboard::Scan::NumpadEnter: return 0xE01C;
case Keyboard::Scan::NumpadDecimal: return 0x53;
case Keyboard::Scan::Numpad1: return 0x4F;
case Keyboard::Scan::Numpad2: return 0x50;
case Keyboard::Scan::Numpad3: return 0x51;
case Keyboard::Scan::Numpad4: return 0x4B;
case Keyboard::Scan::Numpad5: return 0x4C;
case Keyboard::Scan::Numpad6: return 0x4D;
case Keyboard::Scan::Numpad7: return 0x47;
case Keyboard::Scan::Numpad8: return 0x48;
case Keyboard::Scan::Numpad9: return 0x49;
case Keyboard::Scan::Numpad0: return 0x52;
case Keyboard::Scan::NonUsBackslash: return 0x56;
// No known scancode for Keyboard::Scan::Application
// No known scancode for Keyboard::Scan::Execute
// No known scancode for Keyboard::Scan::ModeChange
case Keyboard::Scan::Help: return 0xE061;
case Keyboard::Scan::Menu: return 0xE05D;
case Keyboard::Scan::Select: return 0xE01E;
// No known scancode for Keyboard::Scan::Redo
// No known scancode for Keyboard::Scan::Undo
// No known scancode for Keyboard::Scan::Cut
// No known scancode for Keyboard::Scan::Copy
// No known scancode for Keyboard::Scan::Paste
case Keyboard::Scan::VolumeMute: return 0xE020;
case Keyboard::Scan::VolumeUp: return 0xE02E;
case Keyboard::Scan::VolumeDown: return 0xE02C;
case Keyboard::Scan::MediaPlayPause: return 0xE022;
case Keyboard::Scan::MediaStop: return 0xE024;
case Keyboard::Scan::MediaNextTrack: return 0xE019;
case Keyboard::Scan::MediaPreviousTrack: return 0xE010;
case Keyboard::Scan::LControl: return 0x1D;
case Keyboard::Scan::LShift: return 0x2A;
case Keyboard::Scan::LAlt: return 0x38;
case Keyboard::Scan::LSystem: return 0xE05B;
case Keyboard::Scan::RControl: return 0xE01D;
case Keyboard::Scan::RShift: return 0x36;
case Keyboard::Scan::RAlt: return 0xE038;
case Keyboard::Scan::RSystem: return 0xE05C;
case Keyboard::Scan::Back: return 0xE06A;
case Keyboard::Scan::Forward: return 0xE069;
case Keyboard::Scan::Refresh: return 0xE067;
case Keyboard::Scan::Stop: return 0xE068;
case Keyboard::Scan::Search: return 0xE065;
case Keyboard::Scan::Favorites: return 0xE066;
case Keyboard::Scan::HomePage: return 0xE030;
case Keyboard::Scan::LaunchApplication1: return 0xE06B;
case Keyboard::Scan::LaunchApplication2: return 0xE021;
case Keyboard::Scan::LaunchMail: return 0xE06C;
case Keyboard::Scan::LaunchMediaSelect: return 0xE06D;
// Unable to map to a scancode
default: return 0x0;
}
// clang-format on
}
////////////////////////////////////////////////////////////
WORD sfScanToWinScanExtended(Keyboard::Scancode code)
{
// Convert an SFML scancode to a Windows scancode
// Reference: https://msdn.microsoft.com/en-us/library/aa299374(v=vs.60).aspx
// clang-format off
switch (code)
{
case Keyboard::Scan::PrintScreen: return 55 | 0xE100;
case Keyboard::Scan::Insert: return 82 | 0xE100;
case Keyboard::Scan::Home: return 71 | 0xE100;
case Keyboard::Scan::PageUp: return 73 | 0xE100;
case Keyboard::Scan::Delete: return 83 | 0xE100;
case Keyboard::Scan::End: return 79 | 0xE100;
case Keyboard::Scan::PageDown: return 81 | 0xE100;
case Keyboard::Scan::Right: return 77 | 0xE100;
case Keyboard::Scan::Left: return 75 | 0xE100;
case Keyboard::Scan::Down: return 80 | 0xE100;
case Keyboard::Scan::Up: return 72 | 0xE100;
case Keyboard::Scan::NumLock: return 69 | 0xE100;
case Keyboard::Scan::NumpadEnter: return 28 | 0xE100;
case Keyboard::Scan::NumpadDivide: return 53 | 0xE100;
case Keyboard::Scan::Help: return 97 | 0xE100;
case Keyboard::Scan::Menu: return 93 | 0xE100;
case Keyboard::Scan::Select: return 30 | 0xE100;
case Keyboard::Scan::VolumeMute: return 32 | 0xE100;
case Keyboard::Scan::VolumeUp: return 46 | 0xE100;
case Keyboard::Scan::VolumeDown: return 44 | 0xE100;
case Keyboard::Scan::MediaPlayPause: return 34 | 0xE100;
case Keyboard::Scan::MediaStop: return 36 | 0xE100;
case Keyboard::Scan::MediaNextTrack: return 25 | 0xE100;
case Keyboard::Scan::MediaPreviousTrack: return 16 | 0xE100;
case Keyboard::Scan::LSystem: return 91 | 0xE100;
case Keyboard::Scan::RControl: return 29 | 0xE100;
case Keyboard::Scan::RAlt: return 56 | 0xE100;
case Keyboard::Scan::RSystem: return 92 | 0xE100;
case Keyboard::Scan::Back: return 106 | 0xE100;
case Keyboard::Scan::Forward: return 105 | 0xE100;
case Keyboard::Scan::Refresh: return 103 | 0xE100;
case Keyboard::Scan::Stop: return 104 | 0xE100;
case Keyboard::Scan::Search: return 101 | 0xE100;
case Keyboard::Scan::Favorites: return 102 | 0xE100;
case Keyboard::Scan::HomePage: return 48 | 0xE100;
case Keyboard::Scan::LaunchApplication1: return 107 | 0xE100;
case Keyboard::Scan::LaunchApplication2: return 33 | 0xE100;
case Keyboard::Scan::LaunchMail: return 108 | 0xE100;
case Keyboard::Scan::LaunchMediaSelect: return 109 | 0xE100;
// Use non-extended mapping
default: return sfScanToWinScan(code);
}
// clang-format on
}
UINT sfScanToVirtualKey(Keyboard::Scancode code)
{
WORD winScancode = sfScanToWinScan(code);
// Manually map non-extended key codes
// clang-format off
switch (code)
{
case Keyboard::Scan::Numpad0: return VK_NUMPAD0;
case Keyboard::Scan::Numpad1: return VK_NUMPAD1;
case Keyboard::Scan::Numpad2: return VK_NUMPAD2;
case Keyboard::Scan::Numpad3: return VK_NUMPAD3;
case Keyboard::Scan::Numpad4: return VK_NUMPAD4;
case Keyboard::Scan::Numpad5: return VK_NUMPAD5;
case Keyboard::Scan::Numpad6: return VK_NUMPAD6;
case Keyboard::Scan::Numpad7: return VK_NUMPAD7;
case Keyboard::Scan::Numpad8: return VK_NUMPAD8;
case Keyboard::Scan::Numpad9: return VK_NUMPAD9;
case Keyboard::Scan::NumpadMinus: return VK_SUBTRACT;
case Keyboard::Scan::NumpadDecimal: return VK_DECIMAL;
case Keyboard::Scan::NumpadDivide: return VK_DIVIDE;
case Keyboard::Scan::Pause: return VK_PAUSE;
case Keyboard::Scan::RControl: return VK_RCONTROL;
case Keyboard::Scan::RAlt: return VK_RMENU;
default: return MapVirtualKey(winScancode, MAPVK_VSC_TO_VK_EX);
}
// clang-format on
}
bool isValidScancode(Keyboard::Scancode code)
{
return code > Keyboard::Scan::Unknown && code < Keyboard::Scan::ScancodeCount;
}
bool isValidKey(Keyboard::Key key)
{
return key > Keyboard::Unknown && key < Keyboard::KeyCount;
}
////////////////////////////////////////////////////////////
void InputImpl::ensureMappings()
{
static bool isMappingInitialized = false;
if (isMappingInitialized)
return;
// Phase 1: Initialize mappings with default values
for (auto& scancode : m_keyToScancodeMapping)
scancode = Keyboard::Scan::Unknown;
for (auto& key : m_scancodeToKeyMapping)
key = Keyboard::Unknown;
// Phase 2: Translate scancode to virtual code to key names
for (int i = 0; i < Keyboard::Scan::ScancodeCount; ++i)
{
Keyboard::Scancode scan = static_cast<Keyboard::Scancode>(i);
UINT virtualKey = sfScanToVirtualKey(scan);
Keyboard::Key key = virtualKeyToSfKey(virtualKey);
if (key != Keyboard::Unknown && m_keyToScancodeMapping[key] == Keyboard::Scan::Unknown)
m_keyToScancodeMapping[key] = scan;
m_scancodeToKeyMapping[scan] = key;
}
isMappingInitialized = true;
}
////////////////////////////////////////////////////////////
bool InputImpl::isKeyPressed(Keyboard::Key key)
{
int virtualKey = sfKeyToVirtualKey(key);
return (GetAsyncKeyState(virtualKey) & 0x8000) != 0;
}
////////////////////////////////////////////////////////////
bool InputImpl::isKeyPressed(Keyboard::Scancode code)
{
UINT virtualKey = sfScanToVirtualKey(code);
return (GetAsyncKeyState(static_cast<int>(virtualKey)) & KF_UP) != 0;
}
////////////////////////////////////////////////////////////
Keyboard::Key InputImpl::localize(Keyboard::Scancode code)
{
if (!isValidScancode(code))
return Keyboard::Unknown;
ensureMappings();
return m_scancodeToKeyMapping[code];
}
////////////////////////////////////////////////////////////
Keyboard::Scancode InputImpl::delocalize(Keyboard::Key key)
{
if (!isValidKey(key))
return Keyboard::Scan::Unknown;
ensureMappings();
return m_keyToScancodeMapping[key];
}
////////////////////////////////////////////////////////////
String InputImpl::getDescription(Keyboard::Scancode code)
{
WORD winCode = sfScanToWinScanExtended(code);
const int bufSize = 1024;
WCHAR name[bufSize];
int result = GetKeyNameText(winCode << 16, name, bufSize);
if (result > 0)
{
return name;
}
return "Unknown";
}
////////////////////////////////////////////////////////////
void InputImpl::setVirtualKeyboardVisible(bool /*visible*/)
@ -159,30 +614,30 @@ void InputImpl::setVirtualKeyboardVisible(bool /*visible*/)
////////////////////////////////////////////////////////////
bool InputImpl::isMouseButtonPressed(Mouse::Button button)
{
int vkey = 0;
int virtualKey = 0;
switch (button)
{
case Mouse::Left:
vkey = GetSystemMetrics(SM_SWAPBUTTON) ? VK_RBUTTON : VK_LBUTTON;
virtualKey = GetSystemMetrics(SM_SWAPBUTTON) ? VK_RBUTTON : VK_LBUTTON;
break;
case Mouse::Right:
vkey = GetSystemMetrics(SM_SWAPBUTTON) ? VK_LBUTTON : VK_RBUTTON;
virtualKey = GetSystemMetrics(SM_SWAPBUTTON) ? VK_LBUTTON : VK_RBUTTON;
break;
case Mouse::Middle:
vkey = VK_MBUTTON;
virtualKey = VK_MBUTTON;
break;
case Mouse::XButton1:
vkey = VK_XBUTTON1;
virtualKey = VK_XBUTTON1;
break;
case Mouse::XButton2:
vkey = VK_XBUTTON2;
virtualKey = VK_XBUTTON2;
break;
default:
vkey = 0;
virtualKey = 0;
break;
}
return (GetAsyncKeyState(vkey) & 0x8000) != 0;
return (GetAsyncKeyState(virtualKey) & 0x8000) != 0;
}

View File

@ -41,19 +41,37 @@ class InputImpl
{
public:
////////////////////////////////////////////////////////////
/// \brief Check if a key is pressed
///
/// \param key Key to check
///
/// \return True if the key is pressed, false otherwise
/// \copydoc sf::Keyboard::isKeyPressed(Key)
///
////////////////////////////////////////////////////////////
static bool isKeyPressed(Keyboard::Key key);
////////////////////////////////////////////////////////////
/// \brief Show or hide the virtual keyboard
/// \copydoc sf::Keyboard::isKeyPressed(Scancode)
///
/// \param visible True to show, false to hide
////////////////////////////////////////////////////////////
static bool isKeyPressed(Keyboard::Scancode code);
////////////////////////////////////////////////////////////
/// \copydoc sf::Keyboard::localize
///
////////////////////////////////////////////////////////////
static Keyboard::Key localize(Keyboard::Scancode code);
////////////////////////////////////////////////////////////
/// \copydoc sf::Keyboard::delocalize
///
////////////////////////////////////////////////////////////
static Keyboard::Scancode delocalize(Keyboard::Key key);
////////////////////////////////////////////////////////////
/// \copydoc sf::Keyboard::getDescription
///
////////////////////////////////////////////////////////////
static String getDescription(Keyboard::Scancode code);
////////////////////////////////////////////////////////////
/// \copydoc sf::Keyboard::setVirtualKeyboardVisible
///
////////////////////////////////////////////////////////////
static void setVirtualKeyboardVisible(bool visible);
@ -154,6 +172,21 @@ public:
///
////////////////////////////////////////////////////////////
static Vector2i getTouchPosition(unsigned int finger, const WindowBase& relativeTo);
private:
////////////////////////////////////////////////////////////
/// Ensure the mappings are generated from/to Key and Scancode.
///
////////////////////////////////////////////////////////////
static void ensureMappings();
////////////////////////////////////////////////////////////
// Member data
////////////////////////////////////////////////////////////
// NOLINTBEGIN(readability-identifier-naming)
static Keyboard::Scancode m_keyToScancodeMapping[Keyboard::KeyCount]; ///< Mapping from Key to Scancode
static Keyboard::Key m_scancodeToKeyMapping[Keyboard::Scan::ScancodeCount]; ///< Mapping from Scancode to Key
// NOLINTEND(readability-identifier-naming)
};
} // namespace sf::priv

View File

@ -560,6 +560,133 @@ void WindowImplWin32::grabCursor(bool grabbed)
}
}
////////////////////////////////////////////////////////////
Keyboard::Scancode WindowImplWin32::toScancode(WPARAM wParam, LPARAM lParam)
{
int code = (lParam & (0xFF << 16)) >> 16;
// Retrieve the scancode from the VirtualKey for synthetic key messages
if (code == 0)
{
code = static_cast<int>(MapVirtualKey(static_cast<UINT>(wParam), MAPVK_VK_TO_VSC));
}
// Windows scancodes
// Reference: https://msdn.microsoft.com/en-us/library/aa299374(v=vs.60).aspx
// clang-format off
switch (code)
{
case 1: return Keyboard::Scan::Escape;
case 2: return Keyboard::Scan::Num1;
case 3: return Keyboard::Scan::Num2;
case 4: return Keyboard::Scan::Num3;
case 5: return Keyboard::Scan::Num4;
case 6: return Keyboard::Scan::Num5;
case 7: return Keyboard::Scan::Num6;
case 8: return Keyboard::Scan::Num7;
case 9: return Keyboard::Scan::Num8;
case 10: return Keyboard::Scan::Num9;
case 11: return Keyboard::Scan::Num0;
case 12: return Keyboard::Scan::Hyphen;
case 13: return Keyboard::Scan::Equal;
case 14: return Keyboard::Scan::Backspace;
case 15: return Keyboard::Scan::Tab;
case 16: return (HIWORD(lParam) & KF_EXTENDED) ? Keyboard::Scan::MediaPreviousTrack : Keyboard::Scan::Q;
case 17: return Keyboard::Scan::W;
case 18: return Keyboard::Scan::E;
case 19: return Keyboard::Scan::R;
case 20: return Keyboard::Scan::T;
case 21: return Keyboard::Scan::Y;
case 22: return Keyboard::Scan::U;
case 23: return Keyboard::Scan::I;
case 24: return Keyboard::Scan::O;
case 25: return (HIWORD(lParam) & KF_EXTENDED) ? Keyboard::Scan::MediaNextTrack : Keyboard::Scan::P;
case 26: return Keyboard::Scan::LBracket;
case 27: return Keyboard::Scan::RBracket;
case 28: return (HIWORD(lParam) & KF_EXTENDED) ? Keyboard::Scan::NumpadEnter : Keyboard::Scan::Enter;
case 29: return (HIWORD(lParam) & KF_EXTENDED) ? Keyboard::Scan::RControl : Keyboard::Scan::LControl;
case 30: return (HIWORD(lParam) & KF_EXTENDED) ? Keyboard::Scan::Select : Keyboard::Scan::A;
case 31: return Keyboard::Scan::S;
case 32: return (HIWORD(lParam) & KF_EXTENDED) ? Keyboard::Scan::VolumeMute : Keyboard::Scan::D;
case 33: return (HIWORD(lParam) & KF_EXTENDED) ? Keyboard::Scan::LaunchApplication1 : Keyboard::Scan::F;
case 34: return (HIWORD(lParam) & KF_EXTENDED) ? Keyboard::Scan::MediaPlayPause : Keyboard::Scan::G;
case 35: return Keyboard::Scan::H;
case 36: return (HIWORD(lParam) & KF_EXTENDED) ? Keyboard::Scan::MediaStop : Keyboard::Scan::J;
case 37: return Keyboard::Scan::K;
case 38: return Keyboard::Scan::L;
case 39: return Keyboard::Scan::Semicolon;
case 40: return Keyboard::Scan::Apostrophe;
case 41: return Keyboard::Scan::Grave;
case 42: return Keyboard::Scan::LShift;
case 43: return Keyboard::Scan::Backslash;
case 44: return Keyboard::Scan::Z;
case 45: return Keyboard::Scan::X;
case 46: return (HIWORD(lParam) & KF_EXTENDED) ? Keyboard::Scan::VolumeDown : Keyboard::Scan::C;
case 47: return Keyboard::Scan::V;
case 48: return (HIWORD(lParam) & KF_EXTENDED) ? Keyboard::Scan::VolumeUp : Keyboard::Scan::B;
case 49: return Keyboard::Scan::N;
case 50: return (HIWORD(lParam) & KF_EXTENDED) ? Keyboard::Scan::HomePage : Keyboard::Scan::M;
case 51: return Keyboard::Scan::Comma;
case 52: return Keyboard::Scan::Period;
case 53: return (HIWORD(lParam) & KF_EXTENDED) ? Keyboard::Scan::NumpadDivide : Keyboard::Scan::Slash;
case 54: return Keyboard::Scan::RShift;
case 55: return (HIWORD(lParam) & KF_EXTENDED) ? Keyboard::Scan::PrintScreen : Keyboard::Scan::NumpadMultiply;
case 56: return (HIWORD(lParam) & KF_EXTENDED) ? Keyboard::Scan::RAlt : Keyboard::Scan::LAlt;
case 57: return Keyboard::Scan::Space;
case 58: return Keyboard::Scan::CapsLock;
case 59: return Keyboard::Scan::F1;
case 60: return Keyboard::Scan::F2;
case 61: return Keyboard::Scan::F3;
case 62: return Keyboard::Scan::F4;
case 63: return Keyboard::Scan::F5;
case 64: return Keyboard::Scan::F6;
case 65: return Keyboard::Scan::F7;
case 66: return Keyboard::Scan::F8;
case 67: return Keyboard::Scan::F9;
case 68: return Keyboard::Scan::F10;
case 69: return (HIWORD(lParam) & KF_EXTENDED) ? Keyboard::Scan::NumLock : Keyboard::Scan::Pause;
case 70: return Keyboard::Scan::ScrollLock;
case 71: return (HIWORD(lParam) & KF_EXTENDED) ? Keyboard::Scan::Home : Keyboard::Scan::Numpad7;
case 72: return (HIWORD(lParam) & KF_EXTENDED) ? Keyboard::Scan::Up : Keyboard::Scan::Numpad8;
case 73: return (HIWORD(lParam) & KF_EXTENDED) ? Keyboard::Scan::PageUp : Keyboard::Scan::Numpad9;
case 74: return Keyboard::Scan::NumpadMinus;
case 75: return (HIWORD(lParam) & KF_EXTENDED) ? Keyboard::Scan::Left : Keyboard::Scan::Numpad4;
case 76: return Keyboard::Scan::Numpad5;
case 77: return (HIWORD(lParam) & KF_EXTENDED) ? Keyboard::Scan::Right : Keyboard::Scan::Numpad6;
case 78: return Keyboard::Scan::NumpadPlus;
case 79: return (HIWORD(lParam) & KF_EXTENDED) ? Keyboard::Scan::End : Keyboard::Scan::Numpad1;
case 80: return (HIWORD(lParam) & KF_EXTENDED) ? Keyboard::Scan::Down : Keyboard::Scan::Numpad2;
case 81: return (HIWORD(lParam) & KF_EXTENDED) ? Keyboard::Scan::PageDown : Keyboard::Scan::Numpad3;
case 82: return (HIWORD(lParam) & KF_EXTENDED) ? Keyboard::Scan::Insert : Keyboard::Scan::Numpad0;
case 83: return (HIWORD(lParam) & KF_EXTENDED) ? Keyboard::Scan::Delete : Keyboard::Scan::NumpadDecimal;
case 86: return Keyboard::Scan::NonUsBackslash;
case 87: return Keyboard::Scan::F11;
case 88: return Keyboard::Scan::F12;
case 91: return (HIWORD(lParam) & KF_EXTENDED) ? Keyboard::Scan::LSystem : Keyboard::Scan::Unknown;
case 92: return (HIWORD(lParam) & KF_EXTENDED) ? Keyboard::Scan::RSystem : Keyboard::Scan::Unknown;
case 93: return (HIWORD(lParam) & KF_EXTENDED) ? Keyboard::Scan::Menu : Keyboard::Scan::Unknown;
case 99: return (HIWORD(lParam) & KF_EXTENDED) ? Keyboard::Scan::Help : Keyboard::Scan::Unknown;
case 100: return Keyboard::Scan::F13;
case 101: return (HIWORD(lParam) & KF_EXTENDED) ? Keyboard::Scan::Search : Keyboard::Scan::F14;
case 102: return (HIWORD(lParam) & KF_EXTENDED) ? Keyboard::Scan::Favorites : Keyboard::Scan::F15;
case 103: return (HIWORD(lParam) & KF_EXTENDED) ? Keyboard::Scan::Refresh : Keyboard::Scan::F16;
case 104: return (HIWORD(lParam) & KF_EXTENDED) ? Keyboard::Scan::Stop : Keyboard::Scan::F17;
case 105: return (HIWORD(lParam) & KF_EXTENDED) ? Keyboard::Scan::Forward : Keyboard::Scan::F18;
case 106: return (HIWORD(lParam) & KF_EXTENDED) ? Keyboard::Scan::Back : Keyboard::Scan::F19;
case 107: return (HIWORD(lParam) & KF_EXTENDED) ? Keyboard::Scan::LaunchApplication1 : Keyboard::Scan::F20;
case 108: return (HIWORD(lParam) & KF_EXTENDED) ? Keyboard::Scan::LaunchMail : Keyboard::Scan::F21;
case 109: return (HIWORD(lParam) & KF_EXTENDED) ? Keyboard::Scan::LaunchMediaSelect : Keyboard::Scan::F22;
case 110: return Keyboard::Scan::F23;
case 118: return Keyboard::Scan::F24;
default: return Keyboard::Scan::Unknown;
}
// clang-format on
}
////////////////////////////////////////////////////////////
void WindowImplWin32::processEvent(UINT message, WPARAM wParam, LPARAM lParam)
@ -730,12 +857,13 @@ void WindowImplWin32::processEvent(UINT message, WPARAM wParam, LPARAM lParam)
if (m_keyRepeatEnabled || ((HIWORD(lParam) & KF_REPEAT) == 0))
{
Event event;
event.type = Event::KeyPressed;
event.key.alt = HIWORD(GetKeyState(VK_MENU)) != 0;
event.key.control = HIWORD(GetKeyState(VK_CONTROL)) != 0;
event.key.shift = HIWORD(GetKeyState(VK_SHIFT)) != 0;
event.key.system = HIWORD(GetKeyState(VK_LWIN)) || HIWORD(GetKeyState(VK_RWIN));
event.key.code = virtualKeyCodeToSF(wParam, lParam);
event.type = Event::KeyPressed;
event.key.alt = HIWORD(GetKeyState(VK_MENU)) != 0;
event.key.control = HIWORD(GetKeyState(VK_CONTROL)) != 0;
event.key.shift = HIWORD(GetKeyState(VK_SHIFT)) != 0;
event.key.system = HIWORD(GetKeyState(VK_LWIN)) || HIWORD(GetKeyState(VK_RWIN));
event.key.code = virtualKeyCodeToSF(wParam, lParam);
event.key.scancode = toScancode(wParam, lParam);
pushEvent(event);
}
break;
@ -746,12 +874,13 @@ void WindowImplWin32::processEvent(UINT message, WPARAM wParam, LPARAM lParam)
case WM_SYSKEYUP:
{
Event event;
event.type = Event::KeyReleased;
event.key.alt = HIWORD(GetKeyState(VK_MENU)) != 0;
event.key.control = HIWORD(GetKeyState(VK_CONTROL)) != 0;
event.key.shift = HIWORD(GetKeyState(VK_SHIFT)) != 0;
event.key.system = HIWORD(GetKeyState(VK_LWIN)) || HIWORD(GetKeyState(VK_RWIN));
event.key.code = virtualKeyCodeToSF(wParam, lParam);
event.type = Event::KeyReleased;
event.key.alt = HIWORD(GetKeyState(VK_MENU)) != 0;
event.key.control = HIWORD(GetKeyState(VK_CONTROL)) != 0;
event.key.shift = HIWORD(GetKeyState(VK_SHIFT)) != 0;
event.key.system = HIWORD(GetKeyState(VK_LWIN)) || HIWORD(GetKeyState(VK_RWIN));
event.key.code = virtualKeyCodeToSF(wParam, lParam);
event.key.scancode = toScancode(wParam, lParam);
pushEvent(event);
break;
}
@ -1029,9 +1158,9 @@ Keyboard::Key WindowImplWin32::virtualKeyCodeToSF(WPARAM key, LPARAM flags)
case VK_OEM_6: return Keyboard::RBracket;
case VK_OEM_COMMA: return Keyboard::Comma;
case VK_OEM_PERIOD: return Keyboard::Period;
case VK_OEM_7: return Keyboard::Quote;
case VK_OEM_7: return Keyboard::Apostrophe;
case VK_OEM_5: return Keyboard::Backslash;
case VK_OEM_3: return Keyboard::Tilde;
case VK_OEM_3: return Keyboard::Grave;
case VK_ESCAPE: return Keyboard::Escape;
case VK_SPACE: return Keyboard::Space;
case VK_RETURN: return Keyboard::Enter;

View File

@ -265,6 +265,16 @@ private:
////////////////////////////////////////////////////////////
static LRESULT CALLBACK globalOnEvent(HWND handle, UINT message, WPARAM wParam, LPARAM lParam);
////////////////////////////////////////////////////////////
/// \brief Convert a Win32 scancode to an sfml scancode
///
/// \param flags input flags
///
/// \return SFML scancode corresponding to the key
///
////////////////////////////////////////////////////////////
static Keyboard::Scancode toScancode(WPARAM wParam, LPARAM lParam);
////////////////////////////////////////////////////////////
// Member data
////////////////////////////////////////////////////////////

View File

@ -41,19 +41,37 @@ class InputImpl
{
public:
////////////////////////////////////////////////////////////
/// \brief Check if a key is pressed
///
/// \param key Key to check
///
/// \return True if the key is pressed, false otherwise
/// \copydoc sf::Keyboard::isKeyPressed(Key)
///
////////////////////////////////////////////////////////////
static bool isKeyPressed(Keyboard::Key key);
////////////////////////////////////////////////////////////
/// \brief Show or hide the virtual keyboard
/// \copydoc sf::Keyboard::isKeyPressed(Scancode)
///
/// \param visible True to show, false to hide
////////////////////////////////////////////////////////////
static bool isKeyPressed(Keyboard::Scancode code);
////////////////////////////////////////////////////////////
/// \copydoc sf::Keyboard::localize
///
////////////////////////////////////////////////////////////
static Keyboard::Key localize(Keyboard::Scancode code);
////////////////////////////////////////////////////////////
/// \copydoc sf::Keyboard::delocalize
///
////////////////////////////////////////////////////////////
static Keyboard::Scancode delocalize(Keyboard::Key key);
////////////////////////////////////////////////////////////
/// \copydoc sf::Keyboard::getDescription
///
////////////////////////////////////////////////////////////
static String getDescription(Keyboard::Scancode code);
////////////////////////////////////////////////////////////
/// \copydoc sf::Keyboard::setVirtualKeyboardVisible
///
////////////////////////////////////////////////////////////
static void setVirtualKeyboardVisible(bool visible);

View File

@ -41,6 +41,29 @@ bool InputImpl::isKeyPressed(Keyboard::Key /* key */)
return false;
}
bool InputImpl::isKeyPressed(Keyboard::Scancode /* codes */)
{
// Not applicable
return false;
}
Keyboard::Key InputImpl::localize(Keyboard::Scancode /* code */)
{
// Not applicable
return Keyboard::Unknown;
}
Keyboard::Scancode InputImpl::delocalize(Keyboard::Key /* key */)
{
// Not applicable
return Keyboard::Scan::Unknown;
}
String InputImpl::getDescription(Keyboard::Scancode /* code */)
{
// Not applicable
return "";
}
////////////////////////////////////////////////////////////
void InputImpl::setVirtualKeyboardVisible(bool visible)