diff --git a/config.c b/config.c index 4c5da469..dd39862d 100644 --- a/config.c +++ b/config.c @@ -2016,6 +2016,12 @@ void setup_config_box(struct controlbox *b, bool midsession, I(CONF_funky_type), "ESC[n~", I(0), "Linux", I(1), "Xterm R6", I(2), "VT400", I(3), "VT100+", I(4), "SCO", I(5), NULL); + ctrl_radiobuttons(s, "Shift/Ctrl/Alt with the arrow keys", 'w', 2, + HELPCTX(keyboard_sharrow), + conf_radiobutton_handler, + I(CONF_sharrow_type), + "Ctrl toggles app mode", I(SHARROW_APPLICATION), + "xterm-style bitmap", I(SHARROW_BITMAP), NULL); s = ctrl_getset(b, "Terminal/Keyboard", "appkeypad", "Application keypad settings:"); diff --git a/doc/config.but b/doc/config.but index 904a04a9..a6a14ce9 100644 --- a/doc/config.but +++ b/doc/config.but @@ -599,6 +599,24 @@ to \c{ESC [v}, and with shift and control together they generate If you don't know what any of this means, you probably don't need to fiddle with it. +\S{config-sharrow} Changing the action of the \i{shifted arrow keys} + +This option affects the arrow keys, if you press one with any of the +modifier keys Shift, Ctrl or Alt held down. + +\b In the default mode, labelled \c{Ctrl toggles app mode}, the Ctrl +key toggles between the default arrow-key sequnces like \c{ESC [A} and +\c{ESC [B}, and the sequences Digital's terminals generate in +\q{application cursor keys} mode, i.e. \c{ESC O A} and so on. Shift +and Alt have no effect. + +\b In the \q{xterm-style bitmap} mode, Shift, Ctrl and Alt all +generate different sequences, with a number indicating which set of +modifiers is active. + +If you don't know what any of this means, you probably don't need to +fiddle with it. + \S{config-appcursor} Controlling \i{Application Cursor Keys} mode Application Cursor Keys mode is a way for the server to change the diff --git a/doc/index.but b/doc/index.but index 0629f81b..1e04acc1 100644 --- a/doc/index.but +++ b/doc/index.but @@ -931,3 +931,6 @@ saved sessions from \IM{system tray} system tray, Windows \IM{system tray} notification area, Windows (aka system tray) \IM{system tray} taskbar notification area, Windows (aka system tray) + +\IM{shifted arrow keys} arrow keys, shifted +\IM{shifted arrow keys} shifted arrow keys diff --git a/putty.h b/putty.h index 550b7ee5..77301bf8 100644 --- a/putty.h +++ b/putty.h @@ -533,6 +533,12 @@ enum { FUNKY_SCO }; +enum { + /* Shifted arrow key types (CONF_sharrow_type) */ + SHARROW_APPLICATION, /* Ctrl flips between ESC O A and ESC [ A */ + SHARROW_BITMAP /* ESC [ 1 ; n A, where n = 1 + bitmap of CAS */ +}; + enum { FQ_DEFAULT, FQ_ANTIALIASED, FQ_NONANTIALIASED, FQ_CLEARTYPE }; @@ -1606,6 +1612,7 @@ NORETURN void cleanup_exit(int); X(BOOL, NONE, bksp_is_delete) \ X(BOOL, NONE, rxvt_homeend) \ X(INT, NONE, funky_type) /* FUNKY_XTERM, FUNKY_LINUX, ... */ \ + X(INT, NONE, sharrow_type) /* SHARROW_APPLICATION, SHARROW_BITMAP, ... */ \ X(BOOL, NONE, no_applic_c) /* totally disable app cursor keys */ \ X(BOOL, NONE, no_applic_k) /* totally disable app keypad */ \ X(BOOL, NONE, no_mouse_rep) /* totally disable mouse reporting */ \ @@ -1937,7 +1944,8 @@ void term_palette_override(Terminal *term, unsigned osc4_index, rgb rgb); typedef enum SmallKeypadKey { SKK_HOME, SKK_END, SKK_INSERT, SKK_DELETE, SKK_PGUP, SKK_PGDN, } SmallKeypadKey; -int format_arrow_key(char *buf, Terminal *term, int xkey, bool ctrl); +int format_arrow_key(char *buf, Terminal *term, int xkey, + bool shift, bool ctrl, bool alt); int format_function_key(char *buf, Terminal *term, int key_number, bool shift, bool ctrl); int format_small_keypad_key(char *buf, Terminal *term, SmallKeypadKey key); diff --git a/settings.c b/settings.c index c0f181c5..ae0aebe0 100644 --- a/settings.c +++ b/settings.c @@ -630,6 +630,7 @@ void save_open_settings(settings_w *sesskey, Conf *conf) write_setting_b(sesskey, "BackspaceIsDelete", conf_get_bool(conf, CONF_bksp_is_delete)); write_setting_b(sesskey, "RXVTHomeEnd", conf_get_bool(conf, CONF_rxvt_homeend)); write_setting_i(sesskey, "LinuxFunctionKeys", conf_get_int(conf, CONF_funky_type)); + write_setting_i(sesskey, "ShiftedArrowKeys", conf_get_int(conf, CONF_sharrow_type)); write_setting_b(sesskey, "NoApplicationKeys", conf_get_bool(conf, CONF_no_applic_k)); write_setting_b(sesskey, "NoApplicationCursors", conf_get_bool(conf, CONF_no_applic_c)); write_setting_b(sesskey, "NoMouseReporting", conf_get_bool(conf, CONF_no_mouse_rep)); @@ -1046,6 +1047,8 @@ void load_open_settings(settings_r *sesskey, Conf *conf) gppb(sesskey, "BackspaceIsDelete", true, conf, CONF_bksp_is_delete); gppb(sesskey, "RXVTHomeEnd", false, conf, CONF_rxvt_homeend); gppi(sesskey, "LinuxFunctionKeys", 0, conf, CONF_funky_type); + gppi(sesskey, "ShiftedArrowKeys", SHARROW_APPLICATION, conf, + CONF_sharrow_type); gppb(sesskey, "NoApplicationKeys", false, conf, CONF_no_applic_k); gppb(sesskey, "NoApplicationCursors", false, conf, CONF_no_applic_c); gppb(sesskey, "NoMouseReporting", false, conf, CONF_no_mouse_rep); diff --git a/terminal/terminal.c b/terminal/terminal.c index e44f9f69..da255550 100644 --- a/terminal/terminal.c +++ b/terminal/terminal.c @@ -1555,6 +1555,7 @@ void term_copy_stuff_from_conf(Terminal *term) term->crhaslf = conf_get_bool(term->conf, CONF_crhaslf); term->erase_to_scrollback = conf_get_bool(term->conf, CONF_erase_to_scrollback); term->funky_type = conf_get_int(term->conf, CONF_funky_type); + term->sharrow_type = conf_get_int(term->conf, CONF_sharrow_type); term->lfhascr = conf_get_bool(term->conf, CONF_lfhascr); term->logflush = conf_get_bool(term->conf, CONF_logflush); term->logtype = conf_get_int(term->conf, CONF_logtype); @@ -7240,7 +7241,16 @@ void term_mouse(Terminal *term, Mouse_Button braw, Mouse_Button bcooked, term_schedule_update(term); } -int format_arrow_key(char *buf, Terminal *term, int xkey, bool ctrl) +static int shift_bitmap(bool shift, bool ctrl, bool alt) +{ + int bitmap = (shift ? 1 : 0) + (alt ? 2 : 0) + (ctrl ? 4 : 0); + if (bitmap) + bitmap++; + return bitmap; +} + +int format_arrow_key(char *buf, Terminal *term, int xkey, + bool shift, bool ctrl, bool alt) { char *p = buf; @@ -7263,12 +7273,24 @@ int format_arrow_key(char *buf, Terminal *term, int xkey, bool ctrl) if (!term->app_keypad_keys) app_flg = 0; #endif - /* Useful mapping of Ctrl-arrows */ - if (ctrl) - app_flg = !app_flg; + + int bitmap = 0; + + /* Adjustment based on Shift, Ctrl and/or Alt */ + switch (term->sharrow_type) { + case SHARROW_APPLICATION: + if (ctrl) + app_flg = !app_flg; + break; + case SHARROW_BITMAP: + bitmap = shift_bitmap(shift, ctrl, alt); + break; + } if (app_flg) p += sprintf(p, "\x1BO%c", xkey); + else if (bitmap) + p += sprintf(p, "\x1B[1;%d%c", bitmap, xkey); else p += sprintf(p, "\x1B[%c", xkey); } diff --git a/terminal/terminal.h b/terminal/terminal.h index 3af752e7..2eaaffcc 100644 --- a/terminal/terminal.h +++ b/terminal/terminal.h @@ -317,7 +317,7 @@ struct terminal_tag { int conf_width; bool crhaslf; bool erase_to_scrollback; - int funky_type; + int funky_type, sharrow_type; bool lfhascr; bool logflush; int logtype; diff --git a/unix/window.c b/unix/window.c index beaa2776..9f5948f4 100644 --- a/unix/window.c +++ b/unix/window.c @@ -1876,7 +1876,9 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) xkey = 'G'; goto arrow_key; arrow_key: end = 1 + format_arrow_key(output+1, inst->term, xkey, - event->state & GDK_CONTROL_MASK); + event->state & GDK_SHIFT_MASK, + event->state & GDK_CONTROL_MASK, + event->state & GDK_META_MASK); #ifdef KEY_EVENT_DIAGNOSTICS debug(" - arrow key"); #endif diff --git a/windows/help.h b/windows/help.h index c240f133..0ab0e050 100644 --- a/windows/help.h +++ b/windows/help.h @@ -26,6 +26,7 @@ #define WINHELP_CTX_keyboard_backspace "config-backspace" #define WINHELP_CTX_keyboard_homeend "config-homeend" #define WINHELP_CTX_keyboard_funkeys "config-funkeys" +#define WINHELP_CTX_keyboard_sharrow "config-sharrow" #define WINHELP_CTX_keyboard_appkeypad "config-appkeypad" #define WINHELP_CTX_keyboard_appcursor "config-appcursor" #define WINHELP_CTX_keyboard_nethack "config-nethack" diff --git a/windows/pterm.c b/windows/pterm.c index 57463449..2cdef30c 100644 --- a/windows/pterm.c +++ b/windows/pterm.c @@ -32,6 +32,8 @@ void gui_term_process_cmdline(Conf *conf, char *cmdline) cmdline_error("unexpected non-option argument \"%s\"", arg); } } + + conf_set_int(conf, CONF_sharrow_type, SHARROW_BITMAP); } const struct BackendVtable *backend_vt_from_conf(Conf *conf) diff --git a/windows/window.c b/windows/window.c index aba1c000..3b00ad96 100644 --- a/windows/window.c +++ b/windows/window.c @@ -4536,7 +4536,8 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, case VK_LEFT: xkey = 'D'; goto arrow_key; case VK_CLEAR: xkey = 'G'; goto arrow_key; /* close enough */ arrow_key: - p += format_arrow_key((char *)p, term, xkey, shift_state & 2); + p += format_arrow_key((char *)p, term, xkey, shift_state & 1, + shift_state & 2, left_alt); return p - output; case VK_RETURN: