/* 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() { numlock = false; capslock = false; // ------------------ ACTIONS // FIXME actions should be state keys and not use key repeat add_action("+left", Action::None, "rotate left"); add_action("+right", Action::None, "rotate right"); add_action("+up", Action::None, "rotate up"); add_action("+down", Action::None, "rotate down"); add_action("+rollleft", Action::None, "roll left"); add_action("+rollright", Action::None, "roll right"); add_action("+camleft", Action::None, "rotate camera left"); add_action("+camright", Action::None, "rotate camera right"); add_action("+camup", Action::None, "rotate camera up"); add_action("+camdown", Action::None, "rotate camera down"); add_action("+zoomin", Action::None, "zoom camera in"); add_action("+zoomout", Action::None, "zoom camera out"); add_action("+thrustup", Action::None, "increase thruster"); add_action("+thrustdown", Action::None, "decrease thruster"); add_action("+strafeleft", Action::None, "strafe left"); add_action("+straferight", Action::None, "strafe right"); add_action("+afterburner", Action::None, "afterburner"); add_action("+reverse", Action::None, "reverse engine"); add_action("+control", Action::None, "enable mouse control while pressed"); // TODO the @ is a hack for functions that take the current entity as param add_action("@dock", Action::None, "send docking request to target"); // ------------------ KEYS Key *key = 0; add_key("backspace", SDLK_BACKSPACE); add_key("tab", SDLK_TAB, 0, "impulse"); add_key("clear", SDLK_CLEAR); key = add_key("enter", SDLK_RETURN, 0, "ui_chat"); key->assign(Key::Alt, "toggle r_fullscreen"); add_key("pause", SDLK_PAUSE); add_key("esc", SDLK_ESCAPE); add_key("space", SDLK_SPACE, ' ', "ui_control"); add_key("!", SDLK_EXCLAIM, '!'); add_key("\"", SDLK_QUOTEDBL, '"'); add_key("#", SDLK_HASH, '#'); add_key("$", SDLK_DOLLAR, '$'); add_key("&", SDLK_AMPERSAND, '&'); add_key("'", SDLK_QUOTE, '\''); add_key("(", SDLK_LEFTPAREN, '('); add_key(")", SDLK_RIGHTPAREN, ')'); add_key("*", SDLK_ASTERISK, '*'); add_key("+", SDLK_PLUS, '+'); add_key(",", SDLK_COMMA, ','); add_key("-", SDLK_MINUS, '-'); add_key(".", SDLK_PERIOD, '.'); add_key("/", SDLK_SLASH, '/'); add_key("0", SDLK_0, '0'); add_key("1", SDLK_1, '1'); add_key("2", SDLK_2, '2'); add_key("3", SDLK_3, '3'); add_key("4", SDLK_4, '4'); add_key("5", SDLK_5, '5'); add_key("6", SDLK_6, '6'); add_key("7", SDLK_7, '7'); add_key("8", SDLK_8, '8'); add_key("9", SDLK_9, '9'); add_key(":", SDLK_COLON, ':'); add_key(";", SDLK_SEMICOLON, ';'); add_key("<", SDLK_LESS, '<'); add_key("=", SDLK_EQUALS, '='); add_key(">", SDLK_GREATER, '>'); add_key("?", SDLK_QUESTION, '?'); add_key("@", SDLK_AT, '@'); add_key("[", SDLK_LEFTBRACKET, '['); add_key("\\", SDLK_BACKSLASH, '\\'); add_key("]", SDLK_RIGHTBRACKET, ']'); add_key("^", SDLK_CARET, '^'); add_key("_", SDLK_UNDERSCORE, '_'); add_key("`", SDLK_BACKQUOTE, '`', "ui_console"); add_key("a", SDLK_a, 'a', "+strafeleft"); add_key("b", SDLK_b, 'b'); add_key("c", SDLK_c, 'c'); add_key("d", SDLK_d, 'd', "+straferight"); add_key("e", SDLK_e, 'e', "+rollright"); add_key("f", SDLK_f, 'f'); add_key("g", SDLK_g, 'g'); add_key("h", SDLK_h, 'h'); add_key("i", SDLK_i, 'i'); add_key("j", SDLK_j, 'j'); add_key("k", SDLK_k, 'k'); add_key("l", SDLK_l, 'l'); add_key("m", SDLK_m, 'm'); key = add_key("n", SDLK_n, 'n', "target_next"); key->assign(Key::Shift, "target_prev"); key->assign(Key::Ctrl, "target_none"); add_key("o", SDLK_o, 'o'); add_key("p", SDLK_p, 'p'); add_key("q", SDLK_q, 'q', "+rollleft"); add_key("r", SDLK_r, 'r'); add_key("s", SDLK_s, 's', "+reverse"); add_key("t", SDLK_t, 't', "ui_chatbar"); add_key("u", SDLK_u, 'u'); key = add_key("v", SDLK_v, 'v', "view_next"); key->assign(Key::Shift, "view_prev"); add_key("w", SDLK_w, 'w', "+afterburner"); add_key("x", SDLK_x, 'x', "target_center"); add_key("y", SDLK_y, 'y'); add_key("z", SDLK_z, 'z'); add_key("del", SDLK_DELETE); add_key("kp0", SDLK_KP0); add_key("kp1", SDLK_KP1); add_key("kp2", SDLK_KP2, 0, "+up"); add_key("kp3", SDLK_KP3); add_key("kp4", SDLK_KP4, 0, "+left"); add_key("kp5", SDLK_KP5); add_key("kp6", SDLK_KP6, 0, "+right"); add_key("kp7", SDLK_KP7, 0, "+rollleft"); add_key("kp8", SDLK_KP8, 0, "+down"); add_key("kp9", SDLK_KP9, 0, "+rollright"); add_key("kpperiod", SDLK_KP_PERIOD, '.'); add_key("kpdiv", SDLK_KP_DIVIDE, '/', "+zoomin"); add_key("kpmul", SDLK_KP_MULTIPLY, '*', "+zoomout"); add_key("kpmin", SDLK_KP_MINUS, '-', "+thrustdown"); add_key("kpplus", SDLK_KP_PLUS, '+', "+thrustup"); add_key("kpenter", SDLK_KP_ENTER, '\n', "ui_chat"); add_key("kpequal", SDLK_KP_EQUALS, '='); add_key("up", SDLK_UP, 0, "+camup"); add_key("down", SDLK_DOWN, 0, "+camdown"); add_key("right", SDLK_RIGHT, 0, "+camright"); add_key("left", SDLK_LEFT, 0, "+camleft"); add_key("insert", SDLK_INSERT); add_key("home", SDLK_HOME); add_key("end", SDLK_END); add_key("pageup", SDLK_PAGEUP); add_key("pagedown", SDLK_PAGEDOWN); add_key("f1", SDLK_F1); add_key("f2", SDLK_F2); add_key("f3", SDLK_F3, 0, "@dock"); key = add_key("f4", SDLK_F4); #ifdef _WIN32 key->assign(Key::Alt, "quit"); #endif add_key("f5", SDLK_F5); add_key("f6", SDLK_F6, 0, "ui_map"); add_key("f7", SDLK_F7); add_key("f8", SDLK_F8); add_key("f9", SDLK_F9); add_key("f10", SDLK_F10); add_key("f11", SDLK_F11); add_key("f12", SDLK_F12); add_key("f13", SDLK_F13); add_key("f14", SDLK_F14); add_key("f15", SDLK_F15); add_key("numlock", SDLK_NUMLOCK); add_key("capslock", SDLK_CAPSLOCK); add_key("scrollock", SDLK_SCROLLOCK); add_key("rshift", SDLK_RSHIFT); add_key("lshift", SDLK_LSHIFT); add_key("rctrl", SDLK_RCTRL); add_key("lctrl", SDLK_LCTRL); add_key("ralt", SDLK_RALT); add_key("lalt", SDLK_LALT); add_key("rmeta", SDLK_RMETA); add_key("lmeta", SDLK_LMETA); add_key("lwin", SDLK_LSUPER); add_key("rwin", SDLK_RSUPER); add_key("mode", SDLK_MODE); add_key("help", SDLK_HELP); add_key("print", SDLK_PRINT, 0, "screenshot"); add_key("sysrq", SDLK_SYSREQ); add_key("break", SDLK_BREAK); add_key("menu", SDLK_MENU); add_key("power", SDLK_POWER); add_key("euro", SDLK_EURO); // mouse button aliases add_key("mouse1", 512 + SDL_BUTTON_LEFT, 0, "+control"); add_key("mouse2", 512 + SDL_BUTTON_RIGHT); add_key("mouse3", 512 + SDL_BUTTON_MIDDLE); add_key("mouse4", 512 + SDL_BUTTON_WHEELUP, 0, "+thrustup"); add_key("mouse5", 512 + SDL_BUTTON_WHEELDOWN, 0, "+thrustdown"); // joystick button aliases add_key("joy0", 564); add_key("joy1", 565, 0, "target_center"); add_key("joy2", 566); add_key("joy3", 567); add_key("joy4", 568); add_key("joy5", 569); add_key("joy6", 570); add_key("joy7", 571); add_key("joy8", 572); add_key("joy9", 573); add_key("joy10", 574); add_key("joy11", 575); add_key("joy12", 576); add_key("joy13", 577); add_key("joy14", 578); add_key("joy15", 579); } Keyboard::~Keyboard() { // clear key map for (iterator it = begin(); it != end(); it++) delete(*it).second; keys.clear(); // clear action list for (std::list::iterator ait = actions.begin(); ait != actions.end(); ait++) delete(*ait); actions.clear(); } void Keyboard::save_binds() { 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; iterator it; for (it = begin(); it != 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::cmd() << line << '\n'; } // execute commands in the buffer core::CommandBuffer::exec(); } Key * Keyboard::release(unsigned int sym) { Key *key = find(sym); 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(unsigned int sym) { Key *key = find(sym); 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 (iterator it = begin(); it != end() && !key; it++) { if ((*it).second->name().compare(name) == 0) { key = (*it).second; } } return key; } Key *Keyboard::find(unsigned int keysym) { iterator it = keys.find(keysym); if (it == 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) { if (str.size()) key->assign(modifier, str.c_str()); if (modifier == Key::None) { con_debug << " " << aux::pad_right(key->name(), 6) << " " << key->bind(Key::None) << std::endl; } else if (modifier == Key::Shift) { con_debug << " shift+" << aux::pad_right(key->name(), 6) << " " << key->bind(Key::Shift) << std::endl; } else if (modifier == Key::Ctrl) { con_debug << " ctrl+" << aux::pad_right(key->name(), 6) << " " << key->bind(Key::Ctrl) << std::endl; } else if (modifier == Key::Alt) { con_debug << " alt+" << aux::pad_right(key->name(), 6) << " " << key->bind(Key::Alt) << std::endl; } } else { con_print << "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(name); if (key) { key->clear(modifier); } else { con_print << "Key '" << name << "' not found." << std::endl; } } void Keyboard::unbindall() { for (iterator it = begin(); it != end(); it++) { Key *key = (*it).second; key->clear(); } } Key * Keyboard::add_key(const char *name, const unsigned int keysym, const char ascii, const char *bind) { Key *newkey = new Key(name, keysym, ascii, bind); keys[keysym] = newkey; return newkey; } Action * Keyboard::add_action(const char *name, Action::Identifier action, const char *info) { Action *newaction = new Action(name, action, info); actions.push_back(newaction); return newaction; } void Keyboard::list_actions() { for (std::list::iterator it = actions.begin(); it != actions.end(); it++) { con_print << " " << (*it)->name() << " " << (*it)->info() << std::endl; } con_print << actions.size() << " registered actions" << std::endl; } void Keyboard::list_keys() { for (iterator it = begin(); it != 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() { size_t n = 0; for (iterator it = begin(); it != 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(int keysym, int modifier) { bool shift = false; bool numlock = false; // keypad keys if (modifier & KMOD_NUM) { numlock = true; switch (keysym) { case SDLK_KP0: return '0'; break; case SDLK_KP1: return '1'; break; case SDLK_KP2: return '2'; break; case SDLK_KP3: return '3'; break; case SDLK_KP4: return '4'; break; case SDLK_KP5: return '5'; break; case SDLK_KP6: return '6'; break; case SDLK_KP7: return '7'; break; case SDLK_KP8: return '8'; break; case SDLK_KP9: return '9'; break; case SDLK_KP_PERIOD: return '.'; break; } } else { switch (keysym) { case SDLK_KP0: return SDLK_INSERT; break; case SDLK_KP1: return SDLK_END; break; case SDLK_KP2: return SDLK_DOWN; break; case SDLK_KP3: return SDLK_PAGEDOWN; break; case SDLK_KP4: return SDLK_LEFT; break; case SDLK_KP6: return SDLK_RIGHT; break; case SDLK_KP7: return SDLK_HOME; break; case SDLK_KP8: return SDLK_UP; break; case SDLK_KP9: 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 (modifier & KMOD_CAPS) shift = true; // left/right shift if ((KMOD_LSHIFT + KMOD_RSHIFT) & modifier) { 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; } /* void setkeyboardmode(bool input) { if(input) SDL_EnableKeyRepeat(250, SDL_DEFAULT_REPEAT_INTERVAL); else SDL_EnableKeyRepeat(10, SDL_DEFAULT_REPEAT_INTERVAL); } */ } // namespace client