Compare commits

...
Author SHA1 Message Date
agrynco 2ea4f6f914 Merge pull request 'Release KSwitcher v0.6.93' (#37)
Release KSwitcher v0.6.93
2026-11-16 01:26:42 +02:00
agrynco 36f0b6ef8e Release KSwitcher v0.6.93 2026-11-16 01:26:12 +02:00
agrynco 3aafc1f937 Merge pull request 'Release KSwitcher v0.6.92' (#36)
Release KSwitcher v0.6.92
2026-11-16 01:19:49 +02:00
13 changed files with 108 additions and 73 deletions

No files matched your search

+1 -1
View File
@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.24)
project(KSwitcher VERSION 0.6.92 LANGUAGES CXX RC)
project(KSwitcher VERSION 0.6.93 LANGUAGES CXX RC)
if(NOT WIN32)
message(FATAL_ERROR "KSwitcher uses native Windows APIs")
endif()
+3
View File
@@ -67,6 +67,9 @@ Warning і початковий фокус на No.
лише до шляхів із пробілами. Для `..` вставляється шлях батьківської папки.
- Ctrl+Enter вставляє лише назву файла або папки під курсором активної панелі
за тими ж правилами вставлення й лапок. Рядок `..` пропускається.
- Ctrl+R перечитує поточну папку активної панелі. Позиція курсора й позначки
зберігаються для наявних елементів, а підраховані через F3 розміри папок
скидаються. F2 також виконує цю дію.
- Ctrl+C копіює весь введений у командний рядок текст, навіть коли виділено
лише його частину.
- Ctrl+Insert копіює імена позначених файлів і папок активної панелі в порядку
Binary file not shown.
+6
View File
@@ -1,5 +1,11 @@
# Latest Windows release
## v0.6.93 — 2026-11-16
In Files, Ctrl+R refreshes the active pane as in FAR Manager. The menu and key bar show Ctrl+R. F2 also refreshes the pane. Refresh preserves marks and the cursor where possible, and clears folder sizes calculated with F3.
**Українською.** У Files Ctrl+R перечитує активну панель, як у FAR Manager. Комбінація показана в меню та рядку клавіш. F2 також перечитує панель. Перечитування зберігає позначки й курсор для наявних елементів і скидає розміри папок, підраховані через F3.
## v0.6.92 — 2026-11-16
In Files, F3 on a folder measures file sizes throughout the directory tree. If folders are marked, Files measures each marked folder separately. Results appear in the Size column in Wide mode. F3 on a file opens the viewer even when folders are marked. Folder sizing runs in the background and supports LAN panes.
+1 -1
View File
@@ -1 +1 @@
448c242568f80cb07788173b1182f3f5b20cf152290f5de85efa148456406cff KSwitcher-win-x64.zip
21b9e32cfbd5e5cc8898d675a3b53e4b510a427dbeb2c26a957d104f1154dc05 KSwitcher-win-x64.zip
+55 -55
View File
@@ -1,136 +1,136 @@
{
"version": "0.6.92",
"schema": 1,
"files": [
{
"path": "KSwitcher.exe",
"size": 2467840,
"sha256": "daaf3c8f0b1090f89416bcc6771985c006e80a40c7027172d20bfbefaba1dde5"
"sha256": "3ad872f175c26ec2e9e06f9c5edf54f817fb281174d3be84d3286f9c38796b6e",
"path": "KSwitcher.exe"
},
{
"path": "KSwitcher.Config.exe",
"size": 2446848,
"sha256": "eeb98f92a1a6ef53fa86f3b914a0445e03b757832bfde52853740dc7caebd951"
"sha256": "e7465f15c46278841ed0764f3ac699b95423c3490c375d5481bbf85c100dbf34",
"path": "KSwitcher.Config.exe"
},
{
"path": "KSwitcher.Screenshot.exe",
"size": 3053568,
"sha256": "ed378e0b6868489f05287e34c8d354c5bd7dec887552309aa918beaacd8f3f0a"
"sha256": "e7b2f32b0138b3a3af7f648c5d6cfb17f952f48440ae69fcf7803a58b0ee32f6",
"path": "KSwitcher.Screenshot.exe"
},
{
"path": "KSwitcher.Files.exe",
"size": 3686912,
"sha256": "78068ae7cf5c645508f8e5bbf9e5d9c7f75501445e5ee5e1b745e6abed387052"
"sha256": "1a570823393e2c3e2198408ab44f83bf4456849b9eaa85a0ca52f63f1cb5326e",
"path": "KSwitcher.Files.exe"
},
{
"path": "WebView2Loader.dll",
"size": 194912,
"sha256": "d3fce90bdeecb08596e377dea6a316354dd8949e32ff09b89d51be00c14e21b6"
"sha256": "d3fce90bdeecb08596e377dea6a316354dd8949e32ff09b89d51be00c14e21b6",
"path": "WebView2Loader.dll"
},
{
"path": "terminal/addon-fit-LICENSE.txt",
"size": 1103,
"sha256": "e256f01188af527e4d06d21d06fbf785ae9c50d4b328bf03cbe0ba7f0aa4228f"
"sha256": "e256f01188af527e4d06d21d06fbf785ae9c50d4b328bf03cbe0ba7f0aa4228f",
"path": "terminal/addon-fit-LICENSE.txt"
},
{
"path": "terminal/addon-fit.js",
"size": 1521,
"sha256": "ba3ea256ce0620a0992a197d6c9baea64823fc93d8da07a9e366ca9943c18527"
"sha256": "ba3ea256ce0620a0992a197d6c9baea64823fc93d8da07a9e366ca9943c18527",
"path": "terminal/addon-fit.js"
},
{
"path": "terminal/index.html",
"size": 527,
"sha256": "084d97a727b778fb10d31adcd557ee7840a38377ed60e0ef0f3ece93b349b1ef"
"sha256": "084d97a727b778fb10d31adcd557ee7840a38377ed60e0ef0f3ece93b349b1ef",
"path": "terminal/index.html"
},
{
"path": "terminal/terminal.js",
"size": 4375,
"sha256": "7a31fe8679b7942775c7a9a3e34e836744111b7337e750d6ec7b21188dc4cd61"
"size": 4478,
"sha256": "0f3edde02b30e7b0f76d0cc88daae5791d720a4b74cf8b34e7c0b4dbe0cf9c9d",
"path": "terminal/terminal.js"
},
{
"path": "terminal/xterm-LICENSE.txt",
"size": 1261,
"sha256": "b569f629d00f2626a8100df2a1798210535621e42164dfd426a6fe5aac7b0ccd"
"sha256": "b569f629d00f2626a8100df2a1798210535621e42164dfd426a6fe5aac7b0ccd",
"path": "terminal/xterm-LICENSE.txt"
},
{
"path": "terminal/xterm.css",
"size": 7112,
"sha256": "854a7c0fb70e8b1a083c16797ab827299fb18744f5ad34f227b48337e33293c6"
"sha256": "854a7c0fb70e8b1a083c16797ab827299fb18744f5ad34f227b48337e33293c6",
"path": "terminal/xterm.css"
},
{
"path": "terminal/xterm.js",
"size": 488663,
"sha256": "14903579ff54664cd72f8e8699e6961a6272c21863ec1c3b118cdc8af5d4a972"
"sha256": "14903579ff54664cd72f8e8699e6961a6272c21863ec1c3b118cdc8af5d4a972",
"path": "terminal/xterm.js"
},
{
"path": "LICENSE",
"size": 4401,
"sha256": "d3c81140cce01c26bf6cbf52aa40e0825e1fa35b9a91d1387170a65d2597082c"
"sha256": "d3c81140cce01c26bf6cbf52aa40e0825e1fa35b9a91d1387170a65d2597082c",
"path": "LICENSE"
},
{
"path": "json-LICENSE.txt",
"size": 1075,
"sha256": "c0d068392ea65358b798b8c165103560f06e9e3b38c4ab4e2d8810a7b931af86"
"sha256": "c0d068392ea65358b798b8c165103560f06e9e3b38c4ab4e2d8810a7b931af86",
"path": "json-LICENSE.txt"
},
{
"path": "files-text-license.txt",
"size": 883,
"sha256": "185c5a37521316e940ead89cbf0b1ba5862d810c7c966e6c6a14a4a515b23625"
"sha256": "185c5a37521316e940ead89cbf0b1ba5862d810c7c966e6c6a14a4a515b23625",
"path": "files-text-license.txt"
},
{
"path": "README.md",
"size": 94223,
"sha256": "7b34f2af7341f57d7bac1b5b7e55a40595a6bc20f461f98c0c6320336d0deba7"
"sha256": "7b34f2af7341f57d7bac1b5b7e55a40595a6bc20f461f98c0c6320336d0deba7",
"path": "README.md"
},
{
"path": "LAN-PREVIEW.md",
"size": 11418,
"sha256": "2c13d3ed4761e679c352fb1ade24a1ec3060ad2862376ede801cdee5fcc3bada"
"sha256": "2c13d3ed4761e679c352fb1ade24a1ec3060ad2862376ede801cdee5fcc3bada",
"path": "LAN-PREVIEW.md"
},
{
"path": "dictionaries/en.txt",
"size": 682867,
"sha256": "5f267c141c3d6837870e1c098f86b89a113ba300343119432644ead88f720c21"
"sha256": "5f267c141c3d6837870e1c098f86b89a113ba300343119432644ead88f720c21",
"path": "dictionaries/en.txt"
},
{
"path": "dictionaries/LICENSE-CC-BY-SA-4.0.txt",
"size": 20138,
"sha256": "28a9529c7d0bb4dc51f4bf5c116a3d16ef247a052f7591466768ddf563fd1cf5"
"sha256": "28a9529c7d0bb4dc51f4bf5c116a3d16ef247a052f7591466768ddf563fd1cf5",
"path": "dictionaries/LICENSE-CC-BY-SA-4.0.txt"
},
{
"path": "dictionaries/README.md",
"size": 2265,
"sha256": "3017bf44d3be9d9dfab21bd6778aa52b7947e61acf9ce2bc86b41d6e949ac311"
"sha256": "3017bf44d3be9d9dfab21bd6778aa52b7947e61acf9ce2bc86b41d6e949ac311",
"path": "dictionaries/README.md"
},
{
"path": "dictionaries/ru.txt",
"size": 1060364,
"sha256": "9ef922c7699569304a428f6aba0fd13a21341c0d0cb9561f37ef83c41577a28b"
"sha256": "9ef922c7699569304a428f6aba0fd13a21341c0d0cb9561f37ef83c41577a28b",
"path": "dictionaries/ru.txt"
},
{
"path": "dictionaries/sources.json",
"size": 1280,
"sha256": "98e5b3fe7304e37705c9e5ff48b0b399ccb16e806736d21f09921b99e5f2a408"
"sha256": "98e5b3fe7304e37705c9e5ff48b0b399ccb16e806736d21f09921b99e5f2a408",
"path": "dictionaries/sources.json"
},
{
"path": "dictionaries/uk.txt",
"size": 940799,
"sha256": "d30e990d6ec2983c04f3644a3c61c6c668e8c542323f5931916fdd55b916eebf"
"sha256": "d30e990d6ec2983c04f3644a3c61c6c668e8c542323f5931916fdd55b916eebf",
"path": "dictionaries/uk.txt"
},
{
"path": "tools/README.txt",
"size": 993,
"sha256": "a34b5161a8315af037e1ec71d816bfc688f7c364141d4ee2347cf0515ef0c82a"
"sha256": "a34b5161a8315af037e1ec71d816bfc688f7c364141d4ee2347cf0515ef0c82a",
"path": "tools/README.txt"
},
{
"path": "tools/StayHere.exe",
"size": 133120,
"sha256": "a67a06d20b280c55f02f70b9aae3a967e510bb21d3e1430ef080d628b9e1a484"
"sha256": "db68aff204ab8c69ded43914e397fda151dce4fdc01f8ac1900db07393a97712",
"path": "tools/StayHere.exe"
},
{
"path": "tools/StayHere-README.md",
"size": 2796,
"sha256": "ba214e2aca7405e698b3ab21ceb1f41ce088edd996b3e30e4a9d58ff496f9413"
"sha256": "ba214e2aca7405e698b3ab21ceb1f41ce088edd996b3e30e4a9d58ff496f9413",
"path": "tools/StayHere-README.md"
}
]
],
"version": "0.6.93"
}
+3 -3
View File
@@ -9,8 +9,8 @@ IDC_SCREENSHOT_PENCIL CURSOR "icons/lucide/pencil.cur"
1 RT_MANIFEST "app.manifest"
201 RCDATA "update.ps1"
1 VERSIONINFO
FILEVERSION 0,6,92,0
PRODUCTVERSION 0,6,92,0
FILEVERSION 0,6,93,0
PRODUCTVERSION 0,6,93,0
FILEOS VOS_NT_WINDOWS32
FILETYPE VFT_APP
BEGIN
@@ -20,7 +20,7 @@ BEGIN
BEGIN
VALUE "FileDescription", "KSwitcher — native keyboard and clipboard utility"
VALUE "ProductName", "KSwitcher"
VALUE "FileVersion", "0.6.92"
VALUE "FileVersion", "0.6.93"
END
END
BLOCK "VarFileInfo"
+3
View File
@@ -64,6 +64,9 @@ terminal.attachCustomKeyEventHandler(event => {
else if (event.key === 'Insert') {
if (!event.repeat) bridge.postMessage('copy-panel-names');
}
else if (event.code === 'KeyR') {
if (!event.repeat) bridge.postMessage('refresh-panel');
}
else return true;
event.preventDefault();
return false;
+1 -1
View File
@@ -12,7 +12,7 @@ bool validHistoryKeys(const std::array<WORD,2> &keys)
const bool function=key>=VK_F1 && key<=VK_F12;
if(!letter && !function) return false;
if(modifiers==HOTKEYF_CONTROL)
return (letter && key!='C' && key!='F' && key!='V' && key!='X' && key!='A' && key!='Z' && key!='Y') || function;
return (letter && key!='C' && key!='F' && key!='R' && key!='V' && key!='X' && key!='A' && key!='Z' && key!='Y') || function;
if(modifiers==HOTKEYF_ALT) return function && key!=VK_F1 && key!=VK_F2 && key!=VK_F4 && key!=VK_F10;
return false;
});
+21 -10
View File
@@ -889,10 +889,14 @@ void layout(HWND window)
ShowWindow(terminalOutput,showOutput?SW_SHOWNA:SW_HIDE);
ShowWindow(status,terminalVisible?SW_HIDE:SW_SHOWNA);
terminalView.layout(terminalOutput,showOutput,terminalBottom-4);
constexpr int refreshExtra=4;
for (int i = 0; i < static_cast<int>(std::size(commands)); ++i)
{
const int count=static_cast<int>(std::size(commands));
place(commands[i],i*width/count,height-textHeight,(i+1)*width/count-i*width/count,textHeight);
constexpr int unit=10;
const int total=static_cast<int>(std::size(commands))*unit+refreshExtra;
const int left=i?(i*unit+refreshExtra)*width/total:0;
const int right=((i+1)*unit+refreshExtra)*width/total;
place(commands[i],left,height-textHeight,right-left,textHeight);
}
if(IsWindowVisible(panelSearchPopup)) placePanelSearch(window);
RedrawWindow(window,nullptr,nullptr,RDW_INVALIDATE|RDW_ERASE|RDW_ALLCHILDREN);
@@ -977,6 +981,14 @@ void copyPanelNames(HWND owner)
catch(const std::exception &) { setStatus(L"Could not copy file names."); }
}
void refreshPanel(Panel &panel)
{
panel.folderSizeStop.request_stop();
panel.folderSizeQuery={};
panel.folderSizes.clear();
open(panel,panel.directory,false);
}
std::wstring powerShellPath(const fs::path &path)
{
std::wstring quoted=L"'";
@@ -1059,6 +1071,7 @@ bool ensureTerminalView(HWND owner)
else if(message==L"insert-name") insertCurrentPanelPath(true);
else if(message==L"copy-command-line") SendMessageW(terminalInput,WM_COPY,0,0);
else if(message==L"copy-panel-names") copyPanelNames(owner);
else if(message==L"refresh-panel") refreshPanel(panels[active]);
else if(message==L"toggle") showTerminal(owner,!terminalVisible);
else if(!terminalVisible && (message==L"grow" || message==L"shrink"))
{
@@ -4425,11 +4438,7 @@ LRESULT CALLBACK panelKeys(HWND window, UINT message, WPARAM wp, LPARAM lp, UINT
if (wp == VK_RETURN) { enter(panels[index]); return 0; }
if (wp == VK_F2)
{
auto &panel=panels[index];
panel.folderSizeStop.request_stop();
panel.folderSizeQuery={};
panel.folderSizes.clear();
open(panel,panel.directory);
refreshPanel(panels[index]);
return 0;
}
if (wp == VK_F10) { SendMessageW(GetParent(window), WM_CLOSE, 0, 0); return 0; }
@@ -4526,7 +4535,7 @@ void openMenu(HWND window, int index)
else if(index==1) rows={L"Copy\tF5",L"Move\tF6",L"Make folder\tF7",L"Exit\tF10"};
else if(index==2)
{
rows={L"Refresh\tF2",L"View\tF3",L"Edit\tF4",L"Folder shortcuts",
rows={L"Refresh panel\tCtrl+R",L"View\tF3",L"Edit\tF4",L"Folder shortcuts",
L"View externally\tAlt+F3",L"Edit externally\tAlt+F4"};
if(panels[active].peer)
{
@@ -4820,7 +4829,7 @@ LRESULT CALLBACK filesWindow(HWND window, UINT message, WPARAM wp, LPARAM lp)
SetTimer(window,directoryWatchTimer,200,nullptr);
if (!mono || !blue || !teal || !menuBar || !picker || !pickerFrame || !status || !panelSearchPopup) return -1;
SendMessageW(status, WM_SETFONT, reinterpret_cast<WPARAM>(mono), FALSE);
const wchar_t *labels[]{L"F2 Refresh", L"F3 View", L"F4 Edit", L"F5 Copy", L"F6 Move", L"F7 Mkdir", L"F10 Exit"};
const wchar_t *labels[]{L"Ctrl+R Refresh", L"F3 View", L"F4 Edit", L"F5 Copy", L"F6 Move", L"F7 Mkdir", L"F10 Exit"};
for (int i = 0; i < static_cast<int>(std::size(commands)); ++i)
commands[i] = CreateWindowW(L"BUTTON", labels[i], WS_CHILD | WS_VISIBLE | BS_OWNERDRAW,
0, 0, 0, 0, window, reinterpret_cast<HMENU>(110 + static_cast<INT_PTR>(i)), instance, nullptr);
@@ -5484,11 +5493,13 @@ int WINAPI wWinMain(HINSTANCE instance, HINSTANCE, PWSTR, int show)
const bool ctrl=(GetKeyState(VK_CONTROL)&0x8000)!=0;
const bool shift=(GetKeyState(VK_SHIFT)&0x8000)!=0;
if(ctrl && !shift &&
(message.wParam=='F' || message.wParam=='C' || message.wParam==VK_RETURN || message.wParam==VK_INSERT))
(message.wParam=='F' || message.wParam=='C' || message.wParam=='R' ||
message.wParam==VK_RETURN || message.wParam==VK_INSERT))
{
if(!(message.lParam & (1LL<<30)))
{
if(message.wParam=='F') insertCurrentPanelPath();
else if(message.wParam=='R') refreshPanel(panels[active]);
else if(message.wParam==VK_RETURN) insertCurrentPanelPath(true);
else if(message.wParam==VK_INSERT) copyPanelNames(window);
else SendMessageW(terminalInput,WM_COPY,0,0);
+1 -1
View File
@@ -2,7 +2,7 @@
#include "platform.h"
namespace ks
{
inline constexpr wchar_t AppVersion[] = L"0.6.92";
inline constexpr wchar_t AppVersion[] = L"0.6.93";
inline constexpr UINT UpdateMessage = WM_APP + 7;
inline constexpr UINT UpdateCheckIntervalMs = 6 * 60 * 60 * 1000;
inline constexpr UINT UpdateNotificationRetryMs = 5 * 60 * 1000;
+12
View File
@@ -331,6 +331,18 @@ try {
$viewer=[FilesActivationUi]::FindWindowEx([IntPtr]::Zero,[IntPtr]::Zero,'KSwitcher.Files.Text',$viewerTitle)
[void][FilesActivationUi]::PostMessage($viewer,0x10,[IntPtr]::Zero,[IntPtr]::Zero)
Write-Output 'F3 measured the current folder recursively and measured marked folders without measuring the unmarked cursor folder.'
Select-Row $right '[Size B]'
Wait-Until 'Files activation for Ctrl+R' {
[FilesActivationUi]::Activate($window) -and [FilesActivationUi]::Focus($window) -eq $inputBox
}
$shell.SendKeys('^r')
Wait-Until 'Ctrl+R clearing the measured size and retaining the current folder' {
(Read-Text $status) -ceq 'Size B Folder' -and
[FilesActivationUi]::Send($right,0x188,[IntPtr]::Zero,[IntPtr]::Zero).ToInt32() -eq
(Find-Row $right '[Size B]')
}
Write-Output 'Ctrl+R refreshed the active pane and kept its cursor.'
} finally {
if ($process -and !$process.HasExited) {
[void]$process.CloseMainWindow()
+1 -1
View File
@@ -230,7 +230,7 @@ try {
[void][SearchArrowTest]::GetText($commandMenu,0x189,$i,$label)
$label.ToString()
})
if (($rows -join '|') -cne "Refresh`tF2|Folder shortcuts||View`tF3|Edit`tF4|View externally`tAlt+F3|Edit externally`tAlt+F4") {
if (($rows -join '|') -cne "Refresh panel`tCtrl+R|Folder shortcuts||View`tF3|Edit`tF4|View externally`tAlt+F3|Edit externally`tAlt+F4") {
throw 'Commands did not group local actions or showed a LAN-only section.'
}
Post $commandMenu 0x100 40