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