[Ttssh2-commit] [7130] drag and dropの改良

scmno****@osdn***** scmno****@osdn*****
2018年 6月 11日 (月) 23:34:12 JST


Revision: 7130
          http://sourceforge.jp/projects/ttssh2/scm/svn/commits/7130
Author:   zmatsuo
Date:     2018-06-11 23:34:12 +0900 (Mon, 11 Jun 2018)
Log Message:
-----------
drag and dropの改良
- ダイアログにファイル名ペーストなどを追加
- 複数ファイルのドロップに対応

Modified Paths:
--------------
    branches/drag_and_drop/teraterm/common/tt_res.h
    branches/drag_and_drop/teraterm/common/tttypes.h
    branches/drag_and_drop/teraterm/teraterm/ttermpro.rc
    branches/drag_and_drop/teraterm/teraterm/vtwin.cpp
    branches/drag_and_drop/teraterm/teraterm/vtwin.h

-------------- next part --------------
Modified: branches/drag_and_drop/teraterm/common/tt_res.h
===================================================================
--- branches/drag_and_drop/teraterm/common/tt_res.h	2018-06-11 14:22:14 UTC (rev 7129)
+++ branches/drag_and_drop/teraterm/common/tt_res.h	2018-06-11 14:34:12 UTC (rev 7130)
@@ -164,7 +164,6 @@
 #define IDC_PROT_ELAPSED                2525
 #define IDC_DAD_STATIC                  2525
 #define IDC_PROTOELAPSEDTIME            2526
-#define IDC_DAD_SENDFILE                2526
 #define IDC_TRANS_ELAPSED               2527
 #define IDC_BGIMG_LABEL                 2527
 #define IDC_TRANS_ETIME                 2528
@@ -218,7 +217,16 @@
 #define IDC_NORMALIZE_LINEBREAK         2565
 #define IDC_CLIPBOARD_NOTIFY            2566
 #define IDC_LIST_HIDDEN_FONTS           2567
-
+#define IDC_BINARY_CHECK                2568
+#define IDC_ADAPT_SAME_CHECK            2569
+#define IDC_FILENAME_EDIT               2570
+#define IDC_SCP_RADIO                   2571
+#define IDC_SENDFILE_RADIO              2572
+#define IDC_PASTE_RADIO                 2573
+#define IDC_ESCAPE_CHECK                2574
+#define IDC_DEFAULT_CHECK               2575
+#define IDC_SCP_PATH_LABEL              2576
+#define IDC_SCP_PATH_NOTE               2577
 #define ID_ACC_SENDBREAK                50001
 #define ID_ACC_COPY                     50002
 #define ID_ACC_NEWCONNECTION            50003
@@ -316,7 +324,7 @@
 #define _APS_NO_MFC                     1
 #define _APS_NEXT_RESOURCE_VALUE        126
 #define _APS_NEXT_COMMAND_VALUE         52031
-#define _APS_NEXT_CONTROL_VALUE         2568
+#define _APS_NEXT_CONTROL_VALUE         2578
 #define _APS_NEXT_SYMED_VALUE           101
 #endif
 #endif

Modified: branches/drag_and_drop/teraterm/common/tttypes.h
===================================================================
--- branches/drag_and_drop/teraterm/common/tttypes.h	2018-06-11 14:22:14 UTC (rev 7129)
+++ branches/drag_and_drop/teraterm/common/tttypes.h	2018-06-11 14:34:12 UTC (rev 7130)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 1994-1998 T. Teranishi
- * (C) 2004-2017 TeraTerm Project
+ * (C) 2004-2018 TeraTerm Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -173,6 +173,7 @@
 #define WM_USER_GETSERIALNO  WM_USER+13
 #define WM_USER_CHANGETITLE  WM_USER+14
 #define WM_USER_NOTIFYICON   WM_USER+15
+#define WM_USER_DROPNOTIFY   WM_USER+16
 
 #define WM_USER_DDEREADY     WM_USER+21
 #define WM_USER_DDECMNDEND   WM_USER+22

Modified: branches/drag_and_drop/teraterm/teraterm/ttermpro.rc
===================================================================
--- branches/drag_and_drop/teraterm/teraterm/ttermpro.rc	2018-06-11 14:22:14 UTC (rev 7129)
+++ branches/drag_and_drop/teraterm/teraterm/ttermpro.rc	2018-06-11 14:34:12 UTC (rev 7130)
@@ -26,17 +26,28 @@
 // Dialog
 //
 
-IDD_DAD_DIALOG DIALOGEX 0, 0, 186, 74
+IDD_DAD_DIALOG DIALOGEX 0, 0, 187, 207
 STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
 CAPTION "Tera Term: File Drag and Drop"
 FONT 8, "Tahoma", 400, 0, 0x0
 BEGIN
