window: redefine special key values

This commit is contained in:
Andrzej Rybczak
2015-05-12 20:40:26 +02:00
parent 0dc3752e3f
commit e7b152938b
7 changed files with 208 additions and 199 deletions

View File

@@ -36,47 +36,58 @@ Key stringToSpecialKey(const std::string &s)
{
Key result = Key::noOp;
if (!s.compare("mouse"))
result = Key(KEY_MOUSE, Key::NCurses);
result = Key(NC::Key::Mouse, Key::NCurses);
else if (!s.compare("up"))
result = Key(KEY_UP, Key::NCurses);
result = Key(NC::Key::Up, Key::NCurses);
else if (!s.compare("down"))
result = Key(KEY_DOWN, Key::NCurses);
result = Key(NC::Key::Down, Key::NCurses);
else if (!s.compare("page_up"))
result = Key(KEY_PPAGE, Key::NCurses);
result = Key(NC::Key::PageUp, Key::NCurses);
else if (!s.compare("page_down"))
result = Key(KEY_NPAGE, Key::NCurses);
result = Key(NC::Key::PageDown, Key::NCurses);
else if (!s.compare("home"))
result = Key(KEY_HOME, Key::NCurses);
result = Key(NC::Key::Home, Key::NCurses);
else if (!s.compare("end"))
result = Key(KEY_END, Key::NCurses);
result = Key(NC::Key::End, Key::NCurses);
else if (!s.compare("space"))
result = Key(KEY_SPACE, Key::Standard);
result = Key(NC::Key::Space, Key::Standard);
else if (!s.compare("enter"))
result = Key(KEY_ENTER, Key::Standard);
result = Key(NC::Key::Enter, Key::Standard);
else if (!s.compare("insert"))
result = Key(KEY_IC, Key::NCurses);
result = Key(NC::Key::Insert, Key::NCurses);
else if (!s.compare("delete"))
result = Key(KEY_DC, Key::NCurses);
result = Key(NC::Key::Delete, Key::NCurses);
else if (!s.compare("left"))
result = Key(KEY_LEFT, Key::NCurses);
result = Key(NC::Key::Left, Key::NCurses);
else if (!s.compare("right"))
result = Key(KEY_RIGHT, Key::NCurses);
result = Key(NC::Key::Right, Key::NCurses);
else if (!s.compare("tab"))
result = Key(KEY_TAB, Key::Standard);
result = Key(NC::Key::Tab, Key::Standard);
else if (!s.compare("shift_tab"))
result = Key(KEY_SHIFT_TAB, Key::NCurses);
else if (!s.compare(0, 5, "ctrl_") && s.length() > 5 && s[5] >= 'a' && s[5] <= 'z')
result = Key(KEY_CTRL_A + (s[5] - 'a'), Key::Standard);
result = Key(NC::Key::Shift | NC::Key::Tab, Key::NCurses);
else if (!s.compare(0, 5, "ctrl_") && s.length() > 5)
{
if (s[5] >= 'a' && s[5] <= 'z')
result = Key(NC::Key::Ctrl_A + (s[5] - 'a'), Key::Standard);
else if (s[5] == '[')
result = Key(NC::Key::Ctrl_LeftBracket, Key::Standard);
else if (s[5] == '\\')
result = Key(NC::Key::Ctrl_Backslash, Key::Standard);
else if (s[5] == ']')
result = Key(NC::Key::Ctrl_RightBracket, Key::Standard);
else if (s[5] == '^')
result = Key(NC::Key::Ctrl_Caret, Key::Standard);
else if (s[5] == '_')
result = Key(NC::Key::Ctrl_Underscore, Key::Standard);
}
else if (s.length() > 1 && s[0] == 'f')
{
int n = atoi(s.c_str() + 1);
if (n >= 1 && n <= 12)
result = Key(KEY_F1 + n - 1, Key::NCurses);
result = Key(NC::Key::F1 + n - 1, Key::NCurses);
}
else if (!s.compare("backspace"))
result = Key(KEY_BACKSPACE, Key::NCurses);
else if (!s.compare("backspace_2"))
result = Key(KEY_BACKSPACE_2, Key::Standard);
result = Key(NC::Key::Backspace, Key::Standard);
return result;
}
@@ -442,11 +453,6 @@ void BindingsConfiguration::generateDefaults()
bind(k, Actions::Type::JumpToParentDirectory);
bind(k, Actions::Type::ReplaySong);
}
if (notBound(k = stringToKey("backspace_2")))
{
bind(k, Actions::Type::JumpToParentDirectory);
bind(k, Actions::Type::ReplaySong);
}
if (notBound(k = stringToKey("f")))
bind(k, Actions::Type::SeekForward);
if (notBound(k = stringToKey("b")))

