1 // Copyright 2022 Garrett D'Amore 2 // 3 // Distributed under the Boost Software License, Version 1.0. 4 // (See accompanying file LICENSE or https://www.boost.org/LICENSE_1_0.txt) 5 6 module dcell.key; 7 8 import std.string; 9 import std.algorithm; 10 11 /** 12 * Key represents a single, unmodified key stroke. Modifier keys are 13 * not considered as Keys. 14 */ 15 enum Key 16 { 17 none = 0, 18 19 // control keys are assigned their ASCII values 20 // these definitions should not be used by apps, but instead 21 // by using key rune, the character, and a modifier. 22 // TODO: consider just removing these. 23 ctrlSpace = 0, 24 ctrlA, 25 ctrlB, 26 ctrlC, 27 ctrlD, 28 ctrlE, 29 ctrlF, 30 ctrlG, 31 ctrlH, 32 ctrlI, 33 ctrlJ, 34 ctrlK, 35 ctrlL, 36 ctrlM, 37 ctrlN, 38 ctrlO, 39 ctrlP, 40 ctrlQ, 41 ctrlR, 42 ctrlS, 43 ctrlT, 44 ctrlU, 45 ctrlV, 46 ctrlW, 47 ctrlX, 48 ctrlY, 49 ctrlZ, 50 ctrlLeftSq, // Escape 51 ctrlBackslash, 52 ctrlRightSq, 53 ctrlCarat, 54 ctrlUnderscore, 55 56 rune = 256, // start of defined keys, numbered high to avoid conflicts 57 up, 58 down, 59 right, 60 left, 61 upLeft, 62 upRight, 63 downLeft, 64 downRight, 65 center, 66 pgUp, 67 pgDn, 68 home, 69 end, 70 insert, 71 del2, // secondary delete button, apart from DEL 72 help, 73 exit, 74 clear, 75 cancel, 76 print, 77 pause, 78 backtab, 79 f1, 80 f2, 81 f3, 82 f4, 83 f5, 84 f6, 85 f7, 86 f8, 87 f9, 88 f10, 89 f11, 90 f12, 91 f13, 92 f14, 93 f15, 94 f16, 95 f17, 96 f18, 97 f19, 98 f20, 99 f21, 100 f22, 101 f23, 102 f24, 103 f25, 104 f26, 105 f27, 106 f28, 107 f29, 108 f30, 109 f31, 110 f32, 111 f33, 112 f34, 113 f35, 114 f36, 115 f37, 116 f38, 117 f39, 118 f40, 119 f41, 120 f42, 121 f43, 122 f44, 123 f45, 124 f46, 125 f47, 126 f48, 127 f49, 128 f50, 129 f51, 130 f52, 131 f53, 132 f54, 133 f55, 134 f56, 135 f57, 136 f58, 137 f59, 138 f60, 139 f61, 140 f62, 141 f63, 142 f64, 143 144 // convenience aliases 145 backspace = ctrlH, 146 tab = ctrlI, 147 esc = ctrlLeftSq, 148 enter = ctrlM, 149 del = 0x7F, // Note del2 has a different value 150 } 151 152 static immutable dstring[Key] keyNames; 153 shared static this() 154 { 155 keyNames[Key.enter] = "Enter"; 156 keyNames[Key.backspace] = "Backspace"; 157 keyNames[Key.tab] = "Tab"; 158 keyNames[Key.backtab] = "Backtab"; 159 keyNames[Key.esc] = "Esc"; 160 keyNames[Key.del2] = "Delete2"; 161 keyNames[Key.del] = "Delete"; 162 keyNames[Key.insert] = "Insert"; 163 keyNames[Key.up] = "Up"; 164 keyNames[Key.down] = "Down"; 165 keyNames[Key.left] = "Left"; 166 keyNames[Key.right] = "Right"; 167 keyNames[Key.home] = "Home"; 168 keyNames[Key.end] = "End"; 169 keyNames[Key.upLeft] = "UpLeft"; 170 keyNames[Key.upRight] = "UpRight"; 171 keyNames[Key.downLeft] = "DownLeft"; 172 keyNames[Key.downRight] = "DownRight"; 173 keyNames[Key.center] = "Center"; 174 keyNames[Key.pgDn] = "PgDn"; 175 keyNames[Key.pgUp] = "PgUp"; 176 keyNames[Key.clear] = "Clear"; 177 keyNames[Key.exit] = "Exit"; 178 keyNames[Key.cancel] = "Cancel"; 179 keyNames[Key.pause] = "Pause"; 180 keyNames[Key.print] = "Print"; 181 keyNames[Key.f1] = "F1"; 182 keyNames[Key.f2] = "F2"; 183 keyNames[Key.f3] = "F3"; 184 keyNames[Key.f4] = "F4"; 185 keyNames[Key.f5] = "F5"; 186 keyNames[Key.f6] = "F6"; 187 keyNames[Key.f7] = "F7"; 188 keyNames[Key.f8] = "F8"; 189 keyNames[Key.f9] = "F9"; 190 keyNames[Key.f10] = "F10"; 191 keyNames[Key.f11] = "F11"; 192 keyNames[Key.f12] = "F12"; 193 keyNames[Key.f13] = "F13"; 194 keyNames[Key.f14] = "F14"; 195 keyNames[Key.f15] = "F15"; 196 keyNames[Key.f16] = "F16"; 197 keyNames[Key.f17] = "F17"; 198 keyNames[Key.f18] = "F18"; 199 keyNames[Key.f19] = "F19"; 200 keyNames[Key.f20] = "F20"; 201 keyNames[Key.f21] = "F21"; 202 keyNames[Key.f22] = "F22"; 203 keyNames[Key.f23] = "F23"; 204 keyNames[Key.f24] = "F24"; 205 keyNames[Key.f25] = "F25"; 206 keyNames[Key.f26] = "F26"; 207 keyNames[Key.f27] = "F27"; 208 keyNames[Key.f28] = "F28"; 209 keyNames[Key.f29] = "F29"; 210 keyNames[Key.f30] = "F30"; 211 keyNames[Key.f31] = "F31"; 212 keyNames[Key.f32] = "F32"; 213 keyNames[Key.f33] = "F33"; 214 keyNames[Key.f34] = "F34"; 215 keyNames[Key.f35] = "F35"; 216 keyNames[Key.f36] = "F36"; 217 keyNames[Key.f37] = "F37"; 218 keyNames[Key.f38] = "F38"; 219 keyNames[Key.f39] = "F39"; 220 keyNames[Key.f40] = "F40"; 221 keyNames[Key.f41] = "F41"; 222 keyNames[Key.f42] = "F42"; 223 keyNames[Key.f43] = "F43"; 224 keyNames[Key.f44] = "F44"; 225 keyNames[Key.f45] = "F45"; 226 keyNames[Key.f46] = "F46"; 227 keyNames[Key.f47] = "F47"; 228 keyNames[Key.f48] = "F48"; 229 keyNames[Key.f49] = "F49"; 230 keyNames[Key.f50] = "F50"; 231 keyNames[Key.f51] = "F51"; 232 keyNames[Key.f52] = "F52"; 233 keyNames[Key.f53] = "F53"; 234 keyNames[Key.f54] = "F54"; 235 keyNames[Key.f55] = "F55"; 236 keyNames[Key.f56] = "F56"; 237 keyNames[Key.f57] = "F57"; 238 keyNames[Key.f58] = "F58"; 239 keyNames[Key.f59] = "F59"; 240 keyNames[Key.f60] = "F60"; 241 keyNames[Key.f61] = "F61"; 242 keyNames[Key.f62] = "F62"; 243 keyNames[Key.f63] = "F63"; 244 keyNames[Key.f64] = "F64"; 245 keyNames[Key.ctrlA] = "Ctrl-A"; 246 keyNames[Key.ctrlB] = "Ctrl-B"; 247 keyNames[Key.ctrlC] = "Ctrl-C"; 248 keyNames[Key.ctrlD] = "Ctrl-D"; 249 keyNames[Key.ctrlE] = "Ctrl-E"; 250 keyNames[Key.ctrlF] = "Ctrl-F"; 251 keyNames[Key.ctrlG] = "Ctrl-G"; 252 keyNames[Key.ctrlJ] = "Ctrl-J"; 253 keyNames[Key.ctrlK] = "Ctrl-K"; 254 keyNames[Key.ctrlL] = "Ctrl-L"; 255 keyNames[Key.ctrlN] = "Ctrl-N"; 256 keyNames[Key.ctrlO] = "Ctrl-O"; 257 keyNames[Key.ctrlP] = "Ctrl-P"; 258 keyNames[Key.ctrlQ] = "Ctrl-Q"; 259 keyNames[Key.ctrlR] = "Ctrl-R"; 260 keyNames[Key.ctrlS] = "Ctrl-S"; 261 keyNames[Key.ctrlT] = "Ctrl-T"; 262 keyNames[Key.ctrlU] = "Ctrl-U"; 263 keyNames[Key.ctrlV] = "Ctrl-V"; 264 keyNames[Key.ctrlW] = "Ctrl-W"; 265 keyNames[Key.ctrlX] = "Ctrl-X"; 266 keyNames[Key.ctrlY] = "Ctrl-Y"; 267 keyNames[Key.ctrlZ] = "Ctrl-Z"; 268 keyNames[Key.ctrlSpace] = "Ctrl-Space"; 269 keyNames[Key.ctrlUnderscore] = "Ctrl-_"; 270 keyNames[Key.ctrlRightSq] = "Ctrl-]"; 271 keyNames[Key.ctrlBackslash] = "Ctrl-\\"; 272 keyNames[Key.ctrlCarat] = "Ctrl-^"; 273 } 274 275 /** 276 * Modifiers are special keys that when combined with other keys 277 * change their meaning. 278 */ 279 enum Modifiers 280 { 281 none = 0, 282 shift = 1 << 0, 283 ctrl = 1 << 1, 284 alt = 1 << 2, 285 meta = 1 << 3, 286 } 287 288 /** 289 * This represents a single pressed key, possibly with modifiers. 290 */ 291 struct KeyEvent 292 { 293 Key key; /// Key pressed. 294 dchar ch; /// Set if key == rune. 295 Modifiers mod; /// Any modifiers pressed together. 296 297 dstring toString() const pure 298 { 299 dstring s = ""; 300 if (mod & Modifiers.meta) 301 { 302 s ~= "Meta-"; 303 } 304 if (mod & Modifiers.alt) 305 { 306 s ~= "Alt-"; 307 } 308 dstring kn = ""; 309 if (key in keyNames) 310 { 311 kn = keyNames[key]; 312 } 313 else if (key == Key.rune) 314 { 315 kn = [ch]; 316 } 317 else 318 { 319 320 kn = format("Key[%02X]"d, key); 321 } 322 if ((mod & Modifiers.ctrl) && !startsWith(kn, "Ctrl-")) 323 { 324 s ~= "Ctrl-"; 325 } 326 327 return s ~ kn; 328 } 329 }