1 /* 2 * SPDX-FileCopyrightText: 2015-2015 CSSlayer <wengxt@gmail.com> 3 * 4 * SPDX-License-Identifier: LGPL-2.1-or-later 5 * 6 */ 7 8 #ifndef _FCITX_UTILS_KEY_H_ 9 #define _FCITX_UTILS_KEY_H_ 10 11 /// \addtogroup FcitxUtils 12 /// \{ 13 /// \file 14 /// \brief Class to represent a key. 15 16 #include <algorithm> 17 #include <cstddef> 18 #include <cstdint> 19 #include <string> 20 #include <vector> 21 #include <fcitx-utils/flags.h> 22 #include <fcitx-utils/keysym.h> 23 #include "fcitxutils_export.h" 24 25 namespace fcitx { 26 class Key; 27 typedef FcitxKeySym KeySym; 28 typedef Flags<KeyState> KeyStates; 29 typedef std::vector<Key> KeyList; 30 31 /// Control the behavior of toString function. 32 enum class KeyStringFormat { 33 /// Can be used to parse from a string. 34 Portable, 35 /// Return the human readable string in localized format. 36 Localized, 37 }; 38 39 /// Describe a Key in fcitx. 40 class FCITXUTILS_EXPORT Key { 41 public: 42 explicit Key(KeySym sym = FcitxKey_None, KeyStates states = KeyStates(), 43 int code = 0) sym_(sym)44 : sym_(sym), states_(states), code_(code) {} 45 46 /// Parse a key from string. If string is invalid, it will be set to 47 /// FcitxKey_None 48 explicit Key(const char *keyString); 49 50 /// Parse a key from std::string. 51 /// \see fcitx::Key::Key(const char *) Key(const std::string & keyString)52 explicit Key(const std::string &keyString) : Key(keyString.c_str()) {} 53 FCITX_INLINE_DEFINE_DEFAULT_DTOR_COPY_AND_MOVE(Key)54 FCITX_INLINE_DEFINE_DEFAULT_DTOR_COPY_AND_MOVE(Key) 55 56 /// Create a key code based key with empty key symbol. 57 static Key fromKeyCode(int code = 0, KeyStates states = KeyStates()) { 58 return Key(FcitxKey_None, states, code); 59 } 60 61 /// Check if key is exactly same. 62 bool operator==(const Key &key) const { 63 return sym_ == key.sym_ && states_ == key.states_ && code_ == key.code_; 64 } 65 66 /// Check if key is not same; 67 bool operator!=(const Key &key) const { return !operator==(key); } 68 69 /// Check if current key match the key. 70 bool check(const Key &key) const; 71 72 /// Check if current key match the sym and states. 73 /// \see fcitx::Key::check(const Key &key) 74 bool check(KeySym sym = FcitxKey_None, 75 KeyStates states = KeyStates()) const { 76 return check(Key(sym, states)); 77 } 78 79 /** 80 * Check if current key is a key release of given modifier only key. 81 * 82 * This is a very specialized check for modifier release case. 83 * And it's designed to handle modifier only key. 84 * 85 * For example, if Alt+Shift_L is pressed, then the following release key of 86 * this event can be either: Alt+Shift+Shift_L, or Alt+Shift+Meta_{L,R}. 87 * This is because: Alt -> Meta_{L,R}, if alt is released first, then it 88 * will produce Alt+Shift+Meta_{L,R}. If shift is released first, then it 89 * will produce Alt+Shift+Shift_L. 90 * 91 * Return false if key is not a modifier. 92 */ 93 bool isReleaseOfModifier(const Key &key) const; 94 95 /// Check if key is digit key. 96 bool isDigit() const; 97 98 /// Check if key is upper case. 99 bool isUAZ() const; 100 101 /// Check if key is lower case. 102 bool isLAZ() const; 103 104 /// Check if key is in the range of ascii and has no states. 105 bool isSimple() const; 106 107 /// Check if the key is a modifier press. 108 bool isModifier() const; 109 110 /// Check if this key will cause cursor to move, e.g. arrow key and page up/ 111 /// down. 112 bool isCursorMove() const; 113 114 /// Check if this key is a key pad key. 115 bool isKeyPad() const; 116 117 /// Check if states has modifier. 118 bool hasModifier() const; 119 120 /// \brief Normalize a key, usually used when key is from frontend. 121 /// 122 /// states will be filtered to have only ctrl alt shift and super. 123 /// Shift will be removed if it is key symbol is a-z/A-Z. 124 /// Shift + any other modifier and a-z will be reset to A-Z. So 125 /// key in configuration does not need to bother the case. 126 Key normalize() const; 127 128 /// \brief Convert key to a string. 129 /// 130 /// \arg format will control the format of return value. 131 std::string 132 toString(KeyStringFormat format = KeyStringFormat::Portable) const; 133 134 /// Check if the sym is not FcitxKey_None or FcitxKey_VoidSymbol. 135 bool isValid() const; 136 sym()137 inline KeySym sym() const { return sym_; } states()138 inline KeyStates states() const { return states_; } code()139 inline int code() const { return code_; } 140 141 /// Convert the modifier symbol to its corresponding states. 142 static KeyStates keySymToStates(KeySym sym); 143 144 /// Convert a key symbol string to KeySym. 145 static KeySym keySymFromString(const std::string &keyString); 146 147 /// \brief Convert keysym to a string. 148 /// 149 /// \arg format will control the format of return value. 150 static std::string 151 keySymToString(KeySym sym, 152 KeyStringFormat format = KeyStringFormat::Portable); 153 154 /// Convert unicode to key symbol. Useful when you want to create a 155 /// synthetic key event. 156 static KeySym keySymFromUnicode(uint32_t unicode); 157 158 /// Convert keysym to a unicode. Will return a valid value UCS-4 value if 159 /// this key may produce a character. 160 static uint32_t keySymToUnicode(KeySym sym); 161 162 /// Convert keysym to a unicode string. Will return a non empty value UTF-8 163 /// string if this key may produce a character. 164 /// \see fcitx::Key::keySymToUnicode 165 static std::string keySymToUTF8(KeySym sym); 166 167 /// Parse a list of key string into a KeyList. 168 static KeyList keyListFromString(const std::string &str); 169 170 /// Convert a key list to string. 171 template <typename Container> 172 static std::string 173 keyListToString(Container container, 174 KeyStringFormat format = KeyStringFormat::Portable) { 175 std::string result; 176 bool first = true; 177 for (auto k : container) { 178 if (first) { 179 first = false; 180 } else { 181 result += " "; 182 } 183 result += k.toString(format); 184 } 185 return result; 186 } 187 188 /// Check the current key against a key list. 189 /// \see fcitx::Key::check 190 template <typename Container> checkKeyList(const Container & c)191 bool checkKeyList(const Container &c) const { 192 return std::find_if(c.begin(), c.end(), [this](const Key &toCheck) { 193 return check(toCheck); 194 }) != c.end(); 195 } 196 197 /// Check the current key against a key list and get the matched key index. 198 /// \return Returns the matched key index or -1 if there is no match. 199 /// \see fcitx::Key::check 200 template <typename Container> keyListIndex(const Container & c)201 int keyListIndex(const Container &c) const { 202 size_t idx = 0; 203 for (auto &toCheck : c) { 204 if (check(toCheck)) { 205 break; 206 } 207 idx++; 208 } 209 if (idx == c.size()) { 210 return -1; 211 } 212 return idx; 213 } 214 215 private: 216 KeySym sym_; 217 KeyStates states_; 218 int code_; 219 }; 220 } // namespace fcitx 221 222 #endif // _FCITX_UTILS_KEY_H_ 223