/* * Custom keyboard shortcuts configuration * Copyright (C) 2007 Joshua Langley <joshlangley@optusnet.com.au> * Copyright (C) 2009 The Mana World Development Team * Copyright (C) 2009-2010 The Mana Developers * Copyright (C) 2011-2012 The ManaPlus Developers * * This file is part of The ManaPlus Client. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "gui/setup_input.h" #include "inputmanager.h" #include "keyboardconfig.h" #include "gui/okdialog.h" #include "gui/widgets/button.h" #include "gui/widgets/layouthelper.h" #include "gui/widgets/listbox.h" #include "gui/widgets/scrollarea.h" #include "utils/gettext.h" #include "utils/stringutils.h" #include <guichan/listmodel.hpp> #include <SDL_keyboard.h> #include "debug.h" struct SetupActionData { std::string name; int actionId; }; static SetupActionData const setupActionData[] = { { N_("Basic Keys"), Input::KEY_NO_VALUE }, { N_("Move Up"), Input::KEY_MOVE_UP }, { N_("Move Down"), Input::KEY_MOVE_DOWN }, { N_("Move Left"), Input::KEY_MOVE_LEFT }, { N_("Move Right"), Input::KEY_MOVE_RIGHT }, { N_("Attack"), Input::KEY_ATTACK }, { N_("Target & Attack"), Input::KEY_TARGET_ATTACK }, { N_("Move to Target"), Input::KEY_MOVE_TO_TARGET }, { N_("Change Move to Target type"), Input::KEY_CHANGE_MOVE_TO_TARGET }, { N_("Move to Home location"), Input::KEY_MOVE_TO_HOME }, { N_("Set home location"), Input::KEY_SET_HOME }, { N_("Move to navigation point"), Input::KEY_MOVE_TO_POINT }, { N_("Talk"), Input::KEY_TALK }, { N_("Stop Attack"), Input::KEY_STOP_ATTACK }, { N_("Untarget"), Input::KEY_UNTARGET }, { N_("Target monster"), Input::KEY_TARGET_MONSTER }, { N_("Target NPC"), Input::KEY_TARGET_NPC }, { N_("Target Player"), Input::KEY_TARGET_PLAYER }, { N_("Pickup"), Input::KEY_PICKUP }, { N_("Change Pickup Type"), Input::KEY_CHANGE_PICKUP_TYPE }, { N_("Hide Windows"), Input::KEY_HIDE_WINDOWS }, { N_("Sit"), Input::KEY_SIT }, { N_("Screenshot"), Input::KEY_SCREENSHOT }, { N_("Enable/Disable Trading"), Input::KEY_TRADE }, { N_("Change Map View Mode"), Input::KEY_PATHFIND }, { N_("Select OK"), Input::KEY_OK }, { N_("Quit"), Input::KEY_QUIT }, { N_("Shortcuts Keys"), Input::KEY_NO_VALUE }, { N_("Item Shortcuts Key"), Input::KEY_SHORTCUTS_KEY }, { strprintf(N_("Item Shortcut %d"), 1), Input::KEY_SHORTCUT_1 }, { strprintf(N_("Item Shortcut %d"), 2), Input::KEY_SHORTCUT_2 }, { strprintf(N_("Item Shortcut %d"), 3), Input::KEY_SHORTCUT_3 }, { strprintf(N_("Item Shortcut %d"), 4), Input::KEY_SHORTCUT_4 }, { strprintf(N_("Item Shortcut %d"), 5), Input::KEY_SHORTCUT_5 }, { strprintf(N_("Item Shortcut %d"), 6), Input::KEY_SHORTCUT_6 }, { strprintf(N_("Item Shortcut %d"), 7), Input::KEY_SHORTCUT_7 }, { strprintf(N_("Item Shortcut %d"), 8), Input::KEY_SHORTCUT_8 }, { strprintf(N_("Item Shortcut %d"), 9), Input::KEY_SHORTCUT_9 }, { strprintf(N_("Item Shortcut %d"), 10), Input::KEY_SHORTCUT_10 }, { strprintf(N_("Item Shortcut %d"), 11), Input::KEY_SHORTCUT_11 }, { strprintf(N_("Item Shortcut %d"), 12), Input::KEY_SHORTCUT_12 }, { strprintf(N_("Item Shortcut %d"), 13), Input::KEY_SHORTCUT_13 }, { strprintf(N_("Item Shortcut %d"), 14), Input::KEY_SHORTCUT_14 }, { strprintf(N_("Item Shortcut %d"), 15), Input::KEY_SHORTCUT_15 }, { strprintf(N_("Item Shortcut %d"), 16), Input::KEY_SHORTCUT_16 }, { strprintf(N_("Item Shortcut %d"), 17), Input::KEY_SHORTCUT_17 }, { strprintf(N_("Item Shortcut %d"), 18), Input::KEY_SHORTCUT_18 }, { strprintf(N_("Item Shortcut %d"), 19), Input::KEY_SHORTCUT_19 }, { strprintf(N_("Item Shortcut %d"), 20), Input::KEY_SHORTCUT_20 }, { N_("Windows Keys"), Input::KEY_NO_VALUE }, { N_("Help Window"), Input::KEY_WINDOW_HELP }, { N_("Status Window"), Input::KEY_WINDOW_STATUS }, { N_("Inventory Window"), Input::KEY_WINDOW_INVENTORY }, { N_("Equipment Window"), Input::KEY_WINDOW_EQUIPMENT }, { N_("Skill Window"), Input::KEY_WINDOW_SKILL }, { N_("Minimap Window"), Input::KEY_WINDOW_MINIMAP }, { N_("Chat Window"), Input::KEY_WINDOW_CHAT }, { N_("Item Shortcut Window"), Input::KEY_WINDOW_SHORTCUT }, { N_("Setup Window"), Input::KEY_WINDOW_SETUP }, { N_("Debug Window"), Input::KEY_WINDOW_DEBUG }, { N_("Social Window"), Input::KEY_WINDOW_SOCIAL }, { N_("Emote Shortcut Window"), Input::KEY_WINDOW_EMOTE_SHORTCUT }, { N_("Outfits Window"), Input::KEY_WINDOW_OUTFIT }, { N_("Shop Window"), Input::KEY_WINDOW_SHOP }, { N_("Quick drop Window"), Input::KEY_WINDOW_DROP }, { N_("Kill Stats Window"), Input::KEY_WINDOW_KILLS }, { N_("Commands Window"), Input::KEY_WINDOW_SPELLS }, { N_("Bot Checker Window"), Input::KEY_WINDOW_BOT_CHECKER }, { N_("Who Is Online Window"), Input::KEY_WINDOW_ONLINE }, { N_("Did you know Window"), Input::KEY_WINDOW_DIDYOUKNOW }, { N_("Previous Social Tab"), Input::KEY_PREV_SOCIAL_TAB }, { N_("Next Social Tab"), Input::KEY_NEXT_SOCIAL_TAB }, { N_("Emotes Keys"), Input::KEY_NO_VALUE }, { N_("Smilie"), Input::KEY_EMOTE }, { strprintf(N_("Emote Shortcut %d"), 1), Input::KEY_EMOTE_1 }, { strprintf(N_("Emote Shortcut %d"), 2), Input::KEY_EMOTE_2 }, { strprintf(N_("Emote Shortcut %d"), 3), Input::KEY_EMOTE_3 }, { strprintf(N_("Emote Shortcut %d"), 4), Input::KEY_EMOTE_4 }, { strprintf(N_("Emote Shortcut %d"), 5), Input::KEY_EMOTE_5 }, { strprintf(N_("Emote Shortcut %d"), 6), Input::KEY_EMOTE_6 }, { strprintf(N_("Emote Shortcut %d"), 7), Input::KEY_EMOTE_7 }, { strprintf(N_("Emote Shortcut %d"), 8), Input::KEY_EMOTE_8 }, { strprintf(N_("Emote Shortcut %d"), 9), Input::KEY_EMOTE_9 }, { strprintf(N_("Emote Shortcut %d"), 10), Input::KEY_EMOTE_10 }, { strprintf(N_("Emote Shortcut %d"), 11), Input::KEY_EMOTE_11 }, { strprintf(N_("Emote Shortcut %d"), 12), Input::KEY_EMOTE_12 }, { strprintf(N_("Emote Shortcut %d"), 13), Input::KEY_EMOTE_13 }, { strprintf(N_("Emote Shortcut %d"), 14), Input::KEY_EMOTE_14 }, { strprintf(N_("Emote Shortcut %d"), 15), Input::KEY_EMOTE_15 }, { strprintf(N_("Emote Shortcut %d"), 16), Input::KEY_EMOTE_16 }, { strprintf(N_("Emote Shortcut %d"), 17), Input::KEY_EMOTE_17 }, { strprintf(N_("Emote Shortcut %d"), 18), Input::KEY_EMOTE_18 }, { strprintf(N_("Emote Shortcut %d"), 19), Input::KEY_EMOTE_19 }, { strprintf(N_("Emote Shortcut %d"), 20), Input::KEY_EMOTE_20 }, { strprintf(N_("Emote Shortcut %d"), 21), Input::KEY_EMOTE_21 }, { strprintf(N_("Emote Shortcut %d"), 22), Input::KEY_EMOTE_22 }, { strprintf(N_("Emote Shortcut %d"), 23), Input::KEY_EMOTE_23 }, { strprintf(N_("Emote Shortcut %d"), 24), Input::KEY_EMOTE_24 }, { strprintf(N_("Emote Shortcut %d"), 25), Input::KEY_EMOTE_25 }, { strprintf(N_("Emote Shortcut %d"), 26), Input::KEY_EMOTE_26 }, { strprintf(N_("Emote Shortcut %d"), 27), Input::KEY_EMOTE_27 }, { strprintf(N_("Emote Shortcut %d"), 28), Input::KEY_EMOTE_28 }, { strprintf(N_("Emote Shortcut %d"), 29), Input::KEY_EMOTE_29 }, { strprintf(N_("Emote Shortcut %d"), 30), Input::KEY_EMOTE_30 }, { strprintf(N_("Emote Shortcut %d"), 31), Input::KEY_EMOTE_31 }, { strprintf(N_("Emote Shortcut %d"), 32), Input::KEY_EMOTE_32 }, { strprintf(N_("Emote Shortcut %d"), 33), Input::KEY_EMOTE_33 }, { strprintf(N_("Emote Shortcut %d"), 34), Input::KEY_EMOTE_34 }, { strprintf(N_("Emote Shortcut %d"), 35), Input::KEY_EMOTE_35 }, { strprintf(N_("Emote Shortcut %d"), 36), Input::KEY_EMOTE_36 }, { strprintf(N_("Emote Shortcut %d"), 37), Input::KEY_EMOTE_37 }, { strprintf(N_("Emote Shortcut %d"), 38), Input::KEY_EMOTE_38 }, { strprintf(N_("Emote Shortcut %d"), 39), Input::KEY_EMOTE_39 }, { strprintf(N_("Emote Shortcut %d"), 40), Input::KEY_EMOTE_40 }, { strprintf(N_("Emote Shortcut %d"), 41), Input::KEY_EMOTE_41 }, { strprintf(N_("Emote Shortcut %d"), 42), Input::KEY_EMOTE_42 }, { strprintf(N_("Emote Shortcut %d"), 43), Input::KEY_EMOTE_43 }, { strprintf(N_("Emote Shortcut %d"), 44), Input::KEY_EMOTE_44 }, { strprintf(N_("Emote Shortcut %d"), 45), Input::KEY_EMOTE_45 }, { strprintf(N_("Emote Shortcut %d"), 46), Input::KEY_EMOTE_46 }, { strprintf(N_("Emote Shortcut %d"), 47), Input::KEY_EMOTE_47 }, { strprintf(N_("Emote Shortcut %d"), 48), Input::KEY_EMOTE_48 }, { N_("Outfits Keys"), Input::KEY_NO_VALUE }, { N_("Wear Outfit"), Input::KEY_WEAR_OUTFIT }, { N_("Copy Outfit"), Input::KEY_COPY_OUTFIT }, { N_("Copy equipped to Outfit"), Input::KEY_COPY_EQUIPED_OUTFIT }, { N_("Chat Keys"), Input::KEY_NO_VALUE }, { N_("Toggle Chat"), Input::KEY_TOGGLE_CHAT }, { N_("Scroll Chat Up"), Input::KEY_SCROLL_CHAT_UP }, { N_("Scroll Chat Down"), Input::KEY_SCROLL_CHAT_DOWN }, { N_("Previous Chat Tab"), Input::KEY_PREV_CHAT_TAB }, { N_("Next Chat Tab"), Input::KEY_NEXT_CHAT_TAB }, { N_("Close current Chat Tab"), Input::KEY_CLOSE_CHAT_TAB }, { N_("Previous chat line"), Input::KEY_CHAT_PREV_HISTORY }, { N_("Next chat line"), Input::KEY_CHAT_NEXT_HISTORY }, { N_("Chat Auto Complete"), Input::KEY_AUTOCOMPLETE_CHAT }, { N_("Deactivate Chat Input"), Input::KEY_DEACTIVATE_CHAT }, { N_("Other Keys"), Input::KEY_NO_VALUE }, { N_("Ignore input 1"), Input::KEY_IGNORE_INPUT_1 }, { N_("Ignore input 2"), Input::KEY_IGNORE_INPUT_2 }, { N_("Direct Up"), Input::KEY_DIRECT_UP }, { N_("Direct Down"), Input::KEY_DIRECT_DOWN }, { N_("Direct Left"), Input::KEY_DIRECT_LEFT }, { N_("Direct Right"), Input::KEY_DIRECT_RIGHT }, { N_("Crazy moves"), Input::KEY_CRAZY_MOVES }, { N_("Change Crazy Move mode"), Input::KEY_CHANGE_CRAZY_MOVES_TYPE }, { N_("Quick Drop N Items from 0 slot"), Input::KEY_QUICK_DROP }, { N_("Quick Drop N Items"), Input::KEY_QUICK_DROPN }, { N_("Switch Quick Drop Counter"), Input::KEY_SWITCH_QUICK_DROP }, { N_("Quick heal target or self"), Input::KEY_MAGIC_INMA1 }, { N_("Use #itenplz spell"), Input::KEY_MAGIC_ITENPLZ }, { N_("Use magic attack"), Input::KEY_MAGIC_ATTACK }, { N_("Switch magic attack"), Input::KEY_SWITCH_MAGIC_ATTACK }, { N_("Switch pvp attack"), Input::KEY_SWITCH_PVP_ATTACK }, { N_("Change move type"), Input::KEY_INVERT_DIRECTION }, { N_("Change Attack Weapon Type"), Input::KEY_CHANGE_ATTACK_WEAPON_TYPE }, { N_("Change Attack Type"), Input::KEY_CHANGE_ATTACK_TYPE }, { N_("Change Follow mode"), Input::KEY_CHANGE_FOLLOW_MODE }, { N_("Change Imitation mode"), Input::KEY_CHANGE_IMITATION_MODE }, { N_("Disable / Enable Game modifier keys"), Input::KEY_DISABLE_GAME_MODIFIERS }, { N_("On / Off audio"), Input::KEY_CHANGE_AUDIO }, { N_("Enable / Disable away mode"), Input::KEY_AWAY }, { N_("Emulate right click from keyboard"), Input::KEY_RIGHT_CLICK }, { N_("Toggle camera mode"), Input::KEY_CAMERA }, { N_("Modifier key"), Input::KEY_MOD } }; const int keysSize = sizeof(setupActionData) / sizeof(SetupActionData); /** * The list model for key function list. * * \ingroup Interface */ class KeyListModel : public gcn::ListModel { public: /** * Returns the number of elements in container. */ int getNumberOfElements() { return keysSize; } /** * Returns element from container. */ std::string getElementAt(int i) { return mKeyFunctions[i]; } /** * Sets element from container. */ void setElementAt(int i, const std::string &caption) { mKeyFunctions[i] = caption; } private: std::string mKeyFunctions[keysSize]; }; Setup_Input::Setup_Input(): mKeyListModel(new KeyListModel), mKeyList(new ListBox(mKeyListModel)), mKeySetting(false) { inputManager.setSetupInput(this); setName(_("Input")); refreshKeys(); mKeyList->addActionListener(this); ScrollArea *scrollArea = new ScrollArea(mKeyList); scrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); mAssignKeyButton = new Button(_("Assign"), "assign", this); mAssignKeyButton->addActionListener(this); mAssignKeyButton->setEnabled(false); mUnassignKeyButton = new Button(_("Unassign"), "unassign", this); mUnassignKeyButton->addActionListener(this); mUnassignKeyButton->setEnabled(false); mMakeDefaultButton = new Button(_("Default"), "makeDefault", this); mMakeDefaultButton->addActionListener(this); // Do the layout LayoutHelper h(this); ContainerPlacer place = h.getPlacer(0, 0); place(0, 0, scrollArea, 4, 6).setPadding(2); place(0, 6, mMakeDefaultButton); place(2, 6, mAssignKeyButton); place(3, 6, mUnassignKeyButton); setDimension(gcn::Rectangle(0, 0, 500, 350)); } Setup_Input::~Setup_Input() { delete mKeyList; mKeyList = nullptr; delete mKeyListModel; mKeyListModel = nullptr; delete mAssignKeyButton; mAssignKeyButton = nullptr; delete mUnassignKeyButton; mUnassignKeyButton = nullptr; delete mMakeDefaultButton; mMakeDefaultButton = nullptr; } void Setup_Input::apply() { keyUnresolved(); int key1, key2; if (inputManager.hasConflicts(key1, key2)) { int s1 = keyToSetupData(key1); int s2 = keyToSetupData(key2); new OkDialog(_("Key Conflict(s) Detected."), strprintf(_("Conflict \"%s\" and \"%s\" keys. " "Resolve them, or gameplay may result in strange behaviour."), setupActionData[s1].name.c_str(), setupActionData[s2].name.c_str()), DIALOG_ERROR); } keyboard.setEnabled(true); inputManager.store(); } void Setup_Input::cancel() { keyUnresolved(); inputManager.retrieve(); keyboard.setEnabled(true); refreshKeys(); } void Setup_Input::action(const gcn::ActionEvent &event) { if (event.getSource() == mKeyList) { if (!mKeySetting) { int i(mKeyList->getSelected()); if (i >= 0 && i < keysSize) { if (setupActionData[i].actionId == Input::KEY_NO_VALUE) { mAssignKeyButton->setEnabled(false); mUnassignKeyButton->setEnabled(false); } else { mAssignKeyButton->setEnabled(true); mUnassignKeyButton->setEnabled(true); } } } } else if (event.getId() == "assign") { mKeySetting = true; mAssignKeyButton->setEnabled(false); keyboard.setEnabled(false); int i(mKeyList->getSelected()); if (i >= 0 && i < keysSize) { const SetupActionData &key = setupActionData[i]; int ik = key.actionId; inputManager.setNewKeyIndex(ik); mKeyListModel->setElementAt(i, std::string( gettext(key.name.c_str())) + ": ?"); } } else if (event.getId() == "unassign") { int i(mKeyList->getSelected()); if (i >= 0 && i < keysSize) { const SetupActionData &key = setupActionData[i]; int ik = key.actionId; inputManager.setNewKeyIndex(ik); refreshAssignedKey(mKeyList->getSelected()); inputManager.unassignKey(); } mAssignKeyButton->setEnabled(true); } else if (event.getId() == "makeDefault") { inputManager.makeDefault(); refreshKeys(); } } void Setup_Input::refreshAssignedKey(int index) { const SetupActionData &key = setupActionData[index]; if (key.actionId == Input::KEY_NO_VALUE) { const std::string str = " \342\200\225\342\200\225\342\200\225" "\342\200\225\342\200\225 "; mKeyListModel->setElementAt(index, str + gettext(key.name.c_str()) + str); } else { mKeyListModel->setElementAt(index, strprintf("%s: %s", gettext(key.name.c_str()), inputManager.getKeyStringLong(key.actionId).c_str())); } } void Setup_Input::newKeyCallback(int index) { mKeySetting = false; int i = keyToSetupData(index); if (i >= 0) refreshAssignedKey(i); mAssignKeyButton->setEnabled(true); } int Setup_Input::keyToSetupData(int index) { for (int i = 0; i < keysSize; i++) { const SetupActionData &key = setupActionData[i]; if (key.actionId == index) return i; } return -1; } void Setup_Input::refreshKeys() { for (int i = 0; i < keysSize; i++) refreshAssignedKey(i); } void Setup_Input::keyUnresolved() { if (mKeySetting) { newKeyCallback(inputManager.getNewKeyIndex()); inputManager.setNewKeyIndex(Input::KEY_NO_VALUE); } }