64bitビルド時にttxsshのホスト名エディットボックスで CTRL+k の動作がおかしかったので修正
- 関数名 SetEditboxSubclass() を SetEditboxEmacsKeybind() に変更した
- C-b/C-f(カーソルを1文字前/後ろ)でサロゲートペアに対応
- エディットボックスかコンボボックスかを自動で判別するようにした
- ttxssh のログイン履歴を Unicode 対応とした
@@ -40,6 +40,7 @@ | ||
40 | 40 | #endif |
41 | 41 | #include <stdlib.h> |
42 | 42 | #include <crtdbg.h> |
43 | +#include <wchar.h> | |
43 | 44 | #include "ttlib.h" // for get_lang_font() |
44 | 45 | #include "layer_for_unicode.h" |
45 | 46 | #include "codeconv.h" |
@@ -90,7 +91,7 @@ | ||
90 | 91 | } |
91 | 92 | HControl = GetDlgItem(HDlg, FirstId + R - 1); |
92 | 93 | SendMessage(HControl, BM_SETCHECK, 1, 0); |
93 | - Style = GetClassLongPtr(HControl, GCL_STYLE); | |
94 | + Style = (DWORD)GetClassLongPtr(HControl, GCL_STYLE); | |
94 | 95 | SetClassLongPtr(HControl, GCL_STYLE, Style | WS_TABSTOP); |
95 | 96 | } |
96 | 97 |
@@ -232,24 +233,26 @@ | ||
232 | 233 | typedef struct { |
233 | 234 | WNDPROC OrigProc; // Original window procedure |
234 | 235 | LONG_PTR OrigUser; // DWLP_USER |
235 | - BOOL ComboBox; | |
236 | + BOOL IsComboBox; | |
236 | 237 | } EditSubclassData; |
237 | 238 | |
238 | -// C-n/C-p のためにサブクラス化 (2007.9.4 maya) | |
239 | -// C-p/C-n/C-b/C-f/C-a/C-e をサポート (2007.9.5 maya) | |
240 | -// C-d/C-k をサポート (2007.10.3 yutaka) | |
241 | -// ドロップダウンの中のエディットコントロールを | |
242 | -// サブクラス化するためのウインドウプロシージャ | |
243 | -// TODO サロゲートペア文字の場合の処理 | |
239 | +/** | |
240 | + * サポートするキー | |
241 | + * C-n/C-p コンボボックスのとき1つ上/下を選択 | |
242 | + * C-b/C-f カーソルを1文字前/後ろ | |
243 | + * C-a/C-e カーソルを行頭/行末 | |
244 | + * C-d カーソル配下の1文字削除 | |
245 | + * C-k カーソルから行末まで削除 | |
246 | + * C-u カーソルより行頭まで削除 | |
247 | + */ | |
244 | 248 | static LRESULT CALLBACK HostnameEditProc(HWND dlg, UINT msg, |
245 | 249 | WPARAM wParam, LPARAM lParam) |
246 | 250 | { |
247 | 251 | EditSubclassData *data = (EditSubclassData *)GetWindowLongPtr(dlg, GWLP_USERDATA); |
248 | 252 | LRESULT Result; |
249 | - LRESULT select; | |
250 | - LRESULT max; | |
251 | - int len; | |
252 | - char *str, *orgstr; | |
253 | + DWORD select; | |
254 | + DWORD max; | |
255 | + DWORD len; | |
253 | 256 | |
254 | 257 | switch (msg) { |
255 | 258 | // キーが押されたのを検知する |
@@ -257,64 +260,105 @@ | ||
257 | 260 | if (GetKeyState(VK_CONTROL) < 0) { |
258 | 261 | switch (wParam) { |
259 | 262 | case 0x50: // Ctrl+p ... up |
260 | - if (data->ComboBox) { | |
263 | + if (data->IsComboBox) { | |
261 | 264 | HWND parent = GetParent(dlg); |
262 | - select = SendMessage(parent, CB_GETCURSEL, 0, 0); | |
263 | - if (select > 0) { | |
264 | - PostMessage(parent, CB_SETCURSEL, select - 1, 0); | |
265 | + select = (DWORD)_SendMessageW(parent, CB_GETCURSEL, 0, 0); | |
266 | + if (select == CB_ERR) { | |
267 | + max = (DWORD)_SendMessageW(parent, CB_GETCOUNT, 0, 0); | |
268 | + PostMessageW(parent, CB_SETCURSEL, max - 1, 0); | |
265 | 269 | } |
270 | + else if (select > 0) { | |
271 | + PostMessageW(parent, CB_SETCURSEL, select - 1, 0); | |
272 | + } | |
266 | 273 | return 0; |
267 | 274 | } |
268 | 275 | break; |
269 | 276 | case 0x4e: // Ctrl+n ... down |
270 | - if (data->ComboBox) { | |
277 | + if (data->IsComboBox) { | |
271 | 278 | HWND parent = GetParent(dlg); |
272 | - max = SendMessage(parent, CB_GETCOUNT, 0, 0); | |
273 | - select = SendMessage(parent, CB_GETCURSEL, 0, 0); | |
274 | - if (select < max - 1) { | |
275 | - PostMessage(parent, CB_SETCURSEL, select + 1, 0); | |
279 | + max = (DWORD)_SendMessageW(parent, CB_GETCOUNT, 0, 0); | |
280 | + select = (DWORD)_SendMessageW(parent, CB_GETCURSEL, 0, 0); | |
281 | + if (select == CB_ERR) { | |
282 | + PostMessageW(parent, CB_SETCURSEL, 0, 0); | |
283 | + } else if (select < max - 1) { | |
284 | + PostMessageW(parent, CB_SETCURSEL, select + 1, 0); | |
276 | 285 | } |
277 | 286 | return 0; |
278 | 287 | } |
279 | 288 | break; |
280 | - case 0x42: // Ctrl+b ... left | |
281 | - SendMessage(dlg, EM_GETSEL, 0, (LPARAM)&select); | |
282 | - PostMessage(dlg, EM_SETSEL, select-1, select-1); | |
289 | + case 0x42: { | |
290 | + // Ctrl+b ... left | |
291 | + _SendMessageW(dlg, EM_GETSEL, 0, (LPARAM)&select); | |
292 | + if (select > 0) { | |
293 | + wchar_t *str; | |
294 | + max = _GetWindowTextLengthW(dlg); | |
295 | + max++; // '\0' | |
296 | + str = (wchar_t *)malloc(sizeof(wchar_t) * max); | |
297 | + if (str == NULL) { | |
298 | + return 0; | |
299 | + } | |
300 | + _GetWindowTextW(dlg, str, (int)max); | |
301 | + select = select - 1; | |
302 | + if (IsLowSurrogate(str[select])) { | |
303 | + select = select - 1; | |
304 | + } | |
305 | + PostMessageW(dlg, EM_SETSEL, select, select); | |
306 | + free(str); | |
307 | + } | |
283 | 308 | return 0; |
284 | - case 0x46: // Ctrl+f ... right | |
285 | - SendMessage(dlg, EM_GETSEL, 0, (LPARAM)&select); | |
286 | - max = GetWindowTextLength(dlg) ; | |
287 | - PostMessage(dlg, EM_SETSEL, select+1, select+1); | |
309 | + } | |
310 | + case 0x46: { | |
311 | + // Ctrl+f ... right | |
312 | + _SendMessageW(dlg, EM_GETSEL, 0, (LPARAM)&select); | |
313 | + max = _GetWindowTextLengthW(dlg); | |
314 | + if (select < max) { | |
315 | + wchar_t *str; | |
316 | + max++; // '\0' | |
317 | + str = (wchar_t *)malloc(sizeof(wchar_t) * max); | |
318 | + if (str == NULL) { | |
319 | + return 0; | |
320 | + } | |
321 | + _GetWindowTextW(dlg, str, (int)max); | |
322 | + select = select + 1; | |
323 | + if (IsLowSurrogate(str[select])) { | |
324 | + select = select + 1; | |
325 | + } | |
326 | + PostMessageW(dlg, EM_SETSEL, select, select); | |
327 | + free(str); | |
328 | + } | |
288 | 329 | return 0; |
330 | + } | |
289 | 331 | case 0x41: // Ctrl+a ... home |
290 | - PostMessage(dlg, EM_SETSEL, 0, 0); | |
332 | + PostMessageW(dlg, EM_SETSEL, 0, 0); | |
291 | 333 | return 0; |
292 | 334 | case 0x45: // Ctrl+e ... end |
293 | - max = GetWindowTextLength(dlg) ; | |
294 | - PostMessage(dlg, EM_SETSEL, max, max); | |
335 | + max = _GetWindowTextLengthW(dlg) ; | |
336 | + PostMessageW(dlg, EM_SETSEL, max, max); | |
295 | 337 | return 0; |
296 | 338 | |
297 | 339 | case 0x44: // Ctrl+d |
298 | 340 | case 0x4b: // Ctrl+k |
299 | - case 0x55: // Ctrl+u | |
300 | - SendMessage(dlg, EM_GETSEL, 0, (LPARAM)&select); | |
301 | - max = GetWindowTextLength(dlg); | |
341 | + case 0x55: { | |
342 | + // Ctrl+u | |
343 | + wchar_t *str, *orgstr; | |
344 | + _SendMessageW(dlg, EM_GETSEL, 0, (LPARAM)&select); | |
345 | + max = _GetWindowTextLengthW(dlg); | |
302 | 346 | max++; // '\0' |
303 | - orgstr = str = (char *)malloc(max); | |
347 | + orgstr = str = (wchar_t *)malloc(sizeof(wchar_t) * max); | |
304 | 348 | if (str != NULL) { |
305 | - len = GetWindowTextA(dlg, str, (int)max); | |
306 | - if (select >= 0 && select < len) { | |
307 | - if (wParam == 0x44) { // カーソル配下の文字のみを削除する | |
308 | - memmove(&str[select], &str[select + 1], len - select - 1); | |
349 | + len = _GetWindowTextW(dlg, str, (int)max); | |
350 | + if (select < len) { | |
351 | + if (wParam == 0x44) { // Ctrl+d カーソル配下の文字のみを削除する | |
352 | + wmemmove(&str[select], &str[select + 1], len - select - 1); | |
309 | 353 | str[len - 1] = '\0'; |
310 | 354 | |
311 | - } else if (wParam == 0x4b) { // カーソルから行末まで削除する | |
355 | + } else if (wParam == 0x4b) { // Ctrl+k カーソルから行末まで削除する | |
312 | 356 | str[select] = '\0'; |
313 | 357 | |
314 | 358 | } |
315 | 359 | } |
316 | 360 | |
317 | - if (wParam == 0x55) { // カーソルより左側をすべて消す | |
361 | + if (wParam == 0x55) { // Ctrl+uカーソルより左側をすべて消す | |
318 | 362 | if (select >= len) { |
319 | 363 | str[0] = '\0'; |
320 | 364 | } else { |
@@ -323,12 +367,15 @@ | ||
323 | 367 | select = 0; |
324 | 368 | } |
325 | 369 | |
326 | - SetWindowTextA(dlg, str); | |
327 | - SendMessage(dlg, EM_SETSEL, select, select); | |
370 | + _SetWindowTextW(dlg, str); | |
371 | + _SendMessageW(dlg, EM_SETSEL, select, select); | |
328 | 372 | free(orgstr); |
329 | 373 | return 0; |
330 | 374 | } |
331 | 375 | break; |
376 | + } | |
377 | + default: | |
378 | + break; | |
332 | 379 | } |
333 | 380 | } |
334 | 381 | break; |
@@ -374,19 +421,22 @@ | ||
374 | 421 | * C-n/C-p のためにサブクラス化 |
375 | 422 | * @praram hDlg ダイアログ |
376 | 423 | * @praram nID emacs風にするエディットボックス または コンボボックス |
377 | - * @param comboBox TRUE = nIDがコンボボックス | |
378 | 424 | */ |
379 | -void SetEditboxSubclass(HWND hDlg, int nID, BOOL ComboBox) | |
425 | +void SetEditboxEmacsKeybind(HWND hDlg, int nID) | |
380 | 426 | { |
381 | 427 | EditSubclassData *data; |
382 | 428 | HWND hWndEdit = GetDlgItem(hDlg, nID); |
383 | - if (ComboBox) { | |
429 | + BOOL IsCombobox = FALSE; | |
430 | + char ClassName[32]; | |
431 | + GetClassNameA(hWndEdit, ClassName, _countof(ClassName)); | |
432 | + if (strcmp(ClassName, "ComboBox") == 0) { | |
384 | 433 | hWndEdit = GetWindow(hWndEdit, GW_CHILD); |
434 | + IsCombobox = TRUE; | |
385 | 435 | } |
386 | 436 | data = (EditSubclassData *)malloc(sizeof(EditSubclassData)); |
387 | 437 | data->OrigProc = (WNDPROC)GetWindowLongPtrW(hWndEdit, GWLP_WNDPROC); |
388 | 438 | data->OrigUser = (LONG_PTR)GetWindowLongPtr(hWndEdit, GWLP_USERDATA); |
389 | - data->ComboBox = ComboBox; | |
439 | + data->IsComboBox = IsCombobox; | |
390 | 440 | _SetWindowLongPtrW(hWndEdit, GWLP_WNDPROC, (LONG_PTR)HostnameEditProc); |
391 | 441 | SetWindowLongPtr(hWndEdit, GWLP_USERDATA, (LONG_PTR)data); |
392 | 442 | } |
@@ -49,7 +49,7 @@ | ||
49 | 49 | void SetDropDownListW(HWND HDlg, int Id_Item, const wchar_t *List[], int nsel); |
50 | 50 | LONG GetCurSel(HWND HDlg, int Id_Item); |
51 | 51 | void InitDlgProgress(HWND HDlg, int id_Progress, int *CurProgStat); |
52 | -void SetEditboxSubclass(HWND hDlg, int nID, BOOL ComboBox); | |
52 | +void SetEditboxEmacsKeybind(HWND hDlg, int nID); | |
53 | 53 | |
54 | 54 | #if defined(_UNICODE) |
55 | 55 | #define SetDropDownListT(p1, p2, p3, p4) SetDropDownListW(p1, p2, p3, p4) |
@@ -538,7 +538,7 @@ | ||
538 | 538 | if (pSetWindowLongPtrW != NULL) { |
539 | 539 | return pSetWindowLongPtrW(hWnd, nIndex, dwNewLong); |
540 | 540 | } |
541 | - return SetWindowLongPtr(hWnd, nIndex, dwNewLong); | |
541 | + return SetWindowLongPtrA(hWnd, nIndex, dwNewLong); | |
542 | 542 | #else |
543 | 543 | return _SetWindowLongW(hWnd, nIndex, dwNewLong); |
544 | 544 | #endif |
@@ -1,5 +1,5 @@ | ||
1 | 1 | /* |
2 | - * (C) 2005-2019 TeraTerm Project | |
2 | + * (C) 2005-2020 TeraTerm Project | |
3 | 3 | * All rights reserved. |
4 | 4 | * |
5 | 5 | * Redistribution and use in source and binary forms, with or without |
@@ -111,7 +111,7 @@ | ||
111 | 111 | EnableWindow(GetDlgItem(hDlgWnd, IDC_SCP_PATH), FALSE); |
112 | 112 | EnableWindow(GetDlgItem(hDlgWnd, IDC_SCP_PATH_NOTE), FALSE); |
113 | 113 | } |
114 | - SetEditboxSubclass(hDlgWnd, IDC_SCP_PATH, FALSE); | |
114 | + SetEditboxEmacsKeybind(hDlgWnd, IDC_SCP_PATH); | |
115 | 115 | |
116 | 116 | // Send File |
117 | 117 | if (Param->DropType == DROP_TYPE_SEND_FILE_BINARY) { |
@@ -1902,7 +1902,7 @@ | ||
1902 | 1902 | |
1903 | 1903 | SendDlgItemMessage(Dialog, IDC_HOSTNAME, CB_SETCURSEL,0,0); |
1904 | 1904 | |
1905 | - SetEditboxSubclass(Dialog, IDC_HOSTNAME, TRUE); | |
1905 | + SetEditboxEmacsKeybind(Dialog, IDC_HOSTNAME); | |
1906 | 1906 | |
1907 | 1907 | SetRB(Dialog,GetHNRec->Telnet,IDC_HOSTTELNET,IDC_HOSTTELNET); |
1908 | 1908 | SendDlgItemMessage(Dialog, IDC_HOSTTCPPORT, EM_LIMITTEXT,5,0); |
@@ -1207,7 +1207,6 @@ | ||
1207 | 1207 | static char *ProtocolFamilyList[] = { "AUTO", "IPv6", "IPv4", NULL }; |
1208 | 1208 | PGetHNRec GetHNRec; |
1209 | 1209 | char EntName[128]; |
1210 | - char TempHost[HostNameMaxLength + 1]; | |
1211 | 1210 | WORD i, j, w; |
1212 | 1211 | WORD ComPortTable[MAXCOMPORT]; |
1213 | 1212 | static char *ComPortDesc[MAXCOMPORT]; |
@@ -1235,26 +1234,30 @@ | ||
1235 | 1234 | ) |
1236 | 1235 | GetHNRec->PortType = IdTCPIP; |
1237 | 1236 | |
1238 | - strncpy_s(EntName, sizeof(EntName), "Host", _TRUNCATE); | |
1237 | + { | |
1238 | + wchar_t *SetupFnW = ToWcharA(GetHNRec->SetupFN); | |
1239 | + i = 1; | |
1240 | + do { | |
1241 | + wchar_t EntNameW[128]; | |
1242 | + wchar_t TempHostW[HostNameMaxLength + 1]; | |
1243 | + _snwprintf_s(EntNameW, _countof(EntNameW), _TRUNCATE, L"host%d", i); | |
1244 | + GetPrivateProfileStringW(L"Hosts", EntNameW, L"", | |
1245 | + TempHostW, _countof(TempHostW), | |
1246 | + SetupFnW); | |
1247 | + if (TempHostW[0] != 0) | |
1248 | + SendDlgItemMessageW(dlg, IDC_HOSTNAME, CB_ADDSTRING, | |
1249 | + 0, (LPARAM) TempHostW); | |
1250 | + i++; | |
1251 | + } while (i <= MAXHOSTLIST); | |
1252 | + free(SetupFnW); | |
1253 | + } | |
1239 | 1254 | |
1240 | - i = 1; | |
1241 | - do { | |
1242 | - _snprintf_s(&EntName[4], sizeof(EntName)-4, _TRUNCATE, "%d", i); | |
1243 | - GetPrivateProfileString("Hosts", EntName, "", | |
1244 | - TempHost, sizeof(TempHost), | |
1245 | - GetHNRec->SetupFN); | |
1246 | - if (strlen(TempHost) > 0) | |
1247 | - SendDlgItemMessage(dlg, IDC_HOSTNAME, CB_ADDSTRING, | |
1248 | - 0, (LPARAM) TempHost); | |
1249 | - i++; | |
1250 | - } while (i <= MAXHOSTLIST); | |
1251 | - | |
1252 | 1255 | SendDlgItemMessage(dlg, IDC_HOSTNAME, EM_LIMITTEXT, |
1253 | 1256 | HostNameMaxLength - 1, 0); |
1254 | 1257 | |
1255 | 1258 | SendDlgItemMessage(dlg, IDC_HOSTNAME, CB_SETCURSEL, 0, 0); |
1256 | 1259 | |
1257 | - SetEditboxSubclass(dlg, IDC_HOSTNAME, TRUE); | |
1260 | + SetEditboxEmacsKeybind(dlg, IDC_HOSTNAME); | |
1258 | 1261 | |
1259 | 1262 | CheckRadioButton(dlg, IDC_HOSTTELNET, IDC_HOSTOTHER, |
1260 | 1263 | pvar->settings.Enabled ? IDC_HOSTSSH : GetHNRec-> |