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.
This commit is contained in:
Andreas Löf 2017-04-28 21:18:25 +12:00
parent daef8cd22c
commit 46f16e1a8a
9 changed files with 155 additions and 49 deletions

View file

@ -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));
}
/**
@ -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
{

View file

@ -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.
@ -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.
@ -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.
@ -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;
@ -185,7 +194,9 @@ public:
* @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 @@ public:
* @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 @@ public:
* (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 @@ public:
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.
*
@ -733,6 +793,9 @@ private:
/** 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_;

View file

@ -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

View file

@ -164,6 +164,9 @@ private:
/***** 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<widget&>(*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;

View file

@ -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_<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.
*

View file

@ -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

View file

@ -41,9 +41,7 @@ private:
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;

View file

@ -1,5 +1,5 @@
/*
Copyright (C) 2003 - 2016 by David White <dave@whitevine.net>
Copyright (C) 2003 - 2017 by David White <dave@whitevine.net>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
@ -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<std::string> names;

View file

@ -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);
}