Merge pull request #466 from aginor/hotkeyrewrite

This reworks the hotkey system to rely on scancodes.
This commit is contained in:
Andreas Löf 2015-09-06 20:49:32 +12:00
commit 91cd168ec8
14 changed files with 1834 additions and 691 deletions

View file

@ -66,7 +66,7 @@
[/hotkey]
[hotkey]
command=command
key=:
key=;
[/hotkey]
[hotkey]
command=continue
@ -92,11 +92,11 @@
[/hotkey]
[hotkey]
command=endunitturn
key=" "
key="space"
[/hotkey]
[hotkey]
command=endturn
key=" "
key="space"
#ifdef APPLE
alt=yes
#else
@ -114,7 +114,7 @@
[/hotkey]
[hotkey]
command=holdposition
key=" "
key="space"
shift=yes
[/hotkey]
[hotkey]
@ -262,7 +262,7 @@
[/hotkey]
[hotkey]
command=zoomin
key="+"
key="="
[/hotkey]
[hotkey]
command=zoomout
@ -293,11 +293,11 @@
[/hotkey]
[hotkey]
command=wbbumpupaction
key="page up"
key="PageUp"
[/hotkey]
[hotkey]
command=wbbumpdownaction
key="page down"
key="PageDown"
[/hotkey]
[hotkey]
command=wbsupposedead

View file

@ -443,6 +443,7 @@ set(wesnoth-sdl_SRC
sdl/window.cpp
sdl/utils.cpp
sdl/shader.cpp
sdl/keyboard.cpp
xBRZ/xbrz.cpp
)

View file

