Compare commits
1
Commits
release-v0.6.76
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
34d89db95b |
No files matched your search
+1
-1
@@ -1,5 +1,5 @@
|
||||
cmake_minimum_required(VERSION 3.24)
|
||||
project(KSwitcher VERSION 0.6.76 LANGUAGES CXX RC)
|
||||
project(KSwitcher VERSION 0.6.77 LANGUAGES CXX RC)
|
||||
if(NOT WIN32)
|
||||
message(FATAL_ERROR "KSwitcher uses native Windows APIs")
|
||||
endif()
|
||||
|
||||
Binary file not shown.
@@ -1,5 +1,17 @@
|
||||
# Latest Windows release
|
||||
|
||||
## v0.6.77 — 2026-11-13
|
||||
|
||||
The screenshot editor remembers the local pencil smoothing default across
|
||||
restarts. Adjust the slider with no pencil stroke selected, or use **Apply to
|
||||
all**, to save the value for new strokes. Adjusting a selected stroke changes
|
||||
only that stroke.
|
||||
|
||||
**Українською.** Редактор скріншотів зберігає типове згладжування олівця на
|
||||
цьому ПК та відновлює його після перезапуску. Змініть повзунок без виділеного
|
||||
штриха олівця або натисніть **Apply to all**, щоб запам’ятати значення для
|
||||
нових штрихів. Зміна виділеного штриха впливає лише на нього.
|
||||
|
||||
## v0.6.76 — 2026-11-13
|
||||
|
||||
Incoming LAN files suggest their original filename when saved. KSwitcher shows
|
||||
|
||||
@@ -1 +1 @@
|
||||
1f3b641d5b96f289d2d19792876545920f33bd702735d02912abd0218c5c9365 KSwitcher-win-x64.zip
|
||||
51d95639527590b36453a5ef485532a7d2135950222fa197eb431a5309f1a45c KSwitcher-win-x64.zip
|
||||
+21
-21
@@ -1,86 +1,86 @@
|
||||
{
|
||||
"schema": 1,
|
||||
"version": "0.6.77",
|
||||
"files": [
|
||||
{
|
||||
"size": 2249216,
|
||||
"path": "KSwitcher.exe",
|
||||
"sha256": "a32c5b1b0d86b44d3e4a0b2951f47f04f25a959fdf1f30f0eedd30422a77b0b6"
|
||||
"size": 2249216,
|
||||
"sha256": "f1c79d337d746efcda03946cc833b7b5588ef4e739f1dff7d3afa15d0465469f"
|
||||
},
|
||||
{
|
||||
"size": 2251776,
|
||||
"path": "KSwitcher.Config.exe",
|
||||
"sha256": "175939293f867aa38085578dcad6a7a264f801368ec3c63b71faf92c2e5e1731"
|
||||
"size": 2251776,
|
||||
"sha256": "016edc389007e0d15ee365fff7115fc91a820b46080cb39a3fb362f3b463bae7"
|
||||
},
|
||||
{
|
||||
"size": 3246592,
|
||||
"path": "KSwitcher.Screenshot.exe",
|
||||
"sha256": "b40a1e4c7553a34d83c5db22303f1815224870dfcf106d679be085c82e807dd3"
|
||||
"size": 3247616,
|
||||
"sha256": "c8ef070ad01acc410802c62e0df6a96cb299fe036fe8e99f0cf6a398b7324ec6"
|
||||
},
|
||||
{
|
||||
"size": 4401,
|
||||
"path": "LICENSE",
|
||||
"size": 4401,
|
||||
"sha256": "d3c81140cce01c26bf6cbf52aa40e0825e1fa35b9a91d1387170a65d2597082c"
|
||||
},
|
||||
{
|
||||
"size": 1075,
|
||||
"path": "json-LICENSE.txt",
|
||||
"size": 1075,
|
||||
"sha256": "c0d068392ea65358b798b8c165103560f06e9e3b38c4ab4e2d8810a7b931af86"
|
||||
},
|
||||
{
|
||||
"size": 93885,
|
||||
"path": "README.md",
|
||||
"size": 93885,
|
||||
"sha256": "df6d40d0eb66ad7da8db1cffe6bd211de70dfee474cc228e041c821b3940718b"
|
||||
},
|
||||
{
|
||||
"size": 11418,
|
||||
"path": "LAN-PREVIEW.md",
|
||||
"size": 11418,
|
||||
"sha256": "2c13d3ed4761e679c352fb1ade24a1ec3060ad2862376ede801cdee5fcc3bada"
|
||||
},
|
||||
{
|
||||
"size": 682867,
|
||||
"path": "dictionaries/en.txt",
|
||||
"size": 682867,
|
||||
"sha256": "5f267c141c3d6837870e1c098f86b89a113ba300343119432644ead88f720c21"
|
||||
},
|
||||
{
|
||||
"size": 20138,
|
||||
"path": "dictionaries/LICENSE-CC-BY-SA-4.0.txt",
|
||||
"size": 20138,
|
||||
"sha256": "28a9529c7d0bb4dc51f4bf5c116a3d16ef247a052f7591466768ddf563fd1cf5"
|
||||
},
|
||||
{
|
||||
"size": 2230,
|
||||
"path": "dictionaries/README.md",
|
||||
"size": 2230,
|
||||
"sha256": "2df17fe4e17d527c67ab57269b07dce59a49c1fb128c429a1408decbb47109ec"
|
||||
},
|
||||
{
|
||||
"size": 1060364,
|
||||
"path": "dictionaries/ru.txt",
|
||||
"size": 1060364,
|
||||
"sha256": "9ef922c7699569304a428f6aba0fd13a21341c0d0cb9561f37ef83c41577a28b"
|
||||
},
|
||||
{
|
||||
"size": 1279,
|
||||
"path": "dictionaries/sources.json",
|
||||
"size": 1279,
|
||||
"sha256": "d6e11a3aaba22a8a7eaba19f778d8a5bd66653ff306810e85a1b0e7fff3a6b86"
|
||||
},
|
||||
{
|
||||
"size": 898248,
|
||||
"path": "dictionaries/uk.txt",
|
||||
"size": 898248,
|
||||
"sha256": "caeb097749d4afc84b68ad96b3d7dfb6a6569561cd32ccce0bee94a13b43ba86"
|
||||
},
|
||||
{
|
||||
"size": 993,
|
||||
"path": "tools/README.txt",
|
||||
"size": 993,
|
||||
"sha256": "a34b5161a8315af037e1ec71d816bfc688f7c364141d4ee2347cf0515ef0c82a"
|
||||
},
|
||||
{
|
||||
"size": 134656,
|
||||
"path": "tools/StayHere.exe",
|
||||
"size": 134656,
|
||||
"sha256": "6ef5cf64708d62b7fc63c3c793cc99188a513433ff4774cae01dc014f6664376"
|
||||
},
|
||||
{
|
||||
"size": 2796,
|
||||
"path": "tools/StayHere-README.md",
|
||||
"size": 2796,
|
||||
"sha256": "ba214e2aca7405e698b3ab21ceb1f41ce088edd996b3e30e4a9d58ff496f9413"
|
||||
}
|
||||
],
|
||||
"version": "0.6.76"
|
||||
"schema": 1
|
||||
}
|
||||
+3
-3
@@ -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,76,0
|
||||
PRODUCTVERSION 0,6,76,0
|
||||
FILEVERSION 0,6,77,0
|
||||
PRODUCTVERSION 0,6,77,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.76"
|
||||
VALUE "FileVersion", "0.6.77"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
+31
-4
@@ -180,6 +180,7 @@ struct Capture
|
||||
LineStyle lineStyle=LineStyle::Solid;
|
||||
int smoothing=25;
|
||||
bool smoothingDrag=false;
|
||||
bool smoothingPreferenceDirty=false;
|
||||
LineEnds arrowEnds=LineEnds::End, freehandEnds=LineEnds::None;
|
||||
COLORREF currentColor=RGB(225,42,50);
|
||||
COLORREF customColors[16]{};
|
||||
@@ -221,8 +222,24 @@ struct Capture
|
||||
MarkPart hoveredPart=MarkPart::None;
|
||||
std::wstring statusText;
|
||||
std::filesystem::path savedPath;
|
||||
explicit Capture(ScreenshotHost &a) : app(a), autoOpenEditor(a.autoOpenEditor) {}
|
||||
explicit Capture(ScreenshotHost &a) : app(a), autoOpenEditor(a.autoOpenEditor)
|
||||
{
|
||||
if(a.smoothingPreference.empty()) return;
|
||||
try {
|
||||
auto stored=readFile(a.smoothingPreference,1);
|
||||
if(stored.size()==1 && stored.front()<=100) smoothing=stored.front();
|
||||
} catch(const std::exception &) {} // Missing or unreadable preference uses the default.
|
||||
}
|
||||
void saveSmoothingPreference()
|
||||
{
|
||||
if(!smoothingPreferenceDirty || app.smoothingPreference.empty()) return;
|
||||
try {
|
||||
atomicWrite(app.smoothingPreference,Bytes{static_cast<unsigned char>(smoothing)});
|
||||
smoothingPreferenceDirty=false;
|
||||
} catch(const std::exception &) {} // A failed preference write must not interrupt editing.
|
||||
}
|
||||
~Capture() {
|
||||
saveSmoothingPreference();
|
||||
if(pencilCursor) DestroyCursor(pencilCursor);
|
||||
for(auto cursor:drawingCursors) if(cursor) DestroyCursor(cursor);
|
||||
if (font) DeleteObject(font);
|
||||
@@ -1170,8 +1187,14 @@ LRESULT CALLBACK captureProc(HWND w, UINT msg, WPARAM wp, LPARAM lp)
|
||||
setScreenshotSmoothing(c->marks[c->selected],amount);
|
||||
resolveScreenshotLinks(c->marks);
|
||||
c->smoothingDrag=LOWORD(wp)==TB_THUMBTRACK;
|
||||
} else if(!pencil) c->smoothing=amount;
|
||||
if(LOWORD(wp)!=TB_THUMBTRACK) c->smoothingDrag=false;
|
||||
} else if(!pencil && c->smoothing!=amount) {
|
||||
c->smoothing=amount;
|
||||
c->smoothingPreferenceDirty=true;
|
||||
}
|
||||
if(LOWORD(wp)!=TB_THUMBTRACK) {
|
||||
c->smoothingDrag=false;
|
||||
c->saveSmoothingPreference();
|
||||
}
|
||||
syncLineOptions(w,*c); InvalidateRect(w,nullptr,FALSE);
|
||||
return 0;
|
||||
}
|
||||
@@ -1185,7 +1208,11 @@ LRESULT CALLBACK captureProc(HWND w, UINT msg, WPARAM wp, LPARAM lp)
|
||||
if (c->dragging) return 0;
|
||||
if(LOWORD(wp)==44) {
|
||||
int amount=int(SendDlgItemMessageW(w,41,TBM_GETPOS,0,0));
|
||||
c->smoothing=amount;
|
||||
if(c->smoothing!=amount) {
|
||||
c->smoothing=amount;
|
||||
c->smoothingPreferenceDirty=true;
|
||||
}
|
||||
c->saveSmoothingPreference();
|
||||
if(std::any_of(c->marks.begin(),c->marks.end(),[&](const Mark &m){return m.freehand && m.smoothing!=amount;})) {
|
||||
c->remember(c->marks);
|
||||
for(auto &mark:c->marks) if(mark.freehand) setScreenshotSmoothing(mark,amount);
|
||||
|
||||
@@ -9,6 +9,7 @@ struct ScreenshotHost {
|
||||
unsigned windows{};
|
||||
bool (*notify)(const Clip &){};
|
||||
bool autoOpenEditor = false;
|
||||
std::filesystem::path smoothingPreference;
|
||||
};
|
||||
inline constexpr UINT ScreenshotRequest=WM_APP+71, ScreenshotIdle=WM_APP+72;
|
||||
void showScreenshot(ScreenshotHost &);
|
||||
|
||||
@@ -110,6 +110,8 @@ int WINAPI wWinMain(HINSTANCE instance,HINSTANCE,PWSTR,int)
|
||||
InitCommonControlsEx(&controls);
|
||||
ks::ScreenshotHost host{instance};
|
||||
host.notify=ks::notifyScreenshot;
|
||||
try { host.smoothingPreference=ks::dataDirectory()/L"screenshot-smoothing"; }
|
||||
catch(const std::exception &) {} // The editor can still run without local preferences.
|
||||
WNDCLASSW cls{}; cls.hInstance=instance; cls.lpfnWndProc=controller; cls.lpszClassName=ControllerClass;
|
||||
RegisterClassW(&cls);
|
||||
host.window=CreateWindowW(ControllerClass,L"KSwitcher Screenshot",0,0,0,0,0,nullptr,nullptr,instance,&host);
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
#include "platform.h"
|
||||
namespace ks
|
||||
{
|
||||
inline constexpr wchar_t AppVersion[] = L"0.6.76";
|
||||
inline constexpr wchar_t AppVersion[] = L"0.6.77";
|
||||
inline constexpr UINT UpdateMessage = WM_APP + 7;
|
||||
inline constexpr UINT UpdateCheckIntervalMs = 6 * 60 * 60 * 1000;
|
||||
inline constexpr UINT UpdateNotificationRetryMs = 5 * 60 * 1000;
|
||||
|
||||
@@ -14,7 +14,18 @@ int main(int argc, char **argv)
|
||||
std::filesystem::create_directories(root);
|
||||
struct Cleanup {std::filesystem::path root; ~Cleanup(){std::error_code ec; std::filesystem::remove_all(root,ec);}} cleanup{root};
|
||||
ks::ScreenshotHost app{GetModuleHandleW(nullptr)};
|
||||
app.smoothingPreference=root/L"screenshot-smoothing";
|
||||
ks::Capture c(app);
|
||||
require(c.smoothing==25,"missing preference uses default smoothing");
|
||||
c.smoothing=61;
|
||||
c.smoothingPreferenceDirty=true;
|
||||
c.saveSmoothingPreference();
|
||||
ks::Capture reopened(app);
|
||||
require(reopened.smoothing==61,"new editor restores saved smoothing");
|
||||
ks::atomicWrite(app.smoothingPreference,ks::Bytes{101});
|
||||
ks::Capture invalidPreference(app);
|
||||
require(invalidPreference.smoothing==25,"invalid preference uses default smoothing");
|
||||
std::filesystem::remove(app.smoothingPreference);
|
||||
c.image=std::make_unique<ks::Surface>(320,240);
|
||||
PatBlt(c.image->dc,0,0,320,240,WHITENESS);
|
||||
c.marks={ks::Mark{{40,40},{180,140},0}};
|
||||
|
||||
Reference in new issue
Block a user