1/*
2 SPDX-FileCopyrightText: 2008 Erlend Hamberg <ehamberg@gmail.com>
3 SPDX-FileCopyrightText: 2008 Evgeniy Ivanov <powerfox@kde.ru>
4
5 SPDX-License-Identifier: LGPL-2.0-or-later
6*/
7
8#include "definitions.h"
9#include <QKeyEvent>
10#include <QStringList>
11#include <vimode/keyevent.h>
12#include <vimode/keyparser.h>
13
14using namespace KateVi;
15
16KeyParser *KeyParser::m_instance = nullptr;
17
18KeyParser::KeyParser()
19{
20 initKeyTables();
21}
22
23KeyParser *KeyParser::self()
24{
25 if (m_instance == nullptr) {
26 m_instance = new KeyParser();
27 }
28
29 return m_instance;
30}
31
32void KeyParser::initKeyTables()
33{
34 m_qt2katevi = {
35 {Qt::Key_Escape, QStringLiteral("esc")},
36 {Qt::Key_Tab, QStringLiteral("tab")},
37 {Qt::Key_Backtab, QStringLiteral("backtab")},
38 {Qt::Key_Backspace, QStringLiteral("backspace")},
39 {Qt::Key_Return, QStringLiteral("return")},
40 {Qt::Key_Enter, QStringLiteral("enter")},
41 {Qt::Key_Insert, QStringLiteral("insert")},
42 {Qt::Key_Delete, QStringLiteral("delete")},
43 {Qt::Key_Pause, QStringLiteral("pause")},
44 {Qt::Key_Print, QStringLiteral("print")},
45 {Qt::Key_SysReq, QStringLiteral("sysreq")},
46 {Qt::Key_Clear, QStringLiteral("clear")},
47 {Qt::Key_Home, QStringLiteral("home")},
48 {Qt::Key_End, QStringLiteral("end")},
49 {Qt::Key_Left, QStringLiteral("left")},
50 {Qt::Key_Up, QStringLiteral("up")},
51 {Qt::Key_Right, QStringLiteral("right")},
52 {Qt::Key_Down, QStringLiteral("down")},
53 {Qt::Key_PageUp, QStringLiteral("pageup")},
54 {Qt::Key_PageDown, QStringLiteral("pagedown")},
55 {Qt::Key_Shift, QStringLiteral("shift")},
56 {Qt::Key_Control, QStringLiteral("control")},
57 {Qt::Key_Meta, QStringLiteral("meta")},
58 {Qt::Key_Alt, QStringLiteral("alt")},
59 {Qt::Key_AltGr, QStringLiteral("altgr")},
60 {Qt::Key_CapsLock, QStringLiteral("capslock")},
61 {Qt::Key_NumLock, QStringLiteral("numlock")},
62 {Qt::Key_ScrollLock, QStringLiteral("scrolllock")},
63 {Qt::Key_F1, QStringLiteral("f1")},
64 {Qt::Key_F2, QStringLiteral("f2")},
65 {Qt::Key_F3, QStringLiteral("f3")},
66 {Qt::Key_F4, QStringLiteral("f4")},
67 {Qt::Key_F5, QStringLiteral("f5")},
68 {Qt::Key_F6, QStringLiteral("f6")},
69 {Qt::Key_F7, QStringLiteral("f7")},
70 {Qt::Key_F8, QStringLiteral("f8")},
71 {Qt::Key_F9, QStringLiteral("f9")},
72 {Qt::Key_F10, QStringLiteral("f10")},
73 {Qt::Key_F11, QStringLiteral("f11")},
74 {Qt::Key_F12, QStringLiteral("f12")},
75 {Qt::Key_F13, QStringLiteral("f13")},
76 {Qt::Key_F14, QStringLiteral("f14")},
77 {Qt::Key_F15, QStringLiteral("f15")},
78 {Qt::Key_F16, QStringLiteral("f16")},
79 {Qt::Key_F17, QStringLiteral("f17")},
80 {Qt::Key_F18, QStringLiteral("f18")},
81 {Qt::Key_F19, QStringLiteral("f19")},
82 {Qt::Key_F20, QStringLiteral("f20")},
83 {Qt::Key_F21, QStringLiteral("f21")},
84 {Qt::Key_F22, QStringLiteral("f22")},
85 {Qt::Key_F23, QStringLiteral("f23")},
86 {Qt::Key_F24, QStringLiteral("f24")},
87 {Qt::Key_F25, QStringLiteral("f25")},
88 {Qt::Key_F26, QStringLiteral("f26")},
89 {Qt::Key_F27, QStringLiteral("f27")},
90 {Qt::Key_F28, QStringLiteral("f28")},
91 {Qt::Key_F29, QStringLiteral("f29")},
92 {Qt::Key_F30, QStringLiteral("f30")},
93 {Qt::Key_F31, QStringLiteral("f31")},
94 {Qt::Key_F32, QStringLiteral("f32")},
95 {Qt::Key_F33, QStringLiteral("f33")},
96 {Qt::Key_F34, QStringLiteral("f34")},
97 {Qt::Key_F35, QStringLiteral("f35")},
98 {Qt::Key_Super_L, QStringLiteral("super_l")},
99 {Qt::Key_Super_R, QStringLiteral("super_r")},
100 {Qt::Key_Menu, QStringLiteral("menu")},
101 {Qt::Key_Hyper_L, QStringLiteral("hyper_l")},
102 {Qt::Key_Hyper_R, QStringLiteral("hyper_r")},
103 {Qt::Key_Help, QStringLiteral("help")},
104 {Qt::Key_Direction_L, QStringLiteral("direction_l")},
105 {Qt::Key_Direction_R, QStringLiteral("direction_r")},
106 {Qt::Key_Multi_key, QStringLiteral("multi_key")},
107 {Qt::Key_Codeinput, QStringLiteral("codeinput")},
108 {Qt::Key_SingleCandidate, QStringLiteral("singlecandidate")},
109 {Qt::Key_MultipleCandidate, QStringLiteral("multiplecandidate")},
110 {Qt::Key_PreviousCandidate, QStringLiteral("previouscandidate")},
111 {Qt::Key_Mode_switch, QStringLiteral("mode_switch")},
112 {Qt::Key_Kanji, QStringLiteral("kanji")},
113 {Qt::Key_Muhenkan, QStringLiteral("muhenkan")},
114 {Qt::Key_Henkan, QStringLiteral("henkan")},
115 {Qt::Key_Romaji, QStringLiteral("romaji")},
116 {Qt::Key_Hiragana, QStringLiteral("hiragana")},
117 {Qt::Key_Katakana, QStringLiteral("katakana")},
118 {Qt::Key_Hiragana_Katakana, QStringLiteral("hiragana_katakana")},
119 {Qt::Key_Zenkaku, QStringLiteral("zenkaku")},
120 {Qt::Key_Hankaku, QStringLiteral("hankaku")},
121 {Qt::Key_Zenkaku_Hankaku, QStringLiteral("zenkaku_hankaku")},
122 {Qt::Key_Touroku, QStringLiteral("touroku")},
123 {Qt::Key_Massyo, QStringLiteral("massyo")},
124 {Qt::Key_Kana_Lock, QStringLiteral("kana_lock")},
125 {Qt::Key_Kana_Shift, QStringLiteral("kana_shift")},
126 {Qt::Key_Eisu_Shift, QStringLiteral("eisu_shift")},
127 {Qt::Key_Eisu_toggle, QStringLiteral("eisu_toggle")},
128 {Qt::Key_Hangul, QStringLiteral("hangul")},
129 {Qt::Key_Hangul_Start, QStringLiteral("hangul_start")},
130 {Qt::Key_Hangul_End, QStringLiteral("hangul_end")},
131 {Qt::Key_Hangul_Hanja, QStringLiteral("hangul_hanja")},
132 {Qt::Key_Hangul_Jamo, QStringLiteral("hangul_jamo")},
133 {Qt::Key_Hangul_Romaja, QStringLiteral("hangul_romaja")},
134 {Qt::Key_Hangul_Jeonja, QStringLiteral("hangul_jeonja")},
135 {Qt::Key_Hangul_Banja, QStringLiteral("hangul_banja")},
136 {Qt::Key_Hangul_PreHanja, QStringLiteral("hangul_prehanja")},
137 {Qt::Key_Hangul_PostHanja, QStringLiteral("hangul_posthanja")},
138 {Qt::Key_Hangul_Special, QStringLiteral("hangul_special")},
139 {Qt::Key_Dead_Grave, QStringLiteral("dead_grave")},
140 {Qt::Key_Dead_Acute, QStringLiteral("dead_acute")},
141 {Qt::Key_Dead_Circumflex, QStringLiteral("dead_circumflex")},
142 {Qt::Key_Dead_Tilde, QStringLiteral("dead_tilde")},
143 {Qt::Key_Dead_Macron, QStringLiteral("dead_macron")},
144 {Qt::Key_Dead_Breve, QStringLiteral("dead_breve")},
145 {Qt::Key_Dead_Abovedot, QStringLiteral("dead_abovedot")},
146 {Qt::Key_Dead_Diaeresis, QStringLiteral("dead_diaeresis")},
147 {Qt::Key_Dead_Abovering, QStringLiteral("dead_abovering")},
148 {Qt::Key_Dead_Doubleacute, QStringLiteral("dead_doubleacute")},
149 {Qt::Key_Dead_Caron, QStringLiteral("dead_caron")},
150 {Qt::Key_Dead_Cedilla, QStringLiteral("dead_cedilla")},
151 {Qt::Key_Dead_Ogonek, QStringLiteral("dead_ogonek")},
152 {Qt::Key_Dead_Iota, QStringLiteral("dead_iota")},
153 {Qt::Key_Dead_Voiced_Sound, QStringLiteral("dead_voiced_sound")},
154 {Qt::Key_Dead_Semivoiced_Sound, QStringLiteral("dead_semivoiced_sound")},
155 {Qt::Key_Dead_Belowdot, QStringLiteral("dead_belowdot")},
156 {Qt::Key_Dead_Hook, QStringLiteral("dead_hook")},
157 {Qt::Key_Dead_Horn, QStringLiteral("dead_horn")},
158 {Qt::Key_Back, QStringLiteral("back")},
159 {Qt::Key_Forward, QStringLiteral("forward")},
160 {Qt::Key_Stop, QStringLiteral("stop")},
161 {Qt::Key_Refresh, QStringLiteral("refresh")},
162 {Qt::Key_VolumeDown, QStringLiteral("volumedown")},
163 {Qt::Key_VolumeMute, QStringLiteral("volumemute")},
164 {Qt::Key_VolumeUp, QStringLiteral("volumeup")},
165 {Qt::Key_BassBoost, QStringLiteral("bassboost")},
166 {Qt::Key_BassUp, QStringLiteral("bassup")},
167 {Qt::Key_BassDown, QStringLiteral("bassdown")},
168 {Qt::Key_TrebleUp, QStringLiteral("trebleup")},
169 {Qt::Key_TrebleDown, QStringLiteral("trebledown")},
170 {Qt::Key_MediaPlay, QStringLiteral("mediaplay")},
171 {Qt::Key_MediaStop, QStringLiteral("mediastop")},
172 {Qt::Key_MediaPrevious, QStringLiteral("mediaprevious")},
173 {Qt::Key_MediaNext, QStringLiteral("medianext")},
174 {Qt::Key_MediaRecord, QStringLiteral("mediarecord")},
175 {Qt::Key_HomePage, QStringLiteral("homepage")},
176 {Qt::Key_Favorites, QStringLiteral("favorites")},
177 {Qt::Key_Search, QStringLiteral("search")},
178 {Qt::Key_Standby, QStringLiteral("standby")},
179 {Qt::Key_OpenUrl, QStringLiteral("openurl")},
180 {Qt::Key_LaunchMail, QStringLiteral("launchmail")},
181 {Qt::Key_LaunchMedia, QStringLiteral("launchmedia")},
182 {Qt::Key_Launch0, QStringLiteral("launch0")},
183 {Qt::Key_Launch1, QStringLiteral("launch1")},
184 {Qt::Key_Launch2, QStringLiteral("launch2")},
185 {Qt::Key_Launch3, QStringLiteral("launch3")},
186 {Qt::Key_Launch4, QStringLiteral("launch4")},
187 {Qt::Key_Launch5, QStringLiteral("launch5")},
188 {Qt::Key_Launch6, QStringLiteral("launch6")},
189 {Qt::Key_Launch7, QStringLiteral("launch7")},
190 {Qt::Key_Launch8, QStringLiteral("launch8")},
191 {Qt::Key_Launch9, QStringLiteral("launch9")},
192 {Qt::Key_LaunchA, QStringLiteral("launcha")},
193 {Qt::Key_LaunchB, QStringLiteral("launchb")},
194 {Qt::Key_LaunchC, QStringLiteral("launchc")},
195 {Qt::Key_LaunchD, QStringLiteral("launchd")},
196 {Qt::Key_LaunchE, QStringLiteral("launche")},
197 {Qt::Key_LaunchF, QStringLiteral("launchf")},
198 {Qt::Key_MediaLast, QStringLiteral("medialast")},
199 {Qt::Key_unknown, QStringLiteral("unknown")},
200 {Qt::Key_Call, QStringLiteral("call")},
201 {Qt::Key_Context1, QStringLiteral("context1")},
202 {Qt::Key_Context2, QStringLiteral("context2")},
203 {Qt::Key_Context3, QStringLiteral("context3")},
204 {Qt::Key_Context4, QStringLiteral("context4")},
205 {Qt::Key_Flip, QStringLiteral("flip")},
206 {Qt::Key_Hangup, QStringLiteral("hangup")},
207 {Qt::Key_No, QStringLiteral("no")},
208 {Qt::Key_Select, QStringLiteral("select")},
209 {Qt::Key_Yes, QStringLiteral("yes")},
210 {Qt::Key_Execute, QStringLiteral("execute")},
211 {Qt::Key_Printer, QStringLiteral("printer")},
212 {Qt::Key_Play, QStringLiteral("play")},
213 {Qt::Key_Sleep, QStringLiteral("sleep")},
214 {Qt::Key_Zoom, QStringLiteral("zoom")},
215 {Qt::Key_Cancel, QStringLiteral("cancel")},
216 };
217
218 for (QHash<int, QString>::const_iterator i = m_qt2katevi.constBegin(); i != m_qt2katevi.constEnd(); ++i) {
219 m_katevi2qt.insert(key: i.value(), value: i.key());
220 }
221 m_katevi2qt.insert(QStringLiteral("cr"), value: Qt::Key_Enter);
222
223 m_nameToKeyCode = {
224 {QStringLiteral("invalid"), -1},
225 {QStringLiteral("esc"), 1},
226 {QStringLiteral("tab"), 2},
227 {QStringLiteral("backtab"), 3},
228 {QStringLiteral("backspace"), 4},
229 {QStringLiteral("return"), 5},
230 {QStringLiteral("enter"), 6},
231 {QStringLiteral("insert"), 7},
232 {QStringLiteral("delete"), 8},
233 {QStringLiteral("pause"), 9},
234 {QStringLiteral("print"), 10},
235 {QStringLiteral("sysreq"), 11},
236 {QStringLiteral("clear"), 12},
237 {QStringLiteral("home"), 13},
238 {QStringLiteral("end"), 14},
239 {QStringLiteral("left"), 15},
240 {QStringLiteral("up"), 16},
241 {QStringLiteral("right"), 17},
242 {QStringLiteral("down"), 18},
243 {QStringLiteral("pageup"), 19},
244 {QStringLiteral("pagedown"), 20},
245 {QStringLiteral("shift"), 21},
246 {QStringLiteral("control"), 22},
247 {QStringLiteral("meta"), 23},
248 {QStringLiteral("alt"), 24},
249 {QStringLiteral("altgr"), 25},
250 {QStringLiteral("capslock"), 26},
251 {QStringLiteral("numlock"), 27},
252 {QStringLiteral("scrolllock"), 28},
253 {QStringLiteral("f1"), 29},
254 {QStringLiteral("f2"), 30},
255 {QStringLiteral("f3"), 31},
256 {QStringLiteral("f4"), 32},
257 {QStringLiteral("f5"), 33},
258 {QStringLiteral("f6"), 34},
259 {QStringLiteral("f7"), 35},
260 {QStringLiteral("f8"), 36},
261 {QStringLiteral("f9"), 37},
262 {QStringLiteral("f10"), 38},
263 {QStringLiteral("f11"), 39},
264 {QStringLiteral("f12"), 40},
265 {QStringLiteral("f13"), 41},
266 {QStringLiteral("f14"), 42},
267 {QStringLiteral("f15"), 43},
268 {QStringLiteral("f16"), 44},
269 {QStringLiteral("f17"), 45},
270 {QStringLiteral("f18"), 46},
271 {QStringLiteral("f19"), 47},
272 {QStringLiteral("f20"), 48},
273 {QStringLiteral("f21"), 49},
274 {QStringLiteral("f22"), 50},
275 {QStringLiteral("f23"), 51},
276 {QStringLiteral("f24"), 52},
277 {QStringLiteral("f25"), 53},
278 {QStringLiteral("f26"), 54},
279 {QStringLiteral("f27"), 55},
280 {QStringLiteral("f28"), 56},
281 {QStringLiteral("f29"), 57},
282 {QStringLiteral("f30"), 58},
283 {QStringLiteral("f31"), 59},
284 {QStringLiteral("f32"), 60},
285 {QStringLiteral("f33"), 61},
286 {QStringLiteral("f34"), 62},
287 {QStringLiteral("f35"), 63},
288 {QStringLiteral("super_l"), 64},
289 {QStringLiteral("super_r"), 65},
290 {QStringLiteral("menu"), 66},
291 {QStringLiteral("hyper_l"), 67},
292 {QStringLiteral("hyper_r"), 68},
293 {QStringLiteral("help"), 69},
294 {QStringLiteral("direction_l"), 70},
295 {QStringLiteral("direction_r"), 71},
296 {QStringLiteral("multi_key"), 172},
297 {QStringLiteral("codeinput"), 173},
298 {QStringLiteral("singlecandidate"), 174},
299 {QStringLiteral("multiplecandidate"), 175},
300 {QStringLiteral("previouscandidate"), 176},
301 {QStringLiteral("mode_switch"), 177},
302 {QStringLiteral("kanji"), 178},
303 {QStringLiteral("muhenkan"), 179},
304 {QStringLiteral("henkan"), 180},
305 {QStringLiteral("romaji"), 181},
306 {QStringLiteral("hiragana"), 182},
307 {QStringLiteral("katakana"), 183},
308 {QStringLiteral("hiragana_katakana"), 184},
309 {QStringLiteral("zenkaku"), 185},
310 {QStringLiteral("hankaku"), 186},
311 {QStringLiteral("zenkaku_hankaku"), 187},
312 {QStringLiteral("touroku"), 188},
313 {QStringLiteral("massyo"), 189},
314 {QStringLiteral("kana_lock"), 190},
315 {QStringLiteral("kana_shift"), 191},
316 {QStringLiteral("eisu_shift"), 192},
317 {QStringLiteral("eisu_toggle"), 193},
318 {QStringLiteral("hangul"), 194},
319 {QStringLiteral("hangul_start"), 195},
320 {QStringLiteral("hangul_end"), 196},
321 {QStringLiteral("hangul_hanja"), 197},
322 {QStringLiteral("hangul_jamo"), 198},
323 {QStringLiteral("hangul_romaja"), 199},
324 {QStringLiteral("hangul_jeonja"), 200},
325 {QStringLiteral("hangul_banja"), 201},
326 {QStringLiteral("hangul_prehanja"), 202},
327 {QStringLiteral("hangul_posthanja"), 203},
328 {QStringLiteral("hangul_special"), 204},
329 {QStringLiteral("dead_grave"), 205},
330 {QStringLiteral("dead_acute"), 206},
331 {QStringLiteral("dead_circumflex"), 207},
332 {QStringLiteral("dead_tilde"), 208},
333 {QStringLiteral("dead_macron"), 209},
334 {QStringLiteral("dead_breve"), 210},
335 {QStringLiteral("dead_abovedot"), 211},
336 {QStringLiteral("dead_diaeresis"), 212},
337 {QStringLiteral("dead_abovering"), 213},
338 {QStringLiteral("dead_doubleacute"), 214},
339 {QStringLiteral("dead_caron"), 215},
340 {QStringLiteral("dead_cedilla"), 216},
341 {QStringLiteral("dead_ogonek"), 217},
342 {QStringLiteral("dead_iota"), 218},
343 {QStringLiteral("dead_voiced_sound"), 219},
344 {QStringLiteral("dead_semivoiced_sound"), 220},
345 {QStringLiteral("dead_belowdot"), 221},
346 {QStringLiteral("dead_hook"), 222},
347 {QStringLiteral("dead_horn"), 223},
348 {QStringLiteral("back"), 224},
349 {QStringLiteral("forward"), 225},
350 {QStringLiteral("stop"), 226},
351 {QStringLiteral("refresh"), 227},
352 {QStringLiteral("volumedown"), 228},
353 {QStringLiteral("volumemute"), 229},
354 {QStringLiteral("volumeup"), 230},
355 {QStringLiteral("bassboost"), 231},
356 {QStringLiteral("bassup"), 232},
357 {QStringLiteral("bassdown"), 233},
358 {QStringLiteral("trebleup"), 234},
359 {QStringLiteral("trebledown"), 235},
360 {QStringLiteral("mediaplay"), 236},
361 {QStringLiteral("mediastop"), 237},
362 {QStringLiteral("mediaprevious"), 238},
363 {QStringLiteral("medianext"), 239},
364 {QStringLiteral("mediarecord"), 240},
365 {QStringLiteral("homepage"), 241},
366 {QStringLiteral("favorites"), 242},
367 {QStringLiteral("search"), 243},
368 {QStringLiteral("standby"), 244},
369 {QStringLiteral("openurl"), 245},
370 {QStringLiteral("launchmail"), 246},
371 {QStringLiteral("launchmedia"), 247},
372 {QStringLiteral("launch0"), 248},
373 {QStringLiteral("launch1"), 249},
374 {QStringLiteral("launch2"), 250},
375 {QStringLiteral("launch3"), 251},
376 {QStringLiteral("launch4"), 252},
377 {QStringLiteral("launch5"), 253},
378 {QStringLiteral("launch6"), 254},
379 {QStringLiteral("launch7"), 255},
380 {QStringLiteral("launch8"), 256},
381 {QStringLiteral("launch9"), 257},
382 {QStringLiteral("launcha"), 258},
383 {QStringLiteral("launchb"), 259},
384 {QStringLiteral("launchc"), 260},
385 {QStringLiteral("launchd"), 261},
386 {QStringLiteral("launche"), 262},
387 {QStringLiteral("launchf"), 263},
388 {QStringLiteral("medialast"), 264},
389 {QStringLiteral("unknown"), 265},
390 {QStringLiteral("call"), 266},
391 {QStringLiteral("context1"), 267},
392 {QStringLiteral("context2"), 268},
393 {QStringLiteral("context3"), 269},
394 {QStringLiteral("context4"), 270},
395 {QStringLiteral("flip"), 271},
396 {QStringLiteral("hangup"), 272},
397 {QStringLiteral("no"), 273},
398 {QStringLiteral("select"), 274},
399 {QStringLiteral("yes"), 275},
400 {QStringLiteral("execute"), 276},
401 {QStringLiteral("printer"), 277},
402 {QStringLiteral("play"), 278},
403 {QStringLiteral("sleep"), 279},
404 {QStringLiteral("zoom"), 280},
405 {QStringLiteral("cancel"), 281},
406
407 {QStringLiteral("a"), 282},
408 {QStringLiteral("b"), 283},
409 {QStringLiteral("c"), 284},
410 {QStringLiteral("d"), 285},
411 {QStringLiteral("e"), 286},
412 {QStringLiteral("f"), 287},
413 {QStringLiteral("g"), 288},
414 {QStringLiteral("h"), 289},
415 {QStringLiteral("i"), 290},
416 {QStringLiteral("j"), 291},
417 {QStringLiteral("k"), 292},
418 {QStringLiteral("l"), 293},
419 {QStringLiteral("m"), 294},
420 {QStringLiteral("n"), 295},
421 {QStringLiteral("o"), 296},
422 {QStringLiteral("p"), 297},
423 {QStringLiteral("q"), 298},
424 {QStringLiteral("r"), 299},
425 {QStringLiteral("s"), 300},
426 {QStringLiteral("t"), 301},
427 {QStringLiteral("u"), 302},
428 {QStringLiteral("v"), 303},
429 {QStringLiteral("w"), 304},
430 {QStringLiteral("x"), 305},
431 {QStringLiteral("y"), 306},
432 {QStringLiteral("z"), 307},
433 {QStringLiteral("`"), 308},
434 {QStringLiteral("!"), 309},
435 {QStringLiteral("\""), 310},
436 {QStringLiteral("$"), 311},
437 {QStringLiteral("%"), 312},
438 {QStringLiteral("^"), 313},
439 {QStringLiteral("&"), 314},
440 {QStringLiteral("*"), 315},
441 {QStringLiteral("("), 316},
442 {QStringLiteral(")"), 317},
443 {QStringLiteral("-"), 318},
444 {QStringLiteral("_"), 319},
445 {QStringLiteral("="), 320},
446 {QStringLiteral("+"), 321},
447 {QStringLiteral("["), 322},
448 {QStringLiteral("]"), 323},
449 {QStringLiteral("{"), 324},
450 {QStringLiteral("}"), 325},
451 {QStringLiteral(":"), 326},
452 {QStringLiteral(";"), 327},
453 {QStringLiteral("@"), 328},
454 {QStringLiteral("'"), 329},
455 {QStringLiteral("#"), 330},
456 {QStringLiteral("~"), 331},
457 {QStringLiteral("\\"), 332},
458 {QStringLiteral("|"), 333},
459 {QStringLiteral(","), 334},
460 {QStringLiteral("."), 335},
461 // { QLatin1String( ">" ), 336 },
462 {QStringLiteral("/"), 337},
463 {QStringLiteral("?"), 338},
464 {QStringLiteral(" "), 339},
465 // { QLatin1String( "<" ), 341 },
466 {QStringLiteral("0"), 340},
467 {QStringLiteral("1"), 341},
468 {QStringLiteral("2"), 342},
469 {QStringLiteral("3"), 343},
470 {QStringLiteral("4"), 344},
471 {QStringLiteral("5"), 345},
472 {QStringLiteral("6"), 346},
473 {QStringLiteral("7"), 347},
474 {QStringLiteral("8"), 348},
475 {QStringLiteral("9"), 349},
476 {QStringLiteral("cr"), 350},
477 {QStringLiteral("leader"), 351},
478 {QStringLiteral("nop"), 352},
479 };
480
481 for (QHash<QString, int>::const_iterator i = m_nameToKeyCode.constBegin(); i != m_nameToKeyCode.constEnd(); ++i) {
482 m_keyCodeToName.insert(key: i.value(), value: i.key());
483 }
484}
485
486QString KeyParser::qt2vi(int key) const
487{
488 auto it = m_qt2katevi.constFind(key);
489 if (it != m_qt2katevi.cend()) {
490 return it.value();
491 }
492 return QStringLiteral("invalid");
493}
494
495int KeyParser::vi2qt(const QString &keypress) const
496{
497 auto it = m_katevi2qt.constFind(key: keypress);
498 if (it != m_katevi2qt.cend()) {
499 return it.value();
500 }
501 return -1;
502}
503
504int KeyParser::encoded2qt(const QString &keypress) const
505{
506 QString key = KeyParser::self()->decodeKeySequence(keys: keypress);
507
508 if (key.length() > 2 && key.at(i: 0) == QLatin1Char('<') && key.at(i: key.length() - 1) == QLatin1Char('>')) {
509 key = key.mid(position: 1, n: key.length() - 2);
510 }
511 auto it = m_katevi2qt.constFind(key);
512 if (it != m_katevi2qt.cend())
513 return it.value();
514 return -1;
515}
516
517const QString KeyParser::encodeKeySequence(const QString &keys) const
518{
519 QString encodedSequence;
520 unsigned int keyCodeTemp = 0;
521
522 const QStringView keysView(keys);
523 bool insideTag = false;
524 QChar c;
525 for (int i = 0; i < keys.length(); i++) {
526 c = keys.at(i);
527 if (insideTag) {
528 if (c == QLatin1Char('>')) {
529 QChar code(0xE000 + keyCodeTemp);
530 encodedSequence.append(c: code);
531 keyCodeTemp = 0;
532 insideTag = false;
533 continue;
534 } else {
535 // contains modifiers
536 if (keysView.mid(pos: i).indexOf(c: QLatin1Char('-')) != -1 && keysView.mid(pos: i).indexOf(c: QLatin1Char('-')) < keysView.mid(pos: i).indexOf(c: QLatin1Char('>'))) {
537 // Perform something similar to a split on '-', except that we want to keep the occurrences of '-'
538 // e.g. <c-s-a> will equate to the list of tokens "c-", "s-", "a".
539 // A straight split on '-' would give us "c", "s", "a", in which case we lose the piece of information that
540 // 'a' is just the 'a' key, not the 'alt' modifier.
541 const QString untilClosing = keys.mid(position: i, n: keysView.mid(pos: i).indexOf(c: QLatin1Char('>'))).toLower();
542 QStringList tokens;
543 int currentPos = 0;
544 int nextHypen = -1;
545 while ((nextHypen = untilClosing.indexOf(c: QLatin1Char('-'), from: currentPos)) != -1) {
546 tokens << untilClosing.mid(position: currentPos, n: nextHypen - currentPos + 1);
547 currentPos = nextHypen + 1;
548 }
549 tokens << untilClosing.mid(position: currentPos);
550
551 for (const QString &str : std::as_const(t&: tokens)) {
552 if (str == QLatin1String("s-") && (keyCodeTemp & 0x01) != 0x1) {
553 keyCodeTemp += 0x1;
554 } else if (str == QLatin1String("c-") && (keyCodeTemp & 0x02) != 0x2) {
555 keyCodeTemp += 0x2;
556 } else if (str == QLatin1String("a-") && (keyCodeTemp & 0x04) != 0x4) {
557 keyCodeTemp += 0x4;
558 } else if (str == QLatin1String("m-") && (keyCodeTemp & 0x08) != 0x8) {
559 keyCodeTemp += 0x8;
560 } else {
561 if (m_nameToKeyCode.contains(key: str) || (str.length() == 1 && str.at(i: 0).isLetterOrNumber())) {
562 if (m_nameToKeyCode.contains(key: str)) {
563 keyCodeTemp += m_nameToKeyCode.value(key: str) * 0x10;
564 } else {
565 keyCodeTemp += str.at(i: 0).unicode() * 0x10;
566 }
567 } else {
568 int endOfBlock = keys.indexOf(c: QLatin1Char('>'));
569 if (endOfBlock -= -1) {
570 endOfBlock = keys.length() - 1;
571 }
572 encodedSequence.clear();
573 encodedSequence.append(v: QChar::fromUcs4(c: m_nameToKeyCode.value(QStringLiteral("invalid"))));
574 break;
575 }
576 }
577 }
578 } else {
579 const QString str = keys.mid(position: i, n: keys.indexOf(c: QLatin1Char('>'), from: i) - i).toLower();
580 if (keys.indexOf(c: QLatin1Char('>'), from: i) != -1 && (m_nameToKeyCode.contains(key: str) || (str.length() == 1 && str.at(i: 0).isLetterOrNumber()))) {
581 if (m_nameToKeyCode.contains(key: str)) {
582 keyCodeTemp += m_nameToKeyCode.value(key: str) * 0x10;
583 } else {
584 keyCodeTemp += str.at(i: 0).unicode() * 0x10;
585 }
586 } else {
587 int endOfBlock = keys.indexOf(c: QLatin1Char('>'));
588 if (endOfBlock -= -1) {
589 endOfBlock = keys.length() - 1;
590 }
591 encodedSequence.clear();
592 keyCodeTemp = m_nameToKeyCode.value(QStringLiteral("invalid")) * 0x10;
593 }
594 }
595 i += keysView.mid(pos: i, n: keysView.mid(pos: i).indexOf(c: QLatin1Char('>'))).length() - 1;
596 }
597 } else {
598 if (c == QLatin1Char('<')) {
599 // If there's no closing '>', or if there is an opening '<' before the next '>', interpret as a literal '<'
600 // If we are <space>, encode as a literal " ".
601 const QStringView rest = keysView.mid(pos: i);
602 if (rest.indexOf(c: QLatin1Char('>'), from: 1) != -1 && rest.mid(pos: 1, n: rest.indexOf(c: QLatin1Char('>'), from: 1) - 1) == QLatin1String("space")) {
603 encodedSequence.append(c: QLatin1Char(' '));
604 i += rest.indexOf(c: QLatin1Char('>'), from: 1);
605 continue;
606 } else if (rest.indexOf(c: QLatin1Char('>'), from: 1) == -1
607 || (rest.indexOf(c: QLatin1Char('<'), from: 1) < rest.indexOf(c: QLatin1Char('>'), from: 1) && rest.indexOf(c: QLatin1Char('<'), from: 1) != -1)) {
608 encodedSequence.append(c);
609 continue;
610 }
611 insideTag = true;
612 continue;
613 } else {
614 encodedSequence.append(c);
615 }
616 }
617 }
618
619 return encodedSequence;
620}
621
622const QString KeyParser::decodeKeySequence(const QString &keys) const
623{
624 QString ret;
625 ret.reserve(asize: keys.length());
626
627 for (int i = 0; i < keys.length(); i++) {
628 QChar c = keys.at(i);
629 int keycode = c.unicode();
630
631 if ((keycode & 0xE000) != 0xE000) {
632 ret.append(c);
633 } else {
634 ret.append(c: QLatin1Char('<'));
635
636 if ((keycode & 0x1) == 0x1) {
637 ret.append(s: QLatin1String("s-"));
638 // keycode -= 0x1;
639 }
640 if ((keycode & 0x2) == 0x2) {
641 ret.append(s: QLatin1String("c-"));
642 // keycode -= 0x2;
643 }
644 if ((keycode & 0x4) == 0x4) {
645 ret.append(s: QLatin1String("a-"));
646 // keycode -= 0x4;
647 }
648 if ((keycode & 0x8) == 0x8) {
649 ret.append(s: QLatin1String("m-"));
650 // keycode -= 0x8;
651 }
652
653 if ((keycode & 0xE000) == 0xE000) {
654 ret.append(s: m_keyCodeToName.value(key: (keycode - 0xE000) / 0x10));
655 } else {
656 ret.append(v: QChar::fromUcs4(c: keycode));
657 }
658 ret.append(c: QLatin1Char('>'));
659 }
660 }
661
662 return ret;
663}
664
665const QChar KeyParser::KeyEventToQChar(const QKeyEvent &keyEvent)
666{
667 return KeyEventToQChar(keyCode: keyEvent.key(), text: keyEvent.text(), mods: keyEvent.modifiers());
668}
669
670const QChar KeyParser::KeyEventToQChar(const KeyEvent &keyEvent)
671{
672 return KeyEventToQChar(keyCode: keyEvent.key(), text: keyEvent.text(), mods: keyEvent.modifiers());
673}
674
675const QChar KeyParser::KeyEventToQChar(int keyCode, const QString &text, Qt::KeyboardModifiers mods) const
676{
677 // If previous key press was AltGr, return key value right away and don't go
678 // down the "handle modifiers" code path. AltGr is really confusing...
679 if (mods & Qt::GroupSwitchModifier) {
680 return (!text.isEmpty()) ? text.at(i: 0) : QChar();
681 }
682
683 if (text.isEmpty() || (text.length() == 1 && text.at(i: 0) < QChar(0x20)) || keyCode == Qt::Key_Delete
684 || (mods != Qt::NoModifier && mods != Qt::ShiftModifier && mods != Qt::KeypadModifier)) {
685 QString keyPress;
686 keyPress.reserve(asize: 11);
687
688 keyPress.append(c: QLatin1Char('<'));
689 keyPress.append(s: (mods & Qt::ShiftModifier) ? QStringLiteral("s-") : QString());
690 keyPress.append(s: (mods & CONTROL_MODIFIER) ? QStringLiteral("c-") : QString());
691 keyPress.append(s: (mods & Qt::AltModifier) ? QStringLiteral("a-") : QString());
692 keyPress.append(s: (mods & META_MODIFIER) ? QStringLiteral("m-") : QString());
693 keyPress.append(s: keyCode <= 0xFF ? QChar(keyCode) : qt2vi(key: keyCode));
694 keyPress.append(c: QLatin1Char('>'));
695
696 return encodeKeySequence(keys: keyPress).at(i: 0);
697 } else {
698 return text.at(i: 0);
699 }
700}
701

source code of ktexteditor/src/vimode/keyparser.cpp