From 8092b38691ca7afe94d450010fb155ce0440637d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20L=C3=B6f?= Date: Fri, 28 Apr 2017 21:18:25 +1200 Subject: [PATCH] Pipe raw SDL events throught the GUI2 event system for hotkeys This adds support for passing raw SDL events throught the GUI2 event system in order to allow for hotkey creation in the GUI2 hotkey dialog. The dialog in turn uses the raw SDL event to query the hotkey subsystem whether it's a suitable event to create a hotkey from or not. The first suitable event is used to create a hotkey. --- src/gui/core/event/dispatcher.cpp | 38 ++++++++++- src/gui/core/event/dispatcher.hpp | 83 ++++++++++++++++++++--- src/gui/core/event/dispatcher_private.hpp | 1 + src/gui/core/event/handler.cpp | 17 +++++ src/gui/core/event/handler.hpp | 11 ++- src/gui/dialogs/hotkey_bind.cpp | 31 ++------- src/gui/dialogs/hotkey_bind.hpp | 4 +- src/hotkey/hotkey_item.cpp | 4 +- src/hotkey/hotkey_item.hpp | 13 ++-- 9 files changed, 154 insertions(+), 48 deletions(-) diff --git a/src/gui/core/event/dispatcher.cpp b/src/gui/core/event/dispatcher.cpp index 6335256213ceb..8dde246214bf6 100644 --- a/src/gui/core/event/dispatcher.cpp +++ b/src/gui/core/event/dispatcher.cpp @@ -96,7 +96,10 @@ bool dispatcher::has_event(const ui_event event, const event_queue_type event_ty *this)) || find(event, dispatcher_implementation::has_handler( - event_type, *this)); + event_type, *this)) + || find(event, + dispatcher_implementation::has_handler( + event_type, *this)); } /** @@ -250,6 +253,39 @@ bool dispatcher::fire(const ui_event event, trigger_keyboard(key, modifier, unicode)); } +/** Helper struct to wrap the functor call. */ +class trigger_raw_event +{ +public: + trigger_raw_event(const SDL_Event& sdlevent) : sdl_event_(sdlevent) + { + } + + void operator()(signal_raw_event_function functor, + dispatcher& dispatcher, + const ui_event event, + bool& handled, + bool& halt) + { + functor(dispatcher, event, handled, halt, sdl_event_); + } + +private: + const SDL_Event& sdl_event_; +}; + +bool dispatcher::fire(const ui_event event, + widget& target, + const SDL_Event& sdlevent) +{ + assert(find(event, event_in_set())); + return fire_event( + event, + dynamic_cast(this), + &target, + trigger_raw_event(sdlevent)); +} + /** Helper struct to wrap the functor call. */ class trigger_touch { diff --git a/src/gui/core/event/dispatcher.hpp b/src/gui/core/event/dispatcher.hpp index 6ce0b330da153..61963f7c8fcb2 100644 --- a/src/gui/core/event/dispatcher.hpp +++ b/src/gui/core/event/dispatcher.hpp @@ -49,9 +49,9 @@ struct message; * * This function is used for the callbacks in set_event. */ -typedef std::function -signal_function; +typedef std::function signal_function; /** * Callback function signature. @@ -75,8 +75,7 @@ typedef std::function -signal_keyboard_function; + const utf8::string& unicode)> signal_keyboard_function; /** * Callback function signature. @@ -88,8 +87,7 @@ typedef std::function -signal_touch_function; + const point& distance)> signal_touch_function; /** * Callback function signature. @@ -115,6 +113,17 @@ typedef std::function signal_message_function; + /** + * Callback function signature. + * + * This function is used for the callbacks in set_event_message. + */ +typedef std::function signal_raw_event_function; + /** Hotkey function handler signature. */ typedef std::function thotkey_function; @@ -185,7 +194,9 @@ class dispatcher * @param target The widget that should receive the event. * @param coordinate The mouse position for the event. */ - bool fire(const ui_event event, widget& target, const point& coordinate); + bool fire(const ui_event event, + widget& target, + const point& coordinate); /** * Fires an event which takes keyboard parameters. @@ -223,7 +234,9 @@ class dispatcher * @param event The event to fire. * @param target The widget that should receive the event. */ - bool fire(const ui_event event, widget& target, void*); + bool fire(const ui_event event, + widget& target, + void*); /** * Fires an event which takes message parameters. @@ -236,7 +249,21 @@ class dispatcher * (or another widget in the chain) to handle * the message. */ - bool fire(const ui_event event, widget& target, message& msg); + bool fire(const ui_event event, + widget& target, + message& msg); + + /** + * Fires an event that's a raw SDL event + * @param event The event to fire. + * @param target The widget that should receive the event. + * Normally this is the window holding the + * widget. + * @param sdlevent The raw SDL event + */ + bool fire(const ui_event event, + widget& target, + const SDL_Event& sdlevent); /** * The position where to add a new callback in the signal handler. @@ -507,6 +534,39 @@ class dispatcher signal_message_queue_.disconnect_signal(E, position, signal); } + /** + * Connect a signal for callback in set_raw_event. + * + * @tparam E The event the callback needs to react to. + * @param signal The callback function. + * @param position The position to place the callback. + */ + template + typename std::enable_if::value>::type + connect_signal(const signal_raw_event_function& signal, + const queue_position position = back_child) + { + signal_raw_event_queue_.connect_signal(E, position, signal); + } + + /** + * Disconnect a signal for callback in set_raw_event. + * + * @tparam E The event the callback was used for. + * @param signal The callback function. + * @param position The place where the function was added. + * Needed remove the event from the right + * place. (The function doesn't care whether + * was added in front or back.) + */ + template + typename std::enable_if::value>::type + disconnect_signal(const signal_raw_event_function& signal, + const queue_position position = back_child) + { + signal_raw_event_queue_.disconnect_signal(E, position, signal); + } + /** * The behavior of the mouse events. * @@ -733,6 +793,9 @@ class dispatcher /** Signal queue for callbacks in set_event_message. */ signal_queue signal_message_queue_; + /** Signal queue for callbacks in set_raw_event. */ + signal_queue signal_raw_event_queue_; + /** Are we connected to the event handler. */ bool connected_; diff --git a/src/gui/core/event/dispatcher_private.hpp b/src/gui/core/event/dispatcher_private.hpp index 94683decb3c5b..6563cfb8efb89 100644 --- a/src/gui/core/event/dispatcher_private.hpp +++ b/src/gui/core/event/dispatcher_private.hpp @@ -110,6 +110,7 @@ struct dispatcher_implementation IMPLEMENT_EVENT_SIGNAL_WRAPPER(touch) IMPLEMENT_EVENT_SIGNAL_WRAPPER(notification) IMPLEMENT_EVENT_SIGNAL_WRAPPER(message) + IMPLEMENT_EVENT_SIGNAL_WRAPPER(raw_event) #undef IMPLEMENT_EVENT_SIGNAL_WRAPPER #undef IMPLEMENT_EVENT_SIGNAL diff --git a/src/gui/core/event/handler.cpp b/src/gui/core/event/handler.cpp index 31bd56bf8ffe1..35c538977c71c 100644 --- a/src/gui/core/event/handler.cpp +++ b/src/gui/core/event/handler.cpp @@ -164,6 +164,9 @@ class sdl_event_handler : public events::sdl_handler /***** Handlers *****/ + /** Fires a raw SDL event. */ + void raw_event(const SDL_Event &event); + /** Fires a draw event. */ using events::sdl_handler::draw; void draw(const bool force); @@ -445,6 +448,8 @@ void sdl_event_handler::handle_event(const SDL_Event& event) #endif break; } + + raw_event(event); } void sdl_event_handler::handle_window_event(const SDL_Event& event) @@ -559,6 +564,15 @@ void sdl_event_handler::video_resize(const point& new_size) } } +void sdl_event_handler::raw_event(const SDL_Event& event) { + DBG_GUI_E << "Firing raw event\n"; + + for(auto dispatcher : dispatchers_) + { + dispatcher->fire(SDL_RAW_EVENT, dynamic_cast(*dispatcher), event); + } +} + void sdl_event_handler::mouse(const ui_event event, const point& position) { DBG_GUI_E << "Firing: " << event << ".\n"; @@ -961,6 +975,9 @@ std::ostream& operator<<(std::ostream& stream, const ui_event event) case SDL_TOUCH_DOWN: stream << "SDL touch down"; break; + case SDL_RAW_EVENT: + stream << "SDL raw event"; + break; } return stream; diff --git a/src/gui/core/event/handler.hpp b/src/gui/core/event/handler.hpp index ee57d762eddaf..8dc8dffc89f5c 100644 --- a/src/gui/core/event/handler.hpp +++ b/src/gui/core/event/handler.hpp @@ -113,7 +113,9 @@ enum ui_event { SDL_TOUCH_MOTION, SDL_TOUCH_UP, - SDL_TOUCH_DOWN + SDL_TOUCH_DOWN, + + SDL_RAW_EVENT /**< Raw SDL event. */ }; /** @@ -213,6 +215,13 @@ typedef boost::mpl::set, boost::mpl::int_ > set_event_message; +/** + * Helper for catching use error of dispatcher::connect_signal. + * + * This version is for callbacks of raw events. + */ +typedef boost::mpl::set > set_event_raw_event; + /** * Connects a dispatcher to the event handler. * diff --git a/src/gui/dialogs/hotkey_bind.cpp b/src/gui/dialogs/hotkey_bind.cpp index 2006ca7e6f001..74156a32a005f 100644 --- a/src/gui/dialogs/hotkey_bind.cpp +++ b/src/gui/dialogs/hotkey_bind.cpp @@ -36,37 +36,20 @@ hotkey_bind::hotkey_bind(const std::string& hotkey_id) void hotkey_bind::pre_show(window& window) { - connect_signal_pre_key_press(window, std::bind(&hotkey_bind::key_press_callback, this, std::ref(window), _5)); + window.connect_signal( + std::bind(&hotkey_bind::sdl_event_callback, this, std::ref(window), _5), + event::dispatcher::front_child); - window.connect_signal( - std::bind(&hotkey_bind::mouse_button_callback, this, std::ref(window), SDL_BUTTON_LEFT), event::dispatcher::front_child); - window.connect_signal( - std::bind(&hotkey_bind::mouse_button_callback, this, std::ref(window), SDL_BUTTON_MIDDLE), event::dispatcher::front_child); - window.connect_signal( - std::bind(&hotkey_bind::mouse_button_callback, this, std::ref(window), SDL_BUTTON_RIGHT), event::dispatcher::front_child); } -void hotkey_bind::key_press_callback(window& window, const SDL_Keycode key) +void hotkey_bind::sdl_event_callback(window& win, const SDL_Event &event) { - /* HACK: SDL_KEYDOWN and SDL_TEXTINPUT events forward to the same GUI2 event (SDL_KEY_DOWN), meaning - * this even gets fired twice, causing problems since 'key' will be 0 in the latter case. SDLK_UNKNOWN - * is the key value used by SDL_TEXTINPUT handling, so exit here if that's detected. - */ - if(key == SDLK_UNKNOWN) { - return; + if (hotkey::is_hotkeyable_event(event)) { + new_binding_ = hotkey::create_hotkey(hotkey_id_, event); + win.set_retval(window::OK); } - - new_binding_ = hotkey::create_hotkey(hotkey_id_, SDL_GetScancodeFromKey(key)); - - window.set_retval(window::OK); } -void hotkey_bind::mouse_button_callback(window& window, Uint8 button) -{ - new_binding_ = hotkey::create_hotkey(hotkey_id_, button); - - window.set_retval(window::OK); -} } // namespace dialogs } // namespace gui2 diff --git a/src/gui/dialogs/hotkey_bind.hpp b/src/gui/dialogs/hotkey_bind.hpp index 12a3bb05de9b5..c555cef314cdd 100644 --- a/src/gui/dialogs/hotkey_bind.hpp +++ b/src/gui/dialogs/hotkey_bind.hpp @@ -41,9 +41,7 @@ class hotkey_bind : public modal_dialog hotkey::hotkey_ptr new_binding_; - void key_press_callback(window& window, const SDL_Keycode key); - - void mouse_button_callback(window& window, Uint8 button); + void sdl_event_callback(window& win, const SDL_Event &event); /** Inherited from modal_dialog, implemented by REGISTER_DIALOG. */ virtual const std::string& window_id() const override; diff --git a/src/hotkey/hotkey_item.cpp b/src/hotkey/hotkey_item.cpp index d5cb484ecbe49..2bffc9a9c6a91 100644 --- a/src/hotkey/hotkey_item.cpp +++ b/src/hotkey/hotkey_item.cpp @@ -143,7 +143,7 @@ void hotkey_base::save(config& item) const save_helper(item); } -hotkey_ptr create_hotkey(const std::string &id, SDL_Event &event) +hotkey_ptr create_hotkey(const std::string &id, const SDL_Event &event) { hotkey_ptr base = hotkey_ptr(new hotkey_void); unsigned mods = sdl_get_mods(); @@ -450,7 +450,7 @@ void save_hotkeys(config& cfg) } } -std::string get_names(std::string id) +std::string get_names(const std::string& id) { // Names are used in places like the hot-key preferences menu std::vector names; diff --git a/src/hotkey/hotkey_item.hpp b/src/hotkey/hotkey_item.hpp index 47ae38e536575..a2114f34497c5 100644 --- a/src/hotkey/hotkey_item.hpp +++ b/src/hotkey/hotkey_item.hpp @@ -379,11 +379,12 @@ void add_hotkey(const hotkey_ptr item); */ void del_hotkey(const hotkey_ptr item); -/** Create a new hotkey item bound to a keyboard key. */ -hotkey_ptr create_hotkey(const std::string& id, SDL_Scancode new_val); - -/** Create a new hotkey item bound to a mouse button. */ -hotkey_ptr create_hotkey(const std::string& id, Uint8 new_val); +/** + * Create a new hotkey item for a command from an SDL_Event. + * @param id The command to bind to. + * @param event The SDL_Event to base the creation on. + */ +hotkey_ptr create_hotkey(const std::string &id, const SDL_Event &event); /** * Iterate through the list of hotkeys and return a hotkey that matches @@ -437,8 +438,6 @@ std::string get_names(const std::string& id); */ void save_hotkeys(config& cfg); -hotkey_ptr show_binding_dialog(CVideo& video, const std::string& id); - bool is_hotkeyable_event(const SDL_Event &event); }