Skip to content

Commit

Permalink
Issue 720: Spanish Keyboard Layout Accents
Browse files Browse the repository at this point in the history
Accent characters are not handled correctly for the Spanish Keyboard Layout.

TODO Adding tests only, not sure if these are correct...
TODO Fix For Windows. Validate MacOS/Linux
  • Loading branch information
jgehrig committed May 31, 2021
1 parent a7c7d0c commit 7487dee
Show file tree
Hide file tree
Showing 6 changed files with 129 additions and 24 deletions.
39 changes: 37 additions & 2 deletions src/gui/input.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,26 @@ static QString KeyToText(int key, Qt::KeyboardModifiers mod) noexcept
return text;
}

static bool IsControlCaretKeyEvent(
int key,
Qt::KeyboardModifiers mod,
const QString& text) noexcept
{
if (key != Qt::Key_6 && key != Qt::Key_AsciiCircum) {
return false;
}

if (!(mod & ControlModifier())) {
return false;
}

if (text != "\u001E" && text != "^" && text != "6" && !text.isEmpty()) {
return false;
}

return true;
}

QString convertKey(const QKeyEvent& ev) noexcept
{
QString text{ ev.text() };
Expand Down Expand Up @@ -177,6 +197,11 @@ QString convertKey(const QKeyEvent& ev) noexcept
const QMap<int, QString>& specialKeys { GetSpecialKeysMap() };

if (specialKeys.contains(key)) {
// Issue#720: International keyboards may insert an accent on space.
if (key == Qt::Key_Space && text != " ") {
return text;
}

// Issue#728: Shift + Space inserts ;2u in `:terminal`. Incorrectly sent as <S-Space>.
// Issue#259: Shift + BackSpace inserts 7;2u in `:terminal`. Incorrectly sent as <S-BS>.
if (key == Qt::Key_Space
Expand All @@ -194,9 +219,19 @@ QString convertKey(const QKeyEvent& ev) noexcept
return ToKeyString(GetModifierPrefix(modNoShift), "lt");
}

// Issue#720: Spanish keyboard "[" character insertion
if (key == Qt::Key_AsciiCircum && text == "[") {
const Qt::KeyboardModifiers modNoAlt{ mod & ~Qt::AltModifier };

if (modNoAlt == Qt::NoModifier) {
return QStringLiteral("[");
}

return ToKeyString(GetModifierPrefix(modNoAlt), "[");
}

// Issue#170: Normalize modifiers, CTRL+^ always sends as <C-^>
const bool isCaretKey{ key == Qt::Key_6 || key == Qt::Key_AsciiCircum };
if (isCaretKey && mod & ControlModifier()) {
if (IsControlCaretKeyEvent(key, mod, text)) {
const Qt::KeyboardModifiers modNoShiftMeta{
mod & ~Qt::KeyboardModifier::ShiftModifier & ~CmdModifier() };
return ToKeyString(GetModifierPrefix(modNoShiftMeta), "^");
Expand Down
9 changes: 5 additions & 4 deletions test/tst_input.h
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
#pragma once

#include <QKeyEvent>
#include <QString>

// A class to hold test data. An event type/key/modifiers
// as used in QKeyEvent and a matching Neovim input string.
struct InputTest
struct InputTest final
{
QEvent::Type event_type;
int key;
Qt::KeyboardModifiers modifiers;
QKeyEvent event;
QString expected_input;
};
54 changes: 54 additions & 0 deletions test/tst_input_common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ private slots:
void AltGrKeyEventWellFormed() noexcept;
void ShiftSpaceWellFormed() noexcept;
void ShiftBackSpaceWellFormed() noexcept;
void SpanishKeyboardLayout() noexcept;

// Mouse Input
void MouseLeftClick() noexcept;
Expand Down Expand Up @@ -265,5 +266,58 @@ void TestInputCommon::MouseMiddleClick() noexcept
QCOMPARE(middleClickRelease, QString{ "<MiddleRelease><1,2>" });
}

void TestInputCommon::SpanishKeyboardLayout() noexcept
{
// Issue 720: Spanish layout ignores Left Square Bracket [
// NOTE: The "`" referenced below is "[" on a US layout keyboard for Windows/Linux and literal for MacOS.

// Windows ` + Space. Prints: `
QKeyEvent evAccentSpace{ QKeyEvent::KeyPress, Qt::Key_Space, Qt::NoModifier, QStringLiteral("`") };
QCOMPARE(NeovimQt::Input::convertKey(evAccentSpace), QStringLiteral("`"));

// Windows ``: two events are sent on the second key event. Prints: ``
// NOTE: Linux/MacOS do not send QKeyEvents for this scenario.
QKeyEvent evAccentFirst{ QKeyEvent::KeyPress, Qt::Key_QuoteLeft, Qt::NoModifier, QStringLiteral("`") };
QKeyEvent evAccentSecond{ QKeyEvent::KeyPress, 0, Qt::NoModifier, QStringLiteral("`") };

// Windows AltGr (Right Alt) + `. Prints: [
QKeyEvent evAltGrSquareBracketWindows{ QKeyEvent::KeyPress, Qt::Key_AsciiCircum, Qt::AltModifier, QStringLiteral("[") };
QCOMPARE(NeovimQt::Input::convertKey(evAltGrSquareBracketWindows), QStringLiteral("["));

// Linux AltGr (Right Alt) + `. Prints: [
QKeyEvent evAltGrSquareBracketLinux{ QKeyEvent::KeyPress, Qt::Key_BracketLeft, Qt::GroupSwitchModifier, QStringLiteral("[") };
QCOMPARE(NeovimQt::Input::convertKey(evAltGrSquareBracketLinux), QStringLiteral("["));

// // MacOS Alt + `: Prints [
// QKeyEvent evAltLeftSquareBracketMacOS{ QKeyEvent::KeyPress, Qt::Key_Less, Qt::AltModifier, QStringLiteral("[") };
// QCOMPARE(NeovimQt::Input::convertKey(evAltLeftSquareBracketMacOS), QStringLiteral("["));
//
// // MacOS Alt + \: Prints [
// QKeyEvent evAltRightSquareBracketMacOS{ QKeyEvent::KeyPress, Qt::Key_Apostrophe, Qt::AltModifier, QStringLiteral("]") };
// QCOMPARE(NeovimQt::Input::convertKey(evAltRightSquareBracketMacOS), QStringLiteral("["));

// Windows Shift + ` then Space. Prints ^
// NOTE: Linux does not send QKeyEvents for this scenario.
QKeyEvent evShiftAccentSpace{ QKeyEvent::KeyPress, Qt::Key_Space, Qt::NoModifier, QStringLiteral("^") };
QCOMPARE(NeovimQt::Input::convertKey(evShiftAccentSpace), QStringLiteral("^"));

// Windows Shift + ``. Prints ^^ (Windows) and ^ (Linux)
// NOTE: Linux/MacOS do not send QKeyEvents for this scenario.
QKeyEvent evShiftAccentAccent1{ QKeyEvent::KeyPress, Qt::Key_AsciiCircum, Qt::ShiftModifier, QStringLiteral("^") };
QKeyEvent evShiftAccentAccent2{ QKeyEvent::KeyPress, 0, Qt::ShiftModifier, QStringLiteral("^") };
QCOMPARE(NeovimQt::Input::convertKey(evShiftAccentAccent1), QStringLiteral("^"));
QCOMPARE(NeovimQt::Input::convertKey(evShiftAccentAccent2), QStringLiteral("^"));

// Windows ` then e. Prints: è
// NOTE: Linux/MacOS do not send QKeyEvents for this scenario.
QKeyEvent evAccentE{ QKeyEvent::KeyPress, Qt::Key_E, Qt::NoModifier, QStringLiteral("ê") };
QCOMPARE(NeovimQt::Input::convertKey(evAccentE), QStringLiteral("ê"));

// Windows Shift + ^ then e. Prints: ê
// NOTE: Linux/MacOS do not send QKeyEvents for this scenario.
QKeyEvent evShiftAccentE{ QKeyEvent::KeyPress, Qt::Key_E, Qt::NoModifier, QStringLiteral("ê") };
QCOMPARE(NeovimQt::Input::convertKey(evShiftAccentE), QStringLiteral("ê"));
}

#include "tst_input_common.moc"
QTEST_MAIN(TestInputCommon)
17 changes: 11 additions & 6 deletions test/tst_input_mac.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,17 +47,22 @@ void TestInputMac::SpecialKeys() noexcept
const QList<int> specialKeys{ NeovimQt::Input::GetSpecialKeysMap().keys() };

for (const auto k : specialKeys) {
// Key_Space events send with text=" "
QString text;
if (k == Qt::Key_Space) {
text = QStringLiteral(" ");
}

// On Mac Meta is the Control key, treated as C-.
QList<InputTest> keyEventList{
{ QEvent::KeyPress, k, Qt::NoModifier, "<%1>" },
{ QEvent::KeyPress, k, Qt::ControlModifier, "<D-%1>" },
{ QEvent::KeyPress, k, Qt::AltModifier, "<A-%1>" },
{ QEvent::KeyPress, k, Qt::MetaModifier, "<C-%1>" },
{ { QEvent::KeyPress, k, Qt::NoModifier, text }, "<%1>" },
{ { QEvent::KeyPress, k, Qt::ControlModifier, text }, "<D-%1>" },
{ { QEvent::KeyPress, k, Qt::AltModifier, text }, "<A-%1>" },
{ { QEvent::KeyPress, k, Qt::MetaModifier,text }, "<C-%1>" },
};

for (const auto& keyTest : keyEventList) {
auto event = QKeyEvent(keyTest.event_type, keyTest.key, keyTest.modifiers);
QCOMPARE(NeovimQt::Input::convertKey(event),
QCOMPARE(NeovimQt::Input::convertKey(keyTest.event),
keyTest.expected_input.arg(NeovimQt::Input::GetSpecialKeysMap().value(k)));
}
}
Expand Down
17 changes: 11 additions & 6 deletions test/tst_input_unix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,22 @@ void TestInputUnix::SpecialKeys() noexcept
const QList<int> specialKeys{ NeovimQt::Input::GetSpecialKeysMap().keys() };

for (const auto k : specialKeys) {
// Key_Space events send with text=" "
QString text;
if (k == Qt::Key_Space) {
text = QStringLiteral(" ");
}

// On Mac Meta is the Control key, treated as C-.
QList<InputTest> keyEventList{
{ QEvent::KeyPress, k, Qt::NoModifier, "<%1>" },
{ QEvent::KeyPress, k, Qt::ControlModifier, "<C-%1>" },
{ QEvent::KeyPress, k, Qt::AltModifier, "<A-%1>" },
{ QEvent::KeyPress, k, Qt::MetaModifier, "<D-%1>" },
{ { QEvent::KeyPress, k, Qt::NoModifier, text }, "<%1>" },
{ { QEvent::KeyPress, k, Qt::ControlModifier, text }, "<C-%1>" },
{ { QEvent::KeyPress, k, Qt::AltModifier, text }, "<A-%1>" },
{ { QEvent::KeyPress, k, Qt::MetaModifier, text }, "<D-%1>" },
};

for (const auto& keyTest : keyEventList) {
auto event = QKeyEvent(keyTest.event_type, keyTest.key, keyTest.modifiers);
QCOMPARE(NeovimQt::Input::convertKey(event),
QCOMPARE(NeovimQt::Input::convertKey(keyTest.event),
keyTest.expected_input.arg(NeovimQt::Input::GetSpecialKeysMap().value(k)));
}
}
Expand Down
17 changes: 11 additions & 6 deletions test/tst_input_win32.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,22 @@ void TestInputWin32::SpecialKeys() noexcept
const QList<int> specialKeys{ NeovimQt::Input::GetSpecialKeysMap().keys() };

for (const auto k : specialKeys) {
// Key_Space events send with text=" "
QString text;
if (k == Qt::Key_Space) {
text = QStringLiteral(" ");
}

// On Mac Meta is the Control key, treated as C-.
QList<InputTest> keyEventList{
{ QEvent::KeyPress, k, Qt::NoModifier, "<%1>" },
{ QEvent::KeyPress, k, Qt::ControlModifier, "<C-%1>" },
{ QEvent::KeyPress, k, Qt::AltModifier, "<A-%1>" },
{ QEvent::KeyPress, k, Qt::MetaModifier, "<%1>" },
{ { QEvent::KeyPress, k, Qt::NoModifier, text }, "<%1>" },
{ { QEvent::KeyPress, k, Qt::ControlModifier, text }, "<C-%1>" },
{ { QEvent::KeyPress, k, Qt::AltModifier, text }, "<A-%1>" },
{ { QEvent::KeyPress, k, Qt::MetaModifier, text }, "<%1>" },
};

for (const auto& keyTest : keyEventList) {
auto event = QKeyEvent(keyTest.event_type, keyTest.key, keyTest.modifiers);
QCOMPARE(NeovimQt::Input::convertKey(event),
QCOMPARE(NeovimQt::Input::convertKey(keyTest.event),
keyTest.expected_input.arg(NeovimQt::Input::GetSpecialKeysMap().value(k)));
}
}
Expand Down

0 comments on commit 7487dee

Please sign in to comment.