/* client/keyboard.cc This file is part of the Osirion project and is distributed under the terms and conditions of the GNU General Public License version 2 */ #include #include #include #include "auxiliary/functions.h" #include "client/keyboard.h" #include "core/application.h" #include "core/commandbuffer.h" #include "filesystem/filesystem.h" #include "sys/sys.h" namespace client { /* Notes: http://docs.mandragor.org/files/Common_libs_documentation/SDL/SDL_Documentation_project_en/sdlkey.html */ Keyboard::Keyboard() { // ------------------ ACTIONS // FIXME actions should be state keys and not use key repeat add_action("+console", Action::Console, "console key"); add_action("+left", Action::Left, "rotate left"); add_action("+right", Action::Right, "rotate right"); add_action("+up", Action::Up, "rotate up"); add_action("+down", Action::Down, "rotate down"); add_action("+rollleft", Action::RollLeft, "roll left"); add_action("+rollright", Action::RollRight, "roll right"); add_action("+lookleft", Action::LookLeft, "look left"); add_action("+lookright", Action::LookRight, "look right"); add_action("+lookup", Action::LookUp, "look up"); add_action("+lookdown", Action::LookDown, "look down"); add_action("+zoomin", Action::ZoomIn, "zoom camera in"); add_action("+zoomout", Action::ZoomOut, "zoom camera out"); add_action("+thrustup", Action::ThrustUp, "increase thruster"); add_action("+thrustdown", Action::ThrustDown, "decrease thruster"); add_action("+strafeleft", Action::StrafeLeft, "strafe left"); add_action("+straferight", Action::StrafeRight, "strafe right"); add_action("+strafeup", Action::StrafeUp, "strafe up"); add_action("+strafedown", Action::StrafeDown, "strafe down"); add_action("+afterburner", Action::Afterburner, "afterburner"); add_action("+reverse", Action::Reverse, "reverse engine"); add_action("+control", Action::Control, "enable mouse control while pressed"); add_action("+fire", Action::Fire, "fire weapons"); add_action("+freelook", Action::FreeLook, "free look"); // ------------------ KEYS Key *key = 0; add_key(SDL_SCANCODE_BACKSPACE, "backspace"); add_key(SDL_SCANCODE_TAB, "tab", 0, "impulse"); add_key(SDL_SCANCODE_CLEAR, "clear"); key = add_key( SDL_SCANCODE_RETURN, "enter", 0, "ui_chat"); key->assign(Key::Alt, "toggle r_fullscreen"); add_key(SDL_SCANCODE_PAUSE, "pause"); add_key(SDL_SCANCODE_ESCAPE, "esc"); add_key(SDL_SCANCODE_SPACE, "space", ' ', "ui_control"); add_key(SDL_SCANCODE_0, "0", '0'); add_key(SDL_SCANCODE_1, "1", '1'); add_key(SDL_SCANCODE_2, "2", '2'); add_key(SDL_SCANCODE_3, "3", '3'); add_key(SDL_SCANCODE_4, "4", '4'); add_key(SDL_SCANCODE_5, "5", '5'); add_key(SDL_SCANCODE_6, "6", '6'); add_key(SDL_SCANCODE_7, "7", '7'); add_key(SDL_SCANCODE_8, "8", '8'); add_key(SDL_SCANCODE_9, "9", '9'); add_key(SDL_SCANCODE_MINUS, "-", '-'); add_key(SDL_SCANCODE_EQUALS, "=", '='); add_key(SDL_SCANCODE_LEFTBRACKET, "[", '['); add_key(SDL_SCANCODE_RIGHTBRACKET, "]", ']'); add_key(SDL_SCANCODE_SEMICOLON, ";", ';'); add_key(SDL_SCANCODE_APOSTROPHE,"'", '\''); add_key(SDL_SCANCODE_BACKSLASH, "\\", '\\'); add_key(SDL_SCANCODE_COMMA, ",", ','); add_key(SDL_SCANCODE_PERIOD, ".", '.'); add_key(SDL_SCANCODE_SLASH, "/", '/'); add_key(SDL_SCANCODE_GRAVE,"`", '`', "+console"); add_key(SDL_SCANCODE_A, "a", 'a', "+strafeleft"); add_key(SDL_SCANCODE_B, "b", 'b', "beam"); add_key(SDL_SCANCODE_C, "c", 'c'); add_key(SDL_SCANCODE_D, "d", 'd', "+straferight"); add_key(SDL_SCANCODE_E, "e", 'e', "+rollright"); add_key(SDL_SCANCODE_F, "f", 'f', "+strafedown"); add_key(SDL_SCANCODE_G, "g", 'g'); add_key(SDL_SCANCODE_H, "h", 'h'); add_key(SDL_SCANCODE_I, "i", 'i', "ui_inventory"); add_key(SDL_SCANCODE_J, "j", 'j'); add_key(SDL_SCANCODE_K, "k", 'k'); add_key(SDL_SCANCODE_L, "l", 'l'); add_key(SDL_SCANCODE_M, "m", 'm', "ui_map"); key = add_key(SDL_SCANCODE_N, "n", 'n', "target_next"); key->assign(Key::Shift, "target_prev"); key->assign(Key::Ctrl, "target_none"); add_key(SDL_SCANCODE_O, "o", 'o'); add_key(SDL_SCANCODE_P, "p", 'p'); add_key(SDL_SCANCODE_Q, "q", 'q', "+rollleft"); add_key(SDL_SCANCODE_R, "r", 'r', "+strafeup"); add_key(SDL_SCANCODE_S, "s", 's', "+reverse"); add_key(SDL_SCANCODE_T, "t", 't', "ui_chatbar"); add_key(SDL_SCANCODE_U, "u", 'u'); key = add_key(SDL_SCANCODE_V, "v", 'v', "view_next"); key->assign(Key::Shift, "view_prev"); add_key(SDL_SCANCODE_W, "w", 'w', "+afterburner"); key = add_key(SDL_SCANCODE_X, "x", 'x', "target_controlable_next"); key->assign(Key::Shift, "target_controlable_prev"); key->assign(Key::Ctrl, "target_center"); add_key(SDL_SCANCODE_Y, "y", 'y'); add_key(SDL_SCANCODE_Z, "z", 'z'); add_key(SDL_SCANCODE_DELETE, "del"); add_key(SDL_SCANCODE_KP_0, "kp0"); add_key(SDL_SCANCODE_KP_1, "kp1"); add_key(SDL_SCANCODE_KP_2, "kp2", 0, "+up"); add_key(SDL_SCANCODE_KP_3, "kp3"); add_key(SDL_SCANCODE_KP_4, "kp4", 0, "+left"); add_key(SDL_SCANCODE_KP_5, "kp5"); add_key(SDL_SCANCODE_KP_6, "kp6", 0, "+right"); add_key(SDL_SCANCODE_KP_7, "kp7", 0, "+rollleft"); add_key(SDL_SCANCODE_KP_8, "kp8", 0, "+down"); add_key(SDL_SCANCODE_KP_9, "kp9", 0, "+rollright"); add_key(SDL_SCANCODE_KP_PERIOD, "kpperiod", '.'); add_key(SDL_SCANCODE_KP_DIVIDE, "kpdiv", '/', "+zoomin"); add_key(SDL_SCANCODE_KP_MULTIPLY, "kpmul", '*', "+zoomout"); add_key(SDL_SCANCODE_KP_MINUS, "kpmin", '-', "+thrustdown"); add_key(SDL_SCANCODE_KP_PLUS, "kpplus", '+', "+thrustup"); add_key(SDL_SCANCODE_KP_ENTER, "kpenter", '\n', "ui_chat"); add_key(SDL_SCANCODE_KP_EQUALS, "kpequal", '='); add_key(SDL_SCANCODE_KP_LESS, "kpless", '<'); add_key(SDL_SCANCODE_LEFT, "left", 0, "+ lookleft"); add_key(SDL_SCANCODE_RIGHT, "right", 0, "+lookright"); add_key(SDL_SCANCODE_UP, "up", 0, "+lookup"); add_key(SDL_SCANCODE_DOWN, "down", 0, "+lookdown"); add_key(SDL_SCANCODE_INSERT, "insert"); add_key(SDL_SCANCODE_HOME, "home"); add_key(SDL_SCANCODE_END, "end"); add_key(SDL_SCANCODE_PAGEUP, "pageup"); add_key(SDL_SCANCODE_PAGEDOWN, "pagedown"); add_key(SDL_SCANCODE_F1, "f1", 0, "freeflight"); add_key(SDL_SCANCODE_F2, "f2", 0, "@goto"); add_key(SDL_SCANCODE_F3, "f3", 0, "@dock"); key = add_key(SDL_SCANCODE_F4, "f4", 0, "@formation"); #ifdef _WIN32 key->assign(Key::Alt, "quit"); #endif add_key(SDL_SCANCODE_F5, "f5", 0, "savegame"); add_key(SDL_SCANCODE_F6, "f6"); add_key(SDL_SCANCODE_F7, "f7"); add_key(SDL_SCANCODE_F8, "f8"); add_key(SDL_SCANCODE_F9, "f9", 0, "loadgame"); add_key(SDL_SCANCODE_F10, "f10"); add_key(SDL_SCANCODE_F11, "f11"); add_key(SDL_SCANCODE_F12, "f12"); add_key(SDL_SCANCODE_F13, "f13"); add_key(SDL_SCANCODE_F14, "f14"); add_key(SDL_SCANCODE_F15, "F15"); add_key(SDL_SCANCODE_NUMLOCKCLEAR, "numlock"); add_key(SDL_SCANCODE_CAPSLOCK, "capslock"); add_key(SDL_SCANCODE_SCROLLLOCK, "scrollock"); add_key(SDL_SCANCODE_RSHIFT, "rshift"); add_key(SDL_SCANCODE_LSHIFT, "lshift", 0, "+freelook"); add_key(SDL_SCANCODE_RCTRL, "rctrl"); add_key(SDL_SCANCODE_LCTRL, "lctrl"); add_key(SDL_SCANCODE_RALT, "ralt"); add_key(SDL_SCANCODE_LALT, "lalt"); add_key(SDL_SCANCODE_RGUI, "rgui"); add_key(SDL_SCANCODE_LGUI, "lgui"); add_key(SDL_SCANCODE_MODE, "mode"); add_key(SDL_SCANCODE_HELP, "help"); add_key(SDL_SCANCODE_PRINTSCREEN, "print", 0, "screenshot"); add_key(SDL_SCANCODE_SYSREQ, "sysrq"); add_key(SDL_SCANCODE_PAUSE, "pause"); add_key(SDL_SCANCODE_MENU, "menu"); add_key(SDL_SCANCODE_POWER, "power"); // mouse button aliases add_key(512 + SDL_BUTTON_LEFT, "mouse1", 0, "+control"); add_key(512 + SDL_BUTTON_RIGHT, "mouse2", 0, "+fire"); add_key(512 + SDL_BUTTON_MIDDLE, "mouse3"); // mouse wheel aliases add_key(600, "mwheelup", 0, "+thrustup"); add_key(601, "mwheeldown", 0, "+thrustdown"); // joystick button aliases add_key(1024, "joy0"); add_key(1025, "joy1", 0, "target_center"); add_key(1026, "joy2"); add_key(1027, "joy3"); add_key(1028, "joy4"); add_key(1029, "joy5"); add_key(1030, "joy6"); add_key(1031, "joy7"); add_key(1032, "joy8"); add_key(1033, "joy9"); add_key(1034, "joy10"); add_key(1035, "joy11"); add_key(1036, "joy12"); add_key(1037, "joy13"); add_key(1038, "joy14"); add_key(1039, "joy15"); // ------------------ CONTROLS add_control("Toggle mouse control", "ui_control", "space"); add_control("Mouse control", "+control", "mouse1"); add_control("Turn left", "+left", "kp4"); add_control("Turn right", "+right", "kp6"); add_control("Turn up", "+up", "kp8"); add_control("Turn down", "+down", "kp2"); add_control("Strafe left", "+strafeleft", "a"); add_control("Strafe right", "+straferight", "d"); add_control("Strafe up", "+strafeup", "r"); add_control("Strafe down", "+strafedown", "f"); add_control("Roll left", "+rollleft", "q"); add_control("Roll right", "+rollright", "e"); add_control("Decrease thruster", "+thrustdown", "kpmin"); add_control("Increase thruster", "+thrustup", "kpplus"); add_control("Aferburner", "+afterburner", "w"); add_control("Reverse engine", "+reverse", "s"); add_control("Impulse engine", "impulse", "tab"); add_control("Fire weapons", "+fire", "mouse2"); add_control("Beam cargo", "beam", "b"); add_control("Open inventory", "ui_inventory", "i"); add_control("Open map", "ui_map", "m"); add_control("Open chat", "ui_chat", "enter"); add_control("Open talk", "ui_chatbar", "t"); add_control("Target next object", "target_next", "n"); add_control("Target previous object", "target_prev", "shift+n"); add_control("Target none", "target_none", "ctrl+n"); add_control("Target next ship", "target_controlable_next", "x"); add_control("Target previous ship", "target_controlable_prev", "shift+x"); add_control("Target center", "target_center", "ctrl+x"); add_control("Camera next", "view_next", "v"); add_control("Camera previous", "view_prev", "shift+v"); add_control("Camera zoom in", "+zoomin", "kpdiv"); add_control("Camera zoom out", "+zoomout", "kpmul"); add_control("Camera turn left", "+lookleft", "left"); add_control("Camera turn right", "+lookright", "right"); add_control("Camera turn up", "+lookup", "up"); add_control("Camera turn down", "+lookdown", "down"); add_control("Freelook", "+freelook", "lshift"); add_control("Free flight", "freeflight", "f1"); add_control("Autopilot goto", "@goto", "f2"); add_control("Autopilot dock", "@dock", "f3"); add_control("Autopilot formation", "@formation", "f4"); add_control("Quicksave", "savegame", "f5"); add_control("Quickload", "loadgame", "f9"); add_control("Wingmen toggle recall", "wingmen recall", "shift+c"); add_control("Wingmen toggle combat", "wingmen combat", "shift+b"); add_control("Screenshot", "screenshot", "print"); add_control("Toggle fullscreen", "toggle r_fullscreen", "alt+enter"); add_control("Toggle console", "+console", "`"); } Keyboard::~Keyboard() { // clear key map for (Keys::iterator it = _keys.begin(); it != _keys.end(); ++it) { delete(*it).second; } _keys.clear(); // clear action list for (Actions::iterator ait = _actions.begin(); ait != _actions.end(); ++ait) { delete(*ait); } _actions.clear(); // clear control list for (Controls::iterator cit = _controls.begin(); cit != _controls.end(); ++cit) { delete(*cit); } _controls.clear(); } void Keyboard::save_binds() const { std::string filename(filesystem::writedir()); filename.append("binds.cfg"); std::ofstream ofs(filename.c_str()); if (!ofs.is_open()) { con_warn << "Could not write " << filename << std::endl; return; } con_print << " writing keyboard binds to " << filename << std::endl; ofs << "# binds.cfg - osirion keyboard binds" << std::endl; ofs << "# this file is automaticly generated" << std::endl; ofs << std::endl; for (Keys::const_iterator it = _keys.begin(); it != _keys.end(); ++it) { Key *key = (*it).second; if (key->bind(Key::None).size()) { ofs << "bind " << key->name() << " \"" << key->bind(Key::None) << '\"' << std::endl; } if (key->bind(Key::Shift).size()) { ofs << "bind shift+" << key->name() << " \"" << key->bind(Key::Shift) << '\"' << std::endl; } if (key->bind(Key::Ctrl).size()) { ofs << "bind ctrl+" << key->name() << " \"" << key->bind(Key::Ctrl) << '\"' << std::endl; } if (key->bind(Key::Alt).size()) { ofs << "bind alt+" << key->name() << " \"" << key->bind(Key::Alt) << '\"' << std::endl; } /* } else { ofs << "unbind " << key->name() << std::endl; } */ } ofs.close(); } void Keyboard::load_binds() { std::string filename(filesystem::writedir()); filename.append("binds.cfg"); std::ifstream ifs(filename.c_str(), std::ifstream::in); if (!ifs.is_open()) { con_warn << "Could not read " << filename << std::endl; return; } con_print << " reading keyboard binds from " << filename << std::endl; char line[MAXCMDSIZE]; while (ifs.getline(line, MAXCMDSIZE - 1)) { if (line[0] && line[0] != '#' && line[0] != ';') { core::CommandBuffer::exec(line); } } load_controls(); } void Keyboard::load_controls() { for (Controls::iterator cit = _controls.begin(); cit != _controls.end(); ++cit) { Control *control = *cit; bool found = false; for (Keys::iterator kit = _keys.begin(); kit != _keys.end();) { Key *key = (*kit).second; if (control->command().compare(key->bind(Key::None)) == 0) { control->set_keyname(key->name()); kit = _keys.end(); found = true; } else if (control->command().compare(key->bind(Key::Shift)) == 0) { control->set_keyname("shift+" + key->name()); kit = _keys.end(); found = true; } else if (control->command().compare(key->bind(Key::Ctrl)) == 0) { control->set_keyname("ctrl+" + key->name()); kit = _keys.end(); found = true; } else if (control->command().compare(key->bind(Key::Alt)) == 0) { control->set_keyname("alt+" + key->name()); kit = _keys.end(); found = true; } else { ++kit; } } if (!found) { control->set_keyname(""); } } } void Keyboard::reset() { for (Keys::iterator it = _keys.begin(); it != _keys.end(); ++it) { Key *key = (*it).second; if (key) { key->key_pressed = 0; key->key_lastpressed = 0; key->key_waspressed = 0; } } } Key * Keyboard::release(const unsigned int scancode) { Key *key = find(scancode); if (!key) { return 0; } key->key_waspressed = (core::application()->time() - key->pressed()); key->key_pressed = 0; key->key_lastpressed = 0; return key; } Key * Keyboard::press(const unsigned int scancode) { Key *key = find(scancode); if (!key) { return 0; } return press(key); } Key * Keyboard::press(Key *key) { if (key->pressed() == 0) { key->key_pressed = core::application()->time(); key->key_waspressed = 0; } key->key_lastpressed = core::application()->time(); return key; } Key *Keyboard::find(std::string const & name) { Key *key = 0; for (Keys::iterator it = _keys.begin(); it != _keys.end(); ++it) { if ((*it).second->name().compare(name) == 0) { key = (*it).second; } } return key; } Key *Keyboard::find(const unsigned int scancode) { Keys::iterator it = _keys.find(scancode); if (it == _keys.end()) { return 0; } else { return (*it).second; } } void Keyboard::bind(std::string const &name, const std::string str) { Key::Modifier modifier = Key::None; std::string keyname(name); if ((keyname.size() > 6) && (keyname.substr(0, 6).compare("shift+") == 0)) { keyname.erase(0, 6); modifier = Key::Shift; } else if ((keyname.size() > 5) && (keyname.substr(0, 5).compare("ctrl+") == 0)) { keyname.erase(0, 5); modifier = Key::Ctrl; } else if ((keyname.size() > 4) && (keyname.substr(0, 4).compare("alt+") == 0)) { keyname.erase(0, 4); modifier = Key::Alt; } else if ((keyname.size() > 6) && (keyname.substr(keyname.size() - 6, 6).compare("+shift") == 0)) { keyname.erase(keyname.size() - 6, 6); modifier = Key::Shift; } else if ((keyname.size() > 5) && (keyname.substr(keyname.size() - 5, 5).compare("+ctrl") == 0)) { keyname.erase(keyname.size() - 5, 5); modifier = Key::Ctrl; } else if ((keyname.size() > 4) && (keyname.substr(keyname.size() - 4, 4).compare("+alt") == 0)) { keyname.erase(0, keyname.size() - 46); modifier = Key::Alt; } Key *key = find(keyname); if (key) { // assign new bind of requested if (str.size()) { Action *action = 0; for (Actions::iterator it = _actions.begin(); it != _actions.end(); ++it) { if ((*it)->name().compare(str) == 0) { action = (*it); } } if (action && (modifier != Key::None)) { if (modifier == Key::Shift) { con_warn << "Key with modifier 'shift+" << key->name() << "' can not be bound to action '" << action->name() << "'!" << std::endl; } else if (modifier == Key::Ctrl) { con_warn << "Key with modifier 'ctrl+" << key->name() << "' can not be bound to action '" << action->name() << "'!" << std::endl; } else if (modifier == Key::Alt) { con_warn << "Key with modifier 'alt+" << key->name() << "' can not be bound to action '" << action->name() << "'!" << std::endl; } return; } key->assign(modifier, str.c_str(), action); } // print current bind to console, even when no new bind was assigned if (modifier == Key::None) { con_print << " " << aux::pad_right(key->name(), 6) << " " << key->bind(Key::None) << std::endl; } else if (modifier == Key::Shift) { con_print << " shift+" << aux::pad_right(key->name(), 6) << " " << key->bind(Key::Shift) << std::endl; } else if (modifier == Key::Ctrl) { con_print << " ctrl+" << aux::pad_right(key->name(), 6) << " " << key->bind(Key::Ctrl) << std::endl; } else if (modifier == Key::Alt) { con_print << " alt+" << aux::pad_right(key->name(), 6) << " " << key->bind(Key::Alt) << std::endl; } } else { con_warn << "Key '" << name << "' not found!" << std::endl; } } void Keyboard::unbind(std::string const &name) { Key::Modifier modifier = Key::None; std::string keyname(name); if ((keyname.size() > 6) && (keyname.substr(0, 6).compare("shift+") == 0)) { keyname.erase(0, 6); modifier = Key::Shift; } else if ((keyname.size() > 5) && (keyname.substr(0, 5).compare("ctrl+") == 0)) { keyname.erase(0, 5); modifier = Key::Ctrl; } else if ((keyname.size() > 4) && (keyname.substr(0, 4).compare("alt+") == 0)) { keyname.erase(0, 4); modifier = Key::Alt; } else if ((keyname.size() > 6) && (keyname.substr(keyname.size() - 6, 6).compare("+shift") == 0)) { keyname.erase(keyname.size() - 6, 6); modifier = Key::Shift; } else if ((keyname.size() > 5) && (keyname.substr(keyname.size() - 5, 5).compare("+ctrl") == 0)) { keyname.erase(keyname.size() - 5, 5); modifier = Key::Ctrl; } else if ((keyname.size() > 4) && (keyname.substr(keyname.size() - 4, 4).compare("+alt") == 0)) { keyname.erase(0, keyname.size() - 46); modifier = Key::Alt; } Key *key = find(keyname); if (key) { key->clear(modifier); } else { con_print << "Key '" << name << "' not found." << std::endl; } } void Keyboard::unbindall() { for (Keys::iterator it = _keys.begin(); it != _keys.end(); ++it) { Key *key = (*it).second; key->clear(); } } Key * Keyboard::add_key(const unsigned int scancode, const char *name, const char ascii, const char *bind) { Key *key = new Key(scancode, name, ascii); _keys[scancode] = key; if (bind) { std::string bindstr(bind); this->bind(key->name(), bindstr); } return key; } Action * Keyboard::add_action(const char *name, Action::Identifier id, const char *description) { Action *action = new Action(name, id, description); _actions.push_back(action); return action; } Control *Keyboard::add_control(const char *name, const char *command, const char *keyname) { Control *control = new Control(name, command, keyname); _controls.push_back(control); return control; } void Keyboard::list_actions() const { for (Actions::const_iterator it = _actions.begin(); it != _actions.end(); ++it) { con_print << " " << (*it)->name() << " " << (*it)->description() << std::endl; } con_print << _actions.size() << " registered actions" << std::endl; } void Keyboard::list_keys() const { for (Keys::const_iterator it = _keys.begin(); it != _keys.end(); ++it) { con_print << " " << aux::pad_left((*it).second->name(), 6) << " " << (*it).second->bind(Key::None) << std::endl; } con_print << _keys.size() << " registered keys" << std::endl; } void Keyboard::list_binds() const { size_t n = 0; for (Keys::const_iterator it = _keys.begin(); it != _keys.end(); ++it) { if ((*it).second->bind(Key::None).size()) { con_print << " " << aux::pad_right((*it).second->name(), 6) << " " << (*it).second->bind(Key::None) << std::endl; n++; } if ((*it).second->bind(Key::Shift).size()) { con_print << " shift+" << aux::pad_right((*it).second->name(), 6) << " " << (*it).second->bind(Key::Shift) << std::endl; n++; } if ((*it).second->bind(Key::Ctrl).size()) { con_print << " ctrl+" << aux::pad_right((*it).second->name(), 6) << " " << (*it).second->bind(Key::Ctrl) << std::endl; n++; } if ((*it).second->bind(Key::Alt).size()) { con_print << " alt+" << aux::pad_right((*it).second->name(), 6) << " " << (*it).second->bind(Key::Alt) << std::endl; n++; } } con_print << n << " registered binds" << std::endl; } unsigned int Keyboard::translate_keysym(const unsigned int keysym, const int modifiers) { bool shift = false; // keypad keys if (modifiers & KMOD_NUM) { switch (keysym) { case SDLK_KP_0: return '0'; break; case SDLK_KP_1: return '1'; break; case SDLK_KP_2: return '2'; break; case SDLK_KP_3: return '3'; break; case SDLK_KP_4: return '4'; break; case SDLK_KP_5: return '5'; break; case SDLK_KP_6: return '6'; break; case SDLK_KP_7: return '7'; break; case SDLK_KP_8: return '8'; break; case SDLK_KP_9: return '9'; break; case SDLK_KP_PERIOD: return '.'; break; } } else { switch (keysym) { case SDLK_KP_0: return SDLK_INSERT; break; case SDLK_KP_1: return SDLK_END; break; case SDLK_KP_2: return SDLK_DOWN; break; case SDLK_KP_3: return SDLK_PAGEDOWN; break; case SDLK_KP_4: return SDLK_LEFT; break; case SDLK_KP_6: return SDLK_RIGHT; break; case SDLK_KP_7: return SDLK_HOME; break; case SDLK_KP_8: return SDLK_UP; break; case SDLK_KP_9: return SDLK_PAGEUP; break; case SDLK_KP_PERIOD: return SDLK_DELETE; break; } } // special keys switch (keysym) { case SDLK_ESCAPE: return SDLK_ESCAPE; break; case SDLK_KP_ENTER: return SDLK_RETURN; break; case SDLK_KP_DIVIDE: return '/'; break; case SDLK_KP_MULTIPLY: return '*'; break; case SDLK_KP_MINUS: return '-'; break; case SDLK_KP_PLUS: return '+'; break; case SDLK_KP_EQUALS: return '='; break; } // caps lock if (modifiers & KMOD_CAPS) { shift = true; } // left/right shift if ((KMOD_LSHIFT + KMOD_RSHIFT) & modifiers) { shift = !shift; } if (shift) { if ((keysym >= 'a' && keysym <= 'z')) { return keysym + 'A' - 'a'; } switch (keysym) { case '`': return '~'; break; case '1': return '!'; break; case '2': return '@'; break; case '3': return '#'; break; case '4': return '$'; break; case '5': return '%'; break; case '6': return '^'; break; case '7': return '&'; break; case '8': return '*'; break; case '9': return '('; break; case '0': return ')'; break; case '-': return '_'; break; case '=': return '+'; break; // second row case '[': return '{'; break; case ']': return '}'; break; case '|': return '\\'; break; // third row case ';': return ':'; break; case '\'': return '"'; break; // fourth row case ',': return '<'; break; case '.': return '>'; break; case '/': return '?'; break; } } return keysym; } } // namespace client