@ -167,6 +167,7 @@ libwesnoth_sdl_sources = Split("""
sdl/exception.cpp
sdl/rect.cpp
sdl/image.cpp
sdl/keyboard.cpp
sdl/window.cpp
tracer.cpp
xBRZ/xbrz.cpp

View file

@ -56,7 +56,7 @@ void controller_base::handle_event(const SDL_Event& event)
// in which case the key press events should go only to it.
if(have_keyboard_focus()) {
process_keydown_event(event);
hotkey::key_event(get_display(), event.key, get_hotkey_command_executor());
hotkey::key_event(get_display(), event, get_hotkey_command_executor());
} else {
process_focus_keydown_event(event);
break;
@ -67,11 +67,11 @@ void controller_base::handle_event(const SDL_Event& event)
break;
case SDL_JOYBUTTONDOWN:
process_keydown_event(event);
hotkey::jbutton_event(get_display(), event.jbutton, get_hotkey_command_executor());
hotkey::jbutton_event(get_display(), event, get_hotkey_command_executor());
break;
case SDL_JOYHATMOTION:
process_keydown_event(event);
hotkey::jhat_event(get_display(), event.jhat, get_hotkey_command_executor());
hotkey::jhat_event(get_display(), event, get_hotkey_command_executor());
break;
case SDL_MOUSEMOTION:
// Ignore old mouse motion events in the event queue
@ -91,7 +91,7 @@ void controller_base::handle_event(const SDL_Event& event)
if (get_mouse_handler_base().get_show_menu()){
show_menu(get_display().get_theme().context_menu()->items(),event.button.x,event.button.y,true, get_display());
}
hotkey::mbutton_event(get_display(), event.button, get_hotkey_command_executor());
hotkey::mbutton_event(get_display(), event, get_hotkey_command_executor());
break;
case SDL_MOUSEBUTTONUP:
get_mouse_handler_base().mouse_press(event.button, is_browsing());

View file

@ -220,7 +220,7 @@ private:
*
* @param event The SDL joystick hat event triggered.
*/
void hat_motion(const SDL_JoyHatEvent& event);
void hat_motion(const SDL_Event& event);
/**
@ -228,7 +228,7 @@ private:
*
* @param event The SDL joystick button event triggered.
*/
void button_down(const SDL_JoyButtonEvent& event);
void button_down(const SDL_Event& event);
/**
@ -236,7 +236,7 @@ private:
*
* @param event The SDL keyboard event triggered.
*/
void key_down(const SDL_KeyboardEvent& event);
void key_down(const SDL_Event& event);
/**
* Handles the pressing of a hotkey.
@ -245,7 +245,7 @@ private:
*
* @returns True if the hotkey is handled false otherwise.
*/
bool hotkey_pressed(const hotkey::hotkey_item& key);
bool hotkey_pressed(const hotkey::hotkey_ptr key);
/**
* Fires a key down event.
@ -372,7 +372,7 @@ void thandler::handle_event(const SDL_Event& event)
} break;
case SDL_JOYBUTTONDOWN:
button_down(event.jbutton);
button_down(event);
break;
case SDL_JOYBUTTONUP:
@ -382,11 +382,11 @@ void thandler::handle_event(const SDL_Event& event)
break;
case SDL_JOYHATMOTION:
hat_motion(event.jhat);
hat_motion(event);
break;
case SDL_KEYDOWN:
key_down(event.key);
key_down(event);
break;
#if SDL_VERSION_ATLEAST(2, 0, 0)
@ -689,11 +689,11 @@ tdispatcher* thandler::keyboard_dispatcher()
return NULL;
}
void thandler::hat_motion(const SDL_JoyHatEvent& event)
void thandler::hat_motion(const SDL_Event& event)
{
const hotkey::hotkey_item& hk = hotkey::get_hotkey(event);
const hotkey::hotkey_ptr& hk = hotkey::get_hotkey(event);
bool done = false;
if(!hk.null()) {
if(!hk->null()) {
done = hotkey_pressed(hk);
}
if(!done) {
@ -702,11 +702,11 @@ void thandler::hat_motion(const SDL_JoyHatEvent& event)
}
}
void thandler::button_down(const SDL_JoyButtonEvent& event)
void thandler::button_down(const SDL_Event& event)
{
const hotkey::hotkey_item& hk = hotkey::get_hotkey(event);
const hotkey::hotkey_ptr hk = hotkey::get_hotkey(event);
bool done = false;
if(!hk.null()) {
if(!hk->null()) {
done = hotkey_pressed(hk);
}
if(!done) {
@ -715,22 +715,22 @@ void thandler::button_down(const SDL_JoyButtonEvent& event)
}
}
void thandler::key_down(const SDL_KeyboardEvent& event)
void thandler::key_down(const SDL_Event& event)
{
const hotkey::hotkey_item& hk = hotkey::get_hotkey(event);
const hotkey::hotkey_ptr hk = hotkey::get_hotkey(event);
bool done = false;
if(!hk.null()) {
if(!hk->null()) {
done = hotkey_pressed(hk);
}
if(!done) {
#if SDL_VERSION_ATLEAST(2, 0, 0)
key_down(event.keysym.sym,
static_cast<const SDL_Keymod>(event.keysym.mod),
key_down(event.key.keysym.sym,
static_cast<const SDL_Keymod>(event.key.keysym.mod),
"");
#else
key_down(event.keysym.sym,
event.keysym.mod,
unicode_cast<std::string>(static_cast<ucs4::char_t>(event.keysym.unicode)));
key_down(event.key.keysym.sym,
event.key.keysym.mod,
unicode_cast<std::string>(static_cast<ucs4::char_t>(event.key.keysym.unicode)));
#endif
}
}
@ -740,7 +740,7 @@ void thandler::text_input(const std::string& unicode)
key_down(static_cast<SDLKey>(0), static_cast<SDLMod>(0), unicode);
}
bool thandler::hotkey_pressed(const hotkey::hotkey_item& key)
bool thandler::hotkey_pressed(const hotkey::hotkey_ptr key)
{
tdispatcher* dispatcher = keyboard_dispatcher();
@ -748,7 +748,7 @@ bool thandler::hotkey_pressed(const hotkey::hotkey_item& key)
return false;
}
return dispatcher->execute_hotkey(hotkey::get_id(key.get_command()));
return dispatcher->execute_hotkey(hotkey::get_id(key->get_command()));
}
void thandler::key_down(const SDLKey key,

View file

@ -43,10 +43,7 @@ static lg::log_domain log_config("config");
namespace hotkey {
static void key_event_execute(display& disp, const SDL_KeyboardEvent& event, command_executor* executor);
static void jbutton_event_execute(display& disp, const SDL_JoyButtonEvent& event, command_executor* executor);
static void jhat_event_execute(display& disp, const SDL_JoyHatEvent& event, command_executor* executor);
static void mbutton_event_execute(display& disp, const SDL_MouseButtonEvent& event, command_executor* executor);
static void event_execute(display& disp, const SDL_Event& event, command_executor* executor);
bool command_executor::execute_command(const hotkey_command& cmd, int /*index*/)
{
@ -480,47 +477,47 @@ void basic_handler::handle_event(const SDL_Event& event)
// handled by the executor.
// If we're not in a dialog we can call the regular key event handler.
if (!gui::in_dialog()) {
key_event(*disp_, event.key,exec_);
key_event(*disp_, event,exec_);
} else if (exec_ != NULL) {
key_event_execute(*disp_, event.key,exec_);
event_execute(*disp_, event,exec_);
}
break;
case SDL_JOYBUTTONDOWN:
if (!gui::in_dialog()) {
jbutton_event(*disp_, event.jbutton,exec_);
jbutton_event(*disp_, event,exec_);
} else if (exec_ != NULL) {
jbutton_event_execute(*disp_, event.jbutton,exec_);
event_execute(*disp_, event,exec_);
}
break;
case SDL_MOUSEBUTTONDOWN:
if (!gui::in_dialog()) {
mbutton_event(*disp_, event.button,exec_);
mbutton_event(*disp_, event,exec_);
} else if (exec_ != NULL) {
mbutton_event_execute(*disp_, event.button,exec_);
event_execute(*disp_, event,exec_);
}
break;
}
}
void mbutton_event(display& disp, const SDL_MouseButtonEvent& event, command_executor* executor)
void mbutton_event(display& disp, const SDL_Event& event, command_executor* executor)
{
mbutton_event_execute(disp, event, executor);
event_execute(disp, event, executor);
}
void jbutton_event(display& disp, const SDL_JoyButtonEvent& event, command_executor* executor)
void jbutton_event(display& disp, const SDL_Event& event, command_executor* executor)
{
jbutton_event_execute(disp, event, executor);
event_execute(disp, event, executor);
}
void jhat_event(display& disp, const SDL_JoyHatEvent& event, command_executor* executor)
void jhat_event(display& disp, const SDL_Event& event, command_executor* executor)
{
jhat_event_execute(disp, event, executor);
event_execute(disp, event, executor);
}
void key_event(display& disp, const SDL_KeyboardEvent& event, command_executor* executor)
void key_event(display& disp, const SDL_Event& event, command_executor* executor)
{
if (!executor) return;
if(event.keysym.sym == SDLK_ESCAPE && disp.in_game()) {
if(event.key.keysym.sym == SDLK_ESCAPE && disp.in_game()) {
LOG_G << "escape pressed..showing quit\n";
const int res = gui2::show_message(disp.video(), _("Quit"),
_("Do you really want to quit?"), gui2::tmessage::yes_no_buttons);
@ -531,13 +528,13 @@ void key_event(display& disp, const SDL_KeyboardEvent& event, command_executor*
}
}
key_event_execute(disp, event,executor);
event_execute(disp, event,executor);
}
void mbutton_event_execute(display& disp, const SDL_MouseButtonEvent& event, command_executor* executor)
static void event_execute(display& disp, const SDL_Event& event, command_executor* executor)
{
if (!executor) return;
const hotkey_item* hk = &get_hotkey(event);
const hotkey_ptr hk = get_hotkey(event);
if (!hk->active()) {
return;
}
@ -546,52 +543,6 @@ void mbutton_event_execute(display& disp, const SDL_MouseButtonEvent& event, com
executor->set_button_state(disp);
}
void jbutton_event_execute(display& disp, const SDL_JoyButtonEvent& event, command_executor* executor)
{
if (!executor) return;
const hotkey_item* hk = &get_hotkey(event);
if (!hk->active()) {
return;
}
execute_command(disp, get_hotkey_command(hk->get_command()), executor);
executor->set_button_state(disp);
}
void jhat_event_execute(display& disp, const SDL_JoyHatEvent& event, command_executor* executor)
{
if (!executor) return;
const hotkey_item* hk = &get_hotkey(event);
if (!hk->active()) {
return;
}
execute_command(disp, get_hotkey_command(hk->get_command()), executor);
executor->set_button_state(disp);
}
void key_event_execute(display& disp, const SDL_KeyboardEvent& event, command_executor* executor)
{
if (!executor) return;
const hotkey_item* hk = &get_hotkey(event);
#if 0
// This is not generally possible without knowing keyboard layout.
if (hk->null()) {
//no matching hotkey was found, but try an in-exact match.
hk = &get_hotkey(event, true);
}
#endif
if (!hk->active()) {
return;
}
execute_command(disp, get_hotkey_command(hk->get_command()), executor);
executor->set_button_state(disp);
}
void execute_command(display& disp, const hotkey_command& command, command_executor* executor, int index)
{
const int zoom_amount = 4;

View file

@ -133,10 +133,11 @@ public:
* Also handles some events in the function itself,
* and so is still meaningful to call with executor=NULL
*/
void jbutton_event(display& disp, const SDL_JoyButtonEvent& event, command_executor* executor);
void jhat_event(display& disp, const SDL_JoyHatEvent& event, command_executor* executor);
void key_event(display& disp, const SDL_KeyboardEvent& event, command_executor* executor);
void mbutton_event(display& disp, const SDL_MouseButtonEvent& event, command_executor* executor);
void jbutton_event(display& disp, const SDL_Event& event, command_executor* executor);
void jhat_event(display& disp, const SDL_Event& event, command_executor* executor);
void key_event(display& disp, const SDL_Event& event, command_executor* executor);
void mbutton_event(display& disp, const SDL_Event& event, command_executor* executor);
//TODO
void execute_command(display& disp, const hotkey_command& command, command_executor* executor, int index=-1);

View file

@ -389,9 +389,9 @@ void add_wml_hotkey(const std::string& id, const t_string& description, const co
if(!default_hotkey.empty() && !has_hotkey_item(id))
{
hotkey_item new_item(default_hotkey, true);
new_item.set_command(id);
if(new_item.valid())
hotkey::hotkey_ptr new_item = hotkey::load_from_config(default_hotkey);
new_item->set_command(id);
if(new_item->valid())
{
DBG_G << "added default description for the wml hotkey with id=" + id;
add_hotkey(new_item);

View file

@ -12,6 +12,7 @@
See the COPYING file for more details.
*/
#include "log.hpp"
#include "hotkey_item.hpp"
#include "hotkey_command.hpp"
@ -24,243 +25,384 @@
#include <boost/foreach.hpp>
#include <boost/algorithm/string/join.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/bind.hpp>
#include "key.hpp"
#include "SDL.h"
#if !SDL_VERSION_ATLEAST(2,0,0)
#include "sdl/keyboard.hpp"
#endif
static lg::log_domain log_config("config");
#define ERR_G LOG_STREAM(err, lg::general)
#define LOG_G LOG_STREAM(info, lg::general)
#define DBG_G LOG_STREAM(debug, lg::general)
#define ERR_CF LOG_STREAM(err, log_config)
namespace {
std::vector<hotkey::hotkey_item> hotkeys_;
config default_hotkey_cfg_;
hotkey::hotkey_item null_hotkey_("null");
hotkey::hotkey_item& get_hotkey(int mouse, int joystick, int button, int hat, int value,
bool shift, bool ctrl, bool cmd, bool alt)
{
std::vector<hotkey::hotkey_item>::iterator itor;
for (itor = hotkeys_.begin(); itor != hotkeys_.end(); ++itor) {
if ( !( hotkey::is_scope_active(hotkey::get_hotkey_command(itor->get_command()).scope) && itor->active() ) ) {
continue;
}
if ( itor->get_shift() != shift || itor->get_ctrl() != ctrl
|| itor->get_cmd() != cmd || itor->get_alt() != alt ) {
continue;
}
if ( itor->get_joystick() == joystick && itor->get_button() == button
&& itor->get_hat() == hat && itor->get_value() == value
&& itor->get_mouse() == mouse ) {
return *itor;
}
}
return null_hotkey_;
}
hotkey::hotkey_item& get_hotkey(int character, int keycode,
bool shift, bool ctrl, bool cmd, bool alt)
{
std::vector<hotkey::hotkey_item>::iterator itor;
DBG_G << "getting hotkey: char=" << lexical_cast<std::string>(character)
<< " keycode=" << lexical_cast<std::string>(keycode) << " "
<< (shift ? "shift," : "")
<< (ctrl ? "ctrl," : "")
<< (cmd ? "cmd," : "")
<< (alt ? "alt," : "")
<< "\n";
// Sometimes control modifies by -64, ie ^A == 1.
if (0 < character && character < 64 && ctrl) {
if (shift) {
character += 64;
} else {
character += 96;
}
/// @todo
DBG_G << "Mapped to character " << lexical_cast<std::string>(character) << "\n";
}
// For some reason on Mac OS, if cmd and shift are down, the character doesn't get upper-cased
if (cmd && character > 96 && character < 123 && shift) {
character -= 32; }
bool found = false;
for (itor = hotkeys_.begin(); itor != hotkeys_.end(); ++itor) {
// Special case for Ctrl+Return/Enter keys, which gets resolved to Ctrl-j and Ctrl-m characters (LF and CR respectively).
// In such cases, do not match by character but go straight to key code.
if (itor->get_character() != -1 &&
!(tolower(character) == 'j' && keycode != SDLK_j) &&
!(tolower(character) == 'm' && keycode != SDLK_m)) {
if (character == itor->get_character()) {
if (ctrl == itor->get_ctrl()
&& cmd == itor->get_cmd()
&& alt == itor->get_alt()) {
if (hotkey::is_scope_active(hotkey::get_hotkey_command(itor->get_command()).scope) && itor->active()) {
DBG_G << "Could match by character..." << "yes\n";
found = true;
break;
} else {
DBG_G << "Could match by character..." << "yes, but scope is inactive\n";
}
}
DBG_G << "Could match by character..." << "but modifiers different\n";
}
} else if (itor->get_keycode() != -1) {
if (keycode == itor->get_keycode()) {
if (shift == itor->get_shift()
&& ctrl == itor->get_ctrl()
&& cmd == itor->get_cmd()
&& alt == itor->get_alt()) {
if (hotkey::is_scope_active(hotkey::get_hotkey_command(itor->get_command()).scope) && itor->active()) {
DBG_G << "Could match by keycode..." << "yes\n";
found = true;
break;
} else {
DBG_G << "Could match by keycode..." << "yes, but scope is inactive\n";
}
}
DBG_G << "Could match by keycode..." << "but modifiers different\n";
}
}
if (found) { break; }
}
if (!found) {
return null_hotkey_; }
return *itor;
}
}
namespace hotkey {
hotkey_list hotkeys_;
config default_hotkey_cfg_;
const hotkey_item& get_hotkey(const SDL_JoyButtonEvent& event)
static unsigned int sdl_get_mods()
{
CKey keystate;
bool shift = keystate[SDLK_RSHIFT] || keystate[SDLK_LSHIFT];
bool ctrl = keystate[SDLK_RCTRL] || keystate[SDLK_LCTRL];
bool cmd = keystate[SDLK_RMETA] || keystate[SDLK_LMETA];
bool alt = keystate[SDLK_RALT] || keystate[SDLK_LALT];
unsigned int mods;
mods = SDL_GetModState();
return get_hotkey(-1, event.which, event.button, -1, -1, shift, ctrl, cmd, alt);
}
mods &= ~KMOD_NUM;
mods &= ~KMOD_CAPS;
mods &= ~KMOD_MODE;
const hotkey_item& get_hotkey(const SDL_JoyHatEvent& event)
{
CKey keystate;
bool shift = keystate[SDLK_RSHIFT] || keystate[SDLK_LSHIFT];
bool ctrl = keystate[SDLK_RCTRL] || keystate[SDLK_LCTRL];
bool cmd = keystate[SDLK_RMETA] || keystate[SDLK_LMETA];
bool alt = keystate[SDLK_RALT] || keystate[SDLK_LALT];
// save the matching for checking right vs left keys
if (mods & KMOD_SHIFT)
mods |= KMOD_SHIFT;
return get_hotkey(-1, event.which, -1, event.hat, event.value, shift, ctrl, cmd, alt);
}
if (mods & KMOD_CTRL)
mods |= KMOD_CTRL;
if (mods & KMOD_ALT)
mods |= KMOD_ALT;
const hotkey_item& get_hotkey(const SDL_MouseButtonEvent& event)
{
CKey keystate;
bool shift = keystate[SDLK_RSHIFT] || keystate[SDLK_LSHIFT];
bool ctrl = keystate[SDLK_RCTRL] || keystate[SDLK_LCTRL];
bool cmd = keystate[SDLK_RMETA] || keystate[SDLK_LMETA];
bool alt = keystate[SDLK_RALT] || keystate[SDLK_LALT];
return get_hotkey(event.which, -1, event.button, -1, -1, shift, ctrl, cmd, alt);
}
const hotkey_item& get_hotkey(const SDL_KeyboardEvent& event)
{
return get_hotkey(
#if SDL_VERSION_ATLEAST(2, 0, 0)
event.keysym.scancode,
#if SDL_VERSION_ATLEAST(2,0,0)
if (mods & KMOD_GUI)
mods |= KMOD_GUI;
#else
event.keysym.unicode,
if (mods & KMOD_META)
mods |= KMOD_META;
#endif
event.keysym.sym,
(event.keysym.mod & KMOD_SHIFT) != 0,
(event.keysym.mod & KMOD_CTRL) != 0,
(event.keysym.mod & KMOD_META) != 0,
(event.keysym.mod & KMOD_ALT) != 0
);
return mods;
}
const std::string hotkey_base::get_name() const
{
std::string ret = "";
if (mod_ & KMOD_CTRL)
ret += "ctrl";
std::string get_names(std::string id) {
ret +=
(!ret.empty() && !boost::algorithm::ends_with(ret, "+") ?
"+" : "");
if (mod_ & KMOD_ALT)
ret += "alt";
std::vector<std::string> names;
BOOST_FOREACH(const hotkey::hotkey_item& item, hotkeys_) {
if (item.get_command() == id && (!item.null()) ) {
names.push_back(item.get_name());
}
ret +=
(!ret.empty() && !boost::algorithm::ends_with(ret, "+") ?
"+" : "");
if (mod_ & KMOD_SHIFT)
ret += "shift";
ret +=
(!ret.empty() && !boost::algorithm::ends_with(ret, "+") ?
"+" : "");
#if SDL_VERSION_ATLEAST(2, 0, 0)
if (mod_ & KMOD_GUI)
#else
if (mod_ & KMOD_META)
#endif
#ifdef __APPLE__
ret += "cmd";
#else
ret += "win";
#endif
ret +=
(!ret.empty() && !boost::algorithm::ends_with(ret, "+") ?
"+" : "");
return ret += get_name_helper();
}
bool hotkey_base::bindings_equal(hotkey_ptr other)
{
bool ret;
if (other == hotkey_ptr()) {
return false;
}
return boost::algorithm::join(names, ", ");
hk_scopes scopematch = hotkey::get_hotkey_command(get_command()).scope
& hotkey::get_hotkey_command(other->get_command()).scope;
if (scopematch.none()) {
return false;
}
ret = mod_ == other->mod_ && bindings_equal_helper(other);
return ret;
}
const hotkey_item& get_hotkey(int mouse, int joystick, int button, int hat, int value,
bool shift, bool ctrl, bool cmd, bool alt)
bool hotkey_base::matches(const SDL_Event &event) const
{
return ::get_hotkey(mouse, joystick, button, hat, value,
shift, ctrl, cmd, alt);
unsigned int mods = sdl_get_mods();
if (!hotkey::is_scope_active(hotkey::get_hotkey_command(get_command()).scope) ||
!active()) {
return false;
}
if ((mods != mod_)) {
return false;
}
return matches_helper(event);
}
const hotkey::hotkey_item& get_hotkey(int character, int keycode,
bool shift, bool ctrl, bool cmd, bool alt)
void hotkey_base::save(config& item) const
{
return ::get_hotkey(character, keycode,
shift, ctrl, cmd, alt);
item["command"] = get_command();
item["shift"] = !!(mod_ & KMOD_SHIFT);
item["ctrl"] = !!(mod_ & KMOD_CTRL);
#if SDL_VERSION_ATLEAST(2, 0, 0)
item["cmd"] = !!(mod_ & KMOD_GUI);
#else
item["cmd"] = !!(mod_ & KMOD_META);
#endif
item["alt"] = !!(mod_ & KMOD_ALT);
save_helper(item);
}
hotkey_ptr create_hotkey(const std::string &id, SDL_Event &event)
{
hotkey_ptr base = hotkey_ptr(new hotkey_void);
switch (event.type) {
case SDL_KEYDOWN:
case SDL_KEYUP: {
hotkey_keyboard_ptr keyboard(new hotkey_keyboard());
base = boost::dynamic_pointer_cast<hotkey_base>(keyboard);
SDL_Scancode code;
#if SDL_VERSION_ATLEAST(2, 0, 0)
code = event.key.keysym.scancode;
#else
code = SDL_GetScancodeFromKey(event.key.keysym.sym);
#endif
keyboard->set_scancode(code);
break;
}
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP: {
hotkey_mouse_ptr mouse(new hotkey_mouse());
base = boost::dynamic_pointer_cast<hotkey_base>(mouse);
mouse->set_button(event.button.button);
break;
}
default:
ERR_G<< "Trying to bind an unknown event type:" << event.type << "\n";
break;
}
base->set_mods(sdl_get_mods());
base->set_command(id);
base->unset_default();
return base;
}
hotkey_ptr load_from_config(const config& cfg)
{
hotkey_ptr base = hotkey_ptr(new hotkey_void());
const std::string& mouse_cfg = cfg["mouse"];
if (!mouse_cfg.empty()) {
hotkey_mouse_ptr mouse(new hotkey_mouse());
base = boost::dynamic_pointer_cast<hotkey_base>(mouse);
mouse->set_button(cfg["button"].to_int());
}
// TODO: add joystick support back
#if 0
const std::string& joystick_cfg = cfg["joystick"];
if (!joystick_cfg.empty()) {
joystick_ = cfg["joystick"].to_int();
}
const std::string& hat = cfg["hat"];
if (!hat.empty()) {
hat_ = cfg["hat"].to_int();
value_ = cfg["value"].to_int();
}
const std::string& button = cfg["button"];
if (!button.empty()) {
button_ = cfg["button"].to_int();
}
#endif
const std::string& key_cfg = cfg["key"];
if (!key_cfg.empty()) {
hotkey_keyboard_ptr keyboard(new hotkey_keyboard());
base = boost::dynamic_pointer_cast<hotkey_base>(keyboard);
SDL_Scancode scancode = SDL_GetScancodeFromName(key_cfg.c_str());
if (scancode == SDL_SCANCODE_UNKNOWN) {
ERR_G<< "Unknown key: " << key_cfg << "\n";
}
keyboard->set_scancode(scancode);
}
if (base == hotkey_ptr()) {
return base;
}
unsigned int mods = 0;
if (cfg["shift"].to_bool())
mods |= KMOD_SHIFT;
if (cfg["ctrl"].to_bool())
mods |= KMOD_CTRL;
if (cfg["cmd"].to_bool())
#if SDL_VERSION_ATLEAST(2, 0, 0)
mods |= KMOD_GUI;
#else
mods |= KMOD_META;
#endif
if (cfg["alt"].to_bool())
mods |= KMOD_ALT;
base->set_mods(mods);
base->set_command(cfg["command"].str());
return base;
}
bool hotkey_mouse::matches_helper(const SDL_Event &event) const
{
if (event.type != SDL_MOUSEBUTTONUP && event.type != SDL_MOUSEBUTTONDOWN) {
return false;
}
if (event.button.button != button_) {
return false;
}
return true;
}
const std::string hotkey_mouse::get_name_helper() const
{
return "mouse " + lexical_cast<std::string>(button_);
}
void hotkey_mouse::save_helper(config &item) const
{
item["mouse"] = 0;
if (button_ != 0) {
item["button"] = button_;
}
}
const std::string hotkey_keyboard::get_name_helper() const
{
std::string ret = std::string(SDL_GetKeyName(SDL_GetKeyFromScancode(scancode_)));
if (ret.size() == 1) {
boost::algorithm::to_lower(ret);
}
return ret;
}
bool hotkey_keyboard::matches_helper(const SDL_Event &event) const
{
if (event.type != SDL_KEYDOWN && event.type != SDL_KEYUP) {
return false;
}
SDL_Scancode code;
#if SDL_VERSION_ATLEAST(2, 0, 0)
code = event.key.keysym.scancode;
#else
code = SDL_GetScancodeFromKey(event.key.keysym.sym);
#endif
if (code != scancode_) {
return false;
}
return true;
}
bool hotkey_mouse::bindings_equal_helper(hotkey_ptr other) const
{
hotkey_mouse_ptr other_m = boost::dynamic_pointer_cast<hotkey_mouse>(other);
if (other_m == hotkey_mouse_ptr()) {
return false;
}
return button_ == other_m->button_;
}
void hotkey_keyboard::save_helper(config &item) const
{
if (scancode_ != SDL_SCANCODE_UNKNOWN) {
item["key"] = SDL_GetScancodeName(scancode_);
}
}
bool has_hotkey_item(const std::string& command)
{
BOOST_FOREACH(hotkey_item& item, hotkeys_)
{
if(item.get_command() == command)
BOOST_FOREACH(hotkey_ptr item, hotkeys_) {
if (item->get_command() == command) {
return true;
}
}
return false;
}
void add_hotkey(const hotkey_item& item) {
bool hotkey_keyboard::bindings_equal_helper(hotkey_ptr other) const
{
hotkey_keyboard_ptr other_k = boost::dynamic_pointer_cast<hotkey_keyboard>(
other);
if (other_k == hotkey_keyboard_ptr()) {
return false;
}
return scancode_ == other_k->scancode_;
}
void del_hotkey(hotkey_ptr item)
{
if (!hotkeys_.empty()) {
hotkeys_.erase(std::remove(hotkeys_.begin(), hotkeys_.end(), item));
}
}
void add_hotkey(const hotkey_ptr item)
{
if (item == hotkey_ptr()) {
return;
}
scope_changer scope_ch;
set_active_scopes(hotkey::get_hotkey_command(item.get_command()).scope);
set_active_scopes(hotkey::get_hotkey_command(item->get_command()).scope);
hotkey_item& old_hk = (item.get_mouse() != -1 || item.get_joystick() != -1) ?
::get_hotkey(item.get_mouse(), item.get_joystick(), item.get_button(), item.get_hat()
, item.get_value(), item.get_shift(), item.get_ctrl(), item.get_cmd(), item.get_alt()) :
::get_hotkey(item.get_character(), item.get_keycode(),
item.get_shift(), item.get_ctrl(), item.get_cmd(), item.get_alt());
if (old_hk.active()) {
old_hk.set_command(item.get_command());
old_hk.unset_default();
if (!hotkeys_.empty()) {
hotkeys_.erase(
std::remove_if(hotkeys_.begin(), hotkeys_.end(),
boost::bind(&hotkey_base::bindings_equal, _1, (item))),
hotkeys_.end());
}
else
hotkeys_.push_back(item);
hotkeys_.push_back(item);
}
void clear_hotkeys(const std::string& command)
{
BOOST_FOREACH(hotkey::hotkey_item& item, hotkeys_) {
if (item.get_command() == command) {
item.clear(); }
BOOST_FOREACH(hotkey::hotkey_ptr item, hotkeys_) {
if (item->get_command() == command) {
item->clear();
}
}
}
@ -269,11 +411,26 @@ void clear_hotkeys()
hotkeys_.clear();
}
const hotkey_ptr get_hotkey(const SDL_Event &event)
{
BOOST_FOREACH(hotkey_ptr item, hotkeys_) {
if (item->matches(event)) {
return item;
}
}
return hotkey_ptr(new hotkey_void());
}
void load_hotkeys(const config& cfg, bool set_as_default)
{
BOOST_FOREACH(const config &hk, cfg.child_range("hotkey")) {
hotkey_item item = hotkey_item(hk, set_as_default);
if(!item.null()){
hotkey_ptr item = load_from_config(hk);
if (!set_as_default) {
item->unset_default();
}
if (!item->null()) {
add_hotkey(item);
}
}
@ -287,14 +444,14 @@ void reset_default_hotkeys()
{
hotkeys_.clear();
if(!default_hotkey_cfg_.empty()) {
if (!default_hotkey_cfg_.empty()) {
load_hotkeys(default_hotkey_cfg_, true);
} else {
ERR_G << "no default hotkeys set yet; all hotkeys are now unassigned!" << std::endl;
ERR_G<< "no default hotkeys set yet; all hotkeys are now unassigned!" << std::endl;
}
}
const std::vector<hotkey_item>& get_hotkeys()
const hotkey_list& get_hotkeys()
{
return hotkeys_;
}
@ -303,258 +460,24 @@ void save_hotkeys(config& cfg)
{
cfg.clear_children("hotkey");
for(std::vector<hotkey_item>::iterator i = hotkeys_.begin();
i != hotkeys_.end(); ++i)
{
if (!i->is_default())
i->save(cfg.add_child("hotkey"));
}
}
bool hotkey_item::active() const
{
return !(command_ == "null");
}
bool hotkey_item::valid() const
{
return (character_ | keycode_ | joystick_ | mouse_ | button_ | hat_ | value_) != 0;
}
// There are two kinds of "key" values.
// One refers to actual keys, like F1 or SPACE.
// The other refers to characters produced, eg 'M' or ':'.
// For the latter, specifying shift+; doesn't make sense,
// because ; is already shifted on French keyboards, for example.
// You really want to say ':', however that is typed.
// However, when you say shift+SPACE,
// you're really referring to the space bar,
// as shift+SPACE usually just produces a SPACE character.
void hotkey_item::load_from_config(const config& cfg)
{
command_ = cfg["command"].str();
const std::string& mouse = cfg["mouse"];
if (!mouse.empty()) {
mouse_ = cfg["mouse"].to_int();
button_ = cfg["button"].to_int();
}
const std::string& joystick = cfg["joystick"];
if (!joystick.empty()) {
joystick_ = cfg["joystick"].to_int();
}
const std::string& hat = cfg["hat"];
if (!hat.empty()) {
hat_ = cfg["hat"].to_int();
value_ = cfg["value"].to_int();
}
const std::string& button = cfg["button"];
if (!button.empty()) {
button_ = cfg["button"].to_int();
}
shift_ = cfg["shift"].to_bool();
ctrl_ = cfg["ctrl"].to_bool();
cmd_ = cfg["cmd"].to_bool();
alt_ = cfg["alt"].to_bool();
const std::string& key = cfg["key"];
if (key.empty()) {
return;
}
ucs4::string wkey = unicode_cast<ucs4::string>(key);
// They may really want a specific key on the keyboard:
// we assume that any single character keyname is a character.
if (wkey.size() > 1) {
keycode_ = sdl_keysym_from_name(key);
if (keycode_ == SDLK_UNKNOWN) {
if (tolower(key[0]) != 'f') {
ERR_CF << "hotkey key '" << key << "' invalid" << std::endl;
} else {
int num = lexical_cast_default<int>(key.c_str() + 1);
keycode_ = num + SDLK_F1 - 1;
}
BOOST_FOREACH(hotkey_ptr item, hotkeys_) {
if (!item->is_default()) {
item->save(cfg.add_child("hotkey"));
}
} else if (key == " " || shift_
#ifdef __APPLE__
|| alt_
#endif
) {
// Space must be treated as a key because shift-space
// isn't a different character from space,
// and control key makes it go weird.
// shift=yes should never be specified on single characters
// (eg. key=m, shift=yes would be key=M),
// but we don't want to break old preferences files.
keycode_ = wkey[0];
} else {
character_ = wkey[0];
}
}
void hotkey_item::set_command(const std::string& command) {
command_ = command;
}
std::string hotkey_item::get_name() const
std::string get_names(std::string id)
{
std::stringstream str;
if (shift_) { str << "shift+"; }
if (ctrl_) { str << "ctrl+"; }
if (cmd_) { str << "cmd+"; }
if (alt_) { str << "alt+"; }
if (mouse_ >= 0) { str << _("Mouse") << mouse_ << _("Button") << button_; }
if (character_ != -1) { str << static_cast<char>(character_); }
if (keycode_ != -1) { str << SDL_GetKeyName(SDLKey(keycode_)); }
if (joystick_ >= 0) { str << _("Joystick") << joystick_ << _("Button") << button_; }
if (value_ >= 0) {
std::string direction;
switch (value_) {
case SDL_HAT_CENTERED:
direction = _("Centered");
break;
case SDL_HAT_UP:
direction = _("Up");
break;
case SDL_HAT_RIGHT:
direction = _("Right");
break;
case SDL_HAT_DOWN:
direction = _("Down");
break;
case SDL_HAT_LEFT:
direction = _("Left");
break;
case SDL_HAT_RIGHTUP:
direction = _("RightUp");
break;
case SDL_HAT_RIGHTDOWN:
direction = _("RightDown");
break;
case SDL_HAT_LEFTUP:
direction = _("LeftUp");
break;
case SDL_HAT_LEFTDOWN:
direction = _("LeftDown");
break;
default:
direction = _("Unknown");
break;
std::vector<std::string> names;
BOOST_FOREACH(const hotkey::hotkey_ptr item, hotkeys_) {
if (item->get_command() == id && (!item->null())) {
names.push_back(item->get_name());
}
str << _("Joystick") << joystick_ << _("Hat") << button_ << direction;
}
return str.str();
}
void hotkey_item::clear()
{
command_ = "null";
}
void hotkey_item::save(config& item) const
{
if (get_button() >= 0) item["button"] = get_button();
if (get_joystick() >= 0) item["joystick"] = get_joystick();
if (get_hat() >= 0) item["hat"] = get_hat();
if (get_value() >= 0) item["value"] = get_value();
if (get_keycode() >= 0) item["key"] = SDL_GetKeyName(SDLKey(get_keycode()));
if (get_character() >= 0) item["key"] = unicode_cast<utf8::string>(static_cast<ucs4::char_t>(get_character()));
if (get_mouse() >= 0) item["mouse"] = get_mouse();
if (get_button() >= 0) item["button"] = get_button();
item["command"] = get_command();
if (get_shift()) item["shift"] = get_shift();
if (get_ctrl() ) item["ctrl"] = get_ctrl();
if (get_cmd() ) item["cmd"] = get_cmd();
if (get_alt() ) item["alt"] = get_alt();
}
void hotkey_item::set_jbutton(int joystick, int button,
bool shift, bool ctrl, bool cmd, bool alt)
{
joystick_ = joystick;
button_ = button;
shift_ = shift;
ctrl_ = ctrl;
cmd_ = cmd;
alt_ = alt;
}
void hotkey_item::set_jhat(int joystick, int hat, int value,
bool shift, bool ctrl, bool cmd, bool alt)
{
joystick_ = joystick;
hat_ = hat;
value_ = value;
shift_ = shift;
ctrl_ = ctrl;
cmd_ = cmd;
alt_ = alt;
}
void hotkey_item::set_mbutton(int mouse, int button,
bool shift, bool ctrl, bool cmd, bool alt)
{
mouse_ = mouse;
button_ = button;
shift_ = shift;
ctrl_ = ctrl;
cmd_ = cmd;
alt_ = alt;
}
void hotkey_item::set_key(int character, int keycode,
bool shift, bool ctrl, bool cmd, bool alt)
{
LOG_G << "setting hotkey: char=" << lexical_cast<std::string>(character)
<< " keycode=" << lexical_cast<std::string>(keycode) << " "
<< (shift ? "shift," : "")
<< (ctrl ? "ctrl," : "")
<< (cmd ? "cmd," : "")
<< (alt ? "alt," : "")
<< "\n";
// Sometimes control modifies by -64, ie ^A == 1.
if (character < 64 && ctrl) {
if (shift) {
character += 64; }
else {
character += 96; }
LOG_G << "Mapped to character " << lexical_cast<std::string>(character) << "\n";
}
// For some reason on Mac OS, if cmd and shift are down, the character doesn't get upper-cased
if (cmd && character > 96 && character < 123 && shift) {
character -= 32; }
// We handle simple cases by character, others by the actual key.
// @ and ` are exceptions related to the space character. Without these, combinations involving Ctrl or Ctrl+Shift often resolve the character value to null (or @ and `).
// j and m exceptions are to catch Ctrl+Return/Enter, which is interpreted as Ctrl+j and Ctrl+m characters (LF and CR respectively).
if (isprint(character) && !isspace(character) &&
character != '@' && character != '`' &&
!(tolower(character) == 'j' && keycode != SDLK_j) &&
!(tolower(character) == 'm' && keycode != SDLK_m)) {
character_ = character;
ctrl_ = ctrl;
cmd_ = cmd;
alt_ = alt;
LOG_G << "type = BY_CHARACTER\n";
} else {
keycode_ = keycode;
shift_ = shift;
ctrl_ = ctrl;
cmd_ = cmd;
alt_ = alt;
LOG_G << "type = BY_KEYCODE\n";
}
return boost::algorithm::join(names, ", ");
}
}

View file

@ -12,154 +12,403 @@
See the COPYING file for more details.
*/
#ifndef HOTKEY_ITEM_HPP_INCLUDED
#define HOTKEY_ITEM_HPP_INCLUDED
#include "config.hpp"
#include "SDL_events.h"
#include "SDL.h"
#include <boost/shared_ptr.hpp>
#include <vector>
#if !SDL_VERSION_ATLEAST(2, 0, 0)
#include "sdl/keyboard.hpp"
#endif
namespace hotkey {
/* forward declarations */
class hotkey_base;
class hotkey_mouse;
class hotkey_keyboard;
typedef boost::shared_ptr<hotkey_base> hotkey_ptr;
typedef boost::shared_ptr<hotkey_mouse> hotkey_mouse_ptr;
typedef boost::shared_ptr<hotkey_keyboard> hotkey_keyboard_ptr;
class hotkey_item {
typedef std::vector<hotkey::hotkey_ptr> hotkey_list;
typedef std::vector<hotkey::hotkey_ptr>::iterator hotkey_list_iter;
/**
* This is the base class for hotkey event matching.
*/
class hotkey_base
{
public:
explicit hotkey_item(const std::string& command) :
command_(command),
shift_(false), ctrl_(false), cmd_(false), alt_(false),
character_(-1), keycode_(-1),
joystick_(-1), mouse_(-1),
button_(-1), hat_(-1), value_(-1),
is_default_(false)
/**
* Initialises a new empty hotkey that will be disabled
*/
hotkey_base() : command_("null"), is_default_(true), mod_(0)
{}
explicit hotkey_item(const config& cfg, bool is_default):
command_("null"),
shift_(false), ctrl_(false), cmd_(false), alt_(false),
character_(-1), keycode_(-1),
joystick_(-1), mouse_(-1),
button_(-1), hat_(-1), value_(-1),
is_default_(is_default)
void set_command(const std::string& command)
{
load_from_config(cfg);
command_ = command;
}
void load_from_config(const config& cfg);
/**
* Set keyboard modifiers.
* @param mods Bitmask of SDLMod.
*/
void set_mods(unsigned int mods)
{
mod_ = mods;
}
void set_command(const std::string& command);
/**
* Returns the string name of the HOTKEY_COMMAND
* @return The unique string for a hotkey command.
**/
const std::string& get_command() const
{
return command_;
}
/** get the string name of the HOTKEY_COMMAND */
const std::string get_command() const { return command_; }
/** The translated description */
/**
* Returns the translated description
* @todo unused
* @return internationalised description of the command.
**/
const std::string get_description() const;
/** @return if the item should appear in the hotkey preferences */
bool hidden() const;
bool is_default() const { return is_default_; }
void unset_default(bool is_not_default = true) {
is_default_ = !is_not_default;
/**
* This controls whether the item should appear in the hotkey preferences.
* @return true if the item should be hidden
**/
virtual bool hidden() const
{
return false;
}
/// Return "name" of hotkey. Example :"ctrl+alt+g"
std::string get_name() const;
/**
* This indicates whether a hotkey is from the default config or if it's
* from the user preferences.
* @return true if from the default configurations, false otherwise
*/
bool is_default() const
{
return is_default_;
}
void clear();
/**
* Used to indicate that a hotkey is overriden and should be treated as
* a user-set hotkey.
*/
void unset_default()
{
is_default_ = false;
}
bool null() const { return command_ == "null"; }
/**
* Unbind this hotkey by linking it to the null-command
*/
void clear()
{
command_ = "null";
}
/// returns weather there is a associated hotkey_command.
// if the none of the hotkey_commands fits this hotkey_item then get_hotkey_command will return the hotkey_command::null_command().
bool active() const;
/**
* Returns whether this hotkey points to the null-command
* @return true if it points to the null-command, false otherwise.
*/
bool null() const
{
return command_ == "null";
}
/// checks weather that hotkey "makes sense" meaning weather one of character, keycode, joystick, mouse, button, hat, value is set.
/// i don't know what the axis_.. values are so i ignore them.
bool valid() const;
/*
* Returns whether there is a associated hotkey_command.
* If the none of the hotkey_commands fits this hotkey_item then
* @param get_hotkey_command will return the hotkey_command::null_command().
* @return true if the hotkey is not bound to the null-command.
*/
bool active() const
{
return command_ != "null";
}
/**
* Evaluates whether the hotkey bindings are valid.
* @return true if they are valid, false otherwise.
*/
virtual bool valid() const = 0;
/**
* Save the hotkey into the configuration object.
* @param cfg The configuration object to save into.
*/
void save(config& cfg) const;
/// Return the actual key code.
int get_keycode() const { return keycode_; }
/// Returns unicode value of the pressed key.
int get_character() const { return character_; }
/**
* Return "name" of hotkey. Example :"ctrl+alt+g"
* @return The string representation of the keybindings
*/
const std::string get_name() const;
/** for buttons on devices */
int get_button() const { return button_; }
int get_joystick() const { return joystick_; }
int get_hat() const { return hat_; }
int get_mouse() const { return mouse_; }
int get_value() const { return value_; }
/**
* Used to evaluate whether:
* 1. The hotkey is valid in the current scope.
* 2. The Keyboard modifiers and SDL_Event mathes this hotkey.
*
* @param event The @SDL_Event that has triggered and is being evaluated.
*/
bool matches(const SDL_Event &event) const;
/** modifiers */
bool get_shift() const { return shift_; }
bool get_ctrl() const { return ctrl_; }
bool get_cmd() const { return cmd_; }
bool get_alt() const { return alt_; }
/**
* Checks whether the hotkey bindings and scope are equal.
* @param other the hokey bindings to compare against.
* @return true if %other has same scope and bindings.
*/
virtual bool bindings_equal(hotkey_ptr other);
void set_jbutton(int button, int joystick, bool shift, bool ctrl, bool cmd, bool alt);
void set_jhat(int joystick, int hat, int value, bool shift, bool ctrl, bool cmd, bool alt);
void set_key(int character, int keycode, bool shift, bool ctrl, bool cmd, bool alt);
void set_mbutton(int device, int button, bool shift, bool ctrl, bool cmd, bool alt);
virtual ~hotkey_base()
{}
protected:
/**
* This is invoked by hotkey_base::get_name and must be implemented by subclasses.
* Keyboard modifiers are handled in this class, other hotkeys in the respective classes
*/
virtual const std::string get_name_helper() const = 0;
/**
* This is invoked by hotkey_base::matches as a helper for the concrete classes.
* Implementing classes should only check their parts of the hotkey.
* @param event The SDL_Event being generated.
* @returns true if they match, false otherwise.
*/
virtual bool matches_helper(const SDL_Event &event) const = 0;
virtual void save_helper(config& cfg) const = 0;
/**
* This is invoked by hotkey_base::bindings_equal as a helper for the concrete classes.
* Implementing classes should only check their parts of the hotkey.
* @param other The other hotkey the check against. Not guaranteed to be the same subclass.
* @returns true if they match, false otherwise.
*/
virtual bool bindings_equal_helper(hotkey_ptr other) const = 0;
// The unique command associated with this item.
// Used to bind to a hotkey_command struct.
/**
* The command that should be executed, or "null".
*/
std::string command_;
// modifier keys
bool shift_, ctrl_, cmd_, alt_;
// Actual unicode character
int character_;
// These used for function keys (which don't have a unicode value) or
// space (which doesn't have a distinct unicode value when shifted).
int keycode_;
int joystick_, mouse_;
int button_;
int hat_, value_;
/**
*
*/
bool is_default_;
/*
* Keyboard modifiers. Treat as opaque, only do comparisons.
*
*/
unsigned int mod_;
};
/// Initiated weather there is at least one hotkey_item with the given command
/**
* This class is responsible for handling keys, not modifiers.
*/
class hotkey_keyboard: public hotkey_base
{
public:
/**
* Initialise new instance of this class that has no key associated with is.
*/
hotkey_keyboard() : hotkey_base(), scancode_(SDL_SCANCODE_UNKNOWN)
{}
/**
* Set the scancode associated with this class.
* @param scancode The SDL_Scancode that this hotkey should be associated with
*/
void set_scancode(SDL_Scancode scancode)
{
scancode_ = scancode;
}
/**
* Checks whether this hotkey has been set to a sensible value.
* @ return true if it is a known key
*/
virtual bool valid() const
{
return scancode_ != SDL_SCANCODE_UNKNOWN;
}
protected:
SDL_Scancode scancode_;
virtual void save_helper(config& cfg) const;
virtual const std::string get_name_helper() const;
virtual bool matches_helper(const SDL_Event &event) const;
virtual bool bindings_equal_helper (hotkey_ptr other) const;
};
/**
* This class is used to return non-valid results in order to save
* other people from null checks.
*/
class hotkey_void: public hotkey_base
{
public:
hotkey_void() : hotkey_base()
{}
virtual bool valid() const
{
return false;
}
protected:
virtual void save_helper(config&) const
{}
virtual const std::string get_name_helper() const
{
return "";
}
virtual bool matches_helper(const SDL_Event&) const
{
return false;
}
virtual bool bindings_equal_helper(hotkey_ptr) const
{
return false;
}
};
/**
* This class is responsible for handling mouse button presses.
*/
class hotkey_mouse: public hotkey_base
{
public:
/**
* Initialise new instance of this class that has no button associated with is.
*/
hotkey_mouse() : hotkey_base(), button_ (0)
{}
/**
* Returns true if the hotkey has a valid mouse button associated with it.
* @return true if a mouse button is set, false otherwise.
*/
virtual bool valid() const
{
return button_ != 0;
}
/* new functionality for this class */
void set_button(int button)
{
button_ = button;
}
protected:
int button_;
virtual void save_helper(config& cfg) const;
virtual const std::string get_name_helper() const;
virtual bool matches_helper(const SDL_Event &event) const;
virtual bool bindings_equal_helper (hotkey_ptr other) const;
};
/**
* @todo not implemented
*/
class hotkey_joystick: public hotkey_base
{
protected:
int button_;
};
/**
* Create and instantiate a hotkey from a config element.
* @param cfg The config element to read for data.
* @return The new instance of the hotkey item.
*/
hotkey_ptr load_from_config(const config& cfg);
/*
* Scans the list of hotkeys to see if one has been bound to the command.
* @param command The command that is searched for
* @return true if there is a hotkey item that has the command bound.
*/
bool has_hotkey_item(const std::string& command);
void add_hotkey(const hotkey_item& item);
/**
* Add a hotkey to the list of hotkeys.
* @param item The item to add.
*/
void add_hotkey(const hotkey_ptr item);
const hotkey_item& get_hotkey(int mouse, int joystick,
int button, int hat, int value,
bool shift, bool ctrl, bool cmd, bool alt);
const hotkey_item& get_hotkey(int character, int keycode,
bool shift, bool ctrl, bool cmd, bool alt);
/**
* Remove a hotkey from the list of hotkeys
* @todo unusued?
*/
void del_hotkey(const hotkey_ptr item);
const hotkey_item& get_hotkey(const SDL_JoyButtonEvent& event);
const hotkey_item& get_hotkey(const SDL_JoyHatEvent& event);
const hotkey_item& get_hotkey(const SDL_KeyboardEvent& event);
const hotkey_item& get_hotkey(const SDL_MouseButtonEvent& event);
/**
* 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, SDL_Event &event);
/**
* Iterate through the list of hotkeys and return a hotkey that matches
* the SDL_Event and the current keyboard modifier state.
* @param event The SDL_Event to use as a template.
* @return The newly created hotkey item.
*/
const hotkey_ptr get_hotkey(const SDL_Event &event);
/**
* Iterates through all hotkeys present in the config struct and creates and adds
* them to the hotkey list.
* @param cfg The config struct to load from.
* @param set_as_default Indicates whether the config struct should be treated as the
* default game settings.
*/
void load_hotkeys(const config& cfg, bool set_as_default = false);
/**
* Reset all hotkeys to the defaults.
*/
void reset_default_hotkeys();
const std::vector<hotkey_item>& get_hotkeys();
/**
* Returns the list of hotkeys.
*/
const hotkey_list& get_hotkeys();
/**
* Unset the command bindings for all hotkeys matching the command.
* @command The binding to be unset
*/
void clear_hotkeys(const std::string& command);
/**
* Unset the bindings for all hotkeys.
*/
void clear_hotkeys();
/// returns all hotkey_item s that point to this, command in the form "A,Strg+M,F4"
/// used in the preferences menu
/**
* Returns a comma-separated string of hotkey names. A hotkey name is in the form of
* "ctrl+l" or "n" or "mouse 1". The comman separated string is of the form "ctrl+l,n,mouse 1".
* @return The comma separated string of hotkey names.
*/
std::string get_names(std::string id);
/**
* Save the non-default hotkeys to the config.
* @param cfg The config to save to.
*/
void save_hotkeys(config& cfg);
/// Append a single hotkey item to @a cfg.
//void save_hotkey(config& cfg, const hotkey_item & item);
}
#endif

View file

@ -590,8 +590,7 @@ void hotkey_preferences_dialog::show_binding_dialog(
disp_.update_display();
SDL_Event event;
event.type = 0;
int character = -1, keycode = -1, mod = -1;
int mouse = -1, joystick = -1, button = -1, hat = -1, value = -1;
int keycode = -1, mod = -1;
const int any_mod = KMOD_CTRL | KMOD_META | KMOD_ALT;
while ( event.type != SDL_KEYDOWN && event.type != SDL_JOYBUTTONDOWN
@ -605,28 +604,11 @@ void hotkey_preferences_dialog::show_binding_dialog(
case SDL_KEYDOWN:
keycode = event.key.keysym.sym;
#if SDL_VERSION_ATLEAST(2, 0, 0)
character = event.key.keysym.scancode,
#else
character = event.key.keysym.unicode;
#endif
mod = event.key.keysym.mod;
break;
case SDL_JOYBUTTONDOWN:
joystick = event.jbutton.which;
button = event.jbutton.button;
break;
case SDL_JOYHATMOTION:
joystick = event.jhat.which;
hat = event.jhat.hat;
value = event.jhat.value;
break;
case SDL_MOUSEBUTTONDOWN:
mouse = event.button.which;
button = event.button.button;
break;
}
SDL_PollEvent(&event);
disp_.flip();
disp_.delay(10);
@ -637,44 +619,16 @@ void hotkey_preferences_dialog::show_binding_dialog(
restorer.restore();
disp_.update_display();
// only if not canceled.
// only if not cancelled.
if (!(keycode == SDLK_ESCAPE && (mod & any_mod) == 0)) {
hotkey::hotkey_item newhk(id);
const hotkey::hotkey_item* oldhk = NULL;
hotkey::hotkey_ptr newhk;
hotkey::hotkey_ptr oldhk;
CKey keystate;
bool shift = keystate[SDLK_RSHIFT] || keystate[SDLK_LSHIFT];
bool ctrl = keystate[SDLK_RCTRL] || keystate[SDLK_LCTRL];
bool cmd = keystate[SDLK_RMETA] || keystate[SDLK_LMETA];
bool alt = keystate[SDLK_RALT] || keystate[SDLK_LALT];
switch (event.type) {
case SDL_JOYHATMOTION:
oldhk = &hotkey::get_hotkey(mouse, joystick, button, hat, value,
shift, ctrl, cmd, alt);
newhk.set_jhat(joystick, hat, value, shift, ctrl, cmd, alt);
break;
case SDL_JOYBUTTONUP:
oldhk = &hotkey::get_hotkey(-1, joystick, button, -1, -1,
shift, ctrl, cmd, alt);
newhk.set_jbutton(joystick, button, shift, ctrl, cmd, alt);
break;
case SDL_MOUSEBUTTONUP:
oldhk = &hotkey::get_hotkey(mouse, -1, button, -1, -1,
shift, ctrl, cmd, alt);
newhk.set_mbutton(mouse, button, shift, ctrl, cmd, alt);
break;
case SDL_KEYUP:
oldhk =
&hotkey::get_hotkey( character, keycode,
(mod & KMOD_SHIFT) != 0, (mod & KMOD_CTRL) != 0,
(mod & KMOD_LMETA) != 0, (mod & KMOD_ALT) != 0 );
newhk.set_key(character, keycode, (mod & KMOD_SHIFT) != 0,
(mod & KMOD_CTRL) != 0, (mod & KMOD_LMETA) != 0,
(mod & KMOD_ALT) != 0);
oldhk = hotkey::get_hotkey(event);
newhk = hotkey::create_hotkey(id, event);
#if 0
//TODO
// if ( (hotkey::get_id(newhk.get_command()) == hotkey::HOTKEY_SCREENSHOT
// || hotkey::get_id(newhk.get_command()) == hotkey::HOTKEY_MAP_SCREENSHOT)
@ -685,6 +639,7 @@ Control, Alt or Meta modifiers to avoid problems.")); */
// }
break;
}
#endif
if (oldhk && oldhk->active()) {
if (oldhk->get_command() != id) {
@ -692,7 +647,7 @@ Control, Alt or Meta modifiers to avoid problems.")); */
utils::string_map symbols;
symbols["hotkey_sequence"] = oldhk->get_name();
symbols["old_hotkey_action"] = hotkey::get_description(oldhk->get_command());
symbols["new_hotkey_action"] = hotkey::get_description(newhk.get_command());
symbols["new_hotkey_action"] = hotkey::get_description(newhk->get_command());
std::string text =
vgettext("\"$hotkey_sequence|\" is in use by \

641
src/sdl/keyboard.cpp Normal file
View file

@ -0,0 +1,641 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL.h"
#if !SDL_VERSION_ATLEAST(2, 0, 0)
#include "sdl/keyboard.hpp"
#define SDLK_SCANCODE_MASK (1<<30)
#define SDL_SCANCODE_TO_KEYCODE(X) (X | SDLK_SCANCODE_MASK)
static const int SDL_default_keymap[SDL_NUM_SCANCODES] = {
0, 0, 0, 0,
'a',
'b',
'c',
'd',
'e',
'f',
'g',
'h',
'i',
'j',
'k',
'l',
'm',
'n',
'o',
'p',
'q',
'r',
's',
't',
'u',
'v',
'w',
'x',
'y',
'z',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'0',
SDLK_RETURN,
SDLK_ESCAPE,
SDLK_BACKSPACE,
SDLK_TAB,
SDLK_SPACE,
'-',
'=',
'[',
']',
'\\',
'#',
';',
'\'',
'`',
',',
'.',
'/',
SDLK_CAPSLOCK,
SDLK_F1,
SDLK_F2,
SDLK_F3,
SDLK_F4,
SDLK_F5,
SDLK_F6,
SDLK_F7,
SDLK_F8,
SDLK_F9,
SDLK_F10,
SDLK_F11,
SDLK_F12,
SDLK_PRINT,
SDLK_SCROLLOCK,
SDLK_PAUSE,
SDLK_INSERT,
SDLK_HOME,
SDLK_PAGEUP,
SDLK_DELETE,
SDLK_END,
SDLK_PAGEDOWN,
SDLK_RIGHT,
SDLK_LEFT,
SDLK_DOWN,
SDLK_UP,
0,
SDLK_KP_DIVIDE,
SDLK_KP_MULTIPLY,
SDLK_KP_MINUS,
SDLK_KP_PLUS,
SDLK_KP_ENTER,
SDLK_KP1,
SDLK_KP2,
SDLK_KP3,
SDLK_KP4,
SDLK_KP5,
SDLK_KP6,
SDLK_KP7,
SDLK_KP8,
SDLK_KP9,
SDLK_KP0,
SDLK_KP_PERIOD,
0,
0,
SDLK_POWER,
SDLK_KP_EQUALS,
SDLK_F13,
SDLK_F14,
SDLK_F15,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
SDLK_HELP,
SDLK_MENU,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0, 0, 0,
0,
0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0,
SDLK_SYSREQ,
0,
SDLK_CLEAR,
0,
0,
0,
0,
0,
0,
0,
0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0, 0,
SDLK_LCTRL,
SDLK_LSHIFT,
SDLK_LALT,
SDLK_LMETA,
SDLK_RCTRL,
SDLK_RSHIFT,
SDLK_RALT,
SDLK_RMETA,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
SDLK_MODE,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
};
static const char *SDL_scancode_names[SDL_NUM_SCANCODES] = {
NULL, NULL, NULL, NULL,
"A",
"B",
"C",
"D",
"E",
"F",
"G",
"H",
"I",
"J",
"K",
"L",
"M",
"N",
"O",
"P",
"Q",
"R",
"S",
"T",
"U",
"V",
"W",
"X",
"Y",
"Z",
"1",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9",
"0",
"Return",
"Escape",
"Backspace",
"Tab",
"Space",
"-",
"=",
"[",
"]",
"\\",
"#",
";",
"'",
"`",
",",
".",
"/",
"CapsLock",
"F1",
"F2",
"F3",
"F4",
"F5",
"F6",
"F7",
"F8",
"F9",
"F10",
"F11",
"F12",
"PrintScreen",
"ScrollLock",
"Pause",
"Insert",
"Home",
"PageUp",
"Delete",
"End",
"PageDown",
"Right",
"Left",
"Down",
"Up",
"Numlock",
"Keypad /",
"Keypad *",
"Keypad -",
"Keypad +",
"Keypad Enter",
"Keypad 1",
"Keypad 2",
"Keypad 3",
"Keypad 4",
"Keypad 5",
"Keypad 6",
"Keypad 7",
"Keypad 8",
"Keypad 9",
"Keypad 0",
"Keypad .",
NULL,
"Application",
"Power",
"Keypad =",
"F13",
"F14",
"F15",
"F16",
"F17",
"F18",
"F19",
"F20",
"F21",
"F22",
"F23",
"F24",
"Execute",
"Help",
"Menu",
"Select",
"Stop",
"Again",
"Undo",
"Cut",
"Copy",
"Paste",
"Find",
"Mute",
"VolumeUp",
"VolumeDown",
NULL, NULL, NULL,
"Keypad ,",
"Keypad = (AS400)",
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL,
"AltErase",
"SysReq",
"Cancel",
"Clear",
"Prior",
"Return",
"Separator",
"Out",
"Oper",
"Clear / Again",
"CrSel",
"ExSel",
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
"Keypad 00",
"Keypad 000",
"ThousandsSeparator",
"DecimalSeparator",
"CurrencyUnit",
"CurrencySubUnit",
"Keypad (",
"Keypad )",
"Keypad {",
"Keypad }",
"Keypad Tab",
"Keypad Backspace",
"Keypad A",
"Keypad B",
"Keypad C",
"Keypad D",
"Keypad E",
"Keypad F",
"Keypad XOR",
"Keypad ^",
"Keypad %",
"Keypad <",
"Keypad >",
"Keypad &",
"Keypad &&",
"Keypad |",
"Keypad ||",
"Keypad :",
"Keypad #",
"Keypad Space",
"Keypad @",
"Keypad !",
"Keypad MemStore",
"Keypad MemRecall",
"Keypad MemClear",
"Keypad MemAdd",
"Keypad MemSubtract",
"Keypad MemMultiply",
"Keypad MemDivide",
"Keypad +/-",
"Keypad Clear",
"Keypad ClearEntry",
"Keypad Binary",
"Keypad Octal",
"Keypad Decimal",
"Keypad Hexadecimal",
NULL, NULL,
"Left Ctrl",
"Left Shift",
"Left Alt",
"Left GUI",
"Right Ctrl",
"Right Shift",
"Right Alt",
"Right GUI",
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL,
"ModeSwitch",
"AudioNext",
"AudioPrev",
"AudioStop",
"AudioPlay",
"AudioMute",
"MediaSelect",
"WWW",
"Mail",
"Calculator",
"Computer",
"AC Search",
"AC Home",
"AC Back",
"AC Forward",
"AC Stop",
"AC Refresh",
"AC Bookmarks",
"BrightnessDown",
"BrightnessUp",
"DisplaySwitch",
"KBDIllumToggle",
"KBDIllumDown",
"KBDIllumUp",
"Eject",
"Sleep",
};
/**
* \brief Get the key code corresponding to the given scancode according
* to the current keyboard layout.
*
* See ::SDL_Keycode for details.
*
* \sa SDL_GetKeyName()
*/
SDLKey SDL_GetKeyFromScancode(SDL_Scancode scancode);
/**
* \brief Get the scancode corresponding to the given key code according to the
* current keyboard layout.
*
* See ::SDL_Scancode for details.
*
* \sa SDL_GetScancodeName()
*/
SDL_Scancode SDL_GetScancodeFromKey(SDLKey key);
/**
* \brief Get a human-readable name for a scancode.
*
* \return A pointer to the name for the scancode.
* If the scancode doesn't have a name, this function returns
* an empty string ("").
*
* \sa SDL_Scancode
*/
const char * SDL_GetScancodeName(SDL_Scancode scancode);
/**
* \brief Get a scancode from a human-readable name
*
* \return scancode, or SDL_SCANCODE_UNKNOWN if the name wasn't recognized
*
* \sa SDL_Scancode
*/
SDL_Scancode SDL_GetScancodeFromName(const char *name);
SDLKey
SDL_GetKeyFromScancode(SDL_Scancode scancode)
{
if (scancode < SDL_SCANCODE_UNKNOWN || scancode >= SDL_NUM_SCANCODES) {
return SDLK_UNKNOWN;
}
return static_cast<SDLKey>(SDL_default_keymap[scancode]);
}
SDL_Scancode
SDL_GetScancodeFromKey(SDLKey key)
{
for (int scancode = SDL_SCANCODE_UNKNOWN; scancode < SDL_NUM_SCANCODES;
++scancode) {
if (SDL_default_keymap[scancode] == key) {
return static_cast<SDL_Scancode>(scancode);
}
}
return SDL_SCANCODE_UNKNOWN;
}
const char *
SDL_GetScancodeName(SDL_Scancode scancode)
{
const char *name;
if (scancode < SDL_SCANCODE_UNKNOWN || scancode >= SDL_NUM_SCANCODES) {
return "";
}
name = SDL_scancode_names[scancode];
if (name)
return name;
else
return "";
}
SDL_Scancode SDL_GetScancodeFromName(const char *name)
{
unsigned int i;
if (!name || !*name) {
return SDL_SCANCODE_UNKNOWN;
}
for (i = 0; i < SDL_arraysize(SDL_scancode_names); ++i) {
if (!SDL_scancode_names[i]) {
continue;
}
if (SDL_strcasecmp(name, SDL_scancode_names[i]) == 0) {
return static_cast<SDL_Scancode>(i);
}
}
return SDL_SCANCODE_UNKNOWN;
}
SDLKey
SDL_GetKeyFromName(const char *name)
{
int key;
/* Check input */
if (name == NULL) return SDLK_UNKNOWN;
/* If it's a single UTF-8 character, then that's the keycode itself */
key = *reinterpret_cast<const unsigned char *>(name);
if (key >= 0xF0) {
if (SDL_strlen(name) == 4) {
int i = 0;
key = static_cast<Uint16>((name[i]&0x07) << 18);
key |= static_cast<Uint16>((name[++i]&0x3F) << 12);
key |= static_cast<Uint16>((name[++i]&0x3F) << 6);
key |= static_cast<Uint16>((name[++i]&0x3F));
return static_cast<SDLKey>(key);
}
return SDLK_UNKNOWN;
} else if (key >= 0xE0) {
if (SDL_strlen(name) == 3) {
int i = 0;
key = static_cast<Uint16>((name[i]&0x0F) << 12);
key |= static_cast<Uint16>((name[++i]&0x3F) << 6);
key |= static_cast<Uint16>((name[++i]&0x3F));
return static_cast<SDLKey>(key);
}
return SDLK_UNKNOWN;
} else if (key >= 0xC0) {
if (SDL_strlen(name) == 2) {
int i = 0;
key = static_cast<Uint16>((name[i]&0x1F) << 6);
key |= static_cast<Uint16>((name[++i]&0x3F));
return static_cast<SDLKey>(key);
}
return SDLK_UNKNOWN;
} else {
if (SDL_strlen(name) == 1) {
if (key >= 'A' && key <= 'Z') {
key += 32;
}
return static_cast<SDLKey>(key);
}
/* Get the scancode for this name, and the associated keycode */
return static_cast<SDLKey>(SDL_default_keymap[SDL_GetScancodeFromName(name)]);
}
}
#endif
/* vi: set ts=4 sw=4 expandtab: */

422
src/sdl/keyboard.hpp Normal file
View file

@ -0,0 +1,422 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef SDL_KEYBOARD_HPP_INCLUDED
#define SDL_KEYBOARD_HPP_INCLUDED
#if !SDL_VERSION_ATLEAST(2, 0, 0)
/* Set up for C function definitions, even when using C++ */
#ifdef __cplusplus
extern "C" {
#endif
/**
* \brief The SDL keyboard scancode representation.
*
* Values of this type are used to represent keyboard keys, among other places
* in the \link SDL_Keysym::scancode key.keysym.scancode \endlink field of the
* SDL_Event structure.
*
* The values in this enumeration are based on the USB usage page standard:
* http://www.usb.org/developers/devclass_docs/Hut1_12v2.pdf
*/
typedef enum
{
SDL_SCANCODE_UNKNOWN = 0,
/**
* \name Usage page 0x07
*
* These values are from usage page 0x07 (USB keyboard page).
*/
/* @{ */
SDL_SCANCODE_A = 4,
SDL_SCANCODE_B = 5,
SDL_SCANCODE_C = 6,
SDL_SCANCODE_D = 7,
SDL_SCANCODE_E = 8,
SDL_SCANCODE_F = 9,
SDL_SCANCODE_G = 10,
SDL_SCANCODE_H = 11,
SDL_SCANCODE_I = 12,
SDL_SCANCODE_J = 13,
SDL_SCANCODE_K = 14,
SDL_SCANCODE_L = 15,
SDL_SCANCODE_M = 16,
SDL_SCANCODE_N = 17,
SDL_SCANCODE_O = 18,
SDL_SCANCODE_P = 19,
SDL_SCANCODE_Q = 20,
SDL_SCANCODE_R = 21,
SDL_SCANCODE_S = 22,
SDL_SCANCODE_T = 23,
SDL_SCANCODE_U = 24,
SDL_SCANCODE_V = 25,
SDL_SCANCODE_W = 26,
SDL_SCANCODE_X = 27,
SDL_SCANCODE_Y = 28,
SDL_SCANCODE_Z = 29,
SDL_SCANCODE_1 = 30,
SDL_SCANCODE_2 = 31,
SDL_SCANCODE_3 = 32,
SDL_SCANCODE_4 = 33,
SDL_SCANCODE_5 = 34,
SDL_SCANCODE_6 = 35,
SDL_SCANCODE_7 = 36,
SDL_SCANCODE_8 = 37,
SDL_SCANCODE_9 = 38,
SDL_SCANCODE_0 = 39,
SDL_SCANCODE_RETURN = 40,
SDL_SCANCODE_ESCAPE = 41,
SDL_SCANCODE_BACKSPACE = 42,
SDL_SCANCODE_TAB = 43,
SDL_SCANCODE_SPACE = 44,
SDL_SCANCODE_MINUS = 45,
SDL_SCANCODE_EQUALS = 46,
SDL_SCANCODE_LEFTBRACKET = 47,
SDL_SCANCODE_RIGHTBRACKET = 48,
SDL_SCANCODE_BACKSLASH = 49, /**< Located at the lower left of the return
* key on ISO keyboards and at the right end
* of the QWERTY row on ANSI keyboards.
* Produces REVERSE SOLIDUS (backslash) and
* VERTICAL LINE in a US layout, REVERSE
* SOLIDUS and VERTICAL LINE in a UK Mac
* layout, NUMBER SIGN and TILDE in a UK
* Windows layout, DOLLAR SIGN and POUND SIGN
* in a Swiss German layout, NUMBER SIGN and
* APOSTROPHE in a German layout, GRAVE
* ACCENT and POUND SIGN in a French Mac
* layout, and ASTERISK and MICRO SIGN in a
* French Windows layout.
*/
SDL_SCANCODE_NONUSHASH = 50, /**< ISO USB keyboards actually use this code
* instead of 49 for the same key, but all
* OSes I've seen treat the two codes
* identically. So, as an implementor, unless
* your keyboard generates both of those
* codes and your OS treats them differently,
* you should generate SDL_SCANCODE_BACKSLASH
* instead of this code. As a user, you
* should not rely on this code because SDL
* will never generate it with most (all?)
* keyboards.
*/
SDL_SCANCODE_SEMICOLON = 51,
SDL_SCANCODE_APOSTROPHE = 52,
SDL_SCANCODE_GRAVE = 53, /**< Located in the top left corner (on both ANSI
* and ISO keyboards). Produces GRAVE ACCENT and
* TILDE in a US Windows layout and in US and UK
* Mac layouts on ANSI keyboards, GRAVE ACCENT
* and NOT SIGN in a UK Windows layout, SECTION
* SIGN and PLUS-MINUS SIGN in US and UK Mac
* layouts on ISO keyboards, SECTION SIGN and
* DEGREE SIGN in a Swiss German layout (Mac:
* only on ISO keyboards), CIRCUMFLEX ACCENT and
* DEGREE SIGN in a German layout (Mac: only on
* ISO keyboards), SUPERSCRIPT TWO and TILDE in a
* French Windows layout, COMMERCIAL AT and
* NUMBER SIGN in a French Mac layout on ISO
* keyboards, and LESS-THAN SIGN and GREATER-THAN
* SIGN in a Swiss German, German, or French Mac
* layout on ANSI keyboards.
*/
SDL_SCANCODE_COMMA = 54,
SDL_SCANCODE_PERIOD = 55,
SDL_SCANCODE_SLASH = 56,
SDL_SCANCODE_CAPSLOCK = 57,
SDL_SCANCODE_F1 = 58,
SDL_SCANCODE_F2 = 59,
SDL_SCANCODE_F3 = 60,
SDL_SCANCODE_F4 = 61,
SDL_SCANCODE_F5 = 62,
SDL_SCANCODE_F6 = 63,
SDL_SCANCODE_F7 = 64,
SDL_SCANCODE_F8 = 65,
SDL_SCANCODE_F9 = 66,
SDL_SCANCODE_F10 = 67,
SDL_SCANCODE_F11 = 68,
SDL_SCANCODE_F12 = 69,
SDL_SCANCODE_PRINTSCREEN = 70,
SDL_SCANCODE_SCROLLLOCK = 71,
SDL_SCANCODE_PAUSE = 72,
SDL_SCANCODE_INSERT = 73, /**< insert on PC, help on some Mac keyboards (but
does send code 73, not 117) */
SDL_SCANCODE_HOME = 74,
SDL_SCANCODE_PAGEUP = 75,
SDL_SCANCODE_DELETE = 76,
SDL_SCANCODE_END = 77,
SDL_SCANCODE_PAGEDOWN = 78,
SDL_SCANCODE_RIGHT = 79,
SDL_SCANCODE_LEFT = 80,
SDL_SCANCODE_DOWN = 81,
SDL_SCANCODE_UP = 82,
SDL_SCANCODE_NUMLOCKCLEAR = 83, /**< num lock on PC, clear on Mac keyboards
*/
SDL_SCANCODE_KP_DIVIDE = 84,
SDL_SCANCODE_KP_MULTIPLY = 85,
SDL_SCANCODE_KP_MINUS = 86,
SDL_SCANCODE_KP_PLUS = 87,
SDL_SCANCODE_KP_ENTER = 88,
SDL_SCANCODE_KP_1 = 89,
SDL_SCANCODE_KP_2 = 90,
SDL_SCANCODE_KP_3 = 91,
SDL_SCANCODE_KP_4 = 92,
SDL_SCANCODE_KP_5 = 93,
SDL_SCANCODE_KP_6 = 94,
SDL_SCANCODE_KP_7 = 95,
SDL_SCANCODE_KP_8 = 96,
SDL_SCANCODE_KP_9 = 97,
SDL_SCANCODE_KP_0 = 98,
SDL_SCANCODE_KP_PERIOD = 99,
SDL_SCANCODE_NONUSBACKSLASH = 100, /**< This is the additional key that ISO
* keyboards have over ANSI ones,
* located between left shift and Y.
* Produces GRAVE ACCENT and TILDE in a
* US or UK Mac layout, REVERSE SOLIDUS
* (backslash) and VERTICAL LINE in a
* US or UK Windows layout, and
* LESS-THAN SIGN and GREATER-THAN SIGN
* in a Swiss German, German, or French
* layout. */
SDL_SCANCODE_APPLICATION = 101, /**< windows contextual menu, compose */
SDL_SCANCODE_POWER = 102, /**< The USB document says this is a status flag,
* not a physical key - but some Mac keyboards
* do have a power key. */
SDL_SCANCODE_KP_EQUALS = 103,
SDL_SCANCODE_F13 = 104,
SDL_SCANCODE_F14 = 105,
SDL_SCANCODE_F15 = 106,
SDL_SCANCODE_F16 = 107,
SDL_SCANCODE_F17 = 108,
SDL_SCANCODE_F18 = 109,
SDL_SCANCODE_F19 = 110,
SDL_SCANCODE_F20 = 111,
SDL_SCANCODE_F21 = 112,
SDL_SCANCODE_F22 = 113,
SDL_SCANCODE_F23 = 114,
SDL_SCANCODE_F24 = 115,
SDL_SCANCODE_EXECUTE = 116,
SDL_SCANCODE_HELP = 117,
SDL_SCANCODE_MENU = 118,
SDL_SCANCODE_SELECT = 119,
SDL_SCANCODE_STOP = 120,
SDL_SCANCODE_AGAIN = 121, /**< redo */
SDL_SCANCODE_UNDO = 122,
SDL_SCANCODE_CUT = 123,
SDL_SCANCODE_COPY = 124,
SDL_SCANCODE_PASTE = 125,
SDL_SCANCODE_FIND = 126,
SDL_SCANCODE_MUTE = 127,
SDL_SCANCODE_VOLUMEUP = 128,
SDL_SCANCODE_VOLUMEDOWN = 129,
/* not sure whether there's a reason to enable these */
/* SDL_SCANCODE_LOCKINGCAPSLOCK = 130, */
/* SDL_SCANCODE_LOCKINGNUMLOCK = 131, */
/* SDL_SCANCODE_LOCKINGSCROLLLOCK = 132, */
SDL_SCANCODE_KP_COMMA = 133,
SDL_SCANCODE_KP_EQUALSAS400 = 134,
SDL_SCANCODE_INTERNATIONAL1 = 135, /**< used on Asian keyboards, see
footnotes in USB doc */
SDL_SCANCODE_INTERNATIONAL2 = 136,
SDL_SCANCODE_INTERNATIONAL3 = 137, /**< Yen */
SDL_SCANCODE_INTERNATIONAL4 = 138,
SDL_SCANCODE_INTERNATIONAL5 = 139,
SDL_SCANCODE_INTERNATIONAL6 = 140,
SDL_SCANCODE_INTERNATIONAL7 = 141,
SDL_SCANCODE_INTERNATIONAL8 = 142,
SDL_SCANCODE_INTERNATIONAL9 = 143,
SDL_SCANCODE_LANG1 = 144, /**< Hangul/English toggle */
SDL_SCANCODE_LANG2 = 145, /**< Hanja conversion */
SDL_SCANCODE_LANG3 = 146, /**< Katakana */
SDL_SCANCODE_LANG4 = 147, /**< Hiragana */
SDL_SCANCODE_LANG5 = 148, /**< Zenkaku/Hankaku */
SDL_SCANCODE_LANG6 = 149, /**< reserved */
SDL_SCANCODE_LANG7 = 150, /**< reserved */
SDL_SCANCODE_LANG8 = 151, /**< reserved */
SDL_SCANCODE_LANG9 = 152, /**< reserved */
SDL_SCANCODE_ALTERASE = 153, /**< Erase-Eaze */
SDL_SCANCODE_SYSREQ = 154,
SDL_SCANCODE_CANCEL = 155,
SDL_SCANCODE_CLEAR = 156,
SDL_SCANCODE_PRIOR = 157,
SDL_SCANCODE_RETURN2 = 158,
SDL_SCANCODE_SEPARATOR = 159,
SDL_SCANCODE_OUT = 160,
SDL_SCANCODE_OPER = 161,
SDL_SCANCODE_CLEARAGAIN = 162,
SDL_SCANCODE_CRSEL = 163,
SDL_SCANCODE_EXSEL = 164,
SDL_SCANCODE_KP_00 = 176,
SDL_SCANCODE_KP_000 = 177,
SDL_SCANCODE_THOUSANDSSEPARATOR = 178,
SDL_SCANCODE_DECIMALSEPARATOR = 179,
SDL_SCANCODE_CURRENCYUNIT = 180,
SDL_SCANCODE_CURRENCYSUBUNIT = 181,
SDL_SCANCODE_KP_LEFTPAREN = 182,
SDL_SCANCODE_KP_RIGHTPAREN = 183,
SDL_SCANCODE_KP_LEFTBRACE = 184,
SDL_SCANCODE_KP_RIGHTBRACE = 185,
SDL_SCANCODE_KP_TAB = 186,
SDL_SCANCODE_KP_BACKSPACE = 187,
SDL_SCANCODE_KP_A = 188,
SDL_SCANCODE_KP_B = 189,
SDL_SCANCODE_KP_C = 190,
SDL_SCANCODE_KP_D = 191,
SDL_SCANCODE_KP_E = 192,
SDL_SCANCODE_KP_F = 193,
SDL_SCANCODE_KP_XOR = 194,
SDL_SCANCODE_KP_POWER = 195,
SDL_SCANCODE_KP_PERCENT = 196,
SDL_SCANCODE_KP_LESS = 197,
SDL_SCANCODE_KP_GREATER = 198,
SDL_SCANCODE_KP_AMPERSAND = 199,
SDL_SCANCODE_KP_DBLAMPERSAND = 200,
SDL_SCANCODE_KP_VERTICALBAR = 201,
SDL_SCANCODE_KP_DBLVERTICALBAR = 202,
SDL_SCANCODE_KP_COLON = 203,
SDL_SCANCODE_KP_HASH = 204,
SDL_SCANCODE_KP_SPACE = 205,
SDL_SCANCODE_KP_AT = 206,
SDL_SCANCODE_KP_EXCLAM = 207,
SDL_SCANCODE_KP_MEMSTORE = 208,
SDL_SCANCODE_KP_MEMRECALL = 209,
SDL_SCANCODE_KP_MEMCLEAR = 210,
SDL_SCANCODE_KP_MEMADD = 211,
SDL_SCANCODE_KP_MEMSUBTRACT = 212,
SDL_SCANCODE_KP_MEMMULTIPLY = 213,
SDL_SCANCODE_KP_MEMDIVIDE = 214,
SDL_SCANCODE_KP_PLUSMINUS = 215,
SDL_SCANCODE_KP_CLEAR = 216,
SDL_SCANCODE_KP_CLEARENTRY = 217,
SDL_SCANCODE_KP_BINARY = 218,
SDL_SCANCODE_KP_OCTAL = 219,
SDL_SCANCODE_KP_DECIMAL = 220,
SDL_SCANCODE_KP_HEXADECIMAL = 221,
SDL_SCANCODE_LCTRL = 224,
SDL_SCANCODE_LSHIFT = 225,
SDL_SCANCODE_LALT = 226, /**< alt, option */
SDL_SCANCODE_LGUI = 227, /**< windows, command (apple), meta */
SDL_SCANCODE_RCTRL = 228,
SDL_SCANCODE_RSHIFT = 229,
SDL_SCANCODE_RALT = 230, /**< alt gr, option */
SDL_SCANCODE_RGUI = 231, /**< windows, command (apple), meta */
SDL_SCANCODE_MODE = 257, /**< I'm not sure if this is really not covered
* by any of the above, but since there's a
* special KMOD_MODE for it I'm adding it here
*/
/* @} *//* Usage page 0x07 */
/**
* \name Usage page 0x0C
*
* These values are mapped from usage page 0x0C (USB consumer page).
*/
/* @{ */
SDL_SCANCODE_AUDIONEXT = 258,
SDL_SCANCODE_AUDIOPREV = 259,
SDL_SCANCODE_AUDIOSTOP = 260,
SDL_SCANCODE_AUDIOPLAY = 261,
SDL_SCANCODE_AUDIOMUTE = 262,
SDL_SCANCODE_MEDIASELECT = 263,
SDL_SCANCODE_WWW = 264,
SDL_SCANCODE_MAIL = 265,
SDL_SCANCODE_CALCULATOR = 266,
SDL_SCANCODE_COMPUTER = 267,
SDL_SCANCODE_AC_SEARCH = 268,
SDL_SCANCODE_AC_HOME = 269,
SDL_SCANCODE_AC_BACK = 270,
SDL_SCANCODE_AC_FORWARD = 271,
SDL_SCANCODE_AC_STOP = 272,
SDL_SCANCODE_AC_REFRESH = 273,
SDL_SCANCODE_AC_BOOKMARKS = 274,
/* @} *//* Usage page 0x0C */
/**
* \name Walther keys
*
* These are values that Christian Walther added (for mac keyboard?).
*/
/* @{ */
SDL_SCANCODE_BRIGHTNESSDOWN = 275,
SDL_SCANCODE_BRIGHTNESSUP = 276,
SDL_SCANCODE_DISPLAYSWITCH = 277, /**< display mirroring/dual display
switch, video mode switch */
SDL_SCANCODE_KBDILLUMTOGGLE = 278,
SDL_SCANCODE_KBDILLUMDOWN = 279,
SDL_SCANCODE_KBDILLUMUP = 280,
SDL_SCANCODE_EJECT = 281,
SDL_SCANCODE_SLEEP = 282,
SDL_SCANCODE_APP1 = 283,
SDL_SCANCODE_APP2 = 284,
/* @} *//* Walther keys */
/* Add any other keys here. */
SDL_NUM_SCANCODES = 512 /**< not a key, just marks the number of scancodes
for array bounds */
} SDL_Scancode;
extern SDL_Scancode SDL_GetScancodeFromKey(SDLKey key);
extern SDL_Scancode SDL_GetScancodeFromName(const char *name);
extern const char *
SDL_GetScancodeName(SDL_Scancode scancode);
/**
* \brief Get a key code from a human-readable name
*
* \return key code, or SDLK_UNKNOWN if the name wasn't recognized
*
* \sa SDL_Keycode
*/
extern SDLKey SDL_GetKeyFromName(const char *name);
extern SDLKey SDL_GetKeyFromScancode(SDL_Scancode scancode);
/* Ends C function definitions when using C++ */
#ifdef __cplusplus
}
#endif
#endif
#endif /* SDL_KEYBOARD_HPP_INCLUDED */

View file

@ -2735,4 +2735,3 @@ std::ostream& operator<<(std::ostream& s, const SDL_Rect& rect)
s << rect.x << ',' << rect.y << " x " << rect.w << ',' << rect.h;
return s;
}