View File

@@ -95,7 +95,7 @@ void setProperties(NC::Menu<T> &menu, const MPD::Song &s, const SongList &list,
if (separate_albums)
{
menu << NC::Format::Underline;
mvwhline(menu.raw(), menu.getY(), 0, KEY_SPACE, menu.getWidth());
mvwhline(menu.raw(), menu.getY(), 0, NC::Key::Space, menu.getWidth());
}
is_selected = menu.drawn()->isSelected();
@@ -216,7 +216,7 @@ void showSongsInColumns(NC::Menu<T> &menu, const MPD::Song &s, const SongList &l
if (it->right_alignment)
x_off = std::max(0, width - int(wideLength(tag)));
whline(menu.raw(), KEY_SPACE, width);
whline(menu.raw(), NC::Key::Space, width);
menu.goToXY(x + x_off, y);
menu << tag;
menu.goToXY(x + width, y);
@@ -302,13 +302,13 @@ std::string Display::Columns(size_t list_width)
int x_off = std::max(0, width - int(wideLength(name)));
if (it->right_alignment)
{
result += std::string(x_off, KEY_SPACE);
result += std::string(x_off, NC::Key::Space);
result += Charset::utf8ToLocale(ToString(name));
}
else
{
result += Charset::utf8ToLocale(ToString(name));
result += std::string(x_off, KEY_SPACE);
result += std::string(x_off, NC::Key::Space);
}
if (it != last)

View File

@@ -36,59 +36,49 @@ Help *myHelp;
namespace {
std::string key_to_string(const Key &key, bool *print_backspace)
std::string key_to_string(const Key &key)
{
std::string result;
if (key == Key(KEY_UP, Key::NCurses))
if (key == Key(NC::Key::Up, Key::NCurses))
result += "Up";
else if (key == Key(KEY_DOWN, Key::NCurses))
else if (key == Key(NC::Key::Down, Key::NCurses))
result += "Down";
else if (key == Key(KEY_PPAGE, Key::NCurses))
else if (key == Key(NC::Key::PageUp, Key::NCurses))
result += "Page Up";
else if (key == Key(KEY_NPAGE, Key::NCurses))
else if (key == Key(NC::Key::PageDown, Key::NCurses))
result += "Page Down";
else if (key == Key(KEY_HOME, Key::NCurses))
else if (key == Key(NC::Key::Home, Key::NCurses))
result += "Home";
else if (key == Key(KEY_END, Key::NCurses))
else if (key == Key(NC::Key::End, Key::NCurses))
result += "End";
else if (key == Key(KEY_SPACE, Key::Standard))
else if (key == Key(NC::Key::Space, Key::Standard))
result += "Space";
else if (key == Key(KEY_ENTER, Key::Standard))
else if (key == Key(NC::Key::Enter, Key::Standard))
result += "Enter";
else if (key == Key(KEY_IC, Key::NCurses))
else if (key == Key(NC::Key::Insert, Key::NCurses))
result += "Insert";
else if (key == Key(KEY_DC, Key::NCurses))
else if (key == Key(NC::Key::Delete, Key::NCurses))
result += "Delete";
else if (key == Key(KEY_RIGHT, Key::NCurses))
else if (key == Key(NC::Key::Right, Key::NCurses))
result += "Right";
else if (key == Key(KEY_LEFT, Key::NCurses))
else if (key == Key(NC::Key::Left, Key::NCurses))
result += "Left";
else if (key == Key(KEY_TAB, Key::Standard))
else if (key == Key(NC::Key::Tab, Key::Standard))
result += "Tab";
else if (key == Key(KEY_SHIFT_TAB, Key::NCurses))
else if (key == Key(NC::Key::Shift | NC::Key::Tab, Key::NCurses))
result += "Shift-Tab";
else if (key >= Key(KEY_CTRL_A, Key::Standard) && key <= Key(KEY_CTRL_Z, Key::Standard))
else if (key >= Key(NC::Key::Ctrl_A, Key::Standard) && key <= Key(NC::Key::Ctrl_Z, Key::Standard))
{
result += "Ctrl-";
result += key.getChar()+64;
}
else if (key >= Key(KEY_F1, Key::NCurses) && key <= Key(KEY_F12, Key::NCurses))
else if (key >= Key(NC::Key::F1, Key::NCurses) && key <= Key(NC::Key::F12, Key::NCurses))
{
result += "F";
result += boost::lexical_cast<std::string>(key.getChar()-264);
result += boost::lexical_cast<std::string>(key.getChar()-NC::Key::F1+1);
}
else if ((key == Key(KEY_BACKSPACE, Key::NCurses) || key == Key(KEY_BACKSPACE_2, Key::Standard)))
{
// since some terminals interpret KEY_BACKSPACE as backspace and other need KEY_BACKSPACE_2,
// actions have to be bound to either of them, but we want to display "Backspace" only once,
// hance this 'print_backspace' switch.
if (!print_backspace || *print_backspace)
{
else if (key == Key(NC::Key::Backspace, Key::Standard))
result += "Backspace";
if (print_backspace)
*print_backspace = false;
}
}
else
result += ToString(std::wstring(1, key.getChar()));
return result;
@@ -96,7 +86,6 @@ std::string key_to_string(const Key &key, bool *print_backspace)
std::string display_keys(const Actions::Type at)
{
bool print_backspace = true;
std::string result, skey;
for (auto it = Bindings.begin(); it != Bindings.end(); ++it)
{
@@ -104,7 +93,7 @@ std::string display_keys(const Actions::Type at)
{
if (j->isSingle() && j->action()->type() == at)
{
skey = key_to_string(it->first, &print_backspace);
skey = key_to_string(it->first);
if (!skey.empty())
{
result += std::move(skey);

View File

@@ -189,7 +189,7 @@ void Menu<ItemT>::refresh()
if (m_drawn_position >= m_items.size())
{
for (; line < m_height; ++line)
mvwhline(m_window, line, 0, KEY_SPACE, m_width);
mvwhline(m_window, line, 0, NC::Key::Space, m_width);
break;
}
if (m_items[m_drawn_position].isSeparator())
@@ -204,7 +204,7 @@ void Menu<ItemT>::refresh()
*this << Format::Reverse;
*this << m_highlight_color;
}
mvwhline(m_window, line, 0, KEY_SPACE, m_width);
mvwhline(m_window, line, 0, NC::Key::Space, m_width);
if (m_items[m_drawn_position].isSelected())
*this << m_selected_prefix;
if (m_item_displayer)

View File

@@ -319,11 +319,11 @@ void enable()
if (mouseEnabled)
return;
// save old highlight mouse tracking
printf("\e[?1001s");
std::printf("\e[?1001s");
// enable mouse tracking
printf("\e[?1000h");
std::printf("\e[?1000h");
// try to enable extended (urxvt) mouse tracking
printf("\e[?1015h");
std::printf("\e[?1015h");
mouseEnabled = true;
}
@@ -332,11 +332,11 @@ void disable()
if (!mouseEnabled)
return;
// disable extended (urxvt) mouse tracking
printf("\e[?1015l");
std::printf("\e[?1015l");
// disable mouse tracking
printf("\e[?1000l");
std::printf("\e[?1000l");
// restore old highlight mouse tracking
printf("\e[?1001r");
std::printf("\e[?1001r");
mouseEnabled = false;
}
@@ -380,8 +380,8 @@ void initScreen(bool enable_colors, bool enable_mouse)
return 0;
};
// if ctrl-c or ctrl-g is pressed, abort the prompt
rl_bind_key(KEY_CTRL_C, abort_prompt);
rl_bind_key(KEY_CTRL_G, abort_prompt);
rl_bind_key('\3', abort_prompt);
rl_bind_key('\7', abort_prompt);
// do not change the state of the terminal
rl_prep_term_function = nullptr;
rl_deprep_term_function = nullptr;
@@ -726,7 +726,7 @@ bool Window::FDCallbacksListEmpty() const
int Window::getInputChar()
{
int key = wgetch(m_window);
if (!m_escape_terminal_sequences || key != KEY_ESCAPE)
if (!m_escape_terminal_sequences || key != Key::Escape)
return key;
auto define_mouse_event = [this](int type) {
switch (type & ~28)
@@ -747,7 +747,7 @@ int Window::getInputChar()
m_mouse_event.bstate = BUTTON5_PRESSED;
break;
default:
return ERR;
return Key::None;
}
if (type & 4)
m_mouse_event.bstate |= BUTTON_SHIFT;
@@ -756,10 +756,10 @@ int Window::getInputChar()
if (type & 16)
m_mouse_event.bstate |= BUTTON_CTRL;
if (m_mouse_event.x < 0 || m_mouse_event.x >= COLS)
return ERR;
return Key::None;
if (m_mouse_event.y < 0 || m_mouse_event.y >= LINES)
return ERR;
return KEY_MOUSE;
return Key::None;
return Key::Mouse;
};
auto parse_number = [this](int &result) {
int x;
@@ -776,25 +776,25 @@ int Window::getInputChar()
switch (key)
{
case '\t': // tty
return KEY_SHIFT_TAB;
return Key::Shift | Key::Tab;
case 'O': // F1 to F4 in xterm
key = wgetch(m_window);
switch (key)
{
case 'P':
key = KEY_F1;
key = Key::F1;
break;
case 'Q':
key = KEY_F2;
key = Key::F2;
break;
case 'R':
key = KEY_F3;
key = Key::F3;
break;
case 'S':
key = KEY_F4;
key = Key::F4;
break;
default:
key = ERR;
key = Key::None;
break;
}
return key;
@@ -803,17 +803,17 @@ int Window::getInputChar()
switch (key)
{
case 'A':
return KEY_UP;
return Key::Up;
case 'B':
return KEY_DOWN;
return Key::Down;
case 'C':
return KEY_RIGHT;
return Key::Right;
case 'D':
return KEY_LEFT;
return Key::Left;
case 'F': // xterm
return KEY_END;
return Key::End;
case 'H': // xterm
return KEY_HOME;
return Key::Home;
case 'M':
{
key = wgetch(m_window);
@@ -825,28 +825,28 @@ int Window::getInputChar()
return define_mouse_event(key);
}
case 'Z':
return KEY_SHIFT_TAB;
return Key::Shift | Key::Tab;
case '[': // F1 to F5 in tty
key = wgetch(m_window);
switch (key)
{
case 'A':
key = KEY_F1;
key = Key::F1;
break;
case 'B':
key = KEY_F2;
key = Key::F2;
break;
case 'C':
key = KEY_F3;
key = Key::F3;
break;
case 'D':
key = KEY_F4;
key = Key::F4;
break;
case 'E':
key = KEY_F5;
key = Key::F5;
break;
default:
key = ERR;
key = Key::None;
break;
}
return key;
@@ -862,73 +862,77 @@ int Window::getInputChar()
switch (key)
{
case 1: // tty
return KEY_HOME;
return Key::Home;
case 11:
return KEY_F1;
return Key::F1;
case 12:
return KEY_F2;
return Key::F2;
case 13:
return KEY_F3;
return Key::F3;
case 14:
return KEY_F4;
return Key::F4;
case 15:
return KEY_F5;
return Key::F5;
case 17: // not a typo
return KEY_F6;
return Key::F6;
case 18:
return KEY_F7;
return Key::F7;
case 19:
return KEY_F8;
return Key::F8;
case 2:
return KEY_IC;
return Key::Insert;
case 20:
return KEY_F9;
return Key::F9;
case 21:
return KEY_F10;
return Key::F10;
case 23: // not a typo
return KEY_F11;
return Key::F11;
case 24:
return KEY_F12;
return Key::F12;
case 3:
return KEY_DC;
return Key::Delete;
case 4:
return KEY_END;
return Key::End;
case 5:
return KEY_PPAGE;
return Key::PageUp;
case 6:
return KEY_NPAGE;
return Key::PageDown;
case 7:
return KEY_HOME;
return Key::Home;
case 8:
return KEY_END;
return Key::End;
default:
return ERR;
return Key::None;
}
case ';': // urxvt mouse
m_mouse_event.x = 0;
delim = parse_number(m_mouse_event.x);
if (delim != ';')
return ERR;
return Key::None;
m_mouse_event.y = 0;
delim = parse_number(m_mouse_event.y);
if (delim != 'M')
return ERR;
return Key::None;
--m_mouse_event.x;
--m_mouse_event.y;
return define_mouse_event(key);
default:
return ERR;
return Key::None;
}
}
default:
return ERR;
return Key::None;
}
break;
case ERR:
return KEY_ESCAPE;
return Key::Escape;
default:
m_input_queue.push(key);
return KEY_ESCAPE;
// this should always succeed as we just got it
assert(ungetch(key) == OK);
key = getInputChar();
if (key != Key::None)
m_input_queue.push(key);
return Key::Alt;
}
}
@@ -959,14 +963,14 @@ int Window::readKey()
if (select(fd_max+1, &fdset, 0, 0, m_window_timeout < 0 ? 0 : &timeout) > 0)
{
result = FD_ISSET(STDIN_FILENO, &fdset) ? getInputChar() : ERR;
result = FD_ISSET(STDIN_FILENO, &fdset) ? getInputChar() : Key::None;
for (FDCallbacks::const_iterator it = m_fds.begin(); it != m_fds.end(); ++it)
if (FD_ISSET(it->first, &fdset))
it->second();
}
else
result = ERR;
result = Key::None;
return result;
}

View File

@@ -35,66 +35,6 @@
#include <tuple>
#include <queue>
// define some Ctrl-? keys
const int KEY_CTRL_A = 1;
const int KEY_CTRL_B = 2;
const int KEY_CTRL_C = 3;
const int KEY_CTRL_D = 4;
const int KEY_CTRL_E = 5;
const int KEY_CTRL_F = 6;
const int KEY_CTRL_G = 7;
const int KEY_CTRL_H = 8;
const int KEY_CTRL_I = 9;
const int KEY_CTRL_J = 10;
const int KEY_CTRL_K = 11;
const int KEY_CTRL_L = 12;
const int KEY_CTRL_M = 13;
const int KEY_CTRL_N = 14;
const int KEY_CTRL_O = 15;
const int KEY_CTRL_P = 16;
const int KEY_CTRL_Q = 17;
const int KEY_CTRL_R = 18;
const int KEY_CTRL_S = 19;
const int KEY_CTRL_T = 20;
const int KEY_CTRL_U = 21;
const int KEY_CTRL_V = 22;
const int KEY_CTRL_W = 23;
const int KEY_CTRL_X = 24;
const int KEY_CTRL_Y = 25;
const int KEY_CTRL_Z = 26;
inline int KEY_ALT(int key)
{
return key << 8;
}
// define F? keys
const int KEY_F1 = 265;
const int KEY_F2 = 266;
const int KEY_F3 = 267;
const int KEY_F4 = 268;
const int KEY_F5 = 269;
const int KEY_F6 = 270;
const int KEY_F7 = 271;
const int KEY_F8 = 272;
const int KEY_F9 = 273;
const int KEY_F10 = 274;
const int KEY_F11 = 275;
const int KEY_F12 = 276;
// other handy keys
const int KEY_ESCAPE = 27;
const int KEY_SHIFT_TAB = 353;
const int KEY_SPACE = 32;
const int KEY_TAB = 9;
// define alternative KEY_BACKSPACE (used in some terminal emulators)
const int KEY_BACKSPACE_2 = 127;
// KEY_ENTER is 343, which doesn't make any sense. This makes it useful.
#undef KEY_ENTER
const int KEY_ENTER = 13;
#if NCURSES_MOUSE_VERSION == 1
# define BUTTON5_PRESSED (1U << 27)
#endif // NCURSES_MOUSE_VERSION == 1
@@ -107,6 +47,87 @@ const int KEY_ENTER = 13;
/// wrappers over original curses library.
namespace NC {
namespace Key {
typedef const int Type;
Type None = -1;
// modifier masks
Type Alt = 1 << 16;
Type Ctrl = 1 << 17;
Type Shift = 1 << 18;
Type Ctrl_A = 1;
Type Ctrl_B = 2;
Type Ctrl_C = 3;
Type Ctrl_D = 4;
Type Ctrl_E = 5;
Type Ctrl_F = 6;
Type Ctrl_G = 7;
Type Ctrl_H = 8;
Type Ctrl_I = 9;
Type Ctrl_J = 10;
Type Ctrl_K = 11;
Type Ctrl_L = 12;
Type Ctrl_M = 13;
Type Ctrl_N = 14;
Type Ctrl_O = 15;
Type Ctrl_P = 16;
Type Ctrl_Q = 17;
Type Ctrl_R = 18;
Type Ctrl_S = 19;
Type Ctrl_T = 20;
Type Ctrl_U = 21;
Type Ctrl_V = 22;
Type Ctrl_W = 23;
Type Ctrl_X = 24;
Type Ctrl_Y = 25;
Type Ctrl_Z = 26;
Type Ctrl_LeftBracket = 27;
Type Ctrl_Backslash = 28;
Type Ctrl_RightBracket = 29;
Type Ctrl_Caret = 30;
Type Ctrl_Underscore = 31;
Type Space = 32;
Type Backspace = 127;
// useful duplicates
Type Tab = 9;
Type Enter = 13;
Type Escape = 27;
// special values, beyond one byte
Type Insert = 256;
Type Delete = 257;
Type Home = 258;
Type End = 259;
Type PageUp = 260;
Type PageDown = 261;
Type Up = 262;
Type Down = 263;
Type Left = 264;
Type Right = 265;
Type F1 = 266;
Type F2 = 267;
Type F3 = 268;
Type F4 = 269;
Type F5 = 270;
Type F6 = 271;
Type F7 = 272;
Type F8 = 273;
Type F9 = 274;
Type F10 = 275;
Type F11 = 276;
Type F12 = 277;
Type Mouse = 278;
}
/// Thrown if Ctrl-C or Ctrl-G is pressed during the call to Window::getString()
/// @see Window::getString()
struct PromptAborted : std::exception