diff --git a/.gitignore b/.gitignore index 09c8eb4..910ae38 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ *.o -windows/putty.map \ No newline at end of file +windows/putty.map +windows/make__quickrun.sh +windows/putty.log diff --git a/terminal.c b/terminal.c index 634656a..ad9f348 100644 --- a/terminal.c +++ b/terminal.c @@ -1677,6 +1677,7 @@ Terminal *term_init(Conf *myconf, struct unicode_data *ucsdata, TermWin *win) term->far2l_ext = 0; term->is_apc = 0; term->clip_allowed = -1; + term->clip_empty_pending = 0; term->win = win; term->ucsdata = ucsdata; @@ -2821,6 +2822,72 @@ static void do_osc(Terminal *term) // next from the end byte is command switch (d_out[d_count-2]) { + case 'n':; + + /* // not ready yet + + // todo: generate some reply + // todo: show notification only if window is out of focus + // todo: remove icon after notification timeout or by mouse click + + // title length, source, utf8, no zero-terminate, bytes + DWORD len1; + memcpy(&len1, d_out+d_count-6, sizeof(len1)); + + // text length, source, utf8, no zero-terminate, bytes + DWORD len2; + memcpy(&len2, d_out+d_count-6-4-len1, sizeof(len2)); + + // destination (wide char) + LPWSTR text_wc, title_wc; + int textsz_wc, titlesz_wc; + + // notification may contain file names in non-latin + // or may have localized title + // so we can not assume ascii here and should do + // full utf8->multibyte conversion + + titlesz_wc = MultiByteToWideChar(CP_UTF8, 0, (LPCCH)(d_out+len2+4), len1, 0, 0); + textsz_wc = MultiByteToWideChar(CP_UTF8, 0, (LPCCH)d_out, len2, 0, 0); + + if (titlesz_wc && textsz_wc) { + title_wc = malloc((titlesz_wc+1)*sizeof(wchar_t)); + MultiByteToWideChar(CP_UTF8, 0, (LPCCH)(d_out+len2+4), len1, title_wc, titlesz_wc); + text_wc = malloc((textsz_wc+1)*sizeof(wchar_t)); + MultiByteToWideChar(CP_UTF8, 0, (LPCCH)d_out, len2, text_wc, textsz_wc); + + title_wc[titlesz_wc] = 0; + text_wc[textsz_wc] = 0; + + NOTIFYICONDATAW pnid; + + // todo: do this on window focus also + pnid.cbSize = sizeof(pnid); + pnid.hWnd = hwnd; + pnid.hIcon = LoadIcon(0, IDI_APPLICATION); + pnid.uID = 200; + Shell_NotifyIconW(NIM_DELETE, &pnid); + + // todo: use putty icon + pnid.cbSize = sizeof(pnid); + pnid.hWnd = hwnd; + pnid.hIcon = LoadIcon(0, IDI_APPLICATION); + pnid.uID = 200; + pnid.uFlags = NIF_ICON | NIF_INFO | NIF_MESSAGE; + pnid.uCallbackMessage = (WM_USER + 200); + pnid.dwInfoFlags = NIIF_INFO | NIIF_NOSOUND; + memcpy(pnid.szInfoTitle, title_wc, (titlesz_wc+1)*sizeof(wchar_t)); + memcpy(pnid.szInfo, text_wc, (textsz_wc+1)*sizeof(wchar_t)); + Shell_NotifyIconW(NIM_ADD, &pnid); + + free(text_wc); + free(title_wc); + } + + */ + + break; + case 'w': // get largest console window size @@ -2868,18 +2935,29 @@ static void do_osc(Terminal *term) case 'e':; - OpenClipboard(hwnd); - char ec_status = EmptyClipboard() ? 1 : 0; - CloseClipboard(); + char ec_status; + /* + // EmptyClipboard() behaves VERY strange if called from here + // (test case: many continious Ctrl+Ins presses + // with selected text string of 174 characters in size), + // but works well if called just before SetClipboardData(). + // So deferreing a call to it. + if (term->clip_allowed == -1) { + OpenClipboard(hwnd); + ec_status = EmptyClipboard() ? 1 : 0; + CloseClipboard(); + } + */ + term->clip_empty_pending = 1; + ec_status = 1; // simulate "ok" reply_size = 2; reply = malloc(reply_size); - memcpy(reply, &ec_status, sizeof(char)); + reply[0] = ec_status; break; - case 'a':; DWORD a_fmt = (DWORD)d_out[d_count-7]; @@ -2960,19 +3038,27 @@ static void do_osc(Terminal *term) memcpy(GData,buffer,BufferSize); GlobalUnlock(hData); - OpenClipboard(hwnd); + if (OpenClipboard(hwnd)) { + + if (term->clip_empty_pending) { + EmptyClipboard(); // todo: check errors + term->clip_empty_pending = 0; + } + + if (!SetClipboardData(fmt, (HANDLE)hData)) { - if (SetClipboardData(fmt, (HANDLE)hData)) { + GlobalFree(hData); + } CloseClipboard(); - } else { + } else { GlobalFree(hData); } - } - else - { + + } else { + GlobalFree(hData); } } @@ -3004,11 +3090,13 @@ static void do_osc(Terminal *term) // clipboard stuff itself - wchar_t *ClipText=NULL; + wchar_t *ClipText = NULL; + HANDLE hClipData = NULL; - OpenClipboard(hwnd); - HANDLE hClipData=GetClipboardData(gfmt); - CloseClipboard(); + if (OpenClipboard(hwnd)) { + hClipData = GetClipboardData(gfmt); + CloseClipboard(); + } if (hClipData) { @@ -3025,6 +3113,7 @@ static void do_osc(Terminal *term) GlobalUnlock(hClipData); } + } else { // todo: process errors } diff --git a/terminal.h b/terminal.h index c0f30ea..a655c2b 100644 --- a/terminal.h +++ b/terminal.h @@ -191,6 +191,7 @@ struct terminal_tag { int far2l_ext; bool is_apc; int clip_allowed; + bool clip_empty_pending; char id_string[1024]; diff --git a/windows/putty.exe b/windows/putty.exe index e51dbe3..1eef29c 100755 Binary files a/windows/putty.exe and b/windows/putty.exe differ diff --git a/windows/window.c b/windows/window.c index 7beb00d..e1cf7cb 100644 --- a/windows/window.c +++ b/windows/window.c @@ -3217,19 +3217,6 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, /* far2l */ if (term->far2l_ext) { - // out base64 library splits long strings with \n - // do we actuall need this behavour? - - // get unicode char - BYTE kb[256]; - GetKeyboardState(kb); - WCHAR uc[5] = {}; - - ToUnicode(wParam, MapVirtualKey(wParam, MAPVK_VK_TO_VSC), kb, uc, 4, 0); - - // todo: check result - //int result = ToUnicode(wParam, MapVirtualKey(wParam, MAPVK_VK_TO_VSC), kb, uc, 4, 0); - // far2l_ext keyboard input event structure DWORD repeat; // 4 WORD vkc; // 2 @@ -3243,38 +3230,35 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, vkc = LOWORD(wParam); vsc = HIWORD(lParam) & 0xFF; + // set control keys state ctrl = 0; - - if (GetAsyncKeyState(VK_CONTROL)) { - ctrl |= LEFT_CTRL_PRESSED; - } - if (GetAsyncKeyState(VK_RCONTROL)) { - ctrl |= RIGHT_CTRL_PRESSED; - } - if (GetAsyncKeyState(VK_MENU)) { - ctrl |= LEFT_ALT_PRESSED; - } - if (GetAsyncKeyState(VK_SHIFT)) { - ctrl |= SHIFT_PRESSED; - } - - if ((lParam & ( 1 << 24 )) >> 24) { - ctrl |= ENHANCED_KEY; - } - - if ((((u_short)GetKeyState(VK_NUMLOCK)) & 0xffff) != 0) { - ctrl |= NUMLOCK_ON; - } - - if ((((u_short)GetKeyState(VK_SCROLL)) & 0xffff) != 0) { - ctrl |= SCROLLLOCK_ON; - } - - if ((((u_short)GetKeyState(VK_CAPITAL)) & 0xffff) != 0) { - ctrl |= CAPSLOCK_ON; - } + if (GetAsyncKeyState(VK_LCONTROL)) { ctrl |= LEFT_CTRL_PRESSED; } + if (GetAsyncKeyState(VK_RCONTROL)) { ctrl |= RIGHT_CTRL_PRESSED; } + if (GetAsyncKeyState(VK_LMENU)) { ctrl |= LEFT_ALT_PRESSED; } + if (GetAsyncKeyState(VK_RMENU)) { ctrl |= RIGHT_ALT_PRESSED; } + if (GetAsyncKeyState(VK_SHIFT)) { ctrl |= SHIFT_PRESSED; } + // begin: reserved for future usage + // Console WinAPI does not allow us to distinguish between left and right + // shift keys. But PuTTY is not a console app, so why not to send + // all information about control keys state that we actually have here? + // Using bits not used by any other status for backward compatibility. + #define RIGHT_SHIFT_PRESSED 0x1000 + #define LEFT_SHIFT_PRESSED 0x2000 + if (GetAsyncKeyState(VK_LSHIFT)) { ctrl |= RIGHT_SHIFT_PRESSED; } + if (GetAsyncKeyState(VK_RSHIFT)) { ctrl |= LEFT_SHIFT_PRESSED; } + // end + if ((lParam & ( 1 << 24 )) >> 24) { ctrl |= ENHANCED_KEY; } + if ((((u_short)GetKeyState(VK_NUMLOCK)) & 0xffff) != 0) { ctrl |= NUMLOCK_ON; } + if ((((u_short)GetKeyState(VK_SCROLL)) & 0xffff) != 0) { ctrl |= SCROLLLOCK_ON; } + if ((((u_short)GetKeyState(VK_CAPITAL)) & 0xffff) != 0) { ctrl |= CAPSLOCK_ON; } // set unicode character + BYTE kb[256]; + GetKeyboardState(kb); + WCHAR uc[5] = {}; + ToUnicode(wParam, MapVirtualKey(wParam, MAPVK_VK_TO_VSC), kb, uc, 4, 0); + // todo: check result + //int result = ToUnicode(wParam, MapVirtualKey(wParam, MAPVK_VK_TO_VSC), kb, uc, 4, 0); uchar = uc[0]; // set event type @@ -3292,6 +3276,13 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, memcpy(kev + 12, &uchar, sizeof(uchar)); memcpy(kev + 16, &type, sizeof(type)); + /* + FILE *f; f = fopen("putty.log", "a"); + fprintf(f, "r: %ld, vkc: %c, vsc: %c, ctrl: %ld, uchar: %ld, type: %lc\n", + repeat, vkc, vsc, ctrl, uchar, type); + fclose(f); + */ + // base64-encode kev // result in null-terminated char* out base64_encodestate _state;