Skip to content

Commit

Permalink
Pipe raw SDL events throught the GUI2 event system for hotkeys
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
aginor committed Apr 28, 2017
1 parent daef8cd commit c127e6f
Show file tree
Hide file tree
Showing 9 changed files with 154 additions and 48 deletions.
38 changes: 37 additions & 1 deletion src/gui/core/event/dispatcher.cpp
Expand Up @@ -96,7 +96,10 @@ bool dispatcher::has_event(const ui_event event, const event_queue_type event_ty
*this))
|| find<set_event_message>(event,
dispatcher_implementation::has_handler(
event_type, *this));
event_type, *this))
|| find<set_event_raw_event>(event,
dispatcher_implementation::has_handler(
event_type, *this));
}

/**
Expand Down Expand Up @@ -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<set_event_raw_event>(event, event_in_set()));
return fire_event<signal_raw_event_function>(
event,
dynamic_cast<widget*>(this),
&target,
trigger_raw_event(sdlevent));
}

/** Helper struct to wrap the functor call. */
class trigger_touch
{
Expand Down
83 changes: 73 additions & 10 deletions src/gui/core/event/dispatcher.hpp
Expand Up @@ -49,9 +49,9 @@ struct message;
*
* This function is used for the callbacks in set_event.
*/
typedef std::function<void(
dispatcher& dispatcher, const ui_event event, bool& handled, bool& halt)>
signal_function;
typedef std::function<void(dispatcher& dispatcher,
const ui_event event,
bool& handled, bool& halt)> signal_function;

/**
* Callback function signature.
Expand All @@ -75,8 +75,7 @@ typedef std::function<void(dispatcher& dispatcher,
bool& halt,
const SDL_Keycode key,
const SDL_Keymod modifier,
const utf8::string& unicode)>
signal_keyboard_function;
const utf8::string& unicode)> signal_keyboard_function;

/**
* Callback function signature.
Expand All @@ -88,8 +87,7 @@ typedef std::function<void(dispatcher& dispatcher,
bool& handled,
bool& halt,
const point& pos,
const point& distance)>
signal_touch_function;
const point& distance)> signal_touch_function;

/**
* Callback function signature.
Expand All @@ -115,6 +113,17 @@ typedef std::function<void(dispatcher& dispatcher,
bool& halt,
message& message)> signal_message_function;

/**
* Callback function signature.
*
* This function is used for the callbacks in set_event_message.
*/
typedef std::function<void(dispatcher& dispatcher,
const ui_event event,
bool& handled,
bool& halt,
const SDL_Event& sdlevent)> signal_raw_event_function;

/** Hotkey function handler signature. */
typedef std::function<bool(dispatcher& dispatcher,
hotkey::HOTKEY_COMMAND id)> thotkey_function;
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand All @@ -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.
Expand Down Expand Up @@ -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 <ui_event E>
typename std::enable_if<has_key<set_event_raw_event, E>::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 <ui_event E>
typename std::enable_if<has_key<set_event_raw_event, E>::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.
*
Expand Down Expand Up @@ -733,6 +793,9 @@ class dispatcher
/** Signal queue for callbacks in set_event_message. */
signal_queue<signal_message_function> signal_message_queue_;

/** Signal queue for callbacks in set_raw_event. */
signal_queue<signal_raw_event_function> signal_raw_event_queue_;

/** Are we connected to the event handler. */
bool connected_;

Expand Down
1 change: 1 addition & 0 deletions src/gui/core/event/dispatcher_private.hpp
Expand Up @@ -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
Expand Down
17 changes: 17 additions & 0 deletions src/gui/core/event/handler.cpp
Expand Up @@ -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);
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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<widget&>(*dispatcher), event);
}
}

void sdl_event_handler::mouse(const ui_event event, const point& position)
{
DBG_GUI_E << "Firing: " << event << ".\n";
Expand Down Expand Up @@ -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;
Expand Down
11 changes: 10 additions & 1 deletion src/gui/core/event/handler.hpp
Expand Up @@ -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. */
};

/**
Expand Down Expand Up @@ -213,6 +215,13 @@ typedef boost::mpl::set<boost::mpl::int_<MESSAGE_SHOW_TOOLTIP>,
boost::mpl::int_<REQUEST_PLACEMENT> >
set_event_message;

/**
* Helper for catching use error of dispatcher::connect_signal.
*
* This version is for callbacks of raw events.
*/
typedef boost::mpl::set<boost::mpl::int_<SDL_RAW_EVENT> > set_event_raw_event;

/**
* Connects a dispatcher to the event handler.
*
Expand Down
31 changes: 7 additions & 24 deletions src/gui/dialogs/hotkey_bind.cpp
Expand Up @@ -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<event::SDL_RAW_EVENT>(
std::bind(&hotkey_bind::sdl_event_callback, this, std::ref(window), _5),
event::dispatcher::front_child);

window.connect_signal<event::SDL_LEFT_BUTTON_DOWN>(
std::bind(&hotkey_bind::mouse_button_callback, this, std::ref(window), SDL_BUTTON_LEFT), event::dispatcher::front_child);
window.connect_signal<event::SDL_MIDDLE_BUTTON_DOWN>(
std::bind(&hotkey_bind::mouse_button_callback, this, std::ref(window), SDL_BUTTON_MIDDLE), event::dispatcher::front_child);
window.connect_signal<event::SDL_RIGHT_BUTTON_DOWN>(
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
4 changes: 1 addition & 3 deletions src/gui/dialogs/hotkey_bind.hpp
Expand Up @@ -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;
Expand Down
4 changes: 2 additions & 2 deletions src/hotkey/hotkey_item.cpp
Expand Up @@ -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();
Expand Down Expand Up @@ -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<std::string> names;
Expand Down
13 changes: 6 additions & 7 deletions src/hotkey/hotkey_item.hpp
Expand Up @@ -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
Expand Down Expand Up @@ -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);

}
Expand Down

0 comments on commit c127e6f

Please sign in to comment.