-    LTEXT           "Are you sure that you want to send the file content?",IDC_DAD_STATIC,7,9,172,8
-    LTEXT           "SCP:",IDC_STATIC,15,27,16,8
-    EDITTEXT        IDC_SCP_PATH,31,25,122,14,ES_AUTOHSCROLL
-    PUSHBUTTON      "Send file",IDOK,7,45,50,14
-    DEFPUSHBUTTON   "SCP",IDC_DAD_SENDFILE,69,45,50,14
-    PUSHBUTTON      "Cancel",IDCANCEL,129,45,50,14
+    EDITTEXT        IDC_FILENAME_EDIT,7,6,172,14,ES_AUTOHSCROLL | ES_READONLY | NOT WS_TABSTOP
+    LTEXT           "Are you sure that you want to send the file content?",IDC_DAD_STATIC,7,25,173,8
+    CONTROL         "&SCP",IDC_SCP_RADIO,"Button",BS_AUTORADIOBUTTON | BS_NOTIFY,7,36,29,10
+    CONTROL         "S&end File (Paste content of file)",IDC_SENDFILE_RADIO,
+                    "Button",BS_AUTORADIOBUTTON | BS_NOTIFY,7,77,172,10
+    CONTROL         "&Paste Filename",IDC_PASTE_RADIO,"Button",BS_AUTORADIOBUTTON | BS_NOTIFY,7,109,172,10
+    LTEXT           "SCP des&t:",IDC_SCP_PATH_LABEL,19,50,36,8
+    EDITTEXT        IDC_SCP_PATH,57,47,122,14,ES_AUTOHSCROLL
+    LTEXT           "dest is home directory if empty",IDC_SCP_PATH_NOTE,50,64,120,8
+    CONTROL         "Bina&ry",IDC_BINARY_CHECK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,19,92,151,10
+    CONTROL         "Es&cape",IDC_ESCAPE_CHECK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,19,125,151,10
+    CONTROL         "&Adapt same process to remaing %d files",IDC_ADAPT_SAME_CHECK,
+                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,144,172,10
+    CONTROL         "&Default process from next drop\n(Drop with CTRL, this dialog is dispalyed)",IDC_DEFAULT_CHECK,
+                    "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,7,160,172,18
+    DEFPUSHBUTTON   "OK",IDOK,69,185,50,14
+    PUSHBUTTON      "Cancel",IDCANCEL,130,185,50,14
 END
 
 IDD_COMMENT_DIALOG DIALOGEX 0, 0, 239, 19

Modified: branches/drag_and_drop/teraterm/teraterm/vtwin.cpp
===================================================================
--- branches/drag_and_drop/teraterm/teraterm/vtwin.cpp	2018-06-11 14:22:14 UTC (rev 7129)
+++ branches/drag_and_drop/teraterm/teraterm/vtwin.cpp	2018-06-11 14:34:12 UTC (rev 7130)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 1994-1998 T. Teranishi
- * (C) 2004-2017 TeraTerm Project
+ * (C) 2004-2018 TeraTerm Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -254,6 +254,7 @@
 	ON_COMMAND(ID_WINDOW_UNDO, OnWindowUndo)
 	ON_COMMAND(ID_HELP_INDEX2, OnHelpIndex)
 	ON_COMMAND(ID_HELP_ABOUT, OnHelpAbout)
+	ON_MESSAGE(WM_USER_DROPNOTIFY, OnDropNotify)
 	//}}AFX_MSG_MAP
 END_MESSAGE_MAP()
 
@@ -918,6 +919,9 @@
 	// Tera Term\x82̋N\x93\xAE\x8E\x9E\x81AVirtual Store\x82\xAA\x93\xAD\x82\xAD\x82\xA9\x82ǂ\xA4\x82\xA9\x82\xF0\x8Ao\x82\xA6\x82Ă\xA8\x82\xAD\x81B
 	// (2015.11.14 yutaka)
 	cv.VirtualStoreEnabled = GetVirtualStoreEnvironment();
+
+	DropLists = NULL;
+	DropListCount = 0;
 }
 
 /////////////////////////////////////////////////////////////////////////////
@@ -1986,6 +1990,7 @@
 
 	/* Disable drag-drop */
 	::DragAcceptFiles(HVTWin,FALSE);
+	DropListFree();
 
 	EndDDE();
 
@@ -2019,57 +2024,135 @@
 	DeleteNotifyIcon(&cv);
 }
 
