Rework NCurses key parsing to properly handle <a-special key>

This commit is contained in:
Maxime Coste 2017-01-30 13:38:56 +00:00
parent f30e164232
commit 34870eb353
2 changed files with 76 additions and 66 deletions

View File

@ -94,9 +94,18 @@ class StringView;
KeyList parse_keys(StringView str);
String key_to_str(Key key);
constexpr Key alt(Codepoint key) { return { Key::Modifiers::Alt, key }; }
constexpr Key ctrl(Codepoint key) { return { Key::Modifiers::Control, key }; }
constexpr Key ctrlalt(Codepoint key) { return { Key::Modifiers::ControlAlt, key }; }
constexpr Key alt(Key key)
{
return { key.modifiers | Key::Modifiers::Alt, key.key };
}
constexpr Key ctrl(Key key)
{
return { key.modifiers | Key::Modifiers::Control, key.key };
}
constexpr Key ctrlalt(Key key)
{
return { key.modifiers | Key::Modifiers::ControlAlt, key.key };
}
constexpr Codepoint encode_coord(DisplayCoord coord) { return (Codepoint)(((int)coord.line << 16) | ((int)coord.column & 0x0000FFFF)); }

View File

@ -499,9 +499,6 @@ Optional<Key> NCursesUI::get_next_key()
const int c = wgetch(m_window);
wtimeout(m_window, -1);
if (c == ERR)
return {};
if (c == KEY_MOUSE)
{
MEVENT ev;
@ -531,25 +528,70 @@ Optional<Key> NCursesUI::get_next_key()
}
}
if (c > 0 and c < 27)
{
if (c == control('m') or c == control('j'))
return {Key::Return};
if (c == control('i'))
return {Key::Tab};
if (c == control('h'))
return {Key::Backspace};
if (c == control('z'))
{
raise(SIGTSTP);
auto parse_key = [this](int c) -> Optional<Key> {
if (c == ERR)
return {};
switch (c)
{
case KEY_BACKSPACE: case 127: return {Key::Backspace};
case KEY_DC: return {Key::Delete};
case KEY_UP: return {Key::Up};
case KEY_DOWN: return {Key::Down};
case KEY_LEFT: return {Key::Left};
case KEY_RIGHT: return {Key::Right};
case KEY_PPAGE: return {Key::PageUp};
case KEY_NPAGE: return {Key::PageDown};
case KEY_HOME: return {Key::Home};
case KEY_END: return {Key::End};
case KEY_BTAB: return {Key::BackTab};
case KEY_RESIZE: return resize(m_dimensions);
}
return ctrl(Codepoint(c) - 1 + 'a');
}
else if (c == 27)
if (c > 0 and c < 27)
{
if (c == control('m') or c == control('j'))
return {Key::Return};
if (c == control('i'))
return {Key::Tab};
if (c == control('h'))
return {Key::Backspace};
if (c == control('z'))
{
raise(SIGTSTP);
return {};
}
return ctrl(Codepoint(c) - 1 + 'a');
}
for (int i = 0; i < 12; ++i)
{
if (c == KEY_F(i+1))
return {Key::F1 + i};
}
if (c >= 0 and c < 256)
{
ungetch(c);
struct getch_iterator
{
getch_iterator(WINDOW* win) : window(win) {}
int operator*() { return wgetch(window); }
getch_iterator& operator++() { return *this; }
getch_iterator& operator++(int) { return *this; }
bool operator== (const getch_iterator&) const { return false; }
WINDOW* window;
};
return Key{utf8::codepoint(getch_iterator{m_window},
getch_iterator{m_window})};
}
};
if (c == 27)
{
wtimeout(m_window, 0);
const Codepoint new_c = wgetch(m_window);
const int new_c = wgetch(m_window);
if (new_c == '[') // potential CSI
{
const Codepoint csi_val = wgetch(m_window);
@ -561,54 +603,13 @@ Optional<Key> NCursesUI::get_next_key()
}
}
wtimeout(m_window, -1);
if (new_c != ERR)
{
if (new_c > 0 and new_c < 27)
return ctrlalt(Codepoint(new_c) - 1 + 'a');
return alt(new_c);
}
if (auto key = parse_key(new_c))
return alt(*key);
else
return {Key::Escape};
}
else switch (c)
{
case KEY_BACKSPACE: case 127: return {Key::Backspace};
case KEY_DC: return {Key::Delete};
case KEY_UP: return {Key::Up};
case KEY_DOWN: return {Key::Down};
case KEY_LEFT: return {Key::Left};
case KEY_RIGHT: return {Key::Right};
case KEY_PPAGE: return {Key::PageUp};
case KEY_NPAGE: return {Key::PageDown};
case KEY_HOME: return {Key::Home};
case KEY_END: return {Key::End};
case KEY_BTAB: return {Key::BackTab};
case KEY_RESIZE: return resize(m_dimensions);
}
for (int i = 0; i < 12; ++i)
{
if (c == KEY_F(i+1))
return {Key::F1 + i};
}
if (c >= 0 and c < 256)
{
ungetch(c);
struct getch_iterator
{
getch_iterator(WINDOW* win) : window(win) {}
int operator*() { return wgetch(window); }
getch_iterator& operator++() { return *this; }
getch_iterator& operator++(int) { return *this; }
bool operator== (const getch_iterator&) const { return false; }
WINDOW* window;
};
return Key{utf8::codepoint(getch_iterator{m_window},
getch_iterator{m_window})};
}
return {};
return parse_key(c);
}
template<typename T>