Browse Source

Platform: expose key scan codes and related APIs.

Unlike the Key enum, which shows what a user would perceive as given key
in a particular layout, the scancode is a layout-independent identifier
for e.g. WASD movement in games.

Unfortunately the API availability is wildly different among the
toolkits -- SDL's is the most complete, GLFW is second, and then there's
Emscripten / HTML5 which provides just string identifiers. I tried to
add these for X11 as well, but quick googling led to a SO question where
it was left unanswered. Not worth my time.
pull/651/head
Vladimír Vondruš 2 years ago
parent
commit
414a65f9db
  1. 24
      doc/changelog.dox
  2. 4
      src/Magnum/Platform/EmscriptenApplication.cpp
  3. 28
      src/Magnum/Platform/EmscriptenApplication.h
  4. 21
      src/Magnum/Platform/GlfwApplication.cpp
  5. 85
      src/Magnum/Platform/GlfwApplication.h
  6. 42
      src/Magnum/Platform/Sdl2Application.cpp
  7. 145
      src/Magnum/Platform/Sdl2Application.h
  8. 4
      src/Magnum/Platform/Test/EmscriptenApplicationTest.cpp
  9. 12
      src/Magnum/Platform/Test/GlfwApplicationTest.cpp
  10. 256
      src/Magnum/Platform/Test/Sdl2ApplicationTest.cpp

24
doc/changelog.dox

@ -827,6 +827,16 @@ See also:
- Added more keys to @ref Platform::AbstractXApplication::KeyEvent::Key and
implemented @ref Platform::AbstractXApplication::scrollEvent() for better
consistency with other application implementations
- Added @ref Platform::Sdl2Application::KeyEvent::scanCode(),
@relativeref{Platform::Sdl2Application::KeyEvent,scanCodeName()},
@ref Platform::GlfwApplication::KeyEvent::scanCode() and
@ref Platform::EmscriptenApplication::KeyEvent::scanCodeName() for querying
layout-independent key identifiers as well as
@ref Platform::Sdl2Application::scanCodeName(UnsignedInt),
@relativeref{Platform::Sdl2Application,keyToScanCode()},
@relativeref{Platform::Sdl2Application,scanCodeToKey()} and
@ref Platform::GlfwApplication::keyToScanCode() helpers for key / scan code
conversion outside of event handlers
@subsubsection changelog-latest-changes-scenegraph SceneGraph library
@ -1423,12 +1433,14 @@ See also:
wrappers as well.
- @cpp Platform::Sdl2Application::InputEvent::Modifier @ce,
@cpp Modifiers @ce and @cpp Platform::Sdl2Application::KeyEvent::Key @ce
enums are deprecated in favor of @ref Platform::Sdl2Application::Modifier,
@relativeref{Platform::Sdl2Application,Modifiers} and
@relativeref{Platform::Sdl2Application,Key} enums contained directly in
the application class. Besides the obvious advantage of them being shorter
to type, this allows them to be used outside of the event class scope. The
same change is done in @ref Platform::AbstractXApplication,
enums and the @cpp Platform::Sdl2Application::KeyEvent::keyName(Key) @ce
function are deprecated in favor of @ref Platform::Sdl2Application::Modifier,
@relativeref{Platform::Sdl2Application,Modifiers},
@relativeref{Platform::Sdl2Application,Key} and
@relativeref{Platform::Sdl2Application,keyName()} APIs contained directly
in the application class. Besides the obvious advantage of them being
shorter to type, this allows the enums to be used outside of the event
class scope. The same change is done in @ref Platform::AbstractXApplication,
@ref Platform::EmscriptenApplication and @ref Platform::GlfwApplication.
- @cpp Platform::AbstractXApplication::MouseEvent::Button::WheelUp @ce and
`WheelDown` members are deprecated in favor of a dedicated

4
src/Magnum/Platform/EmscriptenApplication.cpp

@ -1283,6 +1283,10 @@ Containers::StringView EmscriptenApplication::KeyEvent::keyName() const {
return _event.code;
}
Containers::StringView EmscriptenApplication::KeyEvent::scanCodeName() const {
return _event.code;
}
EmscriptenApplication::Modifiers EmscriptenApplication::KeyEvent::modifiers() const {
return eventModifiers(_event);
}

28
src/Magnum/Platform/EmscriptenApplication.h

@ -2456,23 +2456,43 @@ class EmscriptenApplication::KeyEvent: public EmscriptenApplication::InputEvent
/**
* @brief Key
*
* Note that the key is mapped from @m_class{m-doc-external}
* Layout-dependent name of given key. Mapped from @m_class{m-doc-external}
* [EmscriptenKeyboardEvent::code](https://emscripten.org/docs/api_reference/html5.h.html#c.EmscriptenKeyboardEvent.code)
* in all cases except A--Z, which are mapped from
* @m_class{m-doc-external} [EmscriptenkeyboardEvent::key](https://emscripten.org/docs/api_reference/html5.h.html#c.EmscriptenKeyboardEvent.key),
* which respects the keyboard layout.
* which respects the keyboard layout. Note that, unlike e.g.
* @ref Sdl2Application::KeyEvent::scanCode(), there's no numeric
* layout-independent identifier of given key, you have to use
* @ref scanCodeName() instead.
*/
EmscriptenApplication::Key key() const;
/**
* @brief Key name
*
* The returned view is always
* Layout-dependent name of given key. Returns
* @m_class{m-doc-external} [EmscriptenkeyboardEvent::key](https://emscripten.org/docs/api_reference/html5.h.html#c.EmscriptenKeyboardEvent.key)
* for keys A--Z and @m_class{m-doc-external} [EmscriptenKeyboardEvent::code](https://emscripten.org/docs/api_reference/html5.h.html#c.EmscriptenKeyboardEvent.code)
* for other keys, the view is always
* @relativeref{Corrade,Containers::StringViewFlag::NullTerminated} and
* is valid until the event is destroyed.
* is valid until the event is destroyed. Use @ref scanCodeName() to
* get a platform-specific but layout-independent identifier of given
* key.
*/
Containers::StringView keyName() const;
/**
* @brief Scancode name
* @m_since_latest
*
* Platform-specific but layout-independent identifier of given key.
* Returns @m_class{m-doc-external} [EmscriptenKeyboardEvent::code](https://emscripten.org/docs/api_reference/html5.h.html#c.EmscriptenKeyboardEvent.code),
* the view is always @relativeref{Corrade,Containers::StringViewFlag::NullTerminated}
* and is valid until the event is destroyed. Use @ref keyName() to get
* a key name in the currently used layout.
*/
Containers::StringView scanCodeName() const;
/** @brief Modifiers */
EmscriptenApplication::Modifiers modifiers() const;

21
src/Magnum/Platform/GlfwApplication.cpp

@ -662,10 +662,10 @@ void GlfwApplication::setupCallbacks() {
#endif
app.viewportEvent(e);
});
glfwSetKeyCallback(_window, [](GLFWwindow* const window, const int key, int, const int action, const int mods) {
glfwSetKeyCallback(_window, [](GLFWwindow* const window, const int key, const int scancode, const int action, const int mods) {
auto& app = *static_cast<GlfwApplication*>(glfwGetWindowUserPointer(window));
KeyEvent e(Key(key), Modifiers{mods}, action == GLFW_REPEAT);
KeyEvent e(Key(key), scancode, Modifiers{mods}, action == GLFW_REPEAT);
if(action == GLFW_PRESS || action == GLFW_REPEAT)
app.keyPressEvent(e);
@ -741,6 +741,19 @@ GlfwApplication::~GlfwApplication() {
glfwTerminate();
}
Containers::StringView GlfwApplication::keyName(const Key key, const UnsignedInt scancode) const {
return glfwGetKeyName(int(key), scancode);
}
#if GLFW_VERSION_MAJOR*100 + GLFW_VERSION_MINOR >= 303
Containers::Optional<UnsignedInt> GlfwApplication::keyToScanCode(const Key key) const {
const int scancode = glfwGetKeyScancode(int(key));
if(scancode == -1)
return {};
return UnsignedInt(scancode);
}
#endif
Vector2i GlfwApplication::windowSize() const {
CORRADE_ASSERT(_window, "Platform::GlfwApplication::windowSize(): no window opened", {});
@ -1107,12 +1120,14 @@ GlfwApplication::Configuration::Configuration():
GlfwApplication::Configuration::~Configuration() = default;
#ifdef MAGNUM_BUILD_DEPRECATED
Containers::StringView GlfwApplication::KeyEvent::keyName(const GlfwApplication::Key key) {
return glfwGetKeyName(int(key), 0);
}
#endif
Containers::StringView GlfwApplication::KeyEvent::keyName() const {
return keyName(_key);
return glfwGetKeyName(Int(_key), _scancode);
}
GlfwApplication::Pointers GlfwApplication::PointerMoveEvent::pointers() {

85
src/Magnum/Platform/GlfwApplication.h

@ -276,6 +276,43 @@ class GlfwApplication {
/** @brief Moving is not allowed */
GlfwApplication& operator=(GlfwApplication&&) = delete;
/**
* @brief Name for given key
* @m_since_latest
*
* Human-readable localized UTF-8 name for given @p key, intended for
* displaying to the user in e.g. a key binding configuration. For
* @ref Key::Unknown, a concrete @p scanCode can be passed. If there is
* no name for given key, an empty string is returned. If non-empty,
* the returned view is always
* @relativeref{Corrade,Containers::StringViewFlag::NullTerminated} and
* is valid until the keyboard layout is changed or the application
* exits.
*
* Unlike e.g. @ref Sdl2Application::keyName(), the function isn't
* @cpp static @ce because it relies on GLFW being initialized.
* @see @ref KeyEvent::keyName(), @ref keyToScanCode()
*/
Containers::StringView keyName(Key key, UnsignedInt scanCode = 0) const;
#if GLFW_VERSION_MAJOR*100 + GLFW_VERSION_MINOR >= 303 || defined(DOXYGEN_GENERATING_OUTPUT)
/**
* @brief Scan code for given key
* @m_since_latest
*
* If @p key doesn't correspond to a physical key supported on given
* platform, returns @relativeref{Corrade,Containers::NullOpt}. Unlike
* e.g. @ref Sdl2Application::scanCodeToKey(), GLFW doesn't provide any
* way to map from a scan code to a key.
*
* Unlike e.g. @ref Sdl2Application::keyToScanCode(), the function
* isn't @cpp static @ce because it relies on GLFW being initialized.
* @note Available since GLFW 3.3.
* @see @ref KeyEvent::key(), @ref KeyEvent::scanCode(), @ref keyName()
*/
Containers::Optional<UnsignedInt> keyToScanCode(Key key) const;
#endif
/**
* @brief Execute main loop
* @return Value for returning from @cpp main() @ce
@ -2090,33 +2127,42 @@ class GlfwApplication::KeyEvent: public GlfwApplication::InputEvent {
* @m_deprecated_since_latest Use @ref GlfwApplication::Key instead.
*/
typedef CORRADE_DEPRECATED("use GlfwApplication::Key instead") GlfwApplication::Key Key;
/**
* @brief @copybrief GlfwApplication::keyName()
* @m_deprecated_since_latest Use @ref GlfwApplication::keyName()
* instead.
*/
CORRADE_DEPRECATED("use GlfwApplication::keyName() instead") static Containers::StringView keyName(GlfwApplication::Key key);
#endif
/**
* @brief Name for given key
* @brief Key
*
* Human-readable localized UTF-8 name for given @p key, intended for
* displaying to the user in e.g. key binding configuration. If there
* is no name for given key, empty string is returned. The returned
* view is always @relativeref{Corrade,Containers::StringViewFlag::NullTerminated}
* and is valid until the keyboard layout is changed or the application
* exits.
* @see @ref keyName(Key)
* Layout-dependent name of given key. Use @ref scanCode() to get a
* platform-specific but layout-independent identifier of given key.
* @see @ref keyName() const
*/
static Containers::StringView keyName(GlfwApplication::Key key);
/** @copydoc Sdl2Application::KeyEvent::key() */
GlfwApplication::Key key() const { return _key; }
/**
* @brief Scancode
* @m_since_latest
*
* Platform-specific but layout-independent identifier of given key.
* Use @ref key() to get a key name in the currently used layout.
*/
UnsignedInt scanCode() const { return _scancode; }
/**
* @brief Key name
*
* Human-readable localized UTF-8 name for the key returned by
* @ref key(), intended for displaying to the user in e.g.
* key binding configuration. If there is no name for that key, empty
* string is returned. The returned view is always
* @relativeref{Corrade,Containers::StringViewFlag::NullTerminated} and
* is valid until the keyboard layout is changed or the application
* @ref key() and @ref scanCode(), intended for displaying to the user
* in e.g. key binding configuration. If there is no name for that key,
* an empty string is returned. If non-empty, the returned view is
* always @relativeref{Corrade,Containers::StringViewFlag::NullTerminated}
* and is valid until the keyboard layout is changed or the application
* exits.
* @see @ref keyName(Key)
*/
@ -2131,11 +2177,12 @@ class GlfwApplication::KeyEvent: public GlfwApplication::InputEvent {
private:
friend GlfwApplication;
explicit KeyEvent(GlfwApplication::Key key, GlfwApplication::Modifiers modifiers, bool repeated): _key{key}, _modifiers{modifiers}, _repeated{repeated} {}
explicit KeyEvent(GlfwApplication::Key key, UnsignedInt scancode, GlfwApplication::Modifiers modifiers, bool repeated): _repeated{repeated}, _modifiers{modifiers}, _key{key}, _scancode{scancode} {}
const GlfwApplication::Key _key;
const GlfwApplication::Modifiers _modifiers;
const bool _repeated;
const GlfwApplication::Modifiers _modifiers;
const GlfwApplication::Key _key;
const UnsignedInt _scancode;
};
/**

42
src/Magnum/Platform/Sdl2Application.cpp

@ -121,6 +121,34 @@ enum class Sdl2Application::Flag: UnsignedByte {
#endif
};
Containers::StringView Sdl2Application::keyName(const Key key) {
return SDL_GetKeyName(SDL_Keycode(key));
}
#ifndef CORRADE_TARGET_EMSCRIPTEN
Containers::StringView Sdl2Application::scanCodeName(const UnsignedInt scanCode) {
return SDL_GetScancodeName(SDL_Scancode(scanCode));
}
#endif
/* https://github.com/emscripten-core/emscripten/pull/18060 */
#if !defined(CORRADE_TARGET_EMSCRIPTEN) || __EMSCRIPTEN_major__*10000 + __EMSCRIPTEN_minor__*100 + __EMSCRIPTEN_tiny__ >= 30125
Containers::Optional<UnsignedInt> Sdl2Application::keyToScanCode(const Key key) {
static_assert(SDL_SCANCODE_UNKNOWN == 0, "assumed SDL_SCANCODE_UNKNOWN to be 0");
if(const SDL_Scancode scanCode = SDL_GetScancodeFromKey(SDL_Keycode(key)))
return UnsignedInt(scanCode);
return {};
}
#endif
#ifndef CORRADE_TARGET_EMSCRIPTEN
Containers::Optional<Sdl2Application::Key> Sdl2Application::scanCodeToKey(const UnsignedInt scanCode) {
if(const SDL_Keycode key = SDL_GetKeyFromScancode(SDL_Scancode(scanCode)))
return Key(key);
return {};
}
#endif
Sdl2Application::Sdl2Application(const Arguments& arguments): Sdl2Application{arguments, Configuration{}} {}
Sdl2Application::Sdl2Application(const Arguments& arguments, const Configuration& configuration): Sdl2Application{arguments, NoCreate} {
@ -1041,7 +1069,7 @@ bool Sdl2Application::mainLoopIteration() {
case SDL_KEYDOWN:
case SDL_KEYUP: {
KeyEvent e{event, Key(event.key.keysym.sym), fixedModifiers(event.key.keysym.mod), event.key.repeat != 0};
KeyEvent e{event, Key(event.key.keysym.sym), UnsignedInt(event.key.keysym.scancode), fixedModifiers(event.key.keysym.mod), event.key.repeat != 0};
event.type == SDL_KEYDOWN ? keyPressEvent(e) : keyReleaseEvent(e);
} break;
@ -1598,14 +1626,22 @@ Sdl2Application::Configuration::Configuration():
Sdl2Application::Configuration::~Configuration() = default;
#ifdef MAGNUM_BUILD_DEPRECATED
Containers::StringView Sdl2Application::KeyEvent::keyName(const Sdl2Application::Key key) {
return SDL_GetKeyName(SDL_Keycode(key));
return Sdl2Application::keyName(key);
}
#endif
Containers::StringView Sdl2Application::KeyEvent::keyName() const {
return keyName(_key);
return Sdl2Application::keyName(_key);
}
#ifndef CORRADE_TARGET_EMSCRIPTEN
Containers::StringView Sdl2Application::KeyEvent::scanCodeName() const {
return Sdl2Application::scanCodeName(_scancode);
}
#endif
Sdl2Application::Modifiers Sdl2Application::PointerEvent::modifiers() {
if(!_modifiers)
_modifiers = fixedModifiers(Uint16(SDL_GetModState()));

145
src/Magnum/Platform/Sdl2Application.h

@ -86,6 +86,18 @@
#include <Corrade/Containers/StringStl.h>
#endif
#if defined(CORRADE_TARGET_EMSCRIPTEN) || defined(DOXYGEN_GENERATING_OUTPUT)
/* The __EMSCRIPTEN_major__ etc macros used to be passed implicitly, version
3.1.4 moved them to a version header and version 3.1.23 dropped the
backwards compatibility. To work consistently on all versions, including the
header only if the version macros aren't present.
https://github.com/emscripten-core/emscripten/commit/f99af02045357d3d8b12e63793cef36dfde4530a
https://github.com/emscripten-core/emscripten/commit/f76ddc702e4956aeedb658c49790cc352f892e4c */
#ifndef __EMSCRIPTEN_major__
#include <emscripten/version.h>
#endif
#endif
#ifndef DOXYGEN_GENERATING_OUTPUT
union SDL_Event; /* for anyEvent() */
#endif
@ -574,6 +586,71 @@ class Sdl2Application {
*/
typedef Containers::EnumSet<Pointer> Pointers;
/**
* @brief Name for given key
* @m_since_latest
*
* Human-readable localized UTF-8 name for given @p key, intended for
* displaying to the user in e.g. a key binding configuration. If there
* is no name for given key, empty string is returned. The returned
* view is always @relativeref{Corrade,Containers::StringViewFlag::NullTerminated}
* and is valid at least until the next call to this function, to
* @ref KeyEvent::keyName() const or to the underlying
* @cpp SDL_GetKeyName() @ce API.
* @see @ref scanCodeName(), @ref keyToScanCode(), @ref KeyEvent::key()
*/
static Containers::StringView keyName(Key key);
#ifndef CORRADE_TARGET_EMSCRIPTEN
/**
* @brief Name for given key scan code
* @m_since_latest
*
* Human-readable localized UTF-8 name for given @p scancode. Note that
* unlike @ref keyName(), the scancode names are not consistent across
* platforms. If there is no name for given scancode, empty string is
* returned. The returned view is always
* @relativeref{Corrade,Containers::StringViewFlag::NullTerminated} and
* is valid at least until the next call to this function, to
* @ref KeyEvent::scanCodeName() const or to the underlying
* @cpp SDL_GetScancodeName() @ce API.
* @note Not available on @ref CORRADE_TARGET_EMSCRIPTEN "Emscripten".
* @see @ref scanCodeToKey(), @ref KeyEvent::scanCode()
*/
static Containers::StringView scanCodeName(UnsignedInt scanCode);
#endif
#if !defined(CORRADE_TARGET_EMSCRIPTEN) || __EMSCRIPTEN_major__*10000 + __EMSCRIPTEN_minor__*100 + __EMSCRIPTEN_tiny__ >= 30125
/**
* @brief Scan code for given key
* @m_since_latest
*
* If @p key doesn't correspond to a physical key supported on given
* platform, returns @relativeref{Corrade,Containers::NullOpt}. Note
* that this is implemented as a linear lookup inside SDL, prefer to
* query the scan code directly via @ref KeyEvent::scanCode() rather
* than converting it from a @ref KeyEvent::key() at a later time.
* @note On @ref CORRADE_TARGET_EMSCRIPTEN "Emscripten" available only
* since version 3.1.25.
* @see @ref scanCodeToKey(), @ref keyName()
*/
static Containers::Optional<UnsignedInt> keyToScanCode(Key key);
#endif
#ifndef CORRADE_TARGET_EMSCRIPTEN
/**
* @brief Scan code for given key
* @m_since_latest
*
* If @p scanCode isn't a known scan code, returns
* @relativeref{Corrade,Containers::NullOpt}.
* @note Not available on @ref CORRADE_TARGET_EMSCRIPTEN "Emscripten".
* @see @ref KeyEvent::key(), @ref KeyEvent::scanCode(),
* @ref keyToScanCode(), @ref scanCodeName()
*/
static Containers::Optional<Key> scanCodeToKey(UnsignedInt scanCode);
#endif
#ifdef MAGNUM_TARGET_GL
/**
* @brief Construct with an OpenGL context
@ -2769,41 +2846,68 @@ class Sdl2Application::KeyEvent: public Sdl2Application::InputEvent {
* @m_deprecated_since_latest Use @ref Sdl2Application::Key instead.
*/
typedef CORRADE_DEPRECATED("use Sdl2Application::Key instead") Sdl2Application::Key Key;
#endif
/**
* @brief Name for given key
*
* Human-readable localized UTF-8 name for given @p key, intended for
* displaying to the user in e.g. key binding configuration. If there
* is no name for given key, empty string is returned. The returned
* view is always @relativeref{Corrade,Containers::StringViewFlag::NullTerminated}
* and is valid at least until the next call to this function, to
* @ref keyName() const or to the underlying @cpp SDL_GetKeyName() @ce
* API.
* @brief @copybrief Sdl2Application::keyName()
* @m_deprecated_since_latest Use @ref Sdl2Application::keyName()
* instead.
*/
static Containers::StringView keyName(Sdl2Application::Key key);
CORRADE_DEPRECATED("use Sdl2Application::keyName() instead") static Containers::StringView keyName(Sdl2Application::Key key);
#endif
/**
* @brief Key
*
* @see @ref keyName()
* Layout-dependent name of given key. Use @ref scanCode() to get a
* platform-specific but layout-independent identifier of given key.
* @see @ref keyName() const, @ref keyToScanCode()
*/
Sdl2Application::Key key() const { return _key; }
/**
* @brief Scancode
* @m_since_latest
*
* Platform-specific but layout-independent identifier of given key.
* Use @ref key() to get a key name in the currently used layout.
* @see @ref scanCodeName(), @ref scanCodeToKey()
*/
UnsignedInt scanCode() const { return _scancode; }
/**
* @brief Key name
*
* Human-readable localized UTF-8 name for the key returned by
* @ref key(), intended for displaying to the user in e.g.
* key binding configuration. If there is no name for that key, empty
* string is returned. The returned string is always @relativeref{Corrade,Containers::StringViewFlag::NullTerminated}
* @ref key(), intended for displaying to the user in e.g. a key
* binding configuration. If there is no name for that key, an empty
* string is returned. The returned string is always
* @relativeref{Corrade,Containers::StringViewFlag::NullTerminated}
* and is valid at least until the next call to this function, to
* @ref keyName(Key) or to the underlying @cpp SDL_GetKeyName() @ce
* API.
* @ref Sdl2Application::keyName() or to the underlying
* @cpp SDL_GetKeyName() @ce API.
* @see @ref scanCodeName()
*/
Containers::StringView keyName() const;
#ifndef CORRADE_TARGET_EMSCRIPTEN
/**
* @brief Scan code name
* @m_since_latest
*
* Human-readable localized UTF-8 name for the scancode returned by
* @ref scanCode(), intended for displaying to the user in e.g. a key
* binding configuration. If there is no name for that key, an
* empty string is returned. The returned string is always
* @relativeref{Corrade,Containers::StringViewFlag::NullTerminated}
* and is valid at least until the next call to this function, to
* @ref Sdl2Application::scanCodeName() or to the underlying
* @cpp SDL_GetScancodeName() @ce API.
* @note Not available on @ref CORRADE_TARGET_EMSCRIPTEN "Emscripten".
* @see @ref keyName()
*/
Containers::StringView scanCodeName() const;
#endif
/** @brief Modifiers */
Sdl2Application::Modifiers modifiers() const { return _modifiers; }
@ -2818,11 +2922,12 @@ class Sdl2Application::KeyEvent: public Sdl2Application::InputEvent {
private:
friend Sdl2Application;
explicit KeyEvent(const SDL_Event& event, Sdl2Application::Key key, Sdl2Application::Modifiers modifiers, bool repeated): InputEvent{event}, _key{key}, _modifiers{modifiers}, _repeated{repeated} {}
explicit KeyEvent(const SDL_Event& event, Sdl2Application::Key key, UnsignedInt scancode, Sdl2Application::Modifiers modifiers, bool repeated): InputEvent{event}, _repeated{repeated}, _modifiers{modifiers}, _key{key}, _scancode{scancode} {}
const Sdl2Application::Key _key;
const Sdl2Application::Modifiers _modifiers;
const bool _repeated;
const Sdl2Application::Modifiers _modifiers;
const Sdl2Application::Key _key;
const UnsignedInt _scancode;
};
/**

4
src/Magnum/Platform/Test/EmscriptenApplicationTest.cpp

@ -368,7 +368,7 @@ struct EmscriptenApplicationTest: Platform::Application {
/* For testing keyboard capture */
void keyPressEvent(KeyEvent& event) override {
Debug{} << "key press:" << event.key() << event.keyName() << event.modifiers();
Debug{} << "key press:" << event.key() << event.keyName() << "scancode:" << event.scanCodeName() << event.modifiers();
if(event.key() == Key::F1) {
Debug{} << "starting text input";
@ -395,7 +395,7 @@ struct EmscriptenApplicationTest: Platform::Application {
}
void keyReleaseEvent(KeyEvent& event) override {
Debug{} << "key release:" << event.key() << event.keyName() << event.modifiers();
Debug{} << "key release:" << event.key() << event.keyName() << "scancode:" << event.scanCodeName() << event.modifiers();
event.setAccepted();
}

12
src/Magnum/Platform/Test/GlfwApplicationTest.cpp

@ -299,7 +299,11 @@ struct GlfwApplicationTest: Platform::Application {
}
void keyPressEvent(KeyEvent& event) override {
Debug{} << "key press:" << event.key() << int(event.key()) << event.keyName() << event.modifiers();
Debug{} << "key press:" << event.key() << int(event.key()) << event.keyName() << "scancode:" << event.scanCode() << event.modifiers()
#if GLFW_VERSION_MAJOR*100 + GLFW_VERSION_MINOR >= 303
<< "converted:" << keyToScanCode(event.key())
#endif
;
if(event.key() == Key::F1) {
Debug{} << "starting text input";
@ -337,7 +341,11 @@ struct GlfwApplicationTest: Platform::Application {
}
void keyReleaseEvent(KeyEvent& event) override {
Debug{} << "key release:" << event.key() << int(event.key()) << event.keyName() << event.modifiers();
Debug{} << "key release:" << event.key() << int(event.key()) << event.keyName() << "scancode:" << event.scanCode() << event.modifiers()
#if GLFW_VERSION_MAJOR*100 + GLFW_VERSION_MINOR >= 303
<< "converted:" << keyToScanCode(event.key())
#endif
;
}
/* Set to 0 to test the deprecated mouse events instead */

256
src/Magnum/Platform/Test/Sdl2ApplicationTest.cpp

@ -56,8 +56,8 @@
namespace Magnum { namespace Platform {
/* These cannot be in an anonymous namespace as enumSetDebugOutput() below
wouldn't be able to pick them up */
/* These cannot be in an anonymous namespace as enumSetDebugOutput() /
Optional<Key> below wouldn't be able to pick them up */
static Debug& operator<<(Debug& debug, Application::Modifier value) {
debug << "Modifier" << Debug::nospace;
@ -77,118 +77,7 @@ static Debug& operator<<(Debug& debug, Application::Modifier value) {
return debug << "(" << Debug::nospace << UnsignedInt(value) << Debug::nospace << ")";
}
static Debug& operator<<(Debug& debug, Application::Pointer value) {
debug << "Pointer" << Debug::nospace;
switch(value) {
#define _c(value) case Application::Pointer::value: return debug << "::" #value;
_c(MouseLeft)
_c(MouseMiddle)
_c(MouseRight)
_c(MouseButton4)
_c(MouseButton5)
#ifndef CORRADE_TARGET_EMSCRIPTEN
_c(Finger)
#endif
#undef _c
}
return debug << "(" << Debug::nospace << UnsignedInt(value) << Debug::nospace << ")";
}
#ifdef MAGNUM_BUILD_DEPRECATED
CORRADE_IGNORE_DEPRECATED_PUSH
CORRADE_UNUSED static Debug& operator<<(Debug& debug, Application::MouseMoveEvent::Button value) {
debug << "Button" << Debug::nospace;
switch(value) {
#define _c(value) case Application::MouseMoveEvent::Button::value: return debug << "::" #value;
_c(Left)
_c(Middle)
_c(Right)
_c(X1)
_c(X2)
#undef _c
}
return debug << "(" << Debug::nospace << UnsignedInt(value) << Debug::nospace << ")";
}
CORRADE_IGNORE_DEPRECATED_POP
#endif
namespace Test { namespace {
static Debug& operator<<(Debug& debug, Application::PointerEventSource value) {
debug << "PointerEventSource" << Debug::nospace;
switch(value) {
#define _c(value) case Application::PointerEventSource::value: return debug << "::" #value;
_c(Mouse)
#ifndef CORRADE_TARGET_EMSCRIPTEN
_c(Touch)
#endif
#undef _c
}
return debug << "(" << Debug::nospace << UnsignedInt(value) << Debug::nospace << ")";
}
Debug& operator<<(Debug& debug, Application::Modifiers value) {
return Containers::enumSetDebugOutput(debug, value, "Modifiers{}", {
Application::Modifier::Shift,
Application::Modifier::Ctrl,
Application::Modifier::Alt,
Application::Modifier::Super,
Application::Modifier::AltGr,
Application::Modifier::CapsLock,
Application::Modifier::NumLock,
});
}
Debug& operator<<(Debug& debug, Application::Pointers value) {
return Containers::enumSetDebugOutput(debug, value, "Pointers{}", {
Application::Pointer::MouseLeft,
Application::Pointer::MouseMiddle,
Application::Pointer::MouseRight,
Application::Pointer::MouseButton4,
Application::Pointer::MouseButton5,
#ifndef CORRADE_TARGET_EMSCRIPTEN
Application::Pointer::Finger,
#endif
});
}
#ifdef MAGNUM_BUILD_DEPRECATED
CORRADE_IGNORE_DEPRECATED_PUSH
CORRADE_UNUSED Debug& operator<<(Debug& debug, Application::MouseEvent::Button value) {
debug << "Button" << Debug::nospace;
switch(value) {
#define _c(value) case Application::MouseEvent::Button::value: return debug << "::" #value;
_c(Left)
_c(Middle)
_c(Right)
_c(X1)
_c(X2)
#undef _c
}
return debug << "(" << Debug::nospace << UnsignedInt(value) << Debug::nospace << ")";
}
CORRADE_UNUSED Debug& operator<<(Debug& debug, Application::MouseMoveEvent::Buttons value) {
return Containers::enumSetDebugOutput(debug, value, "Buttons{}", {
Application::MouseMoveEvent::Button::Left,
Application::MouseMoveEvent::Button::Middle,
Application::MouseMoveEvent::Button::Right,
Application::MouseMoveEvent::Button::X1,
Application::MouseMoveEvent::Button::X2,
});
}
CORRADE_IGNORE_DEPRECATED_POP
#endif
Debug& operator<<(Debug& debug, Application::Key value) {
static Debug& operator<<(Debug& debug, Application::Key value) {
debug << "Key" << Debug::nospace;
switch(value) {
@ -308,6 +197,117 @@ Debug& operator<<(Debug& debug, Application::Key value) {
return debug << "(" << Debug::nospace << UnsignedInt(value) << Debug::nospace << ")";
}
static Debug& operator<<(Debug& debug, Application::Pointer value) {
debug << "Pointer" << Debug::nospace;
switch(value) {
#define _c(value) case Application::Pointer::value: return debug << "::" #value;
_c(MouseLeft)
_c(MouseMiddle)
_c(MouseRight)
_c(MouseButton4)
_c(MouseButton5)
#ifndef CORRADE_TARGET_EMSCRIPTEN
_c(Finger)
#endif
#undef _c
}
return debug << "(" << Debug::nospace << UnsignedInt(value) << Debug::nospace << ")";
}
#ifdef MAGNUM_BUILD_DEPRECATED
CORRADE_IGNORE_DEPRECATED_PUSH
CORRADE_UNUSED static Debug& operator<<(Debug& debug, Application::MouseMoveEvent::Button value) {
debug << "Button" << Debug::nospace;
switch(value) {
#define _c(value) case Application::MouseMoveEvent::Button::value: return debug << "::" #value;
_c(Left)
_c(Middle)
_c(Right)
_c(X1)
_c(X2)
#undef _c
}
return debug << "(" << Debug::nospace << UnsignedInt(value) << Debug::nospace << ")";
}
CORRADE_IGNORE_DEPRECATED_POP
#endif
namespace Test { namespace {
static Debug& operator<<(Debug& debug, Application::PointerEventSource value) {
debug << "PointerEventSource" << Debug::nospace;
switch(value) {
#define _c(value) case Application::PointerEventSource::value: return debug << "::" #value;
_c(Mouse)
#ifndef CORRADE_TARGET_EMSCRIPTEN
_c(Touch)
#endif
#undef _c
}
return debug << "(" << Debug::nospace << UnsignedInt(value) << Debug::nospace << ")";
}
Debug& operator<<(Debug& debug, Application::Modifiers value) {
return Containers::enumSetDebugOutput(debug, value, "Modifiers{}", {
Application::Modifier::Shift,
Application::Modifier::Ctrl,
Application::Modifier::Alt,
Application::Modifier::Super,
Application::Modifier::AltGr,
Application::Modifier::CapsLock,
Application::Modifier::NumLock,
});
}
Debug& operator<<(Debug& debug, Application::Pointers value) {
return Containers::enumSetDebugOutput(debug, value, "Pointers{}", {
Application::Pointer::MouseLeft,
Application::Pointer::MouseMiddle,
Application::Pointer::MouseRight,
Application::Pointer::MouseButton4,
Application::Pointer::MouseButton5,
#ifndef CORRADE_TARGET_EMSCRIPTEN
Application::Pointer::Finger,
#endif
});
}
#ifdef MAGNUM_BUILD_DEPRECATED
CORRADE_IGNORE_DEPRECATED_PUSH
CORRADE_UNUSED Debug& operator<<(Debug& debug, Application::MouseEvent::Button value) {
debug << "Button" << Debug::nospace;
switch(value) {
#define _c(value) case Application::MouseEvent::Button::value: return debug << "::" #value;
_c(Left)
_c(Middle)
_c(Right)
_c(X1)
_c(X2)
#undef _c
}
return debug << "(" << Debug::nospace << UnsignedInt(value) << Debug::nospace << ")";
}
CORRADE_UNUSED Debug& operator<<(Debug& debug, Application::MouseMoveEvent::Buttons value) {
return Containers::enumSetDebugOutput(debug, value, "Buttons{}", {
Application::MouseMoveEvent::Button::Left,
Application::MouseMoveEvent::Button::Middle,
Application::MouseMoveEvent::Button::Right,
Application::MouseMoveEvent::Button::X1,
Application::MouseMoveEvent::Button::X2,
});
}
CORRADE_IGNORE_DEPRECATED_POP
#endif
using namespace Containers::Literals;
using namespace Math::Literals;
@ -386,11 +386,19 @@ struct Sdl2ApplicationTest: Platform::Application {
}
void keyPressEvent(KeyEvent& event) override {
Debug{} << "key press:" << event.key() << "keycode:" << SDL_Keycode(event.key()) << event.keyName() << "scancode:" << event.event().key.keysym.scancode
Debug{} << "key press:" << event.key() << event.keyName() << "scancode:" << event.scanCode()
#ifndef CORRADE_TARGET_EMSCRIPTEN
<< event.scanCodeName()
#endif
<< event.modifiers()
#if !defined(CORRADE_TARGET_EMSCRIPTEN) || __EMSCRIPTEN_major__*10000 + __EMSCRIPTEN_minor__*100 + __EMSCRIPTEN_tiny__ >= 30125
<< "converted:"
#ifndef CORRADE_TARGET_EMSCRIPTEN
<< SDL_GetScancodeName(event.event().key.keysym.scancode)
<< scanCodeToKey(event.scanCode())
#endif
<< keyToScanCode(event.key())
#endif
<< event.modifiers();
;
if(event.key() == Key::F1) {
Debug{} << "starting text input";
@ -451,11 +459,19 @@ struct Sdl2ApplicationTest: Platform::Application {
}
void keyReleaseEvent(KeyEvent& event) override {
Debug{} << "key release:" << event.key() << "keycode:" << SDL_Keycode(event.key()) << event.keyName() << "scancode:" << event.event().key.keysym.scancode
Debug{} << "key release:" << event.key() << event.keyName() << "scancode:" << event.scanCode()
#ifndef CORRADE_TARGET_EMSCRIPTEN
<< SDL_GetScancodeName(event.event().key.keysym.scancode)
<< event.scanCodeName()
#endif
<< event.modifiers()
#if !defined(CORRADE_TARGET_EMSCRIPTEN) || __EMSCRIPTEN_major__*10000 + __EMSCRIPTEN_minor__*100 + __EMSCRIPTEN_tiny__ >= 30125
<< "converted:"
#ifndef CORRADE_TARGET_EMSCRIPTEN
<< scanCodeToKey(event.scanCode())
#endif
<< keyToScanCode(event.key())
#endif
<< event.modifiers();
;
/* With EmscriptenApplication, this makes the event stop from
propagating further to the page (such as when pressing F1).

Loading…
Cancel
Save