#define WM_IGNORE_CLIP (WM_APP + 2)
#define WM_FULLSCR_ON_MAX (WM_APP + 3)
#define WM_AGENT_CALLBACK (WM_APP + 4)
+#define WM_GOT_CLIPDATA (WM_APP + 6)
/* Needed for Chinese support and apparently not always defined. */
#ifndef VK_PROCESSKEY
static void make_full_screen(void);
static void clear_full_screen(void);
static void flip_full_screen(void);
+static int process_clipdata(HGLOBAL clipdata, int unicode);
/* Window layout information */
static void reset_window(int);
static HMENU specials_menu = NULL;
static int n_specials = 0;
+static wchar_t *clipboard_contents;
+static size_t clipboard_length;
+
#define TIMING_TIMER_ID 1234
static long timing_next_time;
* Select protocol. This is farmed out into a table in a
* separate file to enable an ssh-free variant.
*/
- back = NULL;
- for (i = 0; backends[i].backend != NULL; i++)
- if (backends[i].protocol == cfg.protocol) {
- back = backends[i].backend;
- break;
- }
+ back = backend_from_proto(cfg.protocol);
if (back == NULL) {
char *str = dupprintf("%s Internal Error", appname);
MessageBox(NULL, "Unsupported protocol number found",
{
char *p;
int got_host = 0;
+ /* By default, we bring up the config dialog, rather than launching
+ * a session. This gets set to TRUE if something happens to change
+ * that (e.g., a hostname is specified on the command-line). */
+ int allow_launch = FALSE;
default_protocol = be_default_protocol;
/* Find the appropriate default port. */
{
- int i;
+ Backend *b = backend_from_proto(default_protocol);
default_port = 0; /* illegal */
- for (i = 0; backends[i].backend != NULL; i++)
- if (backends[i].protocol == default_protocol) {
- default_port = backends[i].backend->default_port;
- break;
- }
+ if (b)
+ default_port = b->default_port;
}
cfg.logtype = LGTYP_NONE;
if (!cfg_launchable(&cfg) && !do_config()) {
cleanup_exit(0);
}
+ allow_launch = TRUE; /* allow it to be launched directly */
} else if (*p == '&') {
/*
* An initial & means we've been given a command line
} else if (!do_config()) {
cleanup_exit(0);
}
+ allow_launch = TRUE;
} else {
/*
* Otherwise, break up the command line and deal with
cmdline_run_saved(&cfg);
- if ((!loaded_session || !cfg_launchable(&cfg)) &&
- !do_config()) {
+ if (loaded_session || got_host)
+ allow_launch = TRUE;
+
+ if ((!allow_launch || !cfg_launchable(&cfg)) && !do_config()) {
cleanup_exit(0);
}
}
}
- /* Check for invalid Port number (i.e. zero) */
- if (cfg.port == 0) {
- char *str = dupprintf("%s Internal Error", appname);
- MessageBox(NULL, "Invalid Port Number",
- str, MB_OK | MB_ICONEXCLAMATION);
- sfree(str);
- cleanup_exit(1);
- }
-
if (!prev) {
wndclass.style = 0;
wndclass.lpfnWndProc = WndProc;
sfree(c);
}
return 0;
+ case WM_GOT_CLIPDATA:
+ if (process_clipdata((HGLOBAL)lParam, wParam))
+ term_do_paste(term);
+ return 0;
default:
if (message == wm_mousewheel || message == WM_MOUSEWHEEL) {
int shift_pressed=0, control_pressed=0;
/*
* Translate a WM_(SYS)?KEY(UP|DOWN) message into a string of ASCII
- * codes. Returns number of bytes used or zero to drop the message
- * or -1 to forward the message to windows.
+ * codes. Returns number of bytes used, zero to drop the message,
+ * -1 to forward the message to Windows, or another negative number
+ * to indicate a NUL-terminated "special" string.
*/
static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
unsigned char *output)
return p - output;
}
if (wParam == VK_CANCEL && shift_state == 2) { /* Ctrl-Break */
- *p++ = 3;
- *p++ = 0;
- return -2;
+ if (back)
+ back->special(backhandle, TS_BRK);
+ return 0;
}
if (wParam == VK_PAUSE) { /* Break/Pause */
*p++ = 26;
*p++ = 0x1F;
return p - output;
}
- if (shift_state == 2 && wParam == 0xDF) {
+ if (shift_state == 2 && (wParam == 0xDF || wParam == 0xDC)) {
*p++ = 0x1C;
return p - output;
}
return -1;
}
-void request_paste(void *frontend)
-{
- /*
- * In Windows, pasting is synchronous: we can read the
- * clipboard with no difficulty, so request_paste() can just go
- * ahead and paste.
- */
- term_do_paste(term);
-}
-
void set_title(void *frontend, char *title)
{
sfree(window_name);
SendMessage(hwnd, WM_IGNORE_CLIP, FALSE, 0);
}
-void get_clip(void *frontend, wchar_t ** p, int *len)
+static DWORD WINAPI clipboard_read_threadfunc(void *param)
{
- static HGLOBAL clipdata = NULL;
- static wchar_t *converted = 0;
- wchar_t *p2;
+ HWND hwnd = (HWND)param;
+ HGLOBAL clipdata;
- if (converted) {
- sfree(converted);
- converted = 0;
- }
- if (!p) {
- if (clipdata)
- GlobalUnlock(clipdata);
- clipdata = NULL;
- return;
- } else if (OpenClipboard(NULL)) {
+ if (OpenClipboard(NULL)) {
if ((clipdata = GetClipboardData(CF_UNICODETEXT))) {
- CloseClipboard();
- *p = GlobalLock(clipdata);
- if (*p) {
- for (p2 = *p; *p2; p2++);
- *len = p2 - *p;
- return;
- }
- } else if ( (clipdata = GetClipboardData(CF_TEXT)) ) {
- char *s;
- int i;
- CloseClipboard();
- s = GlobalLock(clipdata);
+ SendMessage(hwnd, WM_GOT_CLIPDATA, (WPARAM)1, (LPARAM)clipdata);
+ } else if ((clipdata = GetClipboardData(CF_TEXT))) {
+ SendMessage(hwnd, WM_GOT_CLIPDATA, (WPARAM)0, (LPARAM)clipdata);
+ }
+ CloseClipboard();
+ }
+
+ return 0;
+}
+
+static int process_clipdata(HGLOBAL clipdata, int unicode)
+{
+ static wchar_t *converted = 0;
+
+ sfree(clipboard_contents);
+ clipboard_contents = NULL;
+ clipboard_length = 0;
+
+ if (unicode) {
+ wchar_t *p = GlobalLock(clipdata);
+ wchar_t *p2;
+
+ if (p) {
+ /* Unwilling to rely on Windows having wcslen() */
+ for (p2 = p; *p2; p2++);
+ clipboard_length = p2 - p;
+ clipboard_contents = snewn(clipboard_length + 1, wchar_t);
+ memcpy(clipboard_contents, p, clipboard_length * sizeof(wchar_t));
+ clipboard_contents[clipboard_length] = L'\0';
+ return TRUE;
+ }
+ } else {
+ char *s = GlobalLock(clipdata);
+ int i;
+
+ if (s) {
i = MultiByteToWideChar(CP_ACP, 0, s, strlen(s) + 1, 0, 0);
- *p = converted = snewn(i, wchar_t);
- MultiByteToWideChar(CP_ACP, 0, s, strlen(s) + 1, converted, i);
- *len = i - 1;
- return;
- } else
- CloseClipboard();
+ clipboard_contents = snewn(i, wchar_t);
+ MultiByteToWideChar(CP_ACP, 0, s, strlen(s) + 1,
+ clipboard_contents, i);
+ clipboard_length = i - 1;
+ clipboard_contents[clipboard_length] = L'\0';
+ return TRUE;
+ }
}
- *p = NULL;
- *len = 0;
+ return FALSE;
+}
+
+void request_paste(void *frontend)
+{
+ /*
+ * I always thought pasting was synchronous in Windows; the
+ * clipboard access functions certainly _look_ synchronous,
+ * unlike the X ones. But in fact it seems that in some
+ * situations the contents of the clipboard might not be
+ * immediately available, and the clipboard-reading functions
+ * may block. This leads to trouble if the application
+ * delivering the clipboard data has to get hold of it by -
+ * for example - talking over a network connection which is
+ * forwarded through this very PuTTY.
+ *
+ * Hence, we spawn a subthread to read the clipboard, and do
+ * our paste when it's finished. The thread will send a
+ * message back to our main window when it terminates, and
+ * that tells us it's OK to paste.
+ */
+ DWORD in_threadid; /* required for Win9x */
+ CreateThread(NULL, 0, clipboard_read_threadfunc,
+ hwnd, 0, &in_threadid);
+}
+
+void get_clip(void *frontend, wchar_t **p, int *len)
+{
+ if (p) {
+ *p = clipboard_contents;
+ *len = clipboard_length;
+ }
}
#if 0