8#include "definitions.h"
11#include <vimode/keyevent.h>
12#include <vimode/keyparser.h>
14using namespace KateVi;
16KeyParser *KeyParser::m_instance =
nullptr;
25 if (m_instance ==
nullptr) {
26 m_instance =
new KeyParser();
32void KeyParser::initKeyTables()
218 for (QHash<int, QString>::const_iterator i = m_qt2katevi.constBegin(); i != m_qt2katevi.constEnd(); ++i) {
219 m_katevi2qt.insert(i.value(), i.key());
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},
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},
462 {QStringLiteral(
"/"), 337},
463 {QStringLiteral(
"?"), 338},
464 {QStringLiteral(
" "), 339},
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},
481 for (QHash<QString, int>::const_iterator i = m_nameToKeyCode.constBegin(); i != m_nameToKeyCode.constEnd(); ++i) {
482 m_keyCodeToName.insert(i.value(), i.key());
486QString KeyParser::qt2vi(
int key)
const
488 auto it = m_qt2katevi.constFind(key);
489 if (it != m_qt2katevi.cend()) {
492 return QStringLiteral(
"invalid");
495int KeyParser::vi2qt(
const QString &keypress)
const
497 auto it = m_katevi2qt.constFind(keypress);
498 if (it != m_katevi2qt.cend()) {
504int KeyParser::encoded2qt(
const QString &keypress)
const
506 QString key = KeyParser::self()->decodeKeySequence(keypress);
508 if (key.
length() > 2 && key.
at(0) == QLatin1Char(
'<') && key.
at(key.
length() - 1) == QLatin1Char(
'>')) {
511 auto it = m_katevi2qt.constFind(key);
512 if (it != m_katevi2qt.cend())
517const QString KeyParser::encodeKeySequence(
const QString &keys)
const
519 QString encodedSequence;
520 unsigned int keyCodeTemp = 0;
522 const QStringView keysView(keys);
523 bool insideTag =
false;
525 for (
int i = 0; i < keys.
length(); i++) {
528 if (c == QLatin1Char(
'>')) {
529 QChar code(0xE000 + keyCodeTemp);
530 encodedSequence.
append(code);
536 if (keysView.mid(i).indexOf(QLatin1Char(
'-')) != -1 && keysView.mid(i).indexOf(QLatin1Char(
'-')) < keysView.mid(i).indexOf(QLatin1Char(
'>'))) {
541 const QString untilClosing = keys.
mid(i, keysView.mid(i).indexOf(QLatin1Char(
'>'))).
toLower();
545 while ((nextHypen = untilClosing.
indexOf(QLatin1Char(
'-'), currentPos)) != -1) {
546 tokens << untilClosing.
mid(currentPos, nextHypen - currentPos + 1);
547 currentPos = nextHypen + 1;
549 tokens << untilClosing.
mid(currentPos);
551 for (
const QString &str : std::as_const(tokens)) {
552 if (str == QLatin1String(
"s-") && (keyCodeTemp & 0x01) != 0x1) {
554 }
else if (str == QLatin1String(
"c-") && (keyCodeTemp & 0x02) != 0x2) {
556 }
else if (str == QLatin1String(
"a-") && (keyCodeTemp & 0x04) != 0x4) {
558 }
else if (str == QLatin1String(
"m-") && (keyCodeTemp & 0x08) != 0x8) {
561 if (m_nameToKeyCode.contains(str) || (str.length() == 1 && str.at(0).isLetterOrNumber())) {
562 if (m_nameToKeyCode.contains(str)) {
563 keyCodeTemp += m_nameToKeyCode.value(str) * 0x10;
565 keyCodeTemp += str.at(0).unicode() * 0x10;
568 int endOfBlock = keys.
indexOf(QLatin1Char(
'>'));
569 if (endOfBlock -= -1) {
570 endOfBlock = keys.
length() - 1;
572 encodedSequence.
clear();
579 const QString str = keys.
mid(i, keys.
indexOf(QLatin1Char(
'>'), i) - i).
toLower();
581 if (m_nameToKeyCode.contains(str)) {
582 keyCodeTemp += m_nameToKeyCode.value(str) * 0x10;
584 keyCodeTemp += str.
at(0).
unicode() * 0x10;
587 int endOfBlock = keys.
indexOf(QLatin1Char(
'>'));
588 if (endOfBlock -= -1) {
589 endOfBlock = keys.
length() - 1;
591 encodedSequence.
clear();
592 keyCodeTemp = m_nameToKeyCode.value(QStringLiteral(
"invalid")) * 0x10;
595 i += keysView.mid(i, keysView.mid(i).indexOf(QLatin1Char(
'>'))).length() - 1;
598 if (c == QLatin1Char(
'<')) {
601 const QStringView rest = keysView.mid(i);
602 if (rest.
indexOf(QLatin1Char(
'>'), 1) != -1 && rest.
mid(1, rest.
indexOf(QLatin1Char(
'>'), 1) - 1) == QLatin1String(
"space")) {
603 encodedSequence.
append(QLatin1Char(
' '));
604 i += rest.
indexOf(QLatin1Char(
'>'), 1);
606 }
else if (rest.
indexOf(QLatin1Char(
'>'), 1) == -1
607 || (rest.
indexOf(QLatin1Char(
'<'), 1) < rest.
indexOf(QLatin1Char(
'>'), 1) && rest.
indexOf(QLatin1Char(
'<'), 1) != -1)) {
608 encodedSequence.
append(c);
614 encodedSequence.
append(c);
619 return encodedSequence;
622const QString KeyParser::decodeKeySequence(
const QString &keys)
const
627 for (
int i = 0; i < keys.
length(); i++) {
628 QChar c = keys.
at(i);
631 if ((keycode & 0xE000) != 0xE000) {
634 ret.
append(QLatin1Char(
'<'));
636 if ((keycode & 0x1) == 0x1) {
637 ret.
append(QLatin1String(
"s-"));
640 if ((keycode & 0x2) == 0x2) {
641 ret.
append(QLatin1String(
"c-"));
644 if ((keycode & 0x4) == 0x4) {
645 ret.
append(QLatin1String(
"a-"));
648 if ((keycode & 0x8) == 0x8) {
649 ret.
append(QLatin1String(
"m-"));
653 if ((keycode & 0xE000) == 0xE000) {
654 ret.
append(m_keyCodeToName.value((keycode - 0xE000) / 0x10));
658 ret.
append(QLatin1Char(
'>'));
665const QChar KeyParser::KeyEventToQChar(
const QKeyEvent &keyEvent)
670const QChar KeyParser::KeyEventToQChar(
const KeyEvent &keyEvent)
675const QChar KeyParser::KeyEventToQChar(
int keyCode,
const QString &text,
Qt::KeyboardModifiers mods)
const
680 return (!text.
isEmpty()) ? text.
at(0) : QChar();
690 keyPress.append((mods & CONTROL_MODIFIER) ? QStringLiteral(
"c-") : QString());
692 keyPress.append((mods & META_MODIFIER) ? QStringLiteral(
"m-") : QString());
693 keyPress.append(keyCode <= 0xFF ? QChar(keyCode) : qt2vi(keyCode));
696 return encodeKeySequence(keyPress).at(0);
QEvent wrapper for copying/storing key events.
for encoding keypresses w/ modifiers into an internal QChar representation and back again to a descri...
bool isLetterOrNumber(char32_t ucs4)
QString & append(QChar ch)
const QChar at(qsizetype position) const const
qsizetype indexOf(QChar ch, qsizetype from, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
qsizetype length() const const
QString mid(qsizetype position, qsizetype n) const const
void reserve(qsizetype size)
QString toLower() const const
QStringView mid(qsizetype start, qsizetype length) const const
qsizetype indexOf(QChar c, qsizetype from, Qt::CaseSensitivity cs) const const
typedef KeyboardModifiers
void keyEvent(KeyAction action, QWidget *widget, Qt::Key key, Qt::KeyboardModifiers modifier, int delay)
void keyPress(QWidget *widget, Qt::Key key, Qt::KeyboardModifiers modifier, int delay)