From 0e7f0883a955545bb901d7506b362d0b5cdb149b Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 10 Dec 2017 17:16:50 +0000 Subject: [PATCH] Add GUI configuration for choice of clipboards. On all platforms, you can now configure which clipboard the mouse pastes from, which clipboard Ctrl-Ins and Shift-Ins access, and which Ctrl-Shift-C and Ctrl-Shift-V access. In each case, the options are: - nothing at all - a clipboard which is implicitly written by the act of mouse selection (the PRIMARY selection on X, CLIP_LOCAL everywhere else) - the standard clipboard written by explicit copy/paste UI actions (CLIPBOARD on X, the unique system clipboard elsewhere). Also, you can control whether selecting text with the mouse _also_ writes to the explicitly accessed clipboard. The wording of the various messages changes between platforms, but the basic UI shape is the same everywhere. --- config.c | 47 +++++++++++++++++ doc/config.but | 62 +++++++++++++++++++++++ putty.h | 14 +++++ settings.c | 49 ++++++++++++++++++ unix/gtkwin.c | 124 ++++++++++++++++++++++++++++++++++++++++++--- unix/unix.h | 26 ++++++++-- windows/window.c | 92 +++++++++++++++++++++++++++++---- windows/winhelp.h | 2 + windows/winstuff.h | 11 ++++ 9 files changed, 405 insertions(+), 22 deletions(-) diff --git a/config.c b/config.c index d949f423..df999849 100644 --- a/config.c +++ b/config.c @@ -1337,6 +1337,34 @@ static void manual_hostkey_handler(union control *ctrl, void *dlg, } } +static void clipboard_selector_handler(union control *ctrl, void *dlg, + void *data, int event) +{ + Conf *conf = (Conf *)data; + int setting = ctrl->generic.context.i; + + if (event == EVENT_REFRESH) { + int i, val = conf_get_int(conf, setting); + + dlg_update_start(ctrl, dlg); + dlg_listbox_clear(ctrl, dlg); + dlg_listbox_addwithid(ctrl, dlg, "No action", CLIPUI_NONE); + dlg_listbox_addwithid(ctrl, dlg, CLIPNAME_IMPLICIT, CLIPUI_IMPLICIT); + dlg_listbox_addwithid(ctrl, dlg, CLIPNAME_EXPLICIT, CLIPUI_EXPLICIT); + dlg_listbox_select(ctrl, dlg, 0); /* fallback */ + for (i = 0; i < 3; i++) + if (val == dlg_listbox_getid(ctrl, dlg, i)) + dlg_listbox_select(ctrl, dlg, i); + dlg_update_done(ctrl, dlg); + } else if (event == EVENT_SELCHANGE) { + int index = dlg_listbox_index(ctrl, dlg); + if (index >= 0) { + int val = dlg_listbox_getid(ctrl, dlg, index); + conf_set_int(conf, setting, val); + } + } +} + void setup_config_box(struct controlbox *b, int midsession, int protocol, int protcfginfo) { @@ -1860,6 +1888,25 @@ void setup_config_box(struct controlbox *b, int midsession, "Normal", 'n', I(0), "Rectangular block", 'r', I(1), NULL); + s = ctrl_getset(b, "Window/Selection", "clipboards", + "Assign copy/paste actions to clipboards"); + ctrl_checkbox(s, "Auto-copy selected text to " + CLIPNAME_EXPLICIT_OBJECT, + NO_SHORTCUT, HELPCTX(selection_autocopy), + conf_checkbox_handler, I(CONF_mouseautocopy)); + ctrl_droplist(s, "Mouse paste action:", NO_SHORTCUT, 60, + HELPCTX(selection_clipactions), + clipboard_selector_handler, + I(CONF_mousepaste)); + ctrl_droplist(s, "{Ctrl,Shift} + Ins:", NO_SHORTCUT, 60, + HELPCTX(selection_clipactions), + clipboard_selector_handler, + I(CONF_ctrlshiftins)); + ctrl_droplist(s, "Ctrl + Shift + {C,V}:", NO_SHORTCUT, 60, + HELPCTX(selection_clipactions), + clipboard_selector_handler, + I(CONF_ctrlshiftcv)); + /* * The Window/Selection/Words panel. */ diff --git a/doc/config.but b/doc/config.but index c4a7b9ef..3edce1b7 100644 --- a/doc/config.but +++ b/doc/config.but @@ -1469,6 +1469,68 @@ select a rectangular block. Using the \q{Default selection mode} control, you can set \i{rectangular selection} as the default, and then you have to hold down Alt to get the \e{normal} behaviour. +\S{config-clipboards} Assigning copy and paste actions to clipboards + +Here you can configure which clipboard(s) are written or read by +PuTTY's various copy and paste actions. + +The X Window System provides multiple clipboards (or \q{selections}), +and many applications support more than one of them by a different +user interface mechanism. + +The two most commonly used selections are called \cq{PRIMARY} and +\cq{CLIPBOARD}; in applications supporting both, the usual behaviour +is that \cw{PRIMARY} is used by mouse-only actions (selecting text +automatically copies it to \cw{PRIMARY}, and middle-clicking pastes +from \cw{PRIMARY}), whereas \cw{CLIPBOARD} is used by explicit Copy +and Paste menu items or keypresses such as Ctrl-C and Ctrl-V. + +On other platforms, where there is a single system clipboard, PuTTY +provides a second clipboard-like facility by permitting you to paste +the text you last selected in \e{this window}, whether or not it is +currently also in the system clipboard. + +\S2{config-selection-autocopy} \q{Auto-copy selected text} + +\cfg{winhelp-topic}{selection.autocopy} + +The checkbox \q{Auto-copy selected text to system clipboard} controls +whether or not selecting text in the PuTTY terminal window +automatically has the side effect of copying it to the system +clipboard, without requiring a separate user interface action. + +On X, the wording of this option is changed slightly so that +\cq{CLIPBOARD} is mentioned in place of the \q{system clipboard}. Text +selected in the terminal window will \e{always} be automatically +placed in the \cw{PRIMARY} selection, but if you tick this box, it +will \e{also} be placed in \cq{CLIPBOARD} at the same time. + +\S2{config-selection-clipactions} Choosing a clipboard for UI actions + +\cfg{winhelp-topic}{selection.clipactions} + +PuTTY has three user-interface actions which can be configured to +paste into the terminal (not counting menu items). You can click +whichever mouse button (if any) is configured to paste (see +\k{config-mouse}); you can press Shift-Ins; or you can press +Ctrl-Shift-V, although that action is not enabled by default. + +You can configure which of the available clipboards each of these +actions pastes from (including turning the paste action off +completely). On platforms with a single system clipboard, the +available options are to paste from that clipboard or to paste from +PuTTY's internal memory of the last selected text within that window. +On X, the options are \cw{CLIPBOARD} or \cw{PRIMARY}. + +(\cw{PRIMARY} is conceptually similar in that it \e{also} refers to +the last selected text \dash just across all applications instead of +just this window.) + +The two keyboard options each come with a corresponding key to copy +\e{to} the same clipboard. Whatever you configure Shift-Ins to paste +from, Ctrl-Ins will copy to the same location; similarly, Ctrl-Shift-C +will copy to whatever Ctrl-Shift-V pastes from. + \H{config-selection-words} The Words panel PuTTY will \I{word-by-word selection}select a word at a time in the diff --git a/putty.h b/putty.h index e768cf7f..ca00b666 100644 --- a/putty.h +++ b/putty.h @@ -899,6 +899,10 @@ void cleanup_exit(int); X(INT, NONE, rtf_paste) \ X(INT, NONE, mouse_override) \ X(INT, INT, wordness) \ + X(INT, NONE, mouseautocopy) \ + X(INT, NONE, mousepaste) \ + X(INT, NONE, ctrlshiftins) \ + X(INT, NONE, ctrlshiftcv) \ /* translations */ \ X(INT, NONE, vtmode) \ X(STR, NONE, line_codepage) \ @@ -1433,6 +1437,16 @@ enum { }; extern const char *const x11_authnames[]; /* declared in x11fwd.c */ +/* + * An enum for the copy-paste UI action configuration. + */ +enum { + CLIPUI_NONE, /* UI action has no copy/paste effect */ + CLIPUI_IMPLICIT, /* use the default clipboard implicit in mouse actions */ + CLIPUI_EXPLICIT, /* use the default clipboard for explicit Copy/Paste */ + CLIPUI_CUSTOM, /* use a named clipboard (on systems that support it) */ +}; + /* * Miscellaneous exports from the platform-specific code. * diff --git a/settings.c b/settings.c index 47e5b9f7..0433adc3 100644 --- a/settings.c +++ b/settings.c @@ -447,6 +447,42 @@ static void wprefs(void *sesskey, const char *name, sfree(buf); } +static void write_clip_setting(void *handle, const char *savekey, + Conf *conf, int confkey) +{ + int val = conf_get_int(conf, confkey); + switch (val) { + case CLIPUI_NONE: + default: + write_setting_s(handle, savekey, "none"); + break; + case CLIPUI_IMPLICIT: + write_setting_s(handle, savekey, "implicit"); + break; + case CLIPUI_EXPLICIT: + write_setting_s(handle, savekey, "explicit"); + break; + } +} + +static void read_clip_setting(void *handle, const char *savekey, + int def, Conf *conf, int confkey) +{ + char *setting = read_setting_s(handle, savekey); + int val; + + if (!setting) { + val = def; + } else if (!strcmp(setting, "implicit")) { + val = CLIPUI_IMPLICIT; + } else if (!strcmp(setting, "explicit")) { + val = CLIPUI_EXPLICIT; + } else { + val = CLIPUI_NONE; + } + conf_set_int(conf, confkey, val); +} + char *save_settings(const char *section, Conf *conf) { void *sesskey; @@ -638,6 +674,11 @@ void save_open_settings(void *sesskey, Conf *conf) } write_setting_s(sesskey, buf, buf2); } + write_setting_i(sesskey, "MouseAutocopy", + conf_get_int(conf, CONF_mouseautocopy)); + write_clip_setting(sesskey, "MousePaste", conf, CONF_mousepaste); + write_clip_setting(sesskey, "CtrlShiftIns", conf, CONF_ctrlshiftins); + write_clip_setting(sesskey, "CtrlShiftCV", conf, CONF_ctrlshiftcv); write_setting_s(sesskey, "LineCodePage", conf_get_str(conf, CONF_line_codepage)); write_setting_i(sesskey, "CJKAmbigWide", conf_get_int(conf, CONF_cjk_ambig_wide)); write_setting_i(sesskey, "UTF8Override", conf_get_int(conf, CONF_utf8_override)); @@ -1059,6 +1100,14 @@ void load_open_settings(void *sesskey, Conf *conf) } sfree(buf2); } + gppi(sesskey, "MouseAutocopy", CLIPUI_DEFAULT_AUTOCOPY, + conf, CONF_mouseautocopy); + read_clip_setting(sesskey, "MousePaste", CLIPUI_DEFAULT_MOUSE, + conf, CONF_mousepaste); + read_clip_setting(sesskey, "CtrlShiftIns", CLIPUI_DEFAULT_INS, + conf, CONF_ctrlshiftins); + read_clip_setting(sesskey, "CtrlShiftCV", CLIPUI_NONE, + conf, CONF_ctrlshiftcv); /* * The empty default for LineCodePage will be converted later * into a plausible default for the locale. diff --git a/unix/gtkwin.c b/unix/gtkwin.c index 507a9a3e..6811838a 100644 --- a/unix/gtkwin.c +++ b/unix/gtkwin.c @@ -1022,15 +1022,98 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) } /* - * Neither does Shift-Ins. + * Neither do Shift-Ins or Ctrl-Ins (if enabled). */ if (event->keyval == GDK_KEY_Insert && (event->state & GDK_SHIFT_MASK)) { + int cfgval = conf_get_int(inst->conf, CONF_ctrlshiftins); + + switch (cfgval) { + case CLIPUI_IMPLICIT: #ifdef KEY_EVENT_DIAGNOSTICS - debug((" - Shift-Insert paste\n")); + debug((" - Shift-Insert: paste from PRIMARY\n")); #endif - term_request_paste(inst->term, SHIFT_INS_CLIPBOARD); - return TRUE; + term_request_paste(inst->term, CLIP_PRIMARY); + return TRUE; + case CLIPUI_EXPLICIT: +#ifdef KEY_EVENT_DIAGNOSTICS + debug((" - Shift-Insert: paste from CLIPBOARD\n")); +#endif + term_request_paste(inst->term, CLIP_CLIPBOARD); + return TRUE; + default: +#ifdef KEY_EVENT_DIAGNOSTICS + debug((" - Shift-Insert: no paste action\n")); +#endif + break; + } + } + if (event->keyval == GDK_KEY_Insert && + (event->state & GDK_CONTROL_MASK)) { + static const int clips_clipboard[] = { CLIP_CLIPBOARD }; + int cfgval = conf_get_int(inst->conf, CONF_ctrlshiftins); + + switch (cfgval) { + case CLIPUI_IMPLICIT: + /* do nothing; re-copy to PRIMARY is not needed */ +#ifdef KEY_EVENT_DIAGNOSTICS + debug((" - Ctrl-Insert: non-copy to PRIMARY\n")); +#endif + return TRUE; + case CLIPUI_EXPLICIT: +#ifdef KEY_EVENT_DIAGNOSTICS + debug((" - Ctrl-Insert: copy to CLIPBOARD\n")); +#endif + term_request_copy(inst->term, + clips_clipboard, lenof(clips_clipboard)); + return TRUE; + default: +#ifdef KEY_EVENT_DIAGNOSTICS + debug((" - Ctrl-Insert: no copy action\n")); +#endif + break; + } + } + + /* + * Another pair of copy-paste keys. + */ + if ((event->state & GDK_SHIFT_MASK) && + (event->state & GDK_CONTROL_MASK) && + (event->keyval == GDK_KEY_C || event->keyval == GDK_KEY_c || + event->keyval == GDK_KEY_V || event->keyval == GDK_KEY_v)) { + int cfgval = conf_get_int(inst->conf, CONF_ctrlshiftcv); + int paste = (event->keyval == GDK_KEY_V || + event->keyval == GDK_KEY_v); + + switch (cfgval) { + case CLIPUI_IMPLICIT: + if (paste) { +#ifdef KEY_EVENT_DIAGNOSTICS + debug((" - Ctrl-Shift-V: paste from PRIMARY\n")); +#endif + term_request_paste(inst->term, CLIP_PRIMARY); + } else { +#ifdef KEY_EVENT_DIAGNOSTICS + debug((" - Ctrl-Shift-C: non-copy to PRIMARY\n")); +#endif + } + return TRUE; + case CLIPUI_EXPLICIT: + if (paste) { +#ifdef KEY_EVENT_DIAGNOSTICS + debug((" - Ctrl-Shift-V: paste from CLIPBOARD\n")); +#endif + term_request_paste(inst->term, CLIP_CLIPBOARD); + } else { + static const int clips[] = { CLIP_CLIPBOARD }; +#ifdef KEY_EVENT_DIAGNOSTICS + debug((" - Ctrl-Shift-C: copy to CLIPBOARD\n")); +#endif + term_request_copy(inst->term, clips, lenof(clips)); + } + return TRUE; + } } special = FALSE; @@ -3086,7 +3169,7 @@ void init_clipboard(struct gui_data *inst) void paste_menu_action(void *frontend) { struct gui_data *inst = (struct gui_data *)frontend; - term_request_paste(inst->term, MENU_PASTE_CLIPBOARD); + term_request_paste(inst->term, CLIP_CLIPBOARD); } static void set_window_titles(struct gui_data *inst) @@ -4169,6 +4252,32 @@ void event_log_menuitem(GtkMenuItem *item, gpointer data) showeventlog(inst->eventlogstuff, inst->window); } +void setup_clipboards(Terminal *term, Conf *conf) +{ + assert(term->mouse_select_clipboards[0] == CLIP_LOCAL); + + term->n_mouse_select_clipboards = 1; + term->mouse_select_clipboards[ + term->n_mouse_select_clipboards++] = MOUSE_SELECT_CLIPBOARD; + + if (conf_get_int(conf, CONF_mouseautocopy)) { + term->mouse_select_clipboards[ + term->n_mouse_select_clipboards++] = CLIP_CLIPBOARD; + } + + switch (conf_get_int(conf, CONF_mousepaste)) { + case CLIPUI_IMPLICIT: + term->mouse_paste_clipboard = MOUSE_PASTE_CLIPBOARD; + break; + case CLIPUI_EXPLICIT: + term->mouse_paste_clipboard = CLIP_CLIPBOARD; + break; + default: + term->mouse_paste_clipboard = CLIP_NULL; + break; + } +} + struct after_change_settings_dialog_ctx { struct gui_data *inst; Conf *newconf; @@ -4243,6 +4352,7 @@ static void after_change_settings_dialog(void *vctx, int retval) } /* Pass new config data to the terminal */ term_reconfig(inst->term, inst->conf); + setup_clipboards(inst->term, inst->conf); /* Pass new config data to the back end */ if (inst->back) inst->back->reconfig(inst->backhandle, inst->conf); @@ -5021,9 +5131,7 @@ void new_session_window(Conf *conf, const char *geometry_string) inst->eventlogstuff = eventlogstuff_new(); inst->term = term_init(inst->conf, &inst->ucsdata, inst); - inst->term->mouse_select_clipboards[ - inst->term->n_mouse_select_clipboards++] = MOUSE_SELECT_CLIPBOARD; - inst->term->mouse_paste_clipboard = MOUSE_PASTE_CLIPBOARD; + setup_clipboards(inst->term, inst->conf); inst->logctx = log_init(inst, inst->conf); term_provide_logctx(inst->term, inst->logctx); diff --git a/unix/unix.h b/unix/unix.h index d9e8f7a3..25f3cbda 100644 --- a/unix/unix.h +++ b/unix/unix.h @@ -125,15 +125,31 @@ unsigned long getticks(void); #ifdef OSX_GTK /* OS X has no PRIMARY selection */ -#define SHIFT_INS_CLIPBOARD CLIP_CLIPBOARD -#define MOUSE_SELECT_CLIPBOARD CLIP_CLIPBOARD -#define MOUSE_PASTE_CLIPBOARD CLIP_CLIPBOARD +#define MOUSE_SELECT_CLIPBOARD CLIP_NULL +#define MOUSE_PASTE_CLIPBOARD CLIP_LOCAL +#define CLIPNAME_IMPLICIT "Last selected text" +#define CLIPNAME_EXPLICIT "System clipboard" +#define CLIPNAME_EXPLICIT_OBJECT "system clipboard" +/* These defaults are the ones that more or less comply with the OS X + * Human Interface Guidelines, i.e. copy/paste to the system clipboard + * is _not_ implicit but requires a specific UI action. This is at + * odds with all other PuTTY front ends' defaults, but on OS X there + * is no multi-decade precedent for PuTTY working the other way. */ +#define CLIPUI_DEFAULT_AUTOCOPY FALSE +#define CLIPUI_DEFAULT_MOUSE CLIPUI_IMPLICIT +#define CLIPUI_DEFAULT_INS CLIPUI_EXPLICIT #else -#define SHIFT_INS_CLIPBOARD CLIP_PRIMARY #define MOUSE_SELECT_CLIPBOARD CLIP_PRIMARY #define MOUSE_PASTE_CLIPBOARD CLIP_PRIMARY +#define CLIPNAME_IMPLICIT "PRIMARY" +#define CLIPNAME_EXPLICIT "CLIPBOARD" +#define CLIPNAME_EXPLICIT_OBJECT "CLIPBOARD" +/* These defaults are the ones Unix PuTTY has historically had since + * it was first thought of in 2002 */ +#define CLIPUI_DEFAULT_AUTOCOPY FALSE +#define CLIPUI_DEFAULT_MOUSE CLIPUI_IMPLICIT +#define CLIPUI_DEFAULT_INS CLIPUI_IMPLICIT #endif -#define MENU_PASTE_CLIPBOARD CLIP_CLIPBOARD /* The per-session frontend structure managed by gtkwin.c */ struct gui_data; diff --git a/windows/window.c b/windows/window.c index 84799f48..4c63d7b0 100644 --- a/windows/window.c +++ b/windows/window.c @@ -52,7 +52,8 @@ #define IDM_SAVEDSESS 0x0160 #define IDM_COPYALL 0x0170 #define IDM_FULLSCREEN 0x0180 -#define IDM_PASTE 0x0190 +#define IDM_COPY 0x0190 +#define IDM_PASTE 0x01A0 #define IDM_SPECIALSEP 0x0200 #define IDM_SPECIAL_MIN 0x0400 @@ -106,6 +107,7 @@ static void make_full_screen(void); static void clear_full_screen(void); static void flip_full_screen(void); static void process_clipdata(HGLOBAL clipdata, int unicode); +static void setup_clipboards(Terminal *, Conf *); /* Window layout information */ static void reset_window(int); @@ -637,9 +639,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) * timer_change_notify() which will expect hwnd to exist.) */ term = term_init(conf, &ucsdata, NULL); - term->mouse_select_clipboards[ - term->n_mouse_select_clipboards++] = CLIP_SYSTEM; - term->mouse_paste_clipboard = CLIP_SYSTEM; + setup_clipboards(term, conf); logctx = log_init(NULL, conf); term_provide_logctx(term, logctx); term_size(term, conf_get_int(conf, CONF_height), @@ -712,6 +712,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) popup_menus[SYSMENU].menu = GetSystemMenu(hwnd, FALSE); popup_menus[CTXMENU].menu = CreatePopupMenu(); + AppendMenu(popup_menus[CTXMENU].menu, MF_ENABLED, IDM_COPY, "&Copy"); AppendMenu(popup_menus[CTXMENU].menu, MF_ENABLED, IDM_PASTE, "&Paste"); savedsess_menu = CreateMenu(); @@ -853,6 +854,30 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) return msg.wParam; /* ... but optimiser doesn't know */ } +static void setup_clipboards(Terminal *term, Conf *conf) +{ + assert(term->mouse_select_clipboards[0] == CLIP_LOCAL); + + term->n_mouse_select_clipboards = 1; + + if (conf_get_int(conf, CONF_mouseautocopy)) { + term->mouse_select_clipboards[ + term->n_mouse_select_clipboards++] = CLIP_SYSTEM; + } + + switch (conf_get_int(conf, CONF_mousepaste)) { + case CLIPUI_IMPLICIT: + term->mouse_paste_clipboard = CLIP_LOCAL; + break; + case CLIPUI_EXPLICIT: + term->mouse_paste_clipboard = CLIP_SYSTEM; + break; + default: + term->mouse_paste_clipboard = CLIP_NULL; + break; + } +} + /* * Clean up and exit. */ @@ -1998,6 +2023,8 @@ static void conf_cache_data(void) vtmode = conf_get_int(conf, CONF_vtmode); } +static const int clips_system[] = { CLIP_SYSTEM }; + static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { @@ -2210,6 +2237,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, /* Pass new config data to the terminal */ term_reconfig(term, conf); + setup_clipboards(term, conf); /* Pass new config data to the back end */ if (back) @@ -2331,10 +2359,10 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, } break; case IDM_COPYALL: - { - static const int clips[] = { CLIP_SYSTEM }; - term_copyall(term, clips, lenof(clips)); - } + term_copyall(term, clips_system, lenof(clips_system)); + break; + case IDM_COPY: + term_request_copy(term, clips_system, lenof(clips_system)); break; case IDM_PASTE: term_request_paste(term, CLIP_SYSTEM); @@ -4151,8 +4179,54 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, term_scroll_to_selection(term, (wParam == VK_PRIOR ? 0 : 1)); return 0; } + if (wParam == VK_INSERT && shift_state == 2) { + switch (conf_get_int(conf, CONF_ctrlshiftins)) { + case CLIPUI_IMPLICIT: + break; /* no need to re-copy to CLIP_LOCAL */ + case CLIPUI_EXPLICIT: + term_request_copy(term, clips_system, lenof(clips_system)); + break; + default: + break; + } + return 0; + } if (wParam == VK_INSERT && shift_state == 1) { - term_request_paste(term, CLIP_SYSTEM); + switch (conf_get_int(conf, CONF_ctrlshiftins)) { + case CLIPUI_IMPLICIT: + term_request_paste(term, CLIP_LOCAL); + break; + case CLIPUI_EXPLICIT: + term_request_paste(term, CLIP_SYSTEM); + break; + default: + break; + } + return 0; + } + if (wParam == 'C' && shift_state == 3) { + switch (conf_get_int(conf, CONF_ctrlshiftcv)) { + case CLIPUI_IMPLICIT: + break; /* no need to re-copy to CLIP_LOCAL */ + case CLIPUI_EXPLICIT: + term_request_copy(term, clips_system, lenof(clips_system)); + break; + default: + break; + } + return 0; + } + if (wParam == 'V' && shift_state == 3) { + switch (conf_get_int(conf, CONF_ctrlshiftcv)) { + case CLIPUI_IMPLICIT: + term_request_paste(term, CLIP_LOCAL); + break; + case CLIPUI_EXPLICIT: + term_request_paste(term, CLIP_SYSTEM); + break; + default: + break; + } return 0; } if (left_alt && wParam == VK_F4 && conf_get_int(conf, CONF_alt_f4)) { diff --git a/windows/winhelp.h b/windows/winhelp.h index dbe32c91..56f06d78 100644 --- a/windows/winhelp.h +++ b/windows/winhelp.h @@ -123,6 +123,8 @@ #define WINHELP_CTX_selection_charclasses "selection.charclasses:config-charclasses" #define WINHELP_CTX_selection_linedraw "selection.linedraw:config-linedrawpaste" #define WINHELP_CTX_selection_rtf "selection.rtf:config-rtfpaste" +#define WINHELP_CTX_selection_autocopy "selection.autocopy:config-selection-autocopy" +#define WINHELP_CTX_selection_clipactions "selection.clipactions:config-selection-clipactions" #define WINHELP_CTX_colours_ansi "colours.ansi:config-ansicolour" #define WINHELP_CTX_colours_xterm256 "colours.xterm256:config-xtermcolour" #define WINHELP_CTX_colours_truecolour "colours.truecolour:config-truecolour" diff --git a/windows/winstuff.h b/windows/winstuff.h index 39ff9426..84340b2f 100644 --- a/windows/winstuff.h +++ b/windows/winstuff.h @@ -634,4 +634,15 @@ int remove_from_jumplist_registry(const char *item); * empty one. */ char *get_jumplist_registry_entries(void); +/* + * Windows clipboard-UI wording. + */ +#define CLIPNAME_IMPLICIT "Last selected text" +#define CLIPNAME_EXPLICIT "System clipboard" +#define CLIPNAME_EXPLICIT_OBJECT "system clipboard" +/* These defaults are the ones PuTTY has historically had */ +#define CLIPUI_DEFAULT_AUTOCOPY TRUE +#define CLIPUI_DEFAULT_MOUSE CLIPUI_EXPLICIT +#define CLIPUI_DEFAULT_INS CLIPUI_EXPLICIT + #endif