window: support extended urxvt mouse support if applicable

This commit is contained in:
Andrzej Rybczak
2015-05-08 18:49:40 +02:00
parent 9272a0034c
commit 173d23dde6
4 changed files with 254 additions and 181 deletions

View File

@@ -1958,7 +1958,10 @@ void ToggleAddMode::run()
void ToggleMouse::run() void ToggleMouse::run()
{ {
Config.mouse_support = !Config.mouse_support; 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%", Statusbar::printf("Mouse support %1%",
Config.mouse_support ? "enabled" : "disabled" Config.mouse_support ? "enabled" : "disabled"
); );

View File

@@ -109,7 +109,7 @@ int main(int argc, char **argv)
sigignore(SIGINT); sigignore(SIGINT);
# endif // !WIN32 # endif // !WIN32
NC::initScreen(Config.colors_enabled); NC::initScreen(Config.colors_enabled, Config.mouse_support);
Actions::OriginalStatusbarVisibility = Config.statusbar_visibility; 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 connect_attempt = boost::posix_time::from_time_t(0);
auto past = 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) while (!Actions::ExitMainLoop)
{ {
try try

View File

@@ -306,7 +306,51 @@ std::istream &operator>>(std::istream &is, Color &c)
return is; 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(); initscr();
if (has_colors() && enable_colors) if (has_colors() && enable_colors)
@@ -325,6 +369,13 @@ void initScreen(bool enable_colors)
noecho(); noecho();
curs_set(0); 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 // initialize readline (needed, otherwise we get segmentation
// fault on SIGWINCH). also, initialize first as doing this // fault on SIGWINCH). also, initialize first as doing this
// later erases keys bound with rl_bind_key for some users. // later erases keys bound with rl_bind_key for some users.
@@ -355,6 +406,7 @@ void initScreen(bool enable_colors)
void destroyScreen() void destroyScreen()
{ {
Mouse::disable();
curs_set(1); curs_set(1);
endwin(); endwin();
} }
@@ -693,190 +745,210 @@ int Window::getInputChar()
# if NCURSES_SEQUENCE_ESCAPING # if NCURSES_SEQUENCE_ESCAPING
return wgetch(m_window); return wgetch(m_window);
# else # else
ScopedWindowTimeout swt(m_window, 0, m_window_timeout);
int key = wgetch(m_window); int key = wgetch(m_window);
if (!m_escape_terminal_sequences || key != KEY_ESCAPE) if (!m_escape_terminal_sequences || key != KEY_ESCAPE)
return key; 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); key = wgetch(m_window);
switch (key) 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; return KEY_SHIFT_TAB;
case 'O': // F1 to F4 in xterm case '[': // F1 to F5 in tty
key = wgetch(m_window); key = wgetch(m_window);
switch (key) switch (key)
{ {
case 'P': case 'A':
key = KEY_F1; key = KEY_F1;
break; break;
case 'Q': case 'B':
key = KEY_F2; key = KEY_F2;
break; break;
case 'R': case 'C':
key = KEY_F3; key = KEY_F3;
break; break;
case 'S': case 'D':
key = KEY_F4; key = KEY_F4;
break; break;
default: case 'E':
key = ERR; key = KEY_F5;
break; break;
default:
key = ERR;
break;
} }
return key; return key;
case '[': case '1': case '2': case '3':
key = wgetch(m_window); case '4': case '5': case '6':
switch (key) case '7': case '8': case '9':
{
key -= '0';
int delim = parse_number(key);
switch (delim)
{ {
case 'A': case '~':
return KEY_UP; switch (key)
case 'B': {
return KEY_DOWN; case 1: // tty
case 'C':
return KEY_RIGHT;
case 'D':
return KEY_LEFT;
case 'F': // xterm
return KEY_END;
case 'H': // xterm
return KEY_HOME; return KEY_HOME;
case 'M': case 11:
key = wgetch(m_window); return KEY_F1;
m_mouse_event.x = (wgetch(m_window) - 33) & 0xff; case 12:
m_mouse_event.y = (wgetch(m_window) - 33) & 0xff; return KEY_F2;
switch (key & ~24) case 13:
{ return KEY_F3;
case ' ': case 14:
m_mouse_event.bstate = BUTTON1_PRESSED; return KEY_F4;
break; case 15:
case '!': return KEY_F5;
m_mouse_event.bstate = BUTTON2_PRESSED; case 17: // not a typo
break; return KEY_F6;
case '"': case 18:
m_mouse_event.bstate = BUTTON3_PRESSED; return KEY_F7;
break; case 19:
case '`': return KEY_F8;
m_mouse_event.bstate = BUTTON4_PRESSED; case 2:
break; return KEY_IC;
case 'a': case 20:
m_mouse_event.bstate = BUTTON5_PRESSED; return KEY_F9;
break; case 21:
default: return KEY_F10;
return ERR; case 23: // not a typo
} return KEY_F11;
if (key & 8) case 24:
m_mouse_event.bstate |= BUTTON_ALT; return KEY_F12;
if (key & 16) case 3:
m_mouse_event.bstate |= BUTTON_CTRL; return KEY_DC;
if (m_mouse_event.x < 0 || m_mouse_event.x >= COLS) case 4:
return ERR; return KEY_END;
if (m_mouse_event.y < 0 || m_mouse_event.y >= LINES) case 5:
return ERR; return KEY_PPAGE;
return KEY_MOUSE; case 6:
case 'Z': return KEY_NPAGE;
return KEY_SHIFT_TAB; case 7:
case '[': // F1 to F5 in tty return KEY_HOME;
key = wgetch(m_window); case 8:
switch (key) return KEY_END;
{
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;
default: default:
return ERR; 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: default:
m_input_queue.push(key); return ERR;
return KEY_ESCAPE; }
break;
case ERR:
return KEY_ESCAPE;
default:
m_input_queue.push(key);
return KEY_ESCAPE;
} }
# endif // NCURSES_SEQUENCE_ESCAPING # 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::encrypted = encrypted;
rl::base = base.c_str(); rl::base = base.c_str();
mmask_t oldmask;
curs_set(1); curs_set(1);
# if NCURSES_SEQUENCE_ESCAPING # if NCURSES_SEQUENCE_ESCAPING
keypad(m_window, 0); keypad(m_window, 0);
# endif // NCURSES_SEQUENCE_ESCAPING # endif // NCURSES_SEQUENCE_ESCAPING
mousemask(0, &oldmask); Mouse::disable();
m_escape_terminal_sequences = false; m_escape_terminal_sequences = false;
char *input = readline(nullptr); char *input = readline(nullptr);
m_escape_terminal_sequences = true; m_escape_terminal_sequences = true;
mousemask(oldmask, nullptr); Mouse::enable();
# if NCURSES_SEQUENCE_ESCAPING # if NCURSES_SEQUENCE_ESCAPING
keypad(m_window, 1); keypad(m_window, 1);
# endif // NCURSES_SEQUENCE_ESCAPING # endif // NCURSES_SEQUENCE_ESCAPING

View File

@@ -215,9 +215,16 @@ enum class Format {
/// This indicates how much the window has to be scrolled /// This indicates how much the window has to be scrolled
enum class Scroll { Up, Down, PageUp, PageDown, Home, End }; enum class Scroll { Up, Down, PageUp, PageDown, Home, End };
namespace Mouse {
void enable();
void disable();
}
/// Initializes curses screen and sets some additional attributes /// Initializes curses screen and sets some additional attributes
/// @param enable_colors enables colors /// @param enable_colors enables colors
void initScreen(bool enable_colors); void initScreen(bool enable_colors, bool enable_mouse);
/// Destroys the screen /// Destroys the screen
void destroyScreen(); void destroyScreen();