+static void SetDlgFonts(HWND hDlg, const int nIDDlgItems[], int nIDDlgItemCount, HFONT hFont)
+{
+	for (int i = 0 ; i < nIDDlgItemCount ; i++) {
+		const int nIDDlgItem = nIDDlgItems[i];
+		SendDlgItemMessage(hDlg, nIDDlgItem, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE,0));
+	}
+}
+
+enum drop_type {
+	DROP_TYPE_CANCEL,
+	DROP_TYPE_SCP,
+	DROP_TYPE_SEND_FILE,		// past contents of file
+	DROP_TYPE_SEND_FILE_BINARY,
+	DROP_TYPE_PASTE_FILENAME,
+	DROP_TYPE_PASTE_FILENAME_WITH_ESCAPE,
+};
+
+struct DrapDropDlgParam {
+	const char *TargetFilename;
+	enum drop_type DropType;
+	bool ScpEnable;
+	char *ScpSendDirPtr;
+	int ScpSendDirSize;
+	bool SendfileEnable;
+	int RemaingFileCount;
+	bool AdaptSameProcess;
+	bool DefaultProcess;
+};
+
+struct DrapDropDlgData {
+	HFONT DlgDragDropFont;
+	struct DrapDropDlgParam *Param;
+};
+
 static LRESULT CALLBACK OnDragDropDlgProc(HWND hDlgWnd, UINT msg, WPARAM wp, LPARAM lp)
 {
-	static HFONT DlgDragDropFont = NULL;
-	char uimsg[MAX_UIMSG];
-	LOGFONT logfont;
-	HFONT font;
+	struct DrapDropDlgData *DlgData = (struct DrapDropDlgData *)GetWindowLongPtr(hDlgWnd, GWLP_USERDATA);
 
 	switch (msg) {
 		case WM_INITDIALOG:
+		{
+			char uimsg[MAX_UIMSG];
+			LOGFONT logfont;
+			HFONT font;
+			HFONT DlgDragDropFont = NULL;
+			DlgData = (struct DrapDropDlgData *)malloc(sizeof(struct DrapDropDlgData));
+			SetWindowLongPtr(hDlgWnd, GWLP_USERDATA, (LONG_PTR)DlgData);
+			struct DrapDropDlgParam *Param = (struct DrapDropDlgParam *)lp;
+			DlgData->Param = Param;
 			font = (HFONT)SendMessage(hDlgWnd, WM_GETFONT, 0, 0);
 			GetObject(font, sizeof(LOGFONT), &logfont);
 			if (get_lang_font("DLG_TAHOMA_FONT", hDlgWnd, &logfont, &DlgDragDropFont, ts.UILanguageFile)) {
-				SendDlgItemMessage(hDlgWnd, IDC_SCP_PATH, WM_SETFONT, (WPARAM)DlgDragDropFont, MAKELPARAM(TRUE,0));
-				SendDlgItemMessage(hDlgWnd, IDOK, WM_SETFONT, (WPARAM)DlgDragDropFont, MAKELPARAM(TRUE,0));
-				SendDlgItemMessage(hDlgWnd, IDCANCEL, WM_SETFONT, (WPARAM)DlgDragDropFont, MAKELPARAM(TRUE,0));
-				SendDlgItemMessage(hDlgWnd, IDC_DAD_STATIC, WM_SETFONT, (WPARAM)DlgDragDropFont, MAKELPARAM(TRUE,0));
-				SendDlgItemMessage(hDlgWnd, IDC_DAD_SENDFILE, WM_SETFONT, (WPARAM)DlgDragDropFont, MAKELPARAM(TRUE,0));
+				const static int IDs[] = {
+					IDC_FILENAME_EDIT,
+					IDC_DAD_STATIC,
+					IDC_SCP_RADIO, IDC_SENDFILE_RADIO, IDC_PASTE_RADIO,
+					IDC_SCP_PATH_LABEL, IDC_SCP_PATH, IDC_SCP_PATH_NOTE,
+					IDC_BINARY_CHECK, IDC_ESCAPE_CHECK,
+					IDC_ADAPT_SAME_CHECK, IDC_DEFAULT_CHECK,
+					IDOK, IDCANCEL,
+				};
+				SetDlgFonts(hDlgWnd, IDs, _countof(IDs), DlgDragDropFont);
 			} else {
 				DlgDragDropFont = NULL;
 			}
+			DlgData->DlgDragDropFont = DlgDragDropFont;
 
 			GetWindowText(hDlgWnd, uimsg, sizeof(uimsg));
 			get_lang_msg("MSG_DANDD_CONF_TITLE", ts.UIMsg, sizeof(ts.UIMsg), uimsg, ts.UILanguageFile);
 			SetWindowText(hDlgWnd, ts.UIMsg);
 
+			SetDlgItemText(hDlgWnd, IDC_FILENAME_EDIT, Param->TargetFilename);
+
 			get_lang_msg("MSG_DANDD_CONF", ts.UIMsg, sizeof(ts.UIMsg),
 			             "Are you sure that you want to send the file content?", ts.UILanguageFile);
 			SetDlgItemText(hDlgWnd, IDC_DAD_STATIC, ts.UIMsg);
+			
+			// checkbox
+			CheckRadioButton(hDlgWnd, IDC_SCP_RADIO, IDC_PASTE_RADIO,
+							 (Param->DropType == DROP_TYPE_SEND_FILE ||
+							  Param->DropType == DROP_TYPE_SEND_FILE_BINARY) ? IDC_SENDFILE_RADIO :
+							 (Param->DropType == DROP_TYPE_PASTE_FILENAME ||
+							  Param->DropType == DROP_TYPE_PASTE_FILENAME_WITH_ESCAPE) ? IDC_PASTE_RADIO :
+							 IDC_SCP_RADIO);
 
-			get_lang_msg("FILEDLG_TRANS_TITLE_SENDFILE", ts.UIMsg, sizeof(ts.UIMsg),
-						 "Send file", ts.UILanguageFile);
-			SetDlgItemText(hDlgWnd, IDOK, ts.UIMsg);
+			// SCP
+			SendMessage(GetDlgItem(hDlgWnd, IDC_SCP_PATH), WM_SETTEXT, 0, (LPARAM)Param->ScpSendDirPtr);
+			if (!Param->ScpEnable) {
+				// \x96\xB3\x8C\xF8\x89\xBB
+				EnableWindow(GetDlgItem(hDlgWnd, IDC_SCP_RADIO), FALSE);
+				EnableWindow(GetDlgItem(hDlgWnd, IDC_SCP_PATH_LABEL), FALSE);
+				EnableWindow(GetDlgItem(hDlgWnd, IDC_SCP_PATH), FALSE);
+				EnableWindow(GetDlgItem(hDlgWnd, IDC_SCP_PATH_NOTE), FALSE);
+			}
 
-			SendMessage(GetDlgItem(hDlgWnd, IDC_SCP_PATH), WM_SETTEXT, 0, (LPARAM)ts.ScpSendDir);
+			// Send File
+			if (Param->DropType == DROP_TYPE_SEND_FILE_BINARY) {
+				SendMessage(GetDlgItem(hDlgWnd, IDC_BINARY_CHECK), BM_SETCHECK, BST_CHECKED, 0);
+			}
+			if (!Param->SendfileEnable) {
+				// \x96\xB3\x8C\xF8\x89\xBB
+				EnableWindow(GetDlgItem(hDlgWnd, IDC_SENDFILE_RADIO), FALSE);
+				EnableWindow(GetDlgItem(hDlgWnd, IDC_BINARY_CHECK), FALSE);
+			}
 
-			// SSH2 \x90ڑ\xB1\x82ł͂Ȃ\xA2\x8Fꍇ\x82ɂ\xCD "SCP" \x82𖳌\x{27B0B7}\x82\xE9\x81B
-			if (cv.isSSH != 2) {
-				EnableWindow(GetDlgItem(hDlgWnd, IDC_DAD_SENDFILE), FALSE);
-				EnableWindow(GetDlgItem(hDlgWnd, IDC_SCP_PATH), FALSE);
-				EnableWindow(GetDlgItem(hDlgWnd, IDC_STATIC), FALSE);
+			// Paste Filename
+			if (Param->DropType != DROP_TYPE_PASTE_FILENAME) {
+				SendMessage(GetDlgItem(hDlgWnd, IDC_ESCAPE_CHECK), BM_SETCHECK, BST_CHECKED, 0);
+			}
 
-				// \x83t\x83H\x81[\x83J\x83X\x82̏\x89\x8A\xFA\x8F\xF3\x91Ԃ\xF0 Cancel \x82ɂ\xB7\x82\xE9\x88ׁA\x82\xB1\x82̎\x9E\x93_\x82ł\xCD Send File (IDOK)\x82\xC9
+			// Adapt same process
+			GetDlgItemText(hDlgWnd, IDC_ADAPT_SAME_CHECK, uimsg, sizeof(uimsg));
+			char b[MAX_UIMSG];
+			_snprintf_s(b, sizeof(b), _TRUNCATE, uimsg, Param->RemaingFileCount);
+			SetDlgItemText(hDlgWnd, IDC_ADAPT_SAME_CHECK, b);
+			if (Param->RemaingFileCount < 2) {
+				EnableWindow(GetDlgItem(hDlgWnd, IDC_ADAPT_SAME_CHECK), FALSE);
+			}
+
+			// focus to "SCP dest textbox" or "Cancel"
+			if (Param->ScpEnable) {
+				// "SCP" \x97L\x8C\xF8\x8E\x9E\x82\xCD Cancel \x82Ƀt\x83H\x81[\x83J\x83X\x82𓖂āA\x8DŏI\x93I\x82\xC9 SCP PATH \x82Ƀt\x83H\x81[\x83J\x83X\x82\xAA
+				// \x93\x96\x82\xBD\x82\xE9\x82悤\x82ɂ\xB7\x82\xE9\x81B
+				SetFocus(GetDlgItem(hDlgWnd, IDC_SCP_RADIO));
+			} else {
+				// \x83t\x83H\x81[\x83J\x83X\x82̏\x89\x8A\xFA\x8F\xF3\x91Ԃ\xF0 Cancel \x82ɂ\xB7\x82\xE9\x88ׁA\x82\xB1\x82̎\x9E\x93_\x82ł\xCD IDOK \x82\xC9
 				// \x83t\x83H\x81[\x83J\x83X\x82𓖂Ă\xE9\x81B\x8C\xE3\x82\xC5 WM_NEXTDLGCTL \x82Ńt\x83H\x81[\x83J\x83X\x82\xAA\x8E\x9F\x82̃{\x83^\x83\x93\x82ɂȂ\xE9\x81B
 				SetFocus(GetDlgItem(hDlgWnd, IDOK));
 			}
-			else {
-				// SSH2 \x90ڑ\xB1\x8E\x9E\x82\xCD Cancel \x82Ƀt\x83H\x81[\x83J\x83X\x82𓖂āA\x8DŏI\x93I\x82\xC9 SCP PATH \x82Ƀt\x83H\x81[\x83J\x83X\x82\xAA
-				// \x93\x96\x82\xBD\x82\xE9\x82悤\x82ɂ\xB7\x82\xE9\x81B
-				SetFocus(GetDlgItem(hDlgWnd, IDCANCEL));
-			}
-
 			// \x83t\x83H\x81[\x83J\x83X\x82\xF0\x8E\x9F\x82̃{\x83^\x83\x93\x82Ɉڂ\xB7
 			// SetFocus() \x82Œ\xBC\x90ڃt\x83H\x81[\x83J\x83X\x82𓖂Ă\xE9\x82ƃ^\x83u\x83L\x81[\x82̓\xAE\x8D쓙\x82ɖ\xE2\x91肪\x8Fo\x82邽\x82߁A
 			// \x82\xB1\x82̃\x81\x83b\x83Z\x81[\x83W\x82𕹗p\x82\xB7\x82\xE9
@@ -2077,34 +2160,55 @@
 
 			// TRUE\x82ɂ\xB7\x82\xE9\x82ƃ{\x83^\x83\x93\x82Ƀt\x83H\x81[\x83J\x83X\x82\xAA\x93\x96\x82\xBD\x82\xE7\x82Ȃ\xA2\x81B
 			return FALSE;
+		}
 
 		case WM_COMMAND:
-			switch (LOWORD(wp)) {
-				case IDC_DAD_SENDFILE:
-					SendMessage(GetDlgItem(hDlgWnd, IDC_SCP_PATH), WM_GETTEXT, sizeof(ts.ScpSendDir), (LPARAM)ts.ScpSendDir);
-					if (DlgDragDropFont != NULL) {
-						DeleteObject(DlgDragDropFont);
-					}
-					EndDialog(hDlgWnd, IDC_DAD_SENDFILE);
-					break;
-
-				case IDOK:
-					if (DlgDragDropFont != NULL) {
-						DeleteObject(DlgDragDropFont);
-					}
-					EndDialog(hDlgWnd, IDOK);
-					break;
-
-				case IDCANCEL:
-					if (DlgDragDropFont != NULL) {
-						DeleteObject(DlgDragDropFont);
-					}
-					EndDialog(hDlgWnd, IDCANCEL);
-					break;
-
-				default:
-					return FALSE;
+		{
+			WORD wID = GET_WM_COMMAND_ID(wp, lp);
+			const WORD wCMD = GET_WM_COMMAND_CMD(wp, lp);
+			if (wCMD == BN_DBLCLK &&
+				(wID == IDC_SCP_RADIO || wID == IDC_SENDFILE_RADIO || wID == IDC_PASTE_RADIO))
+			{	// radio buttons double click
+				wID = IDOK;
 			}
+			if (wID == IDOK) {
+				if (IsDlgButtonChecked(hDlgWnd, IDC_SCP_RADIO) == BST_CHECKED) {
+					// SCP
+					DlgData->Param->DropType = DROP_TYPE_SCP;
+					SendMessage(GetDlgItem(hDlgWnd, IDC_SCP_PATH), WM_GETTEXT,
+								(WPARAM)DlgData->Param->ScpSendDirSize,
+								(LPARAM)DlgData->Param->ScpSendDirPtr);
+				} else if (IsDlgButtonChecked(hDlgWnd, IDC_SENDFILE_RADIO) == BST_CHECKED) {
+					// Send File
+					DlgData->Param->DropType =
+						(IsDlgButtonChecked(hDlgWnd, IDC_BINARY_CHECK) == BST_CHECKED) ?
+						DROP_TYPE_SEND_FILE_BINARY : DROP_TYPE_SEND_FILE;
+				} else /* if (IsDlgButtonChecked(hDlgWnd, IDC_PASTE_RADIO) == BST_CHECKED) */ {
+					// Paste Filename
+					DlgData->Param->DropType =
+						(IsDlgButtonChecked(hDlgWnd, IDC_ESCAPE_CHECK) == BST_CHECKED) ?
+						DROP_TYPE_PASTE_FILENAME_WITH_ESCAPE : DROP_TYPE_PASTE_FILENAME;
+				}
+				DlgData->Param->AdaptSameProcess = 
+					(IsDlgButtonChecked(hDlgWnd, IDC_ADAPT_SAME_CHECK) == BST_CHECKED) ?
+					true : false;
+				DlgData->Param->DefaultProcess = 
+					(IsDlgButtonChecked(hDlgWnd, IDC_DEFAULT_CHECK) == BST_CHECKED) ?
+					true : false;
+			}
+			if (wID == IDCANCEL) {
+				DlgData->Param->DropType = DROP_TYPE_CANCEL;
+			}
+			if (wID == IDOK || wID == IDCANCEL) {
+				if (DlgData->DlgDragDropFont != NULL) {
+					DeleteObject(DlgData->DlgDragDropFont);
+				}
+				EndDialog(hDlgWnd, wID);
+				free(DlgData);
+				break;
+			}
+			return FALSE;
+		}
 
 		default:
 			return FALSE;
@@ -2112,118 +2216,312 @@
 	return TRUE;
 }
 
-void CVTWindow::OnDropFiles(HDROP hDropInfo)
+static enum drop_type ShowDropDialogBox(
+	HINSTANCE hInstance, HWND hWndParent,
+	const char *TargetFilename,
+	enum drop_type DefaultDropType,
+	int RemaingFileCount,
+	bool EnableSCP,
+	bool EnableSendFile,
+	bool *AdaptSameProcess,
+	bool *DefaultProcess)
 {
-	::SetForegroundWindow(HVTWin);
-	if (cv.Ready && (SendVar==NULL) && NewFileVar(&SendVar))
-	{
-		if (DragQueryFile(hDropInfo,0,SendVar->FullName,
-			sizeof(SendVar->FullName))>0)
-		{
-			DWORD attr;
-			char *ptr, *q;
-			char tmpbuf[_MAX_PATH * 2];
+	struct DrapDropDlgParam Param;
+	Param.TargetFilename = TargetFilename;
+	Param.DropType = DefaultDropType;
+	Param.ScpEnable = EnableSCP;
+	Param.ScpSendDirPtr = ts.ScpSendDir;
+	Param.ScpSendDirSize = sizeof(ts.ScpSendDir);
+	Param.SendfileEnable = EnableSendFile;
+	Param.RemaingFileCount = RemaingFileCount;
+	int ret = DialogBoxParam(
+		hInstance, MAKEINTRESOURCE(IDD_DAD_DIALOG),
+		hWndParent, (DLGPROC)OnDragDropDlgProc,
+		(LPARAM)&Param);
+	if (ret != IDOK) {
+		return DROP_TYPE_CANCEL;
+	}
+	*AdaptSameProcess = Param.AdaptSameProcess;
+	*DefaultProcess = Param.DefaultProcess;
+	return Param.DropType;
+}
 
-			// \x83f\x83B\x83\x8C\x83N\x83g\x83\x8A\x82̏ꍇ\x82̓t\x83\x8B\x83p\x83X\x96\xBC\x82\xF0\x93\\x82\xE8\x95t\x82\xAF\x82\xE9 (2004.11.3 yutaka)
-			attr = GetFileAttributes(SendVar->FullName);
-			if (attr != -1 && (attr & FILE_ATTRIBUTE_DIRECTORY)) {
-				ptr = SendVar->FullName;
-				// \x83p\x83X\x82̋\xE6\x90؂\xE8\x82\xF0 \ -> / \x82\xD6
-				setlocale(LC_ALL, ts.Locale);
-				while (*ptr) {
-					if (isleadbyte(*ptr)) { // multi-byte
-						ptr += 2;
-						continue;
-					}
-					if (*ptr == '\\')
-						*ptr = '/';
-					ptr++;
-				}
+static void EscapeFilename(const char *src, char *dest)
+{
+#define ESCAPE_CHARS	" ;&()$!`'[]{}#^~"
+	setlocale(LC_ALL, ts.Locale);
+	const char *s = src;
+	char *d = dest;
+	while (*s) {
+		if (isleadbyte(*s)) { // multi-byte
+			*d++ = *s++;
+			*d++ = *s++;
+			continue;
+		}
+		char c = *s++;
+		if (c == '\\') {
+			// \x83p\x83X\x82̋\xE6\x90؂\xE8\x82\xF0 \ -> / \x82\xD6
+			*d = '/';
+		} else if (strchr(ESCAPE_CHARS, c) != NULL) {
+			// \x83G\x83X\x83P\x81[\x83v\x82\xAA\x95K\x97v\x82ȕ\xB6\x8E\x9A
+			*d++ = '\\';
+			*d = c;
+		} else {
+			*d = c;
+		}
+		d++;
+	}
+	*d = '\0'; // null-terminate
+}
 
-				// \x83p\x83X\x82ɋ󔒂\xAA\x82\xA0\x82\xEA\x82΃G\x83X\x83P\x81[\x83v\x82\xB7\x82\xE9
-				q = tmpbuf;
-				ptr = SendVar->FullName;
-				while (*ptr) {
-					if (*ptr == ' ')
-						*q++ = '\\';
-					*q++ = *ptr;
-					ptr++;
-				}
-				*q = '\0'; // null-terminate
+static void PasteString(PComVar cv, const char *str, bool escape)
+{
+	PCHAR ptr = (PCHAR)str;
+	char *tmpbuf = NULL;
+	if (escape) {
+		size_t len = strlen(str) * 2;
+		tmpbuf = (char *)malloc(len);
+		EscapeFilename(str, tmpbuf);
+		ptr = tmpbuf;
+	}
 
-				ptr = tmpbuf;
+	// console\x82֑\x97\x90M
+	while (*ptr) {
+		CommTextOut(cv, ptr, 1);
+		if (ts.LocalEcho > 0) {
+			CommTextEcho(cv, ptr, 1);
+		}
+		ptr++;
+	}
 
-				// console\x82֑\x97\x90M
-				while (*ptr) {
-					CommTextOut(&cv, ptr, 1);
-					if (ts.LocalEcho > 0) {
-						CommTextEcho(&cv, ptr, 1);
-					}
-					ptr++;
-				}
-				FreeFileVar(&SendVar); // \x89\xF0\x95\xFA\x82\xF0\x96Y\x82ꂸ\x82\xC9
+	if (tmpbuf != NULL) free(tmpbuf);
+}
 
-			} else {
-				// Confirm send a file when drag and drop (2007.12.28 maya)
-				if (ts.ConfirmFileDragAndDrop) {
-					// \x82\xA2\x82\xAB\x82Ȃ\xE8\x83t\x83@\x83C\x83\x8B\x82̓\xE0\x97e\x82𑗂荞\x82ޑO\x82ɁA\x83\x86\x81[\x83U\x82ɖ₢\x8D\x87\x82킹\x82\xF0\x8Ds\x82\xA4\x81B(2006.1.21 yutaka)
-					// MessageBox\x82\xC5SCP\x82\xE0\x91I\x91\xF0\x82ł\xAB\x82\xE9\x82悤\x82ɂ\xB7\x82\xE9\x81B(2008.1.25 yutaka)
-					// SCP\x83p\x83X\x82\xF0\x8Ew\x92\xE8\x82ł\xAB\x82\xE9\x82悤\x82Ƀ_\x83C\x83A\x83\x8D\x83O\x82ɕύX\x82\xB5\x82\xBD\x81B(2012.4.11 yutaka)
-					int ret;
+/* \x93\xFC\x97͂̓t\x83@\x83C\x83\x8B\x82̂\xDD(\x83t\x83H\x83\x8B\x83_\x82͊܂܂\xEA\x82Ȃ\xA2) */
+static bool SendScp(char *Filenames[], int FileCount, const char *SendDir)
+{
+	typedef int (CALLBACK *PSSH_start_scp)(char *, char *);
+	static PSSH_start_scp func = NULL;
+	static HMODULE h = NULL;
+	char msg[128];
 
-					ret = DialogBox(hInst, MAKEINTRESOURCE(IDD_DAD_DIALOG),
-									HVTWin, (DLGPROC)OnDragDropDlgProc);
+	if (h == NULL) {
+		if ( ((h = GetModuleHandle("ttxssh.dll")) == NULL) ) {
+			_snprintf_s(msg, sizeof(msg), _TRUNCATE, "GetModuleHandle(\"ttxssh.dll\")) %d", GetLastError());
+		scp_send_error:
+			::MessageBox(NULL, msg, "Tera Term: scpsend command error", MB_OK | MB_ICONERROR);
+			return false;
+		}
+	}
+	if (func == NULL) {
+		func = (PSSH_start_scp)GetProcAddress(h, "TTXScpSendfile");
+		if (func == NULL) {
+			_snprintf_s(msg, sizeof(msg), _TRUNCATE, "GetProcAddress(\"TTXScpSendfile\")) %d", GetLastError());
+			goto scp_send_error;
+		}
+	}
 
-					if (ret == IDOK) {   // sendfile
-						HelpId = HlpFileSend;
-						SendVar->DirLen = 0;
-						ts.TransBin = 0;
-						FileSendStart();
+	for (int i = 0; i < FileCount; i++) {
+		const char *FileName = Filenames[i];
+		func((char *)FileName, ts.ScpSendDir);
+	}
+	return true;
+}
 
-					} else if (ret == IDC_DAD_SENDFILE) {   // SCP
-						typedef int (CALLBACK *PSSH_start_scp)(char *, char *);
-						static PSSH_start_scp func = NULL;
-						static HMODULE h = NULL;
-						char msg[128];
+void CVTWindow::DropListFree()
+{
+	if (DropListCount > 0) {
+		for (int i = 0; i < DropListCount; i++) {
+			free(DropLists[i]);
+			DropLists[i] = NULL;
+		}
+		free(DropLists);
+		DropLists = NULL;
+		DropListCount = 0;
+	}
+}
 
-						if (func == NULL) {
-							if ( ((h = GetModuleHandle("ttxssh.dll")) == NULL) ) {
-								_snprintf_s(msg, sizeof(msg), _TRUNCATE, "GetModuleHandle(\"ttxssh.dll\")) %d", GetLastError());
-								goto scp_send_error;
-							}
-							func = (PSSH_start_scp)GetProcAddress(h, "TTXScpSendfile");
-							if (func == NULL) {
-								_snprintf_s(msg, sizeof(msg), _TRUNCATE, "GetProcAddress(\"TTXScpSendfile\")) %d", GetLastError());
-								goto scp_send_error;
-							}
-						}
+LONG CVTWindow::OnDropNotify(UINT ShowDialog, LONG lParam)
+{
+	static enum drop_type DefaultDropType = DROP_TYPE_CANCEL;
 
-						if (func != NULL) {
-							func(SendVar->FullName, ts.ScpSendDir);
-							goto send_success;
-						}
+	(void)lParam;
+	int FileCount = 0;
+	int DirectoryCount = 0;
+	for (int i = 0; i < DropListCount; i++) {
+		const char *FileName = DropLists[i];
+		const DWORD attr = GetFileAttributes(FileName);
+		if (attr == -1 ) {
+			goto finish;
+		}
+		if (attr & FILE_ATTRIBUTE_DIRECTORY) {
+			DirectoryCount++;
+		} else {
+			FileCount++;
+		}
+	}
 
-scp_send_error:
-						::MessageBox(NULL, msg, "Tera Term: scpsend command error", MB_OK | MB_ICONERROR);
-send_success:
-						FreeFileVar(&SendVar);  // \x89\xF0\x95\xFA\x82\xF0\x96Y\x82ꂸ\x82\xC9
-
+	bool AdapatSameProcess = false;
+	const bool isSSH = (cv.isSSH == 2);
+	enum drop_type DropType;
+	if (DefaultDropType == DROP_TYPE_CANCEL) {
+		// default is not set
+		if (!ShowDialog) {
+			if (FileCount == 1 && DirectoryCount == 0) {
+				if (ts.ConfirmFileDragAndDrop) {
+					if (isSSH) {
+						DropType = DROP_TYPE_SCP;
 					} else {
-						FreeFileVar(&SendVar);
-
+						DropType = DROP_TYPE_SEND_FILE;
 					}
+					AdapatSameProcess = false;
+				} else {
+					DropType = DROP_TYPE_SEND_FILE;
+					AdapatSameProcess = true;
 				}
-				else {
-					SendVar->DirLen = 0;
-					ts.TransBin = 0;
-					FileSendStart();
+			} else if (FileCount == 0 && DirectoryCount == 1) {
+				DropType = DROP_TYPE_PASTE_FILENAME_WITH_ESCAPE;
+				AdapatSameProcess = true;
+			} else if (FileCount > 0 && DirectoryCount > 0) {
+				DropType = DROP_TYPE_PASTE_FILENAME_WITH_ESCAPE;
+				AdapatSameProcess = false;
+			} else if (FileCount > 0 && DirectoryCount == 0) {
+				// filename only
+				if (isSSH) {
+					DropType = DROP_TYPE_SCP;
+				} else {
+					DropType = DROP_TYPE_SEND_FILE;
+				}
+				AdapatSameProcess = false;
+			} else {
+				// directory only
+				DropType = DROP_TYPE_PASTE_FILENAME_WITH_ESCAPE;
+				AdapatSameProcess = ts.ConfirmFileDragAndDrop ? false : true;
+			}
+		} else {
+			// show dialog
+			if (DirectoryCount > 0) {
+				DropType = DROP_TYPE_PASTE_FILENAME_WITH_ESCAPE;
+			} else {
+				if (isSSH) {
+					DropType = DROP_TYPE_SCP;
+				} else {
+					DropType = DROP_TYPE_SEND_FILE;
+				}
+			}
+			AdapatSameProcess = false;
+		}
+	} else {
+		if (DirectoryCount > 0 &&
+			(DefaultDropType == DROP_TYPE_SEND_FILE ||
+			 DefaultDropType == DROP_TYPE_SEND_FILE_BINARY ||
+			 DefaultDropType == DROP_TYPE_SCP))
+		{	// \x83f\x83t\x83H\x83\x8B\x83g\x82̂܂܂ł͏\x88\x97\x9D\x82ł\xAB\x82Ȃ\xA2\x91g\x82ݍ\x87\x82킹
+			DropType = DROP_TYPE_PASTE_FILENAME_WITH_ESCAPE;
+			AdapatSameProcess = false;
+		} else {
+			DropType = DefaultDropType;
+			AdapatSameProcess = ShowDialog ? false : true;
+		}
+	}
 
+	for (int i = 0; i < DropListCount; i++) {
+		const char *FileName = DropLists[i];
+
+		if (!AdapatSameProcess) {
+			bool DefaultProcess;
+			DropType =
+				ShowDropDialogBox(hInst, HVTWin,
+								  FileName, DropType,
+								  DropListCount - i,
+								  (DirectoryCount == 0 && isSSH) ? true : false,
+								  DirectoryCount == 0 ? true : false,
+								  &AdapatSameProcess, &DefaultProcess);
+			if (DropType == DROP_TYPE_CANCEL) {
+				goto finish;
+			}
+			if (DefaultProcess) {
+				DefaultDropType = DropType;
+			}
+		}
+			 
+		switch (DropType) {
+		case DROP_TYPE_CANCEL:
+		default:
+			// cancel
+			break;
+		case DROP_TYPE_SEND_FILE:
+		case DROP_TYPE_SEND_FILE_BINARY:
+			if (SendVar==NULL && NewFileVar(&SendVar)) {
+				HelpId = HlpFileSend;
+				strncpy_s(SendVar->FullName, sizeof(SendVar->FullName), FileName,  _TRUNCATE);
+				SendVar->DirLen = 0;
+				ts.TransBin = DropType == DROP_TYPE_SEND_FILE ? 0 : 1;
+				FileSendStart();
+#if 0
+				goto finish;	// send file\x82͘A\x91\xB1\x82\xB5\x82Ăł\xAB\x82Ȃ\xA2
+#else
+				{
+					LONG lCount = 0;
+					CWinApp *app = AfxGetApp();
+					while(1) {
+						if (SendVar == NULL) {
+							break;
+						}
+						app->OnIdle(lCount++);
+					}
 				}
+#endif
 			}
+			break;
+		case DROP_TYPE_PASTE_FILENAME:
+		case DROP_TYPE_PASTE_FILENAME_WITH_ESCAPE:
+		{
+			const bool escape = DropType == DROP_TYPE_PASTE_FILENAME ? false : true;
+			PasteString(&cv, FileName, escape);
+			if (DropListCount > 1) {
+				PasteString(&cv, "\n", false);
+			}
+			break;
 		}
-		else
-			FreeFileVar(&SendVar);
+		case DROP_TYPE_SCP:
+		{
+			// send by scp
+			char **FileNames = &DropLists[i];
+			int FileCount = AdapatSameProcess ? DropListCount - i : 1;
+			if (!SendScp(FileNames, FileCount, ts.ScpSendDir)) {
+				goto finish;
+			}
+			i += FileCount - 1;
+			break;
+		}
+		}
 	}
+
+finish:
+	DropListFree();
+	return 0;
+}
+
+void CVTWindow::OnDropFiles(HDROP hDropInfo)
+{
+	::SetForegroundWindow(HVTWin);
+	if (cv.Ready && SendVar==NULL)
+	{
+		const UINT ShowDialog =
+			((GetAsyncKeyState(VK_CONTROL) & 0x8000) != 0) ? 1 : 0;
+		DropListCount = DragQueryFile(hDropInfo, -1, NULL, 0);
+		DropLists = (char **)malloc(sizeof(char *) * DropListCount);
+
+		for (int i = 0; i < DropListCount; i++) {
+			const UINT cch = DragQueryFile(hDropInfo, i, NULL, 0) + 1;
+			char *FileName = (char *)malloc(cch);
+			DropLists[i] = FileName;
+			DragQueryFile(hDropInfo,i,FileName,cch);
+		}
+
+		::PostMessage(HVTWin, WM_USER_DROPNOTIFY, ShowDialog, 0);
+	}
 	DragFinish(hDropInfo);
 }
 

Modified: branches/drag_and_drop/teraterm/teraterm/vtwin.h
===================================================================
--- branches/drag_and_drop/teraterm/teraterm/vtwin.h	2018-06-11 14:22:14 UTC (rev 7129)
+++ branches/drag_and_drop/teraterm/teraterm/vtwin.h	2018-06-11 14:34:12 UTC (rev 7130)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 1994-1998 T. Teranishi
- * (C) 2004-2017 TeraTerm Project
+ * (C) 2004-2018 TeraTerm Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -50,6 +50,13 @@
   HMENU MainMenu, FileMenu, TransMenu, EditMenu,
     SetupMenu, ControlMenu, WinMenu, HelpMenu;
 
+  // drag and drop handle
+  char **DropLists;
+  int DropListCount;
+  void DropListFree();
+  bool DropWithLeftbutton;
+  bool DropWithRightbutton;
+
 protected:
 
 public:
@@ -214,6 +221,7 @@
 	afx_msg void OnHelpIndex();
 	afx_msg void OnHelpUsing();
 	afx_msg void OnHelpAbout();
+	afx_msg LONG OnDropNotify(UINT ShowMenu, LONG lParam);
 	//}}AFX_MSG
 	DECLARE_MESSAGE_MAP();
 	void Disconnect(BOOL confirm);



Ttssh2-commit メーリングリストの案内