From 9afe7ebe507235f4d2c89088cc6df7f641bd47b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 16 Sep 2019 23:42:17 +0200 Subject: [PATCH] python: expose key and scroll events. --- src/python/magnum/platform/CMakeLists.txt | 8 +- src/python/magnum/platform/application.h | 158 +++++++++++++++++++++- src/python/magnum/platform/glfw.cpp | 55 +++++++- src/python/magnum/platform/sdl2.cpp | 51 ++++++- 4 files changed, 258 insertions(+), 14 deletions(-) diff --git a/src/python/magnum/platform/CMakeLists.txt b/src/python/magnum/platform/CMakeLists.txt index af3ce0a..f1871c3 100644 --- a/src/python/magnum/platform/CMakeLists.txt +++ b/src/python/magnum/platform/CMakeLists.txt @@ -27,7 +27,9 @@ if(NOT MAGNUM_BUILD_STATIC) if(Magnum_GlfwApplication_FOUND) pybind11_add_module(magnum_platform_glfw SYSTEM glfw.cpp) target_link_libraries(magnum_platform_glfw PRIVATE Magnum::GlfwApplication) - target_include_directories(magnum_platform_glfw PRIVATE ${CMAKE_SOURCE_DIR}/src/python) + target_include_directories(magnum_platform_glfw PRIVATE + ${CMAKE_SOURCE_DIR}/src + ${CMAKE_SOURCE_DIR}/src/python) set_target_properties(magnum_platform_glfw PROPERTIES FOLDER "python/platform" OUTPUT_NAME "glfw" @@ -37,7 +39,9 @@ if(NOT MAGNUM_BUILD_STATIC) if(Magnum_Sdl2Application_FOUND) pybind11_add_module(magnum_platform_sdl2 SYSTEM sdl2.cpp) target_link_libraries(magnum_platform_sdl2 PRIVATE Magnum::Sdl2Application) - target_include_directories(magnum_platform_sdl2 PRIVATE ${CMAKE_SOURCE_DIR}/src/python) + target_include_directories(magnum_platform_sdl2 PRIVATE + ${CMAKE_SOURCE_DIR}/src + ${CMAKE_SOURCE_DIR}/src/python) set_target_properties(magnum_platform_sdl2 PROPERTIES FOLDER "python/platform" OUTPUT_NAME "sdl2" diff --git a/src/python/magnum/platform/application.h b/src/python/magnum/platform/application.h index 54ee2a4..4e325b4 100644 --- a/src/python/magnum/platform/application.h +++ b/src/python/magnum/platform/application.h @@ -1,3 +1,5 @@ +#ifndef magnum_platform_application_h +#define magnum_platform_application_h /* This file is part of Magnum. @@ -68,14 +70,144 @@ template void application(py::class_& /* Event handlers */ .def("draw_event", &T::drawEvent, "Draw event") + .def("key_press_event", &T::keyPressEvent, "Key press event") + .def("key_release_event", &T::keyReleaseEvent, "Key release event") .def("mouse_press_event", &T::mousePressEvent, "Mouse press event") .def("mouse_release_event", &T::mouseReleaseEvent, "Mouse release event") .def("mouse_move_event", &T::mouseMoveEvent, "Mouse move event") + .def("mouse_scroll_event", &T::mouseScrollEvent, "Mouse scroll event") /** @todo more */ ; } -template void mouseEvent(py::class_& c) { + +template void inputEvent(py::class_& c) { + py::enum_{c, "Modifier", "Modifier"} + .value("SHIFT", T::Modifier::Shift) + .value("CTRL", T::Modifier::Ctrl) + .value("ALT", T::Modifier::Alt) + .value("SUPER", T::Modifier::Super); + + c.def_property("accepted", &T::isAccepted, &T::setAccepted, "Accepted status of the event"); +} + +template void keyEvent(py::class_& c) { + py::enum_{c, "Key", "Key"} + .value("UNKNOWN", T::Key::Unknown) + .value("LEFT_SHIFT", T::Key::LeftShift) + .value("RIGHT_SHIFT", T::Key::RightShift) + .value("LEFT_CTRL", T::Key::LeftCtrl) + .value("RIGHT_CTRL", T::Key::RightCtrl) + .value("LEFT_ALT", T::Key::LeftAlt) + .value("RIGHT_ALT", T::Key::RightAlt) + .value("LEFT_SUPER", T::Key::LeftSuper) + .value("RIGHT_SUPER", T::Key::RightSuper) + + .value("ENTER", T::Key::Enter) + .value("ESC", T::Key::Esc) + + .value("UP", T::Key::Up) + .value("DOWN", T::Key::Down) + .value("LEFT", T::Key::Left) + .value("RIGHT", T::Key::Right) + .value("HOME", T::Key::Home) + .value("END", T::Key::End) + .value("PAGE_UP", T::Key::PageUp) + .value("PAGE_DOWN", T::Key::PageDown) + .value("BACKSPACE", T::Key::Backspace) + .value("INSERT", T::Key::Insert) + .value("DELETE", T::Key::Delete) + + .value("F1", T::Key::F1) + .value("F2", T::Key::F2) + .value("F3", T::Key::F3) + .value("F4", T::Key::F4) + .value("F5", T::Key::F5) + .value("F6", T::Key::F6) + .value("F7", T::Key::F7) + .value("F8", T::Key::F8) + .value("F9", T::Key::F9) + .value("F10", T::Key::F10) + .value("F11", T::Key::F11) + .value("F12", T::Key::F12) + + .value("SPACE", T::Key::Space) + .value("TAB", T::Key::Tab) + .value("COMMA", T::Key::Comma) + .value("PERIOD", T::Key::Period) + .value("MINUS", T::Key::Minus) + .value("PLUS", T::Key::Plus) + .value("SLASH", T::Key::Slash) + .value("PERCENT", T::Key::Percent) + .value("SEMICOLON", T::Key::Semicolon) + .value("EQUAL", T::Key::Equal) + + .value("ZERO", T::Key::Zero) + .value("ONE", T::Key::One) + .value("TWO", T::Key::Two) + .value("THREE", T::Key::Three) + .value("FOUR", T::Key::Four) + .value("FIVE", T::Key::Five) + .value("SIX", T::Key::Six) + .value("SEVEN", T::Key::Seven) + .value("EIGHT", T::Key::Eight) + .value("NINE", T::Key::Nine) + + .value("A", T::Key::A) + .value("B", T::Key::B) + .value("C", T::Key::C) + .value("D", T::Key::D) + .value("E", T::Key::E) + .value("F", T::Key::F) + .value("G", T::Key::G) + .value("H", T::Key::H) + .value("I", T::Key::I) + .value("J", T::Key::J) + .value("K", T::Key::K) + .value("L", T::Key::L) + .value("M", T::Key::M) + .value("N", T::Key::N) + .value("O", T::Key::O) + .value("P", T::Key::P) + .value("Q", T::Key::Q) + .value("R", T::Key::R) + .value("S", T::Key::S) + .value("T", T::Key::T) + .value("U", T::Key::U) + .value("V", T::Key::V) + .value("W", T::Key::W) + .value("X", T::Key::X) + .value("Y", T::Key::Y) + .value("Z", T::Key::Z) + + .value("NUM_ZERO", T::Key::NumZero) + .value("NUM_ONE", T::Key::NumOne) + .value("NUM_TWO", T::Key::NumTwo) + .value("NUM_THREE", T::Key::NumThree) + .value("NUM_FOUR", T::Key::NumFour) + .value("NUM_FIVE", T::Key::NumFive) + .value("NUM_SIX", T::Key::NumSix) + .value("NUM_SEVEN", T::Key::NumSeven) + .value("NUM_EIGHT", T::Key::NumEight) + .value("NUM_NINE", T::Key::NumNine) + .value("NUM_DECIMAL", T::Key::NumDecimal) + .value("NUM_DIVIDE", T::Key::NumDivide) + .value("NUM_MULTIPLY", T::Key::NumMultiply) + .value("NUM_SUBTRACT", T::Key::NumSubtract) + .value("NUM_ADD", T::Key::NumAdd) + .value("NUM_ENTER", T::Key::NumEnter) + .value("NUM_EQUAL", T::Key::NumEqual); + + c + .def_property_readonly("key", &T::key, "Key") + /** @todo key name? useful? useles?? */ + .def_property_readonly("modifiers", [](T& self) { + return typename T::Modifier(typename std::underlying_type::type(self.modifiers())); + }, "Modifiers") + .def_property_readonly("is_repeated", &T::isRepeated, "Whether the key press is repeated"); +} + +template void mouseEvent(py::class_& c) { py::enum_{c, "Button", "Mouse button"} .value("LEFT", T::Button::Left) .value("MIDDLE", T::Button::Middle) @@ -83,10 +215,13 @@ template void mouseEvent(py::class_& c) { c .def_property_readonly("button", &T::button, "Button") - .def_property_readonly("position", &T::position, "Position"); + .def_property_readonly("position", &T::position, "Position") + .def_property_readonly("modifiers", [](T& self) { + return typename T::Modifier(typename std::underlying_type::type(self.modifiers())); + }, "Modifiers"); } -template void mouseMoveEvent(py::class_& c) { +template void mouseMoveEvent(py::class_& c) { py::enum_ buttons{c, "Buttons", "Set of mouse buttons"}; buttons .value("LEFT", T::Button::Left) @@ -96,9 +231,24 @@ template void mouseMoveEvent(py::class_& c) { c .def_property_readonly("position", &T::position, "Position") + .def_property_readonly("relative_position", &T::position, "Relative position") .def_property_readonly("buttons", [](T& self) { return typename T::Button(typename std::underlying_type::type(self.buttons())); - }, "Mouse buttons"); + }, "Mouse buttons") + .def_property_readonly("modifiers", [](T& self) { + return typename T::Modifier(typename std::underlying_type::type(self.modifiers())); + }, "Modifiers"); +} + +template void mouseScrollEvent(py::class_& c) { + c + .def_property_readonly("offset", &T::offset, "Offset") + .def_property_readonly("position", &T::position, "Position") + .def_property_readonly("modifiers", [](T& self) { + return typename T::Modifier(typename std::underlying_type::type(self.modifiers())); + }, "Modifiers"); } }} + +#endif diff --git a/src/python/magnum/platform/glfw.cpp b/src/python/magnum/platform/glfw.cpp index 4ef511d..f47cb85 100644 --- a/src/python/magnum/platform/glfw.cpp +++ b/src/python/magnum/platform/glfw.cpp @@ -26,6 +26,8 @@ #include #include +#include "Corrade/Python.h" + #include "magnum/bootstrap.h" #include "magnum/platform/application.h" @@ -51,9 +53,12 @@ void glfw(py::module& m) { void drawEvent() override = 0; #endif + void keyPressEvent(KeyEvent&) override {} + void keyReleaseEvent(KeyEvent&) override {} void mousePressEvent(MouseEvent&) override {} void mouseReleaseEvent(MouseEvent&) override {} void mouseMoveEvent(MouseMoveEvent&) override {} + void mouseScrollEvent(MouseScrollEvent&) override {} /* The base doesn't have a virtual destructor because in C++ it's never deleted through a pointer to the base. Here we need it, though. */ @@ -82,6 +87,33 @@ void glfw(py::module& m) { #endif } + /* PYBIND11_OVERLOAD_NAME() calls object_api::operator() with implicit + template param, which is return_value_policy::automatic_reference. + That later gets changed to return_value_policy::copy in + type_caster_base::cast() and there's no way to override that */ + void keyPressEvent(KeyEvent& event) override { + PYBIND11_OVERLOAD_NAME( + void, + PublicizedApplication, + "key_press_event", + keyPressEvent, + /* Have to use std::ref() otherwise pybind tries to copy + it and fails */ + std::ref(event) + ); + } + void keyReleaseEvent(KeyEvent& event) override { + PYBIND11_OVERLOAD_NAME( + void, + PublicizedApplication, + "key_release_event", + keyReleaseEvent, + /* Have to use std::ref() otherwise pybind tries to copy + it and fails */ + std::ref(event) + ); + } + void mousePressEvent(MouseEvent& event) override { PYBIND11_OVERLOAD_NAME( void, @@ -93,7 +125,6 @@ void glfw(py::module& m) { std::ref(event) ); } - void mouseReleaseEvent(MouseEvent& event) override { PYBIND11_OVERLOAD_NAME( void, @@ -105,7 +136,6 @@ void glfw(py::module& m) { std::ref(event) ); } - void mouseMoveEvent(MouseMoveEvent& event) override { PYBIND11_OVERLOAD_NAME( void, @@ -117,17 +147,34 @@ void glfw(py::module& m) { std::ref(event) ); } + void mouseScrollEvent(MouseScrollEvent& event) override { + PYBIND11_OVERLOAD_NAME( + void, + PublicizedApplication, + "mouse_scroll_event", + mouseScrollEvent, + /* Have to use std::ref() otherwise pybind tries to copy + it and fails */ + std::ref(event) + ); + } }; py::class_ glfwApplication{m, "Application", "GLFW application"}; /** @todo def_property_writeonly for swap_interval */ - py::class_ mouseEvent_{glfwApplication, "MouseEvent", "Mouse event"}; - py::class_ mouseMoveEvent_{glfwApplication, "MouseMoveEvent", "Mouse move event"}; + PyNonDestructibleClass inputEvent_{glfwApplication, "InputEvent", "Base for input events"}; + py::class_ keyEvent_{glfwApplication, "KeyEvent", "Key event"}; + py::class_ mouseEvent_{glfwApplication, "MouseEvent", "Mouse event"}; + py::class_ mouseMoveEvent_{glfwApplication, "MouseMoveEvent", "Mouse move event"}; + py::class_ mouseScrollEvent_{glfwApplication, "MouseScrollEvent", "Mouse scroll event"}; application(glfwApplication); + inputEvent(inputEvent_); + keyEvent(keyEvent_); mouseEvent(mouseEvent_); mouseMoveEvent(mouseMoveEvent_); + mouseScrollEvent(mouseScrollEvent_); } }} diff --git a/src/python/magnum/platform/sdl2.cpp b/src/python/magnum/platform/sdl2.cpp index 72f1d3e..cd28cc5 100644 --- a/src/python/magnum/platform/sdl2.cpp +++ b/src/python/magnum/platform/sdl2.cpp @@ -26,6 +26,8 @@ #include #include +#include "Corrade/Python.h" + #include "magnum/bootstrap.h" #include "magnum/platform/application.h" @@ -51,9 +53,12 @@ void sdl2(py::module& m) { void drawEvent() override = 0; #endif + void keyPressEvent(KeyEvent&) override {} + void keyReleaseEvent(KeyEvent&) override {} void mousePressEvent(MouseEvent&) override {} void mouseReleaseEvent(MouseEvent&) override {} void mouseMoveEvent(MouseMoveEvent&) override {} + void mouseScrollEvent(MouseScrollEvent&) override {} /* The base doesn't have a virtual destructor because in C++ it's never deleted through a pointer to the base. Here we need it, though. */ @@ -86,6 +91,29 @@ void sdl2(py::module& m) { template param, which is return_value_policy::automatic_reference. That later gets changed to return_value_policy::copy in type_caster_base::cast() and there's no way to override that */ + void keyPressEvent(KeyEvent& event) override { + PYBIND11_OVERLOAD_NAME( + void, + PublicizedApplication, + "key_press_event", + keyPressEvent, + /* Have to use std::ref() otherwise pybind tries to copy + it and fails */ + std::ref(event) + ); + } + void keyReleaseEvent(KeyEvent& event) override { + PYBIND11_OVERLOAD_NAME( + void, + PublicizedApplication, + "key_release_event", + keyReleaseEvent, + /* Have to use std::ref() otherwise pybind tries to copy + it and fails */ + std::ref(event) + ); + } + void mousePressEvent(MouseEvent& event) override { PYBIND11_OVERLOAD_NAME( void, @@ -97,7 +125,6 @@ void sdl2(py::module& m) { std::ref(event) ); } - void mouseReleaseEvent(MouseEvent& event) override { PYBIND11_OVERLOAD_NAME( void, @@ -109,7 +136,6 @@ void sdl2(py::module& m) { std::ref(event) ); } - void mouseMoveEvent(MouseMoveEvent& event) override { PYBIND11_OVERLOAD_NAME( void, @@ -121,6 +147,17 @@ void sdl2(py::module& m) { std::ref(event) ); } + void mouseScrollEvent(MouseScrollEvent& event) override { + PYBIND11_OVERLOAD_NAME( + void, + PublicizedApplication, + "mouse_scroll_event", + mouseScrollEvent, + /* Have to use std::ref() otherwise pybind tries to copy + it and fails */ + std::ref(event) + ); + } }; py::class_ sdl2application{m, "Application", "SDL2 application"}; @@ -130,12 +167,18 @@ void sdl2(py::module& m) { self.setSwapInterval(interval); }, "Swap interval"); - py::class_ mouseEvent_{sdl2application, "MouseEvent", "Mouse event"}; - py::class_ mouseMoveEvent_{sdl2application, "MouseMoveEvent", "Mouse move event"}; + PyNonDestructibleClass inputEvent_{sdl2application, "InputEvent", "Base for input events"}; + py::class_ keyEvent_{sdl2application, "KeyEvent", "Key event"}; + py::class_ mouseEvent_{sdl2application, "MouseEvent", "Mouse event"}; + py::class_ mouseMoveEvent_{sdl2application, "MouseMoveEvent", "Mouse move event"}; + py::class_ mouseScrollEvent_{sdl2application, "MouseScrollEvent", "Mouse scroll event"}; application(sdl2application); + inputEvent(inputEvent_); + keyEvent(keyEvent_); mouseEvent(mouseEvent_); mouseMoveEvent(mouseMoveEvent_); + mouseScrollEvent(mouseScrollEvent_); } }}