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,10 +745,53 @@ 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)
{ {
@@ -740,38 +835,15 @@ int Window::getInputChar()
case 'H': // xterm case 'H': // xterm
return KEY_HOME; return KEY_HOME;
case 'M': 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 ' ': key = wgetch(m_window);
m_mouse_event.bstate = BUTTON1_PRESSED; int raw_x = wgetch(m_window);
break; int raw_y = wgetch(m_window);
case '!': // support coordinates up to 255
m_mouse_event.bstate = BUTTON2_PRESSED; m_mouse_event.x = (raw_x - 33) & 0xff;
break; m_mouse_event.y = (raw_y - 33) & 0xff;
case '"': return define_mouse_event(key);
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': case 'Z':
return KEY_SHIFT_TAB; return KEY_SHIFT_TAB;
case '[': // F1 to F5 in tty case '[': // F1 to F5 in tty
@@ -798,76 +870,76 @@ int Window::getInputChar()
break; break;
} }
return key; return key;
case '1': // HOME in tty, F1 to F8 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 '~': case '~':
switch (key)
{
case 1: // tty
return KEY_HOME; return KEY_HOME;
case '1': case 11:
key = KEY_F1; return KEY_F1;
break; case 12:
case '2': return KEY_F2;
key = KEY_F2; case 13:
break; return KEY_F3;
case '3': case 14:
key = KEY_F3; return KEY_F4;
break; case 15:
case '4': return KEY_F5;
key = KEY_F4; case 17: // not a typo
break; return KEY_F6;
case '5': case 18:
key = KEY_F5; return KEY_F7;
break; case 19:
case '7': // not a typo return KEY_F8;
key = KEY_F6; case 2:
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; return KEY_IC;
case '0': case 20:
key = KEY_F9; return KEY_F9;
break; case 21:
case '1': return KEY_F10;
key = KEY_F10; case 23: // not a typo
break; return KEY_F11;
case '3': // not a typo case 24:
key = KEY_F11; return KEY_F12;
break; case 3:
case '4': return KEY_DC;
key = KEY_F12; case 4:
break; return KEY_END;
case 5:
return KEY_PPAGE;
case 6:
return KEY_NPAGE;
case 7:
return KEY_HOME;
case 8:
return KEY_END;
default: default:
key = ERR; return ERR;
break; }
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;
}
} }
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;
} }
@@ -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();