From e7b152938b94465900cb2597d204c76fbb502c24 Mon Sep 17 00:00:00 2001 From: Andrzej Rybczak Date: Tue, 12 May 2015 20:40:26 +0200 Subject: [PATCH] window: redefine special key values --- doc/bindings | 17 +----- src/bindings.cpp | 58 ++++++++++--------- src/display.cpp | 8 +-- src/help.cpp | 51 +++++++---------- src/menu_impl.h | 4 +- src/window.cpp | 128 +++++++++++++++++++++--------------------- src/window.h | 141 +++++++++++++++++++++++++++-------------------- 7 files changed, 208 insertions(+), 199 deletions(-) diff --git a/doc/bindings b/doc/bindings index 3352afc3..c4df031b 100644 --- a/doc/bindings +++ b/doc/bindings @@ -51,8 +51,9 @@ ## picked by ncmpcpp upon next call to readKey function. ## Accepted values: mouse, up, down, page_up, page_down, ## home, end, space, enter, insert, delete, left, right, -## tab, shift_tab, ctrl_a, ctrl_b, ..., ctrl_z, f1, f2, -## ..., f12, backspace, backspace_2. +## tab, shift_tab, ctrl_a, ctrl_b, ..., ctrl_z, ctrl_[, +## ctrl_\\, ctrl_], ctrl_^, ctrl__, f1, f2, ..., f12, +## backspace. ## ## - push_characters "string" - pushes given string into ## input queue. @@ -111,12 +112,6 @@ ## could be used. Then ncmpcpp will not wait for confirmation ## (enter) and will execute the command the moment it sees it. ## -## Note: Both 'backspace' and 'backspace_2' are used because some -## terminals interpret backspace using keycode of 'backspace' -## and some the one of 'backspace_2'. You can get away with -## binding once if all your terminal emulators use the same -## value. -## ## Note: There is a difference between: ## ## def_key "key" @@ -294,12 +289,6 @@ #def_key "backspace" # replay_song # -#def_key "backspace_2" -# jump_to_parent_directory -# -#def_key "backspace_2" -# replay_song -# #def_key "f" # seek_forward # diff --git a/src/bindings.cpp b/src/bindings.cpp index 0f6a2b5e..507e5abc 100644 --- a/src/bindings.cpp +++ b/src/bindings.cpp @@ -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"))) diff --git a/src/display.cpp b/src/display.cpp index d3b62b0b..ca21c848 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -95,7 +95,7 @@ void setProperties(NC::Menu &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 &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) diff --git a/src/help.cpp b/src/help.cpp index 74a0833b..1c22a2b3 100644 --- a/src/help.cpp +++ b/src/help.cpp @@ -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(key.getChar()-264); + result += boost::lexical_cast(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); diff --git a/src/menu_impl.h b/src/menu_impl.h index 7b17b580..f3eefa6d 100644 --- a/src/menu_impl.h +++ b/src/menu_impl.h @@ -189,7 +189,7 @@ void Menu::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::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) diff --git a/src/window.cpp b/src/window.cpp index e88981e4..8f994f31 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -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; } diff --git a/src/window.h b/src/window.h index f207f338..4860dd62 100644 --- a/src/window.h +++ b/src/window.h @@ -35,66 +35,6 @@ #include #include -// 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