diff --git a/demos/combustion_demo/src/combustion_demo.cpp b/demos/combustion_demo/src/combustion_demo.cpp index 12764cf1d6e2dcf5ed6d1069ddbd4e6bf9d030b4..e7d284866a64b1e3bae7f9a3b597cd8b72342338 100644 --- a/demos/combustion_demo/src/combustion_demo.cpp +++ b/demos/combustion_demo/src/combustion_demo.cpp @@ -31,7 +31,8 @@ #include "phx/display/display_system_openvr.hpp" #include "phx/display/display_system_window.hpp" #include "phx/input/device_system.hpp" -#include "phx/input/input_system.hpp" +#include "phx/input/keyboard.hpp" +#include "phx/input/mouse.hpp" #include "phx/rendering/auxiliary/splash_screen.hpp" #include "phx/rendering/components/mesh_handle.hpp" #include "phx/rendering/components/mesh_render_settings.hpp" @@ -66,11 +67,13 @@ int main(int, char**) { assimp_loader->SetProgressUpdateCallback( [splash](float progress) { splash->SetLoadProgress(progress); }); - phx::InputSystem* input_system = engine->GetSystem<phx::InputSystem>(); - - input_system->AddKeyPressCallback([&engine](char key) { - if (key == 'q') engine->Stop(); - }); + phx::Keyboard* keyboard = + engine->GetSystem<phx::DeviceSystem>()->GetDevices<phx::Keyboard>()[0]; + keyboard->RegisterKeySignal( + [&engine](char key, phx::Keyboard::KeyEvent key_event, int) { + if (key_event != phx::Keyboard::KEY_PRESSED) return; + if (key == 'q') engine->Stop(); + }); auto right_controller_entities = scene->GetEntitiesWithComponents< phx::RuntimeComponent<phx::RIGHT_CONTROLLER>>(); @@ -83,8 +86,7 @@ int main(int, char**) { } auto handle = std::async([&right_interaction_behavior, &scene, - rendering_system, splash, input_system, - openvr_system]() { + rendering_system, splash, openvr_system]() { auto model_surface_entity = phx::SceneLoader::InsertModelIntoScene( "models/combustion/combustion_opt.stl", scene.get()); auto surface_transform = @@ -204,7 +206,9 @@ int main(int, char**) { } if (!openvr_system) { - camera->AddComponent<DesktopNavigationBehavior>(input_system); + phx::Mouse* mouse = + engine->GetSystem<phx::DeviceSystem>()->GetDevices<phx::Mouse>()[0]; + camera->AddComponent<DesktopNavigationBehavior>(mouse); camera->GetFirstComponent<phx::Transform>()->Translate( glm::vec3(0.0f, 1.0f, 1.0f)); } diff --git a/demos/combustion_demo/src/desktop_navigation_behavior.cpp b/demos/combustion_demo/src/desktop_navigation_behavior.cpp index 0491b8c21da54044d239d8ebce43394ab9c54027..55e1a74e1f34b81e60c0fdcfc287fd152368a95f 100644 --- a/demos/combustion_demo/src/desktop_navigation_behavior.cpp +++ b/demos/combustion_demo/src/desktop_navigation_behavior.cpp @@ -32,15 +32,12 @@ SUPPRESS_WARNINGS_END #include "phx/core/entity.hpp" #include "phx/rendering/components/transform.hpp" -DesktopNavigationBehavior::DesktopNavigationBehavior( - phx::InputSystem* input_system) - : input_system_(input_system) { - input_system_->AddMouseMoveCallback( - [this](int x, int y) { OnMouseMove(x, y); }); - input_system_->AddMousePressCallback( - [this](unsigned btn) { OnMousePress(btn); }); - input_system_->AddMouseReleaseCallback( - [this](unsigned btn) { OnMouseRelease(btn); }); +DesktopNavigationBehavior::DesktopNavigationBehavior(phx::Mouse* mouse) { + mouse->RegisterMoveSignal([this](int x, int y) { OnMouseMove(x, y); }); + mouse->RegisterButtonSignal( + [this](phx::Mouse::ButtonId id, phx::Mouse::ButtonEvent event) { + OnMouseButton(id, event); + }); } void DesktopNavigationBehavior::OnUpdate() { @@ -76,26 +73,27 @@ void DesktopNavigationBehavior::OnMouseMove(int x, int y) { accumulated_mouse_pos_ += glm::ivec2{x, y}; } -void DesktopNavigationBehavior::OnMousePress(unsigned btn) { - if (btn == 1) { - rotation_mode_ = true; - } - if (btn == 2) { - strafe_mode_ = true; - } - if (btn == 3) { - translation_mode_ = true; - } -} - -void DesktopNavigationBehavior::OnMouseRelease(unsigned btn) { - if (btn == 1) { - rotation_mode_ = false; - } - if (btn == 2) { - strafe_mode_ = false; - } - if (btn == 3) { - translation_mode_ = false; +void DesktopNavigationBehavior::OnMouseButton(phx::Mouse::ButtonId id, + phx::Mouse::ButtonEvent event) { + if (event == phx::Mouse::BUTTON_PRESSED) { + if (id == phx::Mouse::LEFT_BUTTON) { + rotation_mode_ = true; + } + if (id == phx::Mouse::MIDDLE_BUTTON) { + strafe_mode_ = true; + } + if (id == phx::Mouse::RIGHT_BUTTON) { + translation_mode_ = true; + } + } else { + if (id == phx::Mouse::LEFT_BUTTON) { + rotation_mode_ = false; + } + if (id == phx::Mouse::MIDDLE_BUTTON) { + strafe_mode_ = false; + } + if (id == phx::Mouse::RIGHT_BUTTON) { + translation_mode_ = false; + } } } diff --git a/demos/combustion_demo/src/desktop_navigation_behavior.hpp b/demos/combustion_demo/src/desktop_navigation_behavior.hpp index c394669cc307d679652fc69e9c4442bb20843625..1f03704f1006b5d9481976f29665835aa88e39e4 100644 --- a/demos/combustion_demo/src/desktop_navigation_behavior.hpp +++ b/demos/combustion_demo/src/desktop_navigation_behavior.hpp @@ -29,12 +29,12 @@ SUPPRESS_WARNINGS_BEGIN #include "glm/glm.hpp" SUPPRESS_WARNINGS_END -#include "phx/input/input_system.hpp" +#include "phx/input/mouse.hpp" #include "phx/scripting/behavior.hpp" class DesktopNavigationBehavior : public phx::Behavior { public: - explicit DesktopNavigationBehavior(phx::InputSystem* input_system); + explicit DesktopNavigationBehavior(phx::Mouse* mouse); DesktopNavigationBehavior(const DesktopNavigationBehavior& that) = default; DesktopNavigationBehavior(DesktopNavigationBehavior&& temp) = default; virtual ~DesktopNavigationBehavior() = default; @@ -45,11 +45,7 @@ class DesktopNavigationBehavior : public phx::Behavior { void OnUpdate() override; void OnMouseMove(int x, int y); - void OnMousePress(unsigned btn); - void OnMouseRelease(unsigned btn); - - protected: - phx::InputSystem* input_system_; + void OnMouseButton(phx::Mouse::ButtonId id, phx::Mouse::ButtonEvent event); private: glm::ivec2 accumulated_mouse_pos_ = glm::ivec2(0); diff --git a/demos/viewer/src/viewer.cpp b/demos/viewer/src/viewer.cpp index a43834aba9cadeb24c0425e9c2373a7b4026f78d..173e5ae2e44988c3eb7ceb0c0b9352a91f2350b6 100644 --- a/demos/viewer/src/viewer.cpp +++ b/demos/viewer/src/viewer.cpp @@ -34,7 +34,7 @@ #include "phx/display/display_system_window.hpp" #include "phx/display/window.hpp" #include "phx/input/device_system.hpp" -#include "phx/input/input_system.hpp" +#include "phx/input/keyboard.hpp" #include "phx/rendering/auxiliary/splash_screen.hpp" #include "phx/rendering/components/light.hpp" #include "phx/rendering/components/transform.hpp" @@ -68,14 +68,18 @@ int main(int, char**) { assimp_loader->SetProgressUpdateCallback( [splash](float progress) { splash->SetLoadProgress(progress); }); - phx::InputSystem* input_system = engine->GetSystem<phx::InputSystem>(); ViewerSystem* viewer_system = engine->CreateSystem<ViewerSystem>(); - input_system->AddKeyPressCallback([&engine, &viewer_system](char key) { - if (key == 'q') engine->Stop(); - if (key == 'f') - viewer_system->SetShowFramerate(!viewer_system->GetShowFramerate()); - }); + phx::Keyboard* keyboard = + engine->GetSystem<phx::DeviceSystem>()->GetDevices<phx::Keyboard>()[0]; + keyboard->RegisterKeySignal( + [&engine, &viewer_system](char key, phx::Keyboard::KeyEvent key_event, + int) { + if (key_event != phx::Keyboard::KEY_PRESSED) return; + if (key == 'q') engine->Stop(); + if (key == 'f') + viewer_system->SetShowFramerate(!viewer_system->GetShowFramerate()); + }); auto handle = std::async([&scene, rendering_system, splash]() { phx::SceneLoader::InsertModelIntoScene("models/bunny.obj", scene.get()); diff --git a/library/phx/display/display_system_window.cpp b/library/phx/display/display_system_window.cpp index 190c2fe08b595e1b073a287a949629ba4b7c6b30..b5ca76366c272ee271027b2d4eeb73c9f7405472 100644 --- a/library/phx/display/display_system_window.cpp +++ b/library/phx/display/display_system_window.cpp @@ -31,9 +31,9 @@ #include "SDL2/SDL_video.h" -#include "phx/core/scene.hpp" #include "phx/core/logger.hpp" #include "phx/core/runtime_component.hpp" +#include "phx/core/scene.hpp" #include "phx/rendering/rendering_system.hpp" #undef CreateWindow @@ -74,4 +74,12 @@ void DisplaySystemWindow::CreateRenderTarget(Scene* scene, float field_of_view, camera->AddComponent<RenderTarget>(window_size); } +boost::signals2::connection DisplaySystemWindow::AddQuitCallback( + const std::function<void()>& callback) { + return sdl_event_receiver.quit_signal_.connect(callback); +} +void DisplaySystemWindow::SDLEventReceiver::OnSDLEvent(const SDL_Event& event) { + if (event.type == SDL_QUIT) quit_signal_(); +} + } // namespace phx diff --git a/library/phx/display/display_system_window.hpp b/library/phx/display/display_system_window.hpp index cf8a3b559bbcc58796be3b1e4b34b76d01c36392..385f6d8d431bf3b42e23d300c585a1a2db9429d1 100644 --- a/library/phx/display/display_system_window.hpp +++ b/library/phx/display/display_system_window.hpp @@ -29,8 +29,9 @@ #include "phx/core/scene.hpp" #include "phx/display/display_system.hpp" #include "phx/display/window.hpp" -#include "phx/rendering/backend/render_target.hpp" #include "phx/export.hpp" +#include "phx/input/sdl_device.hpp" +#include "phx/rendering/backend/render_target.hpp" #undef CreateWindow @@ -58,8 +59,18 @@ class PHOENIX_EXPORT DisplaySystemWindow : public DisplaySystem { void CreateRenderTarget(Scene* scene, float field_of_view, float near_plane, float far_plane); + boost::signals2::connection AddQuitCallback( + const std::function<void()>& callback); + protected: std::unique_ptr<Window> window_; + + class SDLEventReceiver : public SDLDevice { + public: + void OnSDLEvent(const SDL_Event& event) override; + boost::signals2::signal<void()> quit_signal_; + }; + SDLEventReceiver sdl_event_receiver; }; template <typename... Arguments> diff --git a/library/phx/input/input_system.cpp b/library/phx/input/input_system.cpp deleted file mode 100644 index 5b68fd671b36d533dc6a57822b7b4afba9b7590d..0000000000000000000000000000000000000000 --- a/library/phx/input/input_system.cpp +++ /dev/null @@ -1,107 +0,0 @@ -//------------------------------------------------------------------------------ -// Project Phoenix -// -// Copyright (c) 2017-2018 RWTH Aachen University, Germany, -// Virtual Reality & Immersive Visualization Group. -//------------------------------------------------------------------------------ -// License -// -// Licensed under the 3-Clause BSD License (the "License"); -// you may not use this file except in compliance with the License. -// See the file LICENSE for the full text. -// You may obtain a copy of the License at -// -// https://opensource.org/licenses/BSD-3-Clause -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//------------------------------------------------------------------------------ - -#include "phx/input/input_system.hpp" - -#include <string> - -#include "phx/core/logger.hpp" -#include "phx/rendering/rendering_system.hpp" -#include "phx/suppress_warnings.hpp" - -SUPPRESS_WARNINGS_BEGIN -#include "SDL.h" -SUPPRESS_WARNINGS_END - -namespace phx { -InputSystem::InputSystem(Engine* engine) : System(engine) { - SDL_Init(SDL_INIT_EVENTS); -} - -InputSystem::~InputSystem() { SDL_QuitSubSystem(SDL_INIT_EVENTS); } - -void InputSystem::Update(const FrameTimer::TimeInfo&) { - UpdateSDLEvents(); -} - -boost::signals2::connection InputSystem::AddQuitCallback( - const std::function<void()>& callback) { - return quit_signal_.connect(callback); -} - -boost::signals2::connection InputSystem::AddKeyPressCallback( - const std::function<void(char)>& callback) { - return key_press_signal_.connect(callback); -} - -boost::signals2::connection InputSystem::AddKeyReleaseCallback( - const std::function<void(char)>& callback) { - return key_release_signal_.connect(callback); -} - -boost::signals2::connection InputSystem::AddMouseMoveCallback( - const std::function<void(int, int)>& callback) { - return mouse_move_signal_.connect(callback); -} - -boost::signals2::connection InputSystem::AddMousePressCallback( - const std::function<void(unsigned)>& callback) { - return mouse_press_signal_.connect(callback); -} - -boost::signals2::connection InputSystem::AddMouseReleaseCallback( - const std::function<void(unsigned)>& callback) { - return mouse_release_signal_.connect(callback); -} - -std::string InputSystem::ToString() const { return "InputSystem"; } - -void InputSystem::UpdateSDLEvents() { - SDL_Event event; - while (SDL_PollEvent(&event) != 0) { - switch (event.type) { - case SDL_QUIT: - quit_signal_(); - break; - case SDL_KEYDOWN: - key_press_signal_(static_cast<char>(event.key.keysym.sym)); - break; - case SDL_KEYUP: - key_release_signal_(static_cast<char>(event.key.keysym.sym)); - break; - case SDL_MOUSEMOTION: - mouse_move_signal_(static_cast<int>(event.motion.xrel), - static_cast<int>(event.motion.yrel)); - break; - case SDL_MOUSEBUTTONDOWN: - mouse_press_signal_(event.button.button); - break; - case SDL_MOUSEBUTTONUP: - mouse_release_signal_(event.button.button); - break; - default: - break; - } - } -} - -} // namespace phx diff --git a/library/phx/input/input_system.hpp b/library/phx/input/input_system.hpp deleted file mode 100644 index 9862ea78119438869c1e37162909df8c9faba169..0000000000000000000000000000000000000000 --- a/library/phx/input/input_system.hpp +++ /dev/null @@ -1,86 +0,0 @@ -//------------------------------------------------------------------------------ -// Project Phoenix -// -// Copyright (c) 2017-2018 RWTH Aachen University, Germany, -// Virtual Reality & Immersive Visualization Group. -//------------------------------------------------------------------------------ -// License -// -// Licensed under the 3-Clause BSD License (the "License"); -// you may not use this file except in compliance with the License. -// See the file LICENSE for the full text. -// You may obtain a copy of the License at -// -// https://opensource.org/licenses/BSD-3-Clause -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//------------------------------------------------------------------------------ - -#ifndef LIBRARY_PHX_INPUT_INPUT_SYSTEM_HPP_ -#define LIBRARY_PHX_INPUT_INPUT_SYSTEM_HPP_ - -#include <functional> -#include <string> - -#include "phx/suppress_warnings.hpp" - -SUPPRESS_WARNINGS_BEGIN -#define BOOST_BIND_NO_PLACEHOLDERS -#include "boost/signals2/connection.hpp" -#include "boost/signals2/signal.hpp" -SUPPRESS_WARNINGS_END - -#include "phx/core/engine.hpp" -#include "phx/core/system.hpp" -#include "phx/export.hpp" - -namespace phx { - -class PHOENIX_EXPORT InputSystem : public System { - public: - InputSystem() = delete; - InputSystem(const InputSystem&) = delete; - InputSystem(InputSystem&&) = default; - ~InputSystem() override; - - void Update(const FrameTimer::TimeInfo& time_info) override; - - InputSystem& operator=(const InputSystem&) = delete; - InputSystem& operator=(InputSystem&&) = default; - - boost::signals2::connection AddQuitCallback( - const std::function<void()>& callback); - boost::signals2::connection AddKeyPressCallback( - const std::function<void(char)>& callback); - boost::signals2::connection AddKeyReleaseCallback( - const std::function<void(char)>& callback); - boost::signals2::connection AddMouseMoveCallback( - const std::function<void(int, int)>& callback); - boost::signals2::connection AddMousePressCallback( - const std::function<void(unsigned int)>& callback); - boost::signals2::connection AddMouseReleaseCallback( - const std::function<void(unsigned int)>& callback); - - std::string ToString() const override; - - private: - friend InputSystem* Engine::CreateSystem<InputSystem>(); - explicit InputSystem(Engine* engine); - - void UpdateSDLEvents(); - - boost::signals2::signal<void()> quit_signal_; - boost::signals2::signal<void(char)> key_press_signal_; - boost::signals2::signal<void(char)> key_release_signal_; - boost::signals2::signal<void(int, int)> mouse_move_signal_; - boost::signals2::signal<void(unsigned int)> mouse_press_signal_; - boost::signals2::signal<void(unsigned int)> mouse_release_signal_; -}; - -} // namespace phx - -#endif // LIBRARY_PHX_INPUT_INPUT_SYSTEM_HPP_ diff --git a/library/phx/input/keyboard.cpp b/library/phx/input/keyboard.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2bf5757c33c5119fea4a6a8cd97192bfa30e46f8 --- /dev/null +++ b/library/phx/input/keyboard.cpp @@ -0,0 +1,46 @@ +//------------------------------------------------------------------------------ +// Project Phoenix +// +// Copyright (c) 2017-2018 RWTH Aachen University, Germany, +// Virtual Reality & Immersive Visualization Group. +//------------------------------------------------------------------------------ +// License +// +// Licensed under the 3-Clause BSD License (the "License"); +// you may not use this file except in compliance with the License. +// See the file LICENSE for the full text. +// You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//------------------------------------------------------------------------------ + +#include "phx/input/keyboard.hpp" + +#include <string> +#include <vector> + +#include "phx/core/logger.hpp" + +namespace phx { +void Keyboard::Update() { SDLDevice::Update(); } + +void Keyboard::OnSDLEvent(const SDL_Event& event) { + if (event.type == SDL_KEYDOWN) + key_signal_(static_cast<char>(event.key.keysym.sym), KEY_PRESSED, + static_cast<int>(event.key.keysym.mod)); + else if (event.type == SDL_KEYUP) + key_signal_(static_cast<char>(event.key.keysym.sym), KEY_RELEASED, + static_cast<int>(event.key.keysym.mod)); +} + +boost::signals2::connection Keyboard::RegisterKeySignal( + const std::function<void(char, KeyEvent, int)>& callback) { + return key_signal_.connect(callback); +} +} // namespace phx diff --git a/library/phx/input/keyboard.hpp b/library/phx/input/keyboard.hpp new file mode 100644 index 0000000000000000000000000000000000000000..80ca1b3a5d1e93de1f926dd47a94911f3b428abb --- /dev/null +++ b/library/phx/input/keyboard.hpp @@ -0,0 +1,58 @@ +//------------------------------------------------------------------------------ +// Project Phoenix +// +// Copyright (c) 2017-2018 RWTH Aachen University, Germany, +// Virtual Reality & Immersive Visualization Group. +//------------------------------------------------------------------------------ +// License +// +// Licensed under the 3-Clause BSD License (the "License"); +// you may not use this file except in compliance with the License. +// See the file LICENSE for the full text. +// You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//------------------------------------------------------------------------------ + +#ifndef LIBRARY_PHX_INPUT_KEYBOARD_HPP_ +#define LIBRARY_PHX_INPUT_KEYBOARD_HPP_ + +#include <memory> + +#define BOOST_BIND_NO_PLACEHOLDERS +// otherwise boosts _ placeholders conflict with trompeloeil ones +#include "boost/signals2/connection.hpp" +#include "boost/signals2/signal.hpp" + +#include "phx/input/sdl_device.hpp" + +#include "phx/export.hpp" + +namespace phx { + +class PHOENIX_EXPORT Keyboard : public SDLDevice { + public: + enum KeyEvent { KEY_PRESSED, KEY_RELEASED }; + + virtual ~Keyboard() = default; + + void Update() override; + void OnSDLEvent(const SDL_Event& event) override; + + // the 3rd paramter are the modifiers, see SDL_Keymod + boost::signals2::connection RegisterKeySignal( + const std::function<void(char, KeyEvent, int)>& callback); + + private: + boost::signals2::signal<void(char, KeyEvent, int)> key_signal_; +}; + +} // namespace phx + +#endif // LIBRARY_PHX_INPUT_KEYBOARD_HPP_ diff --git a/library/phx/input/mouse.cpp b/library/phx/input/mouse.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f575e1b3dcd5568b19ef7b75a8a1d4e8fd42cee7 --- /dev/null +++ b/library/phx/input/mouse.cpp @@ -0,0 +1,78 @@ +//------------------------------------------------------------------------------ +// Project Phoenix +// +// Copyright (c) 2017-2018 RWTH Aachen University, Germany, +// Virtual Reality & Immersive Visualization Group. +//------------------------------------------------------------------------------ +// License +// +// Licensed under the 3-Clause BSD License (the "License"); +// you may not use this file except in compliance with the License. +// See the file LICENSE for the full text. +// You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//------------------------------------------------------------------------------ + +#include "phx/input/mouse.hpp" + +#include <string> +#include <vector> + +#include "phx/core/logger.hpp" + +namespace phx { + +void Mouse::Update() { SDLDevice::Update(); } + +void Mouse::OnSDLEvent(const SDL_Event& event) { + ButtonEvent event_type = BUTTON_PRESSED; + if (event.type == SDL_MOUSEMOTION) { + move_signal_(static_cast<int>(event.motion.xrel), + static_cast<int>(event.motion.yrel)); + } else if (event.type == SDL_MOUSEBUTTONDOWN) { + event_type = BUTTON_PRESSED; + } else if (event.type == SDL_MOUSEBUTTONUP) { + event_type = BUTTON_RELEASED; + } else { + return; + } + + switch (event.button.button) { + case LEFT_BUTTON: + button_signal_(LEFT_BUTTON, event_type); + break; + case MIDDLE_BUTTON: + button_signal_(MIDDLE_BUTTON, event_type); + break; + case RIGHT_BUTTON: + button_signal_(RIGHT_BUTTON, event_type); + break; + case X1_BUTTON: + button_signal_(X1_BUTTON, event_type); + break; + case X2_BUTTON: + button_signal_(X2_BUTTON, event_type); + break; + default: + break; + } +} + +boost::signals2::connection Mouse::RegisterButtonSignal( + const std::function<void(ButtonId, ButtonEvent)>& callback) { + return button_signal_.connect(callback); +} + +boost::signals2::connection Mouse::RegisterMoveSignal( + const std::function<void(int, int)>& callback) { + return move_signal_.connect(callback); +} + +} // namespace phx diff --git a/library/phx/input/mouse.hpp b/library/phx/input/mouse.hpp new file mode 100644 index 0000000000000000000000000000000000000000..500ffd35ec021075409c2d0fb0acadbdbe95a9bd --- /dev/null +++ b/library/phx/input/mouse.hpp @@ -0,0 +1,68 @@ +//------------------------------------------------------------------------------ +// Project Phoenix +// +// Copyright (c) 2017-2018 RWTH Aachen University, Germany, +// Virtual Reality & Immersive Visualization Group. +//------------------------------------------------------------------------------ +// License +// +// Licensed under the 3-Clause BSD License (the "License"); +// you may not use this file except in compliance with the License. +// See the file LICENSE for the full text. +// You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//------------------------------------------------------------------------------ + +#ifndef LIBRARY_PHX_INPUT_MOUSE_HPP_ +#define LIBRARY_PHX_INPUT_MOUSE_HPP_ + +#include <memory> + +#define BOOST_BIND_NO_PLACEHOLDERS +// otherwise boosts _ placeholders conflict with trompeloeil ones +#include "boost/signals2/connection.hpp" +#include "boost/signals2/signal.hpp" + +#include "phx/input/sdl_device.hpp" +#include "phx/suppress_warnings.hpp" + +#include "phx/export.hpp" + +namespace phx { + +class PHOENIX_EXPORT Mouse : public SDLDevice { + public: + enum ButtonEvent { BUTTON_PRESSED, BUTTON_RELEASED }; + enum ButtonId { + LEFT_BUTTON = SDL_BUTTON_LEFT, + MIDDLE_BUTTON = SDL_BUTTON_MIDDLE, + RIGHT_BUTTON = SDL_BUTTON_RIGHT, + X1_BUTTON = SDL_BUTTON_X1, + X2_BUTTON = SDL_BUTTON_X2 + }; + + virtual ~Mouse() = default; + + void Update() override; + void OnSDLEvent(const SDL_Event& event) override; + + boost::signals2::connection RegisterButtonSignal( + const std::function<void(ButtonId, ButtonEvent)>& callback); + boost::signals2::connection RegisterMoveSignal( + const std::function<void(int, int)>& callback); + + private: + boost::signals2::signal<void(ButtonId, ButtonEvent)> button_signal_; + boost::signals2::signal<void(int, int)> move_signal_; +}; + +} // namespace phx + +#endif // LIBRARY_PHX_INPUT_MOUSE_HPP_ diff --git a/library/phx/setup.cpp b/library/phx/setup.cpp index 4169253e75d4abb6206ed974f45774c7ffe325a6..e15b52e2d225a041f34fb855349c4048e10ea4dc 100644 --- a/library/phx/setup.cpp +++ b/library/phx/setup.cpp @@ -37,7 +37,8 @@ #include "phx/display/display_system_openvr.hpp" #include "phx/display/display_system_window.hpp" #include "phx/display/hmd.hpp" -#include "phx/input/input_system.hpp" +#include "phx/input/keyboard.hpp" +#include "phx/input/mouse.hpp" #include "phx/input/openvr_controller_model_system.hpp" #include "phx/rendering/backend/render_target.hpp" #include "phx/rendering/render_passes/blit_pass.hpp" @@ -56,12 +57,14 @@ std::unique_ptr<Engine> Setup::CreateDefaultEngine(bool use_hmd_if_available) { engine->SetScene(std::make_shared<Scene>()); auto behavior_system = engine->CreateSystem<BehaviorSystem>(); - engine->CreateSystem<InputSystem>()->AddQuitCallback( - [engine_ptr]() { engine_ptr->Stop(); }); auto device_system = engine->CreateSystem<DeviceSystem>(); + device_system->AddDevice<Mouse>(); + device_system->AddDevice<Keyboard>(); auto displaysys_window = engine->CreateSystem<DisplaySystemWindow>(); + displaysys_window->AddQuitCallback([engine_ptr]() { engine_ptr->Stop(); }); + DisplaySystemOpenVR* displaysys_openVR = nullptr; bool using_hmd = false; diff --git a/tests/src/test_keyboard.cpp b/tests/src/test_keyboard.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bfb5f6e79411b0cb6f3245dcc5674d5aae954705 --- /dev/null +++ b/tests/src/test_keyboard.cpp @@ -0,0 +1,77 @@ +//------------------------------------------------------------------------------ +// Project Phoenix +// +// Copyright (c) 2017-2018 RWTH Aachen University, Germany, +// Virtual Reality & Immersive Visualization Group. +//------------------------------------------------------------------------------ +// License +// +// Licensed under the 3-Clause BSD License (the "License"); +// you may not use this file except in compliance with the License. +// See the file LICENSE for the full text. +// You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//------------------------------------------------------------------------------ + +#include <memory> + +#include "catch/catch.hpp" + +#include "phx/input/keyboard.hpp" + +#include "trompeloeil.hpp" + +#include "mocks/sdl_mock.hpp" + +using trompeloeil::_; +using trompeloeil::ne; + +extern template struct trompeloeil::reporter<trompeloeil::specialized>; + +SCENARIO("Keyboard signals received events.", "[phx][phx::Keyboard]") { + SDL_MOCK_ALLOW_ANY_CALL + GIVEN("A keyboard device.") { + phx::Keyboard keyboard; + + WHEN("a key stroke signal is registered") { + char received_character = ' '; + int received_modifiers = 0; + keyboard.RegisterKeySignal( + [&received_character, &received_modifiers]( + char character, phx::Keyboard::KeyEvent event, int modifiers) { + if (event == phx::Keyboard::KEY_PRESSED) { + received_character = character; + received_modifiers = modifiers; + } + }); + + WHEN("A keyboard event is fired by SDL.") { + SDL_Event key_event; + key_event.type = SDL_KEYDOWN; + key_event.key.keysym.sym = 'a'; + key_event.key.keysym.mod = (KMOD_LSHIFT | KMOD_LCTRL); + auto first_call = std::make_shared<bool>(true); + ALLOW_CALL(sdl_mock.Get(), SDL_PollEvent(_)) + .SIDE_EFFECT(*_1 = key_event) + .SIDE_EFFECT(*first_call = false) + .WITH(*first_call == true) + .RETURN(true); + ALLOW_CALL(sdl_mock.Get(), SDL_PollEvent(_)) + .WITH(*first_call == false) + .RETURN(false); + THEN("I should receive a signal.") { + keyboard.Update(); + REQUIRE(received_character == 'a'); + REQUIRE(received_modifiers == (KMOD_LSHIFT | KMOD_LCTRL)); + } + } + } + } +} diff --git a/tests/src/test_mouse.cpp b/tests/src/test_mouse.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b395803e58d310b301f9bb33e93d054e370543e8 --- /dev/null +++ b/tests/src/test_mouse.cpp @@ -0,0 +1,101 @@ +//------------------------------------------------------------------------------ +// Project Phoenix +// +// Copyright (c) 2017-2018 RWTH Aachen University, Germany, +// Virtual Reality & Immersive Visualization Group. +//------------------------------------------------------------------------------ +// License +// +// Licensed under the 3-Clause BSD License (the "License"); +// you may not use this file except in compliance with the License. +// See the file LICENSE for the full text. +// You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//------------------------------------------------------------------------------ + +#include <memory> + +#include "catch/catch.hpp" + +#include "phx/input/mouse.hpp" + +#include "trompeloeil.hpp" + +#include "mocks/sdl_mock.hpp" + +using trompeloeil::_; +using trompeloeil::ne; + +extern template struct trompeloeil::reporter<trompeloeil::specialized>; + +SCENARIO("Mouse signals received events.", "[phx][phx::Mouse]") { + SDL_MOCK_ALLOW_ANY_CALL + GIVEN("A mouse device.") { + phx::Mouse mouse; + + WHEN("a mouse button signal is registered") { + bool success = false; + mouse.RegisterButtonSignal( + [&success](phx::Mouse::ButtonId id, phx::Mouse::ButtonEvent event) { + if (id == phx::Mouse::LEFT_BUTTON && + event == phx::Mouse::BUTTON_PRESSED) + success = true; + }); + + WHEN("A mouse button event is fired by SDL.") { + SDL_Event mouse_event; + mouse_event.type = SDL_MOUSEBUTTONDOWN; + mouse_event.button.button = SDL_BUTTON_LEFT; + auto first_call = std::make_shared<bool>(true); + ALLOW_CALL(sdl_mock.Get(), SDL_PollEvent(_)) + .SIDE_EFFECT(*_1 = mouse_event) + .SIDE_EFFECT(*first_call = false) + .WITH(*first_call == true) + .RETURN(true); + ALLOW_CALL(sdl_mock.Get(), SDL_PollEvent(_)) + .WITH(*first_call == false) + .RETURN(false); + THEN("I should receive a signal.") { + mouse.Update(); + REQUIRE(success); + } + } + } + + WHEN("a mouse move signal is registered") { + int x_received = 0; + int y_received = 0; + mouse.RegisterMoveSignal([&x_received, &y_received](int x, int y) { + x_received = x; + y_received = y; + }); + WHEN("A mouse move event is fired by SDL.") { + SDL_Event mouse_event; + mouse_event.type = SDL_MOUSEMOTION; + mouse_event.motion.xrel = 100; + mouse_event.motion.yrel = 200; + auto first_call = std::make_shared<bool>(true); + ALLOW_CALL(sdl_mock.Get(), SDL_PollEvent(_)) + .SIDE_EFFECT(*_1 = mouse_event) + .SIDE_EFFECT(*first_call = false) + .WITH(*first_call == true) + .RETURN(true); + ALLOW_CALL(sdl_mock.Get(), SDL_PollEvent(_)) + .WITH(*first_call == false) + .RETURN(false); + THEN("I should receive a signal.") { + mouse.Update(); + REQUIRE(x_received == 100); + REQUIRE(y_received == 200); + } + } + } + } +}