#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;
#ifdef FIXME_REMOVE_BEFORE_CHECKIN
debug(("general_textout: done, xn=%d\n", xn));
#endif
- assert(xn - x == lprc->right - lprc->left);
+ assert(xn - x >= lprc->right - lprc->left);
}
/*
{
/* Disable full-screen if resizing forbidden */
- HMENU m = GetSystemMenu (hwnd, FALSE);
- EnableMenuItem(m, IDM_FULLSCREEN, MF_BYCOMMAND |
- (cfg.resize_action == RESIZE_DISABLED)
- ? MF_GRAYED : MF_ENABLED);
+ int i;
+ for (i = 0; i < lenof(popup_menus); i++)
+ EnableMenuItem(popup_menus[i].menu, IDM_FULLSCREEN,
+ MF_BYCOMMAND |
+ (cfg.resize_action == RESIZE_DISABLED)
+ ? MF_GRAYED : MF_ENABLED);
/* Gracefully unzoom if necessary */
if (IsZoomed(hwnd) &&
(cfg.resize_action == RESIZE_DISABLED)) {
term_copyall(term);
break;
case IDM_PASTE:
- term_do_paste(term);
+ request_paste(NULL);
break;
case IDM_CLRSB:
term_clrsb(term);
switch (message) {
case WM_LBUTTONDOWN:
button = MBT_LEFT;
+ wParam |= MK_LBUTTON;
press = 1;
break;
case WM_MBUTTONDOWN:
button = MBT_MIDDLE;
+ wParam |= MK_MBUTTON;
press = 1;
break;
case WM_RBUTTONDOWN:
button = MBT_RIGHT;
+ wParam |= MK_RBUTTON;
press = 1;
break;
case WM_LBUTTONUP:
button = MBT_LEFT;
+ wParam &= ~MK_LBUTTON;
press = 0;
break;
case WM_MBUTTONUP:
button = MBT_MIDDLE;
+ wParam &= ~MK_MBUTTON;
press = 0;
break;
case WM_RBUTTONUP:
button = MBT_RIGHT;
+ wParam &= ~MK_RBUTTON;
press = 0;
break;
default:
TO_CHR_X(X_POS(lParam)),
TO_CHR_Y(Y_POS(lParam)), wParam & MK_SHIFT,
wParam & MK_CONTROL, is_alt_pressed());
- ReleaseCapture();
+ if (!(wParam & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON)))
+ ReleaseCapture();
}
}
return 0;
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;
if (send_raw_mouse &&
!(cfg.mouse_override && shift_pressed)) {
- /* send a mouse-down followed by a mouse up */
- term_mouse(term, b, translate_button(b),
- MA_CLICK,
- TO_CHR_X(X_POS(lParam)),
- TO_CHR_Y(Y_POS(lParam)), shift_pressed,
- control_pressed, is_alt_pressed());
- term_mouse(term, b, translate_button(b),
- MA_RELEASE, TO_CHR_X(X_POS(lParam)),
- TO_CHR_Y(Y_POS(lParam)), shift_pressed,
- control_pressed, is_alt_pressed());
+ /* Mouse wheel position is in screen coordinates for
+ * some reason */
+ POINT p;
+ p.x = X_POS(lParam); p.y = Y_POS(lParam);
+ if (ScreenToClient(hwnd, &p)) {
+ /* send a mouse-down followed by a mouse up */
+ term_mouse(term, b, translate_button(b),
+ MA_CLICK,
+ TO_CHR_X(p.x),
+ TO_CHR_Y(p.y), shift_pressed,
+ control_pressed, is_alt_pressed());
+ term_mouse(term, b, translate_button(b),
+ MA_RELEASE, TO_CHR_X(p.x),
+ TO_CHR_Y(p.y), shift_pressed,
+ control_pressed, is_alt_pressed());
+ } /* else: not sure when this can fail */
} else {
/* trigger a scroll */
term_scroll(term, 0,
return 0;
}
if (wParam == VK_INSERT && shift_state == 1) {
- term_do_paste(term);
+ request_paste(NULL);
return 0;
}
if (left_alt && wParam == VK_F4 && cfg.alt_f4) {
*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)
+{
+ 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
reset_window(0);
- /* Tick the menu item in the System menu. */
- CheckMenuItem(GetSystemMenu(hwnd, FALSE), IDM_FULLSCREEN,
- MF_CHECKED);
+ /* Tick the menu item in the System and context menus. */
+ {
+ int i;
+ for (i = 0; i < lenof(popup_menus); i++)
+ CheckMenuItem(popup_menus[i].menu, IDM_FULLSCREEN, MF_CHECKED);
+ }
}
/*
SWP_FRAMECHANGED);
}
- /* Untick the menu item in the System menu. */
- CheckMenuItem(GetSystemMenu(hwnd, FALSE), IDM_FULLSCREEN,
- MF_UNCHECKED);
+ /* Untick the menu item in the System and context menus. */
+ {
+ int i;
+ for (i = 0; i < lenof(popup_menus); i++)
+ CheckMenuItem(popup_menus[i].menu, IDM_FULLSCREEN, MF_UNCHECKED);
+ }
}
/*