From a7419ea4b837b23a36ea0eb71b0c24a31a49d3fc Mon Sep 17 00:00:00 2001 From: simon Date: Wed, 7 Nov 2001 22:22:53 +0000 Subject: [PATCH] Implement writing RTF to the clipboard (off by default), so that if you enable it text will paste into Word et al in the same font as PuTTY itself is displaying in. In particular, this will be a fixed- pitch font, so tables and `ls' and the like will naturally line up. git-svn-id: svn://svn.tartarus.org/sgt/putty@1373 cda61777-01e9-0310-a592-d414129be87e --- putty.h | 2 + settings.c | 2 + unicode.c | 4 +- windlg.c | 10 ++++- window.c | 126 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 5 files changed, 136 insertions(+), 8 deletions(-) diff --git a/putty.h b/putty.h index 5a521cb3..d8be7e51 100644 --- a/putty.h +++ b/putty.h @@ -328,6 +328,7 @@ typedef struct { int mouse_is_xterm; int rect_select; int rawcnp; + int rtf_paste; int mouse_override; short wordness[256]; /* translations */ @@ -539,6 +540,7 @@ int check_compose(int first, int second); int decode_codepage(char *cp_name); char *cp_enumerate (int index); char *cp_name(int codepage); +void get_unitab(int codepage, wchar_t * unitab, int ftype); /* * Exports from mscrypto.c diff --git a/settings.c b/settings.c index 65c508a8..dbd745e6 100644 --- a/settings.c +++ b/settings.c @@ -234,6 +234,7 @@ void save_settings(char *section, int do_host, Config * cfg) write_setting_s(sesskey, buf, buf2); } write_setting_i(sesskey, "RawCNP", cfg->rawcnp); + write_setting_i(sesskey, "PasteRTF", cfg->rtf_paste); write_setting_i(sesskey, "MouseIsXterm", cfg->mouse_is_xterm); write_setting_i(sesskey, "RectSelect", cfg->rect_select); write_setting_i(sesskey, "MouseOverride", cfg->mouse_override); @@ -440,6 +441,7 @@ void load_settings(char *section, int do_host, Config * cfg) } } gppi(sesskey, "RawCNP", 0, &cfg->rawcnp); + gppi(sesskey, "PasteRTF", 0, &cfg->rtf_paste); gppi(sesskey, "MouseIsXterm", 0, &cfg->mouse_is_xterm); gppi(sesskey, "RectSelect", 0, &cfg->rect_select); gppi(sesskey, "MouseOverride", 1, &cfg->mouse_override); diff --git a/unicode.c b/unicode.c index 60ea85d1..90faf590 100644 --- a/unicode.c +++ b/unicode.c @@ -8,8 +8,6 @@ #include "putty.h" #include "misc.h" -static void get_unitab(int codepage, wchar_t * unitab, int ftype); - /* Character conversion arrays; they are usually taken from windows, * the xterm one has the four scanlines that have no unicode 2.0 * equivalents mapped to their unicode 3.0 locations. @@ -1218,7 +1216,7 @@ char *cp_enumerate(int index) return cp_list[index].name; } -static void get_unitab(int codepage, wchar_t * unitab, int ftype) +void get_unitab(int codepage, wchar_t * unitab, int ftype) { char tbuf[4]; int i, max = 256, flg = MB_ERR_INVALID_CHARS; diff --git a/windlg.c b/windlg.c index 706a68f1..21ed7a78 100644 --- a/windlg.c +++ b/windlg.c @@ -488,6 +488,7 @@ enum { IDCX_ABOUT = IDC_CCSTATIC2, IDC_CCEDIT, IDC_RAWCNP, + IDC_RTFPASTE, selectionpanelend, colourspanelstart, @@ -772,6 +773,7 @@ static void init_dlg_ctrls(HWND hwnd, int keepsess) cfg.rect_select == 0 ? IDC_SELTYPELEX : IDC_SELTYPERECT); CheckDlgButton(hwnd, IDC_MOUSEOVERRIDE, cfg.mouse_override); CheckDlgButton(hwnd, IDC_RAWCNP, cfg.rawcnp); + CheckDlgButton(hwnd, IDC_RTFPASTE, cfg.rtf_paste); { static int tabs[4] = { 25, 61, 96, 128 }; SendDlgItemMessage(hwnd, IDC_CCLIST, LB_SETTABSTOPS, 4, @@ -1145,7 +1147,7 @@ static void create_controls(HWND hwnd, int dlgtype, int panel) } if (panel == selectionpanelstart) { - /* The Selection panel. Accelerators used: [acgo] d wxp hst nr */ + /* The Selection panel. Accelerators used: [acgo] df wxp hst nr */ struct ctlpos cp; ctlposinit(&cp, hwnd, 80, 3, 13); bartitle(&cp, "Options controlling copy and paste", @@ -1155,6 +1157,9 @@ static void create_controls(HWND hwnd, int dlgtype, int panel) checkbox(&cp, "&Don't translate line drawing chars into +, - and |", IDC_RAWCNP); + checkbox(&cp, + "Paste to clipboard in RT&F as well as plain text", + IDC_RTFPASTE); endbox(&cp); beginbox(&cp, "Control which mouse button does which thing", IDC_BOX_SELECTION2); @@ -2412,6 +2417,9 @@ static int GenericMainDlgProc(HWND hwnd, UINT msg, case IDC_RAWCNP: cfg.rawcnp = IsDlgButtonChecked(hwnd, IDC_RAWCNP); break; + case IDC_RTFPASTE: + cfg.rtf_paste = IsDlgButtonChecked(hwnd, IDC_RTFPASTE); + break; case IDC_MBWINDOWS: case IDC_MBXTERM: cfg.mouse_is_xterm = IsDlgButtonChecked(hwnd, IDC_MBXTERM); diff --git a/window.c b/window.c index 01acb83f..a195cc6b 100644 --- a/window.c +++ b/window.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #ifndef AUTO_WINSOCK #ifdef WINSOCK_TWO @@ -14,6 +15,7 @@ #include #include #include +#include #define PUTTY_DO_GLOBALS /* actually _define_ globals */ #include "putty.h" @@ -3642,10 +3644,9 @@ void write_aclip(char *data, int len, int must_deselect) */ void write_clip(wchar_t * data, int len, int must_deselect) { - HGLOBAL clipdata; - HGLOBAL clipdata2; + HGLOBAL clipdata, clipdata2, clipdata3; int len2; - void *lock, *lock2; + void *lock, *lock2, *lock3; len2 = WideCharToMultiByte(CP_ACP, 0, data, len, 0, 0, NULL, NULL); @@ -3653,11 +3654,13 @@ void write_clip(wchar_t * data, int len, int must_deselect) len * sizeof(wchar_t)); clipdata2 = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, len2); - if (!clipdata || !clipdata2) { + if (!clipdata || !clipdata2 || !clipdata3) { if (clipdata) GlobalFree(clipdata); if (clipdata2) GlobalFree(clipdata2); + if (clipdata3) + GlobalFree(clipdata3); return; } if (!(lock = GlobalLock(clipdata))) @@ -3668,6 +3671,119 @@ void write_clip(wchar_t * data, int len, int must_deselect) memcpy(lock, data, len * sizeof(wchar_t)); WideCharToMultiByte(CP_ACP, 0, data, len, lock2, len2, NULL, NULL); + if (cfg.rtf_paste) { + wchar_t unitab[256]; + char *rtf = NULL; + unsigned char *tdata = (unsigned char *)lock2; + wchar_t *udata = (wchar_t *)lock; + int rtflen = 0, uindex = 0, tindex = 0; + int rtfsize = 0; + int multilen, blen, alen, totallen, i; + char before[16], after[4]; + + get_unitab(CP_ACP, unitab, 0); + + rtfsize = 100 + strlen(cfg.font); + rtf = smalloc(rtfsize); + sprintf(rtf, "{\\rtf1\\ansi%d{\\fonttbl\\f0\\fmodern %s;}\\f0", + GetACP(), cfg.font); + rtflen = strlen(rtf); + + /* + * We want to construct a piece of RTF that specifies the + * same Unicode text. To do this we will read back in + * parallel from the Unicode data in `udata' and the + * non-Unicode data in `tdata'. For each character in + * `tdata' which becomes the right thing in `udata' when + * looked up in `unitab', we just copy straight over from + * tdata. For each one that doesn't, we must WCToMB it + * individually and produce a \u escape sequence. + * + * It would probably be more robust to just bite the bullet + * and WCToMB each individual Unicode character one by one, + * then MBToWC each one back to see if it was an accurate + * translation; but that strikes me as a horrifying number + * of Windows API calls so I want to see if this faster way + * will work. If it screws up badly we can always revert to + * the simple and slow way. + */ + while (tindex < len2 && uindex < len && + tdata[tindex] && udata[uindex]) { + if (tindex + 1 < len2 && + tdata[tindex] == '\r' && + tdata[tindex+1] == '\n') { + tindex++; + uindex++; + } + if (unitab[tdata[tindex]] == udata[uindex]) { + multilen = 1; + before[0] = '\0'; + after[0] = '\0'; + blen = alen = 0; + } else { + multilen = WideCharToMultiByte(CP_ACP, 0, unitab+uindex, 1, + NULL, 0, NULL, NULL); + if (multilen != 1) { + blen = sprintf(before, "{\\u%d", udata[uindex]); + alen = 1; strcpy(after, "}"); + } else { + blen = sprintf(before, "\\u%d", udata[uindex]); + alen = 0; after[0] = '\0'; + } + } + assert(tindex + multilen <= len2); + totallen = blen + alen; + for (i = 0; i < multilen; i++) { + if (tdata[tindex+i] == '\\' || + tdata[tindex+i] == '{' || + tdata[tindex+i] == '}') + totallen += 2; + else if (tdata[tindex+i] == 0x0D || tdata[tindex+i] == 0x0A) + totallen += 6; /* \par\r\n */ + else if (tdata[tindex+i] > 0x7E || tdata[tindex+i] < 0x20) + totallen += 4; + else + totallen++; + } + + if (rtfsize < rtflen + totallen + 3) { + rtfsize = rtflen + totallen + 512; + rtf = srealloc(rtf, rtfsize); + } + + strcpy(rtf + rtflen, before); rtflen += blen; + for (i = 0; i < multilen; i++) { + if (tdata[tindex+i] == '\\' || + tdata[tindex+i] == '{' || + tdata[tindex+i] == '}') { + rtf[rtflen++] = '\\'; + rtf[rtflen++] = tdata[tindex+i]; + } else if (tdata[tindex+i] == 0x0D || tdata[tindex+i] == 0x0A) { + rtflen += sprintf(rtf+rtflen, "\\par\r\n"); + } else if (tdata[tindex+i] > 0x7E || tdata[tindex+i] < 0x20) { + rtflen += sprintf(rtf+rtflen, "\\'%02x", tdata[tindex+i]); + } else { + rtf[rtflen++] = tdata[tindex+i]; + } + } + strcpy(rtf + rtflen, after); rtflen += alen; + + tindex += multilen; + uindex++; + } + + strcpy(rtf + rtflen, "}"); + rtflen += 2; + + clipdata3 = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, rtflen); + if (clipdata3 && (lock3 = GlobalLock(clipdata3)) != NULL) { + strcpy(lock3, rtf); + GlobalUnlock(clipdata3); + } + sfree(rtf); + } else + clipdata3 = NULL; + GlobalUnlock(clipdata); GlobalUnlock(clipdata2); @@ -3678,6 +3794,8 @@ void write_clip(wchar_t * data, int len, int must_deselect) EmptyClipboard(); SetClipboardData(CF_UNICODETEXT, clipdata); SetClipboardData(CF_TEXT, clipdata2); + if (clipdata3) + SetClipboardData(RegisterClipboardFormat(CF_RTF), clipdata3); CloseClipboard(); } else { GlobalFree(clipdata); -- 2.11.0