Browse Source

Platform: add {Sdl2,Glfw}Application::isKeyPressed().

And also immediately document it's not recommended to be used if it's
important to not miss any events, so basically next to useless. Yet some
projects implement their own key state caching on top of
Platform::Application, so it's better to give them the builtin thing
than suffer needless wheel reinvention.
pull/674/head
Vladimír Vondruš 1 year ago
parent
commit
70b0d76fcb
  1. 3
      doc/changelog.dox
  2. 7
      src/Magnum/Platform/GlfwApplication.cpp
  3. 26
      src/Magnum/Platform/GlfwApplication.h
  4. 10
      src/Magnum/Platform/Sdl2Application.cpp
  5. 29
      src/Magnum/Platform/Sdl2Application.h
  6. 197
      src/Magnum/Platform/Test/GlfwApplicationTest.cpp
  7. 11
      src/Magnum/Platform/Test/Sdl2ApplicationTest.cpp

3
doc/changelog.dox

@ -882,6 +882,9 @@ See also:
@relativeref{Platform::Sdl2Application,scanCodeToKey()} and
@ref Platform::GlfwApplication::keyToScanCode() helpers for key / scan code
conversion outside of event handlers
- Added @ref Platform::Sdl2Application::isKeyPressed() and
@ref Platform::GlfwApplication::isKeyPressed() for immediate key state
queries
- Updated @ref Platform::AndroidApplication to not use a deprecated API that
was removed in NDK 27 ([mosra/magnum#659](https://github.com/mosra/magnum/pull/659))

7
src/Magnum/Platform/GlfwApplication.cpp

@ -905,6 +905,13 @@ void GlfwApplication::exit(int exitCode) {
if(_window) glfwSetWindowShouldClose(_window, true);
}
bool GlfwApplication::isKeyPressed(const Key key) {
/* Documentation says GLFW_KEY_UNKNOWN is not valid for glfwGetKey() */
if(key == Key::Unknown)
return false;
return glfwGetKey(_window, int(key)) == GLFW_PRESS;
}
namespace {
constexpr Int CursorMap[] {

26
src/Magnum/Platform/GlfwApplication.h

@ -649,11 +649,30 @@ class GlfwApplication {
/** @{ @name Keyboard handling */
public:
/**
* @brief Whether a key is pressed
* @m_since_latest
*
* If a key is pressed, i.e. @ref keyPressEvent() with given @p key was
* fired but not a @ref keyReleaseEvent() yet, the function returns
* @cpp true @ce. For unknown @ref Key values returns @cpp false @ce.
*
* This function only queries immediate keyboard state at given point
* in time, which means that if a particular key got pressed and
* released again in between calls to this function, it will not be
* reported as pressed. To avoid losing key presses, prefer to get
* keyboard press and release events through @ref keyPressEvent() and
* @ref keyReleaseEvent() instead if possible.
*/
bool isKeyPressed(Key key);
private:
/**
* @brief Key press event
*
* Called when a key is pressed. Default implementation does nothing.
* @see @ref platform-windowed-key-events
* @see @ref platform-windowed-key-events, @ref isKeyPressed()
*/
virtual void keyPressEvent(KeyEvent& event);
@ -661,7 +680,7 @@ class GlfwApplication {
* @brief Key release event
*
* Called when a key is released. Default implementation does nothing.
* @see @ref platform-windowed-key-events
* @see @ref platform-windowed-key-events, @ref isKeyPressed()
*/
virtual void keyReleaseEvent(KeyEvent& event);
@ -1061,7 +1080,8 @@ CORRADE_ENUMSET_OPERATORS(GlfwApplication::Modifiers)
@brief Key
@m_since_latest
@see @ref KeyEvent::key(), @ref platform-windowed-key-events
@see @ref KeyEvent::key(), @ref isKeyPressed(), @ref keyToScanCode(),
@ref platform-windowed-key-events
*/
enum class GlfwApplication::Key: Int {
Unknown = GLFW_KEY_UNKNOWN, /**< Unknown key */

10
src/Magnum/Platform/Sdl2Application.cpp

@ -1306,6 +1306,16 @@ bool Sdl2Application::mainLoopIteration() {
return !(_flags & Flag::Exit);
}
#ifndef CORRADE_TARGET_EMSCRIPTEN
bool Sdl2Application::isKeyPressed(const Key key) {
int count;
const Uint8* const state = SDL_GetKeyboardState(&count);
const SDL_Scancode scancode = SDL_GetScancodeFromKey(SDL_Keycode(key));
CORRADE_INTERNAL_DEBUG_ASSERT(scancode < count);
return state[scancode];
}
#endif
namespace {
#ifndef CORRADE_TARGET_EMSCRIPTEN

29
src/Magnum/Platform/Sdl2Application.h

@ -1132,11 +1132,33 @@ class Sdl2Application {
/** @{ @name Keyboard handling */
public:
#ifndef CORRADE_TARGET_EMSCRIPTEN
/**
* @brief Whether a key is pressed
* @m_since_latest
*
* If a key is pressed, i.e. @ref keyPressEvent() with given @p key was
* fired but not a @ref keyReleaseEvent() yet, the function returns
* @cpp true @ce. For unknown @ref Key values returns @cpp false @ce.
*
* This function only queries immediate keyboard state at given point
* in time, which means that if a particular key got pressed and
* released again in between calls to this function, it will not be
* reported as pressed. To avoid losing key presses, prefer to get
* keyboard press and release events through @ref keyPressEvent() and
* @ref keyReleaseEvent() instead if possible.
* @note Not available on @ref CORRADE_TARGET_EMSCRIPTEN "Emscripten".
*/
bool isKeyPressed(Key key);
#endif
private:
/**
* @brief Key press event
*
* Called when a key is pressed. Default implementation does nothing.
* @see @ref platform-windowed-key-events
* @see @ref platform-windowed-key-events, @ref isKeyPressed()
*/
virtual void keyPressEvent(KeyEvent& event);
@ -1144,7 +1166,7 @@ class Sdl2Application {
* @brief Key release event
*
* Called when a key is released. Default implementation does nothing.
* @see @ref platform-windowed-key-events
* @see @ref platform-windowed-key-events, @ref isKeyPressed()
*/
virtual void keyReleaseEvent(KeyEvent& event);
@ -1632,7 +1654,8 @@ CORRADE_ENUMSET_OPERATORS(Sdl2Application::Modifiers)
@brief Key
@m_since_latest
@see @ref KeyEvent::key(), @ref platform-windowed-key-events
@see @ref KeyEvent::key(), @ref isKeyPressed(), @ref keyToScanCode(),
@ref scanCodeToKey(), @ref platform-windowed-key-events
*/
enum class Sdl2Application::Key: SDL_Keycode {
Unknown = SDLK_UNKNOWN, /**< Unknown key */

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

@ -39,8 +39,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() / Key
below wouldn't be able to pick them up */
static Debug& operator<<(Debug& debug, Application::Modifier value) {
debug << "Modifier" << Debug::nospace;
@ -57,99 +57,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)
_c(MouseButton6)
_c(MouseButton7)
_c(MouseButton8)
#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)
#undef _c
}
return debug << "(" << Debug::nospace << UnsignedInt(value) << Debug::nospace << ")";
}
CORRADE_IGNORE_DEPRECATED_POP
#endif
namespace Test { namespace {
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
});
}
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,
Application::Pointer::MouseButton6,
Application::Pointer::MouseButton7,
Application::Pointer::MouseButton8,
});
}
#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(Button4)
_c(Button5)
_c(Button6)
_c(Button7)
_c(Button8)
#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,
});
}
CORRADE_IGNORE_DEPRECATED_POP
#endif
Debug& operator<<(Debug& debug, const Application::Key value) {
static Debug& operator<<(Debug& debug, const Application::Key value) {
debug << "Key" << Debug::nospace;
switch(value) {
@ -270,6 +178,98 @@ Debug& operator<<(Debug& debug, const 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)
_c(MouseButton6)
_c(MouseButton7)
_c(MouseButton8)
#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)
#undef _c
}
return debug << "(" << Debug::nospace << UnsignedInt(value) << Debug::nospace << ")";
}
CORRADE_IGNORE_DEPRECATED_POP
#endif
namespace Test { namespace {
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
});
}
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,
Application::Pointer::MouseButton6,
Application::Pointer::MouseButton7,
Application::Pointer::MouseButton8,
});
}
#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(Button4)
_c(Button5)
_c(Button6)
_c(Button7)
_c(Button8)
#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,
});
}
CORRADE_IGNORE_DEPRECATED_POP
#endif
using namespace Containers::Literals;
using namespace Math::Literals;
@ -294,6 +294,10 @@ struct GlfwApplicationTest: Platform::Application {
Debug{} << "draw";
swapBuffers();
/* Invalid keys are tested in the constructor */
if(isKeyPressed(Key::M))
Debug{} << Key::M << "is pressed";
if(_redraw)
redraw();
}
@ -458,6 +462,9 @@ GlfwApplicationTest::GlfwApplicationTest(const Arguments& arguments): Platform::
importer->openData(rs.getRaw("icon-32.tga")) && (image32 = importer->image2D(0)) &&
importer->openData(rs.getRaw("icon-64.tga")) && (image64 = importer->image2D(0))) setWindowIcon({*image16, *image32, *image64});
else Warning{} << "Can't load the plugin / images, not setting window icon";
/* This shouldn't blow up */
CORRADE_INTERNAL_ASSERT(!isKeyPressed(Key::Unknown) && !isKeyPressed(Key(0x7fffffff)));
}
}}}}

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

@ -334,6 +334,12 @@ struct Sdl2ApplicationTest: Platform::Application {
GL::defaultFramebuffer.clear(GL::FramebufferClear::Color);
#endif
#ifndef CORRADE_TARGET_EMSCRIPTEN
/* Invalid keys are tested in the constructor */
if(isKeyPressed(Key::M))
Debug{} << Key::M << "is pressed";
#endif
swapBuffers();
if(_redraw)
@ -578,6 +584,11 @@ Sdl2ApplicationTest::Sdl2ApplicationTest(const Arguments& arguments): Platform::
Debug{} << "SDL too old, can't set window icon";
#endif
#endif
#ifndef CORRADE_TARGET_EMSCRIPTEN
/* This shouldn't blow up */
CORRADE_INTERNAL_ASSERT(!isKeyPressed(Key::Unknown) && !isKeyPressed(Key(0x7fffffff)));
#endif
}
}}}}

Loading…
Cancel
Save