/* * The ManaPlus Client * Copyright (C) 2007 Joshua Langley * Copyright (C) 2009-2010 The Mana Developers * Copyright (C) 2011-2020 The ManaPlus Developers * Copyright (C) 2020-2023 The ManaVerse 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 . */ #include "input/keyboardconfig.h" #include "configuration.h" #ifdef USE_SDL2 #include "settings.h" #endif // USE_SDL2 #include "input/inputmanager.h" #include "utils/foreach.h" #include "utils/gettext.h" #include "debug.h" extern volatile int tick_time; KeyboardConfig keyboard; KeyboardConfig::KeyboardConfig() : mEnabled(true), mActiveKeys(nullptr), mActiveKeys2(nullptr), mRepeatTime(0), mKeyToAction(), mKeyToId(), mKeyTimeMap(), mBlockAltTab(true) { } void KeyboardConfig::init() { mEnabled = true; delete [] mActiveKeys2; mActiveKeys2 = new uint8_t[500]; mRepeatTime = config.getIntValue("repeateInterval2") / 10; mBlockAltTab = config.getBoolValue("blockAltTab"); } void KeyboardConfig::deinit() { delete [] mActiveKeys2; mActiveKeys2 = nullptr; } InputActionT KeyboardConfig::getKeyIndex(const SDL_Event &event, const int grp) { const int keyValue = getKeyValueFromEvent(event); return inputManager.getKeyIndex(keyValue, grp, InputType::KEYBOARD); } void KeyboardConfig::refreshActiveKeys() { mActiveKeys = SDL_GetKeyState(nullptr); } std::string KeyboardConfig::getKeyName(const int key) { if (key == -1) return ""; if (key > -1) { #ifdef USE_SDL2 return SDL_GetScancodeName( static_cast(key)); #else // USE_SDL2 return SDL_GetKeyName(static_cast(key)); #endif // USE_SDL2 } // TRANSLATORS: long key name, should be short return strprintf(_("key_%d"), CAST_S32(key)); } std::string KeyboardConfig::getKeyShortString(const std::string &key) { if (key == "backspace") return "bksp"; else if (key == "numlock") return "numlock"; else if (key == "caps lock") return "caplock"; else if (key == "scroll lock") return "scrlock"; else if (key == "right shift") return "rshift"; else if (key == "left shift") return "lshift"; else if (key == "right ctrl") return "rctrl"; else if (key == "left ctrl") return "lctrl"; else if (key == "right alt") return "ralt"; else if (key == "left alt") return "lalt"; else if (key == "right meta") return "rmeta"; else if (key == "left meta") return "lmeta"; else if (key == "right super") return "rsuper"; else if (key == "left super") return "lsuper"; else if (key == "print screen") return "print screen"; else if (key == "page up") return "pg up"; else if (key == "page down") return "pg down"; if (key == "unknown key") { // TRANSLATORS: Unknown key short string. // TRANSLATORS: This string must be maximum 5 chars return _("u key"); } return key; } KeysVector *KeyboardConfig::getActionVector(const SDL_Event &event) { const int i = getKeyValueFromEvent(event); // logger->log("key triggerAction: %d", i); if (i != 0 && i < SDLK_LAST && mKeyToAction.find(i) != mKeyToAction.end()) return &mKeyToAction[i]; return nullptr; } KeysVector *KeyboardConfig::getActionVectorByKey(const int i) { // logger->log("key triggerAction: %d", i); if (i != 0 && i < SDLK_LAST && mKeyToAction.find(i) != mKeyToAction.end()) return &mKeyToAction[i]; return nullptr; } InputActionT KeyboardConfig::getActionId(const SDL_Event &event) { const int i = getKeyValueFromEvent(event); // logger->log("getActionId: %d", i); if (i != 0 && i < SDLK_LAST && mKeyToId.find(i) != mKeyToId.end()) return mKeyToId[i]; return InputAction::NO_VALUE; } bool KeyboardConfig::isActionActive(const InputActionT index) const { if ((mActiveKeys == nullptr) || (mActiveKeys2 == nullptr)) return false; const InputFunction &key = inputManager.getKey(index); for (size_t i = 0; i < inputFunctionSize; i ++) { const InputItem &val = key.values[i]; if (val.type != InputType::KEYBOARD) continue; const int value = val.value; if (value >= 0) { if (mActiveKeys[value] != 0U) return true; } else if (value < -1 && value > -500) { if (mActiveKeys2[-value] != 0U) return true; } } return false; } void KeyboardConfig::update() { inputManager.updateKeyActionMap(mKeyToAction, mKeyToId, mKeyTimeMap, InputType::KEYBOARD); } void KeyboardConfig::handleActivateKey(const SDL_Event &event) { if (mActiveKeys2 == nullptr) return; const int key = getKeyValueFromEvent(event); if (key < -1 && key > -500) mActiveKeys2[-key] = 1; resetRepeat(key); } void KeyboardConfig::handleActivateKey(const int key) { if (mActiveKeys2 == nullptr) return; if (key < -1 && key > -500) mActiveKeys2[-key] = 1; resetRepeat(key); } void KeyboardConfig::handleDeActicateKey(const SDL_Event &event) { if (mActiveKeys2 == nullptr) return; const int key = getKeyValueFromEvent(event); if (key < -1 && key > -500) mActiveKeys2[-key] = 0; resetRepeat(key); } void KeyboardConfig::handleDeActicateKey(const int key) { if (mActiveKeys2 == nullptr) return; if (key < -1 && key > -500) mActiveKeys2[-key] = 0; resetRepeat(key); } void KeyboardConfig::handleRepeat(const int time) { BLOCK_START("KeyboardConfig::handleRepeat") FOR_EACH (KeyTimeMapIter, it, mKeyTimeMap) { bool repeat(false); const int key = (*it).first; if (key >= 0) { if ((mActiveKeys != nullptr) && (mActiveKeys[key] != 0U)) repeat = true; } else if (key < -1 && key > -500) { if ((mActiveKeys2 != nullptr) && (mActiveKeys2[-key] != 0U)) repeat = true; } if (repeat) { int &keyTime = (*it).second; if (time > keyTime && abs(time - keyTime) > CAST_S32(mRepeatTime)) { keyTime = time; inputManager.triggerAction(getActionVectorByKey(key)); } } } BLOCK_END("KeyboardConfig::handleRepeat") } void KeyboardConfig::resetRepeat(const int key) { const KeyTimeMapIter it = mKeyTimeMap.find(key); if (it != mKeyTimeMap.end()) (*it).second = tick_time; } #ifdef USE_SDL2 bool KeyboardConfig::ignoreKey(const SDL_Event &restrict event) { if (!mBlockAltTab || mActiveKeys == nullptr) { return false; } const int key = event.key.keysym.scancode; if (key == SDL_SCANCODE_TAB) { #if SDL_VERSION_ATLEAST(2, 0, 5) // SDL_WINDOWEVENT_TAKE_FOCUS not triggered after focus restored if (settings.inputFocused != KeyboardFocus::Focused2) return true; #endif // SDL_VERSION_ATLEAST(2, 0, 5) if (mActiveKeys[SDL_SCANCODE_LALT] != 0) return true; } else if (key == SDL_SCANCODE_LALT) { if (mActiveKeys[SDL_SCANCODE_TAB] != 0) return true; } return false; } #endif // USE_SDL2