window: support extended urxvt mouse support if applicable
This commit is contained in:
@@ -1958,7 +1958,10 @@ void ToggleAddMode::run()
|
||||
void ToggleMouse::run()
|
||||
{
|
||||
Config.mouse_support = !Config.mouse_support;
|
||||
mousemask(Config.mouse_support ? ALL_MOUSE_EVENTS : 0, 0);
|
||||
if (Config.mouse_support)
|
||||
NC::Mouse::enable();
|
||||
else
|
||||
NC::Mouse::disable();
|
||||
Statusbar::printf("Mouse support %1%",
|
||||
Config.mouse_support ? "enabled" : "disabled"
|
||||
);
|
||||
|
||||
@@ -109,7 +109,7 @@ int main(int argc, char **argv)
|
||||
sigignore(SIGINT);
|
||||
# endif // !WIN32
|
||||
|
||||
NC::initScreen(Config.colors_enabled);
|
||||
NC::initScreen(Config.colors_enabled, Config.mouse_support);
|
||||
|
||||
Actions::OriginalStatusbarVisibility = Config.statusbar_visibility;
|
||||
|
||||
@@ -152,13 +152,6 @@ int main(int argc, char **argv)
|
||||
auto connect_attempt = boost::posix_time::from_time_t(0);
|
||||
auto past = boost::posix_time::from_time_t(0);
|
||||
|
||||
// enable mouse
|
||||
# if NCURSES_SEQUENCE_ESCAPING
|
||||
mouseinterval(0);
|
||||
# endif // NCURSES_SEQUENCE_ESCAPING
|
||||
if (Config.mouse_support)
|
||||
mousemask(ALL_MOUSE_EVENTS, nullptr);
|
||||
|
||||
while (!Actions::ExitMainLoop)
|
||||
{
|
||||
try
|
||||
|
||||
412
src/window.cpp
412
src/window.cpp
@@ -306,7 +306,51 @@ std::istream &operator>>(std::istream &is, Color &c)
|
||||
return is;
|
||||
}
|
||||
|
||||
void initScreen(bool enable_colors)
|
||||
namespace Mouse {
|
||||
|
||||
namespace {
|
||||
|
||||
bool mouseEnabled = false;
|
||||
|
||||
}
|
||||
|
||||
void enable()
|
||||
{
|
||||
if (mouseEnabled)
|
||||
return;
|
||||
# if NCURSES_SEQUENCE_ESCAPING
|
||||
mousemask(ALL_MOUSE_EVENTS, nullptr);
|
||||
# else
|
||||
// save old highlight mouse tracking
|
||||
printf("\e[?1001s");
|
||||
// enable mouse tracking
|
||||
printf("\e[?1000h");
|
||||
// try to enable extended (urxvt) mouse tracking
|
||||
printf("\e[?1015h");
|
||||
# endif // NCURSES_SEQUENCE_ESCAPING
|
||||
mouseEnabled = true;
|
||||
}
|
||||
|
||||
void disable()
|
||||
{
|
||||
if (!mouseEnabled)
|
||||
return;
|
||||
# if NCURSES_SEQUENCE_ESCAPING
|
||||
mousemask(0, nullptr);
|
||||
# else
|
||||
// disable extended (urxvt) mouse tracking
|
||||
printf("\e[?1015l");
|
||||
// disable mouse tracking
|
||||
printf("\e[?1000l");
|
||||
// restore old highlight mouse tracking
|
||||
printf("\e[?1001r");
|
||||
# endif // NCURSES_SEQUENCE_ESCAPING
|
||||
mouseEnabled = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void initScreen(bool enable_colors, bool enable_mouse)
|
||||
{
|
||||
initscr();
|
||||
if (has_colors() && enable_colors)
|
||||
@@ -325,6 +369,13 @@ void initScreen(bool enable_colors)
|
||||
noecho();
|
||||
curs_set(0);
|
||||
|
||||
// setup mouse
|
||||
# if NCURSES_SEQUENCE_ESCAPING
|
||||
mouseinterval(0);
|
||||
# endif // NCURSES_SEQUENCE_ESCAPING
|
||||
if (enable_mouse)
|
||||
Mouse::enable();
|
||||
|
||||
// initialize readline (needed, otherwise we get segmentation
|
||||
// fault on SIGWINCH). also, initialize first as doing this
|
||||
// later erases keys bound with rl_bind_key for some users.
|
||||
@@ -355,6 +406,7 @@ void initScreen(bool enable_colors)
|
||||
|
||||
void destroyScreen()
|
||||
{
|
||||
Mouse::disable();
|
||||
curs_set(1);
|
||||
endwin();
|
||||
}
|
||||
@@ -693,190 +745,210 @@ int Window::getInputChar()
|
||||
# if NCURSES_SEQUENCE_ESCAPING
|
||||
return wgetch(m_window);
|
||||
# else
|
||||
ScopedWindowTimeout swt(m_window, 0, m_window_timeout);
|
||||
int key = wgetch(m_window);
|
||||
if (!m_escape_terminal_sequences || key != KEY_ESCAPE)
|
||||
return key;
|
||||
auto define_mouse_event = [this](int type) {
|
||||
switch (type & ~28)
|
||||
{
|
||||
case 32:
|
||||
m_mouse_event.bstate = BUTTON1_PRESSED;
|
||||
break;
|
||||
case 33:
|
||||
m_mouse_event.bstate = BUTTON2_PRESSED;
|
||||
break;
|
||||
case 34:
|
||||
m_mouse_event.bstate = BUTTON3_PRESSED;
|
||||
break;
|
||||
case 96:
|
||||
m_mouse_event.bstate = BUTTON4_PRESSED;
|
||||
break;
|
||||
case 97:
|
||||
m_mouse_event.bstate = BUTTON5_PRESSED;
|
||||
break;
|
||||
default:
|
||||
return ERR;
|
||||
}
|
||||
if (type & 4)
|
||||
m_mouse_event.bstate |= BUTTON_SHIFT;
|
||||
if (type & 8)
|
||||
m_mouse_event.bstate |= BUTTON_ALT;
|
||||
if (type & 16)
|
||||
m_mouse_event.bstate |= BUTTON_CTRL;
|
||||
if (m_mouse_event.x < 0 || m_mouse_event.x >= COLS)
|
||||
return ERR;
|
||||
if (m_mouse_event.y < 0 || m_mouse_event.y >= LINES)
|
||||
return ERR;
|
||||
return KEY_MOUSE;
|
||||
};
|
||||
auto parse_number = [this](int &result) {
|
||||
int x;
|
||||
while (true)
|
||||
{
|
||||
x = wgetch(m_window);
|
||||
if (!isdigit(x))
|
||||
return x;
|
||||
result = result*10 + x - '0';
|
||||
}
|
||||
};
|
||||
ScopedWindowTimeout swt(m_window, 0, m_window_timeout);
|
||||
key = wgetch(m_window);
|
||||
switch (key)
|
||||
{
|
||||
case '\t': // tty
|
||||
case '\t': // tty
|
||||
return KEY_SHIFT_TAB;
|
||||
case 'O': // F1 to F4 in xterm
|
||||
key = wgetch(m_window);
|
||||
switch (key)
|
||||
{
|
||||
case 'P':
|
||||
key = KEY_F1;
|
||||
break;
|
||||
case 'Q':
|
||||
key = KEY_F2;
|
||||
break;
|
||||
case 'R':
|
||||
key = KEY_F3;
|
||||
break;
|
||||
case 'S':
|
||||
key = KEY_F4;
|
||||
break;
|
||||
default:
|
||||
key = ERR;
|
||||
break;
|
||||
}
|
||||
return key;
|
||||
case '[':
|
||||
key = wgetch(m_window);
|
||||
switch (key)
|
||||
{
|
||||
case 'A':
|
||||
return KEY_UP;
|
||||
case 'B':
|
||||
return KEY_DOWN;
|
||||
case 'C':
|
||||
return KEY_RIGHT;
|
||||
case 'D':
|
||||
return KEY_LEFT;
|
||||
case 'F': // xterm
|
||||
return KEY_END;
|
||||
case 'H': // xterm
|
||||
return KEY_HOME;
|
||||
case 'M':
|
||||
{
|
||||
key = wgetch(m_window);
|
||||
int raw_x = wgetch(m_window);
|
||||
int raw_y = wgetch(m_window);
|
||||
// support coordinates up to 255
|
||||
m_mouse_event.x = (raw_x - 33) & 0xff;
|
||||
m_mouse_event.y = (raw_y - 33) & 0xff;
|
||||
return define_mouse_event(key);
|
||||
}
|
||||
case 'Z':
|
||||
return KEY_SHIFT_TAB;
|
||||
case 'O': // F1 to F4 in xterm
|
||||
case '[': // F1 to F5 in tty
|
||||
key = wgetch(m_window);
|
||||
switch (key)
|
||||
{
|
||||
case 'P':
|
||||
key = KEY_F1;
|
||||
break;
|
||||
case 'Q':
|
||||
key = KEY_F2;
|
||||
break;
|
||||
case 'R':
|
||||
key = KEY_F3;
|
||||
break;
|
||||
case 'S':
|
||||
key = KEY_F4;
|
||||
break;
|
||||
default:
|
||||
key = ERR;
|
||||
break;
|
||||
case 'A':
|
||||
key = KEY_F1;
|
||||
break;
|
||||
case 'B':
|
||||
key = KEY_F2;
|
||||
break;
|
||||
case 'C':
|
||||
key = KEY_F3;
|
||||
break;
|
||||
case 'D':
|
||||
key = KEY_F4;
|
||||
break;
|
||||
case 'E':
|
||||
key = KEY_F5;
|
||||
break;
|
||||
default:
|
||||
key = ERR;
|
||||
break;
|
||||
}
|
||||
return key;
|
||||
case '[':
|
||||
key = wgetch(m_window);
|
||||
switch (key)
|
||||
case '1': case '2': case '3':
|
||||
case '4': case '5': case '6':
|
||||
case '7': case '8': case '9':
|
||||
{
|
||||
key -= '0';
|
||||
int delim = parse_number(key);
|
||||
switch (delim)
|
||||
{
|
||||
case 'A':
|
||||
return KEY_UP;
|
||||
case 'B':
|
||||
return KEY_DOWN;
|
||||
case 'C':
|
||||
return KEY_RIGHT;
|
||||
case 'D':
|
||||
return KEY_LEFT;
|
||||
case 'F': // xterm
|
||||
return KEY_END;
|
||||
case 'H': // xterm
|
||||
case '~':
|
||||
switch (key)
|
||||
{
|
||||
case 1: // tty
|
||||
return KEY_HOME;
|
||||
case 'M':
|
||||
key = wgetch(m_window);
|
||||
m_mouse_event.x = (wgetch(m_window) - 33) & 0xff;
|
||||
m_mouse_event.y = (wgetch(m_window) - 33) & 0xff;
|
||||
switch (key & ~24)
|
||||
{
|
||||
case ' ':
|
||||
m_mouse_event.bstate = BUTTON1_PRESSED;
|
||||
break;
|
||||
case '!':
|
||||
m_mouse_event.bstate = BUTTON2_PRESSED;
|
||||
break;
|
||||
case '"':
|
||||
m_mouse_event.bstate = BUTTON3_PRESSED;
|
||||
break;
|
||||
case '`':
|
||||
m_mouse_event.bstate = BUTTON4_PRESSED;
|
||||
break;
|
||||
case 'a':
|
||||
m_mouse_event.bstate = BUTTON5_PRESSED;
|
||||
break;
|
||||
default:
|
||||
return ERR;
|
||||
}
|
||||
if (key & 8)
|
||||
m_mouse_event.bstate |= BUTTON_ALT;
|
||||
if (key & 16)
|
||||
m_mouse_event.bstate |= BUTTON_CTRL;
|
||||
if (m_mouse_event.x < 0 || m_mouse_event.x >= COLS)
|
||||
return ERR;
|
||||
if (m_mouse_event.y < 0 || m_mouse_event.y >= LINES)
|
||||
return ERR;
|
||||
return KEY_MOUSE;
|
||||
case 'Z':
|
||||
return KEY_SHIFT_TAB;
|
||||
case '[': // F1 to F5 in tty
|
||||
key = wgetch(m_window);
|
||||
switch (key)
|
||||
{
|
||||
case 'A':
|
||||
key = KEY_F1;
|
||||
break;
|
||||
case 'B':
|
||||
key = KEY_F2;
|
||||
break;
|
||||
case 'C':
|
||||
key = KEY_F3;
|
||||
break;
|
||||
case 'D':
|
||||
key = KEY_F4;
|
||||
break;
|
||||
case 'E':
|
||||
key = KEY_F5;
|
||||
break;
|
||||
default:
|
||||
key = ERR;
|
||||
break;
|
||||
}
|
||||
return key;
|
||||
case '1': // HOME in tty, F1 to F8
|
||||
key = wgetch(m_window);
|
||||
switch (key)
|
||||
{
|
||||
case '~':
|
||||
return KEY_HOME;
|
||||
case '1':
|
||||
key = KEY_F1;
|
||||
break;
|
||||
case '2':
|
||||
key = KEY_F2;
|
||||
break;
|
||||
case '3':
|
||||
key = KEY_F3;
|
||||
break;
|
||||
case '4':
|
||||
key = KEY_F4;
|
||||
break;
|
||||
case '5':
|
||||
key = KEY_F5;
|
||||
break;
|
||||
case '7': // not a typo
|
||||
key = KEY_F6;
|
||||
break;
|
||||
case '8':
|
||||
key = KEY_F7;
|
||||
break;
|
||||
case '9':
|
||||
key = KEY_F8;
|
||||
break;
|
||||
default:
|
||||
key = ERR;
|
||||
break;
|
||||
}
|
||||
return wgetch(m_window) == '~' ? key : ERR;
|
||||
case '2': // INSERT, F9 to F12
|
||||
key = wgetch(m_window);
|
||||
switch (key)
|
||||
{
|
||||
case '~':
|
||||
return KEY_IC;
|
||||
case '0':
|
||||
key = KEY_F9;
|
||||
break;
|
||||
case '1':
|
||||
key = KEY_F10;
|
||||
break;
|
||||
case '3': // not a typo
|
||||
key = KEY_F11;
|
||||
break;
|
||||
case '4':
|
||||
key = KEY_F12;
|
||||
break;
|
||||
default:
|
||||
key = ERR;
|
||||
break;
|
||||
}
|
||||
return wgetch(m_window) == '~' ? key : ERR;
|
||||
case '3':
|
||||
return wgetch(m_window) == '~' ? KEY_DC : ERR;
|
||||
case '4': // tty
|
||||
return wgetch(m_window) == '~' ? KEY_END : ERR;
|
||||
case '5':
|
||||
return wgetch(m_window) == '~' ? KEY_PPAGE : ERR;
|
||||
case '6':
|
||||
return wgetch(m_window) == '~' ? KEY_NPAGE : ERR;
|
||||
case '7':
|
||||
return wgetch(m_window) == '~' ? KEY_HOME : ERR;
|
||||
case '8':
|
||||
return wgetch(m_window) == '~' ? KEY_END : ERR;
|
||||
case 11:
|
||||
return KEY_F1;
|
||||
case 12:
|
||||
return KEY_F2;
|
||||
case 13:
|
||||
return KEY_F3;
|
||||
case 14:
|
||||
return KEY_F4;
|
||||
case 15:
|
||||
return KEY_F5;
|
||||
case 17: // not a typo
|
||||
return KEY_F6;
|
||||
case 18:
|
||||
return KEY_F7;
|
||||
case 19:
|
||||
return KEY_F8;
|
||||
case 2:
|
||||
return KEY_IC;
|
||||
case 20:
|
||||
return KEY_F9;
|
||||
case 21:
|
||||
return KEY_F10;
|
||||
case 23: // not a typo
|
||||
return KEY_F11;
|
||||
case 24:
|
||||
return KEY_F12;
|
||||
case 3:
|
||||
return KEY_DC;
|
||||
case 4:
|
||||
return KEY_END;
|
||||
case 5:
|
||||
return KEY_PPAGE;
|
||||
case 6:
|
||||
return KEY_NPAGE;
|
||||
case 7:
|
||||
return KEY_HOME;
|
||||
case 8:
|
||||
return KEY_END;
|
||||
default:
|
||||
return ERR;
|
||||
}
|
||||
case ';': // urxvt mouse
|
||||
m_mouse_event.x = 0;
|
||||
delim = parse_number(m_mouse_event.x);
|
||||
if (delim != ';')
|
||||
return ERR;
|
||||
m_mouse_event.y = 0;
|
||||
delim = parse_number(m_mouse_event.y);
|
||||
if (delim != 'M')
|
||||
return ERR;
|
||||
--m_mouse_event.x;
|
||||
--m_mouse_event.y;
|
||||
return define_mouse_event(key);
|
||||
default:
|
||||
return ERR;
|
||||
}
|
||||
break;
|
||||
case ERR:
|
||||
return KEY_ESCAPE;
|
||||
}
|
||||
default:
|
||||
m_input_queue.push(key);
|
||||
return KEY_ESCAPE;
|
||||
return ERR;
|
||||
}
|
||||
break;
|
||||
case ERR:
|
||||
return KEY_ESCAPE;
|
||||
default:
|
||||
m_input_queue.push(key);
|
||||
return KEY_ESCAPE;
|
||||
}
|
||||
# endif // NCURSES_SEQUENCE_ESCAPING
|
||||
}
|
||||
@@ -935,17 +1007,15 @@ std::string Window::prompt(const std::string &base, size_t width, bool encrypted
|
||||
rl::encrypted = encrypted;
|
||||
rl::base = base.c_str();
|
||||
|
||||
mmask_t oldmask;
|
||||
|
||||
curs_set(1);
|
||||
# if NCURSES_SEQUENCE_ESCAPING
|
||||
keypad(m_window, 0);
|
||||
# endif // NCURSES_SEQUENCE_ESCAPING
|
||||
mousemask(0, &oldmask);
|
||||
Mouse::disable();
|
||||
m_escape_terminal_sequences = false;
|
||||
char *input = readline(nullptr);
|
||||
m_escape_terminal_sequences = true;
|
||||
mousemask(oldmask, nullptr);
|
||||
Mouse::enable();
|
||||
# if NCURSES_SEQUENCE_ESCAPING
|
||||
keypad(m_window, 1);
|
||||
# endif // NCURSES_SEQUENCE_ESCAPING
|
||||
|
||||
@@ -215,9 +215,16 @@ enum class Format {
|
||||
/// This indicates how much the window has to be scrolled
|
||||
enum class Scroll { Up, Down, PageUp, PageDown, Home, End };
|
||||
|
||||
namespace Mouse {
|
||||
|
||||
void enable();
|
||||
void disable();
|
||||
|
||||
}
|
||||
|
||||
/// Initializes curses screen and sets some additional attributes
|
||||
/// @param enable_colors enables colors
|
||||
void initScreen(bool enable_colors);
|
||||
void initScreen(bool enable_colors, bool enable_mouse);
|
||||
|
||||
/// Destroys the screen
|
||||
void destroyScreen();
|
||||
|
||||
Reference in New Issue
Block a user