Release v0.6.3: fix capture banner ordering and check updates periodically
This commit is contained in:
@@ -75,9 +75,11 @@ physical key positions and therefore reset recent-word tracking; selection conve
|
|||||||
Press **Win+Shift+S**, choose **Capture screen region…** in the tray menu, or run
|
Press **Win+Shift+S**, choose **Capture screen region…** in the tray menu, or run
|
||||||
`KSwitcher.exe --capture`. Drag a rectangle on the dimmed, frozen desktop; the selected area stays
|
`KSwitcher.exe --capture`. Drag a rectangle on the dimmed, frozen desktop; the selected area stays
|
||||||
at normal brightness. Escape cancels. Selection and annotation frames are buffered to avoid flicker.
|
at normal brightness. Escape cancels. Selection and annotation frames are buffered to avoid flicker.
|
||||||
The selected area is copied immediately and opens in the editor, even when Windows notifications
|
The selected area is copied immediately, the fullscreen selection is hidden, and a Windows notification
|
||||||
are disabled, suppressed or cannot be sent. Disable **Open editor after screen capture** in settings
|
is sent. Click the notification to open the editor. Enable **Open editor after screen capture** in settings
|
||||||
to open it only by clicking the notification; an immediate notification error still opens the editor.
|
to open it automatically; this option is off by default. An immediate notification error still opens the editor.
|
||||||
|
Existing saved preferences are preserved. Windows Do Not Disturb can send notifications directly to the
|
||||||
|
notification center without showing a banner.
|
||||||
The preference applies to each new capture, including while other editors are open.
|
The preference applies to each new capture, including while other editors are open.
|
||||||
KSwitcher also sends a notification with a thumbnail. Notification identity and activation are registered
|
KSwitcher also sends a notification with a thumbnail. Notification identity and activation are registered
|
||||||
at resident startup and refreshed before sending; registration/submission errors are written to the log.
|
at resident startup and refreshed before sending; registration/submission errors are written to the log.
|
||||||
@@ -158,7 +160,9 @@ Captures use ordinary clipboard history settings and limits. Protected video and
|
|||||||
|
|
||||||
Select **Update** in the tray menu to check the stable Releases of
|
Select **Update** in the tray menu to check the stable Releases of
|
||||||
[this repository](https://gitea.hrynco.com/hrynco/hrynco-kswitcher/releases).
|
[this repository](https://gitea.hrynco.com/hrynco/hrynco-kswitcher/releases).
|
||||||
A startup check also reports an available version, but never installs it automatically.
|
A background check runs shortly after startup and every 6 hours while KSwitcher is running.
|
||||||
|
It reports each available version once per session and never installs automatically.
|
||||||
|
Network failures stay in diagnostics; the next scheduled check retries. You can also check manually at any time.
|
||||||
Confirm the offered version to download and install it. The updater uses the existing
|
Confirm the offered version to download and install it. The updater uses the existing
|
||||||
`KSwitcher-win-x64.zip` and `SHA256SUMS.txt` assets, checks the checksum, package contents, x64
|
`KSwitcher-win-x64.zip` and `SHA256SUMS.txt` assets, checks the checksum, package contents, x64
|
||||||
executable identity and version, then closes and restarts KSwitcher. Downloads and staging happen
|
executable identity and version, then closes and restarts KSwitcher. Downloads and staging happen
|
||||||
|
|||||||
Binary file not shown.
+10
-10
@@ -1,17 +1,17 @@
|
|||||||
# Latest Windows release
|
# Latest Windows release
|
||||||
|
|
||||||
## v0.6.2 — 2026-10-29
|
## v0.6.3 — 2026-10-29
|
||||||
|
|
||||||
- Add **Open editor after screen capture**, enabled by default. Disable it to use notification-first capture; an immediate notification error still opens the editor.
|
- Hide the fullscreen capture selection before submitting a notification when automatic editor opening is disabled. Previously the selection remained visible during submission, which could suppress the banner under Windows fullscreen notification rules.
|
||||||
- Save the preference and apply it to each capture, including requests sent to an already running screenshot process.
|
- Default to capture → notification → click → editor. **Open editor after screen capture** is now off by default; explicitly saved preferences are preserved.
|
||||||
- Register screenshot notification identity, shortcut and COM activation during resident startup, as well as before sending a notification.
|
- Retain the editor fallback for immediate notification errors.
|
||||||
- Log notification registration and submission errors when logging is enabled.
|
- Check for updates in the background every 6 hours after the startup check. Notify once per version per session, retry after network failures at the next interval, and install only after confirmation.
|
||||||
- Refresh clipboard history preview row heights when display DPI changes.
|
|
||||||
|
|
||||||
Verified: 175 native checks, 397 input/layout checks at 240 DPI, screenshot editor UI integration,
|
Verified: 176 native checks, 403 input/layout checks at 240 DPI, screenshot editor UI integration,
|
||||||
isolated notification registration checks, and 45 updater checks. A physical transition between
|
isolated notification registration checks, and 45 updater checks. The new UI regression test failed
|
||||||
monitors with different DPI has not been tested. Successful notification submission does not
|
before the fix and passes afterward: the selection is hidden at notification submission.
|
||||||
guarantee a visible Windows banner; asynchronous toast failures are not yet monitored.
|
Banner behavior still needs confirmation on the affected laptop. Windows Do Not Disturb can
|
||||||
|
send notifications directly to the notification center; asynchronous toast failures are not yet monitored.
|
||||||
|
|
||||||
**Upgrade:** choose Update in the tray menu. Legacy v0.3.0–v0.4.1 clients first receive the
|
**Upgrade:** choose Update in the tray menu. Legacy v0.3.0–v0.4.1 clients first receive the
|
||||||
v0.4.2 compatibility bridge, then the current full release. v0.2.3 and earlier require manual installation.
|
v0.4.2 compatibility bridge, then the current full release. v0.2.3 and earlier require manual installation.
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
e0c5a7b4f225ee32790f01ec916ae4706783b7e50b0bf6816c38ae2a6685d43d KSwitcher-win-x64.zip
|
a43786b06878da0f069dbad0fa29587a736dd2d8904c7bc991f5cf0c0570a16f KSwitcher-win-x64.zip
|
||||||
|
|||||||
+3
-3
@@ -9,8 +9,8 @@ IDC_SCREENSHOT_PENCIL CURSOR "icons/lucide/pencil.cur"
|
|||||||
1 RT_MANIFEST "app.manifest"
|
1 RT_MANIFEST "app.manifest"
|
||||||
201 RCDATA "update.ps1"
|
201 RCDATA "update.ps1"
|
||||||
1 VERSIONINFO
|
1 VERSIONINFO
|
||||||
FILEVERSION 0,6,2,0
|
FILEVERSION 0,6,3,0
|
||||||
PRODUCTVERSION 0,6,2,0
|
PRODUCTVERSION 0,6,3,0
|
||||||
FILEOS VOS_NT_WINDOWS32
|
FILEOS VOS_NT_WINDOWS32
|
||||||
FILETYPE VFT_APP
|
FILETYPE VFT_APP
|
||||||
BEGIN
|
BEGIN
|
||||||
@@ -20,7 +20,7 @@ BEGIN
|
|||||||
BEGIN
|
BEGIN
|
||||||
VALUE "FileDescription", "KSwitcher — native keyboard and clipboard utility"
|
VALUE "FileDescription", "KSwitcher — native keyboard and clipboard utility"
|
||||||
VALUE "ProductName", "KSwitcher"
|
VALUE "ProductName", "KSwitcher"
|
||||||
VALUE "FileVersion", "0.6.2"
|
VALUE "FileVersion", "0.6.3"
|
||||||
END
|
END
|
||||||
END
|
END
|
||||||
BLOCK "VarFileInfo"
|
BLOCK "VarFileInfo"
|
||||||
|
|||||||
+6
-3
@@ -1254,8 +1254,9 @@ LRESULT CALLBACK App::windowProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
|
|||||||
if (MessageBoxW(hwnd, prompt.c_str(), L"KSwitcher Update", MB_YESNO | MB_ICONQUESTION) == IDYES)
|
if (MessageBoxW(hwnd, prompt.c_str(), L"KSwitcher Update", MB_YESNO | MB_ICONQUESTION) == IDYES)
|
||||||
app->checkUpdate(true, true, result->version);
|
app->checkUpdate(true, true, result->version);
|
||||||
}
|
}
|
||||||
else
|
else if (app->notifiedUpdate != result->version)
|
||||||
{
|
{
|
||||||
|
app->notifiedUpdate = result->version;
|
||||||
NOTIFYICONDATAW icon{sizeof(icon)};
|
NOTIFYICONDATAW icon{sizeof(icon)};
|
||||||
icon.hWnd = hwnd; icon.uID = 1; icon.uFlags = NIF_INFO; icon.dwInfoFlags = NIIF_INFO;
|
icon.hWnd = hwnd; icon.uID = 1; icon.uFlags = NIF_INFO; icon.dwInfoFlags = NIIF_INFO;
|
||||||
wcscpy_s(icon.szInfoTitle, L"KSwitcher update available");
|
wcscpy_s(icon.szInfoTitle, L"KSwitcher update available");
|
||||||
@@ -1274,7 +1275,7 @@ LRESULT CALLBACK App::windowProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
|
|||||||
else if (result->interactive)
|
else if (result->interactive)
|
||||||
MessageBoxW(hwnd, (L"Update failed.\n\n" + result->error).c_str(), L"KSwitcher Update", MB_OK | MB_ICONERROR);
|
MessageBoxW(hwnd, (L"Update failed.\n\n" + result->error).c_str(), L"KSwitcher Update", MB_OK | MB_ICONERROR);
|
||||||
else
|
else
|
||||||
diagnosticEvent(L"Startup update check failed: " + result->error);
|
diagnosticEvent(L"Background update check failed: " + result->error);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
case WM_HOTKEY:
|
case WM_HOTKEY:
|
||||||
@@ -1338,7 +1339,9 @@ LRESULT CALLBACK App::windowProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
|
|||||||
case WM_TIMER:
|
case WM_TIMER:
|
||||||
if (wp == 5)
|
if (wp == 5)
|
||||||
{
|
{
|
||||||
KillTimer(hwnd, 5);
|
// After the initial 5-second check, repeat while the resident stays open.
|
||||||
|
// Rearm even when a check is already running or the previous one failed.
|
||||||
|
SetTimer(hwnd, 5, UpdateCheckIntervalMs, nullptr);
|
||||||
app->checkUpdate(false);
|
app->checkUpdate(false);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ class App
|
|||||||
std::thread worker;
|
std::thread worker;
|
||||||
std::thread updateWorker;
|
std::thread updateWorker;
|
||||||
bool updateRunning{}, installingUpdate{};
|
bool updateRunning{}, installingUpdate{};
|
||||||
std::wstring availableUpdate;
|
std::wstring availableUpdate, notifiedUpdate;
|
||||||
bool stop{};
|
bool stop{};
|
||||||
UINT taskbarCreated{};
|
UINT taskbarCreated{};
|
||||||
uint64_t pendingAutoVersion{};
|
uint64_t pendingAutoVersion{};
|
||||||
|
|||||||
+1
-1
@@ -48,7 +48,7 @@ struct Settings
|
|||||||
bool elevatedAutostart = false;
|
bool elevatedAutostart = false;
|
||||||
bool autoCorrect = false;
|
bool autoCorrect = false;
|
||||||
bool writeLog = true;
|
bool writeLog = true;
|
||||||
bool screenshotAutoOpenEditor = true;
|
bool screenshotAutoOpenEditor = false;
|
||||||
int autoMaxRank = 0;
|
int autoMaxRank = 0;
|
||||||
int autoMinLength = 3;
|
int autoMinLength = 3;
|
||||||
std::wstring autoPrefixChars = L"([{«“‘\"";
|
std::wstring autoPrefixChars = L"([{«“‘\"";
|
||||||
|
|||||||
@@ -815,6 +815,9 @@ void finishSelection(HWND w,Capture &c,DWORD (*publish)(HWND,const Clip &)=write
|
|||||||
c.copied=true;
|
c.copied=true;
|
||||||
// A successful toast submission does not guarantee that Windows shows a banner.
|
// A successful toast submission does not guarantee that Windows shows a banner.
|
||||||
if(c.autoOpenEditor) edit(w,c);
|
if(c.autoOpenEditor) edit(w,c);
|
||||||
|
// Leave fullscreen capture before submitting the toast: Windows may suppress
|
||||||
|
// banners while a fullscreen application is visible.
|
||||||
|
else ShowWindow(w,SW_HIDE);
|
||||||
bool notified=c.app.notify(clip);
|
bool notified=c.app.notify(clip);
|
||||||
if(!c.autoOpenEditor) {
|
if(!c.autoOpenEditor) {
|
||||||
if(notified) DestroyWindow(w);
|
if(notified) DestroyWindow(w);
|
||||||
|
|||||||
+1
-1
@@ -8,7 +8,7 @@ struct ScreenshotHost {
|
|||||||
HWND window{};
|
HWND window{};
|
||||||
unsigned windows{};
|
unsigned windows{};
|
||||||
bool (*notify)(const Clip &){};
|
bool (*notify)(const Clip &){};
|
||||||
bool autoOpenEditor = true;
|
bool autoOpenEditor = false;
|
||||||
};
|
};
|
||||||
inline constexpr UINT ScreenshotRequest=WM_APP+71, ScreenshotIdle=WM_APP+72;
|
inline constexpr UINT ScreenshotRequest=WM_APP+71, ScreenshotIdle=WM_APP+72;
|
||||||
void showScreenshot(ScreenshotHost &);
|
void showScreenshot(ScreenshotHost &);
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ LRESULT CALLBACK controller(HWND window,UINT message,WPARAM wp,LPARAM lp)
|
|||||||
int WINAPI wWinMain(HINSTANCE instance,HINSTANCE,PWSTR,int)
|
int WINAPI wWinMain(HINSTANCE instance,HINSTANCE,PWSTR,int)
|
||||||
{
|
{
|
||||||
std::wstring token;
|
std::wstring token;
|
||||||
bool autoOpenEditor=true, writeLog=false;
|
bool autoOpenEditor=false, writeLog=false;
|
||||||
int argc{}; auto argv=CommandLineToArgvW(GetCommandLineW(),&argc);
|
int argc{}; auto argv=CommandLineToArgvW(GetCommandLineW(),&argc);
|
||||||
if(argc>1 && std::wstring(argv[argc-1])==L"--write-log") {
|
if(argc>1 && std::wstring(argv[argc-1])==L"--write-log") {
|
||||||
writeLog=true; --argc;
|
writeLog=true; --argc;
|
||||||
|
|||||||
+1
-1
@@ -151,7 +151,7 @@ Settings decodeSettings(const Bytes &bytes, const std::vector<Layout> &layouts)
|
|||||||
s.undo = str(j, "undoHotkey", s.undo);
|
s.undo = str(j, "undoHotkey", s.undo);
|
||||||
s.clipboard = str(j, "clipboardHotkey", s.clipboard);
|
s.clipboard = str(j, "clipboardHotkey", s.clipboard);
|
||||||
s.screenshot = str(j, "screenshotHotkey", s.screenshot);
|
s.screenshot = str(j, "screenshotHotkey", s.screenshot);
|
||||||
s.screenshotAutoOpenEditor = j.value("screenshotAutoOpenEditor", true);
|
s.screenshotAutoOpenEditor = j.value("screenshotAutoOpenEditor", false);
|
||||||
if (j.contains("layouts"))
|
if (j.contains("layouts"))
|
||||||
{
|
{
|
||||||
s.cycle.clear();
|
s.cycle.clear();
|
||||||
|
|||||||
+2
-1
@@ -2,8 +2,9 @@
|
|||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
namespace ks
|
namespace ks
|
||||||
{
|
{
|
||||||
inline constexpr wchar_t AppVersion[] = L"0.6.2";
|
inline constexpr wchar_t AppVersion[] = L"0.6.3";
|
||||||
inline constexpr UINT UpdateMessage = WM_APP + 7;
|
inline constexpr UINT UpdateMessage = WM_APP + 7;
|
||||||
|
inline constexpr UINT UpdateCheckIntervalMs = 6 * 60 * 60 * 1000;
|
||||||
struct UpdateResult
|
struct UpdateResult
|
||||||
{
|
{
|
||||||
std::wstring state, version, error;
|
std::wstring state, version, error;
|
||||||
|
|||||||
+21
-1
@@ -7,6 +7,20 @@
|
|||||||
namespace ks {
|
namespace ks {
|
||||||
struct InputRegressionAccess {
|
struct InputRegressionAccess {
|
||||||
static void setup(App &a) { a.hookBindings = {{Toggle,{MOD_CONTROL,VK_F12}}, {Case,{MOD_CONTROL|MOD_SHIFT,'U'}}}; }
|
static void setup(App &a) { a.hookBindings = {{Toggle,{MOD_CONTROL,VK_F12}}, {Case,{MOD_CONTROL|MOD_SHIFT,'U'}}}; }
|
||||||
|
static bool updateTimer(App &a) {
|
||||||
|
a.updateRunning=true; // Exercise timer scheduling without launching a network request.
|
||||||
|
App::windowProc(a.window,WM_TIMER,5,0);
|
||||||
|
bool first=KillTimer(a.window,5)!=FALSE;
|
||||||
|
App::windowProc(a.window,WM_TIMER,5,0);
|
||||||
|
bool repeated=KillTimer(a.window,5)!=FALSE;
|
||||||
|
a.updateRunning=false;
|
||||||
|
return first && repeated && !a.updateWorker.joinable();
|
||||||
|
}
|
||||||
|
static std::wstring updateResult(App &a,const wchar_t *state,const wchar_t *version) {
|
||||||
|
auto result=new UpdateResult; result->state=state; result->version=version;
|
||||||
|
App::windowProc(a.window,UpdateMessage,0,(LPARAM)result);
|
||||||
|
return a.notifiedUpdate;
|
||||||
|
}
|
||||||
static void click() { MSLLHOOKSTRUCT m{}; m.flags=LLMHF_INJECTED; App::mouseProc(HC_ACTION,WM_LBUTTONDOWN,(LPARAM)&m); }
|
static void click() { MSLLHOOKSTRUCT m{}; m.flags=LLMHF_INJECTED; App::mouseProc(HC_ACTION,WM_LBUTTONDOWN,(LPARAM)&m); }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -31,6 +45,12 @@ int main(int argc, char **argv) {
|
|||||||
// Message-only window: no hooks, synthetic input, clipboard changes or visible editor.
|
// Message-only window: no hooks, synthetic input, clipboard changes or visible editor.
|
||||||
app.window=CreateWindowExW(0,L"STATIC",L"Input tests",0,0,0,0,0,HWND_MESSAGE,nullptr,nullptr,nullptr);
|
app.window=CreateWindowExW(0,L"STATIC",L"Input tests",0,0,0,0,0,HWND_MESSAGE,nullptr,nullptr,nullptr);
|
||||||
require(app.window!=nullptr,"message-only test window");
|
require(app.window!=nullptr,"message-only test window");
|
||||||
|
require(ks::UpdateCheckIntervalMs==21600000,"automatic update interval is six hours");
|
||||||
|
require(ks::InputRegressionAccess::updateTimer(app),"update timer rearms and avoids overlapping checks");
|
||||||
|
require(ks::InputRegressionAccess::updateResult(app,L"available",L"99.0.0")==L"99.0.0","background update records announced version");
|
||||||
|
require(ks::InputRegressionAccess::updateResult(app,L"available",L"99.0.0")==L"99.0.0","same available version remains deduplicated");
|
||||||
|
require(ks::InputRegressionAccess::updateResult(app,L"error",L"")==L"99.0.0","network error preserves announced version");
|
||||||
|
require(ks::InputRegressionAccess::updateResult(app,L"available",L"99.0.1")==L"99.0.1","new version can be announced after an error");
|
||||||
for(int variant=0;variant<3;++variant) for(int icon=0;icon<15;++icon)
|
for(int variant=0;variant<3;++variant) for(int icon=0;icon<15;++icon)
|
||||||
for(int size:{22,44,55}) {
|
for(int size:{22,44,55}) {
|
||||||
auto handle=(HICON)LoadImageW(app.instance,MAKEINTRESOURCEW(icon<9?300+variant*10+icon:400+variant*10+icon-9),IMAGE_ICON,size,size,0);
|
auto handle=(HICON)LoadImageW(app.instance,MAKEINTRESOURCEW(icon<9?300+variant*10+icon:400+variant*10+icon-9),IMAGE_ICON,size,size,0);
|
||||||
@@ -509,7 +529,7 @@ int main(int argc, char **argv) {
|
|||||||
require(EqualRect(&listBefore,&(listAfter=childRect(102))),"DPI refresh preserves history list geometry");
|
require(EqualRect(&listBefore,&(listAfter=childRect(102))),"DPI refresh preserves history list geometry");
|
||||||
}
|
}
|
||||||
auto settings=app.settingsWindow;
|
auto settings=app.settingsWindow;
|
||||||
require(SendDlgItemMessageW(settings,209,BM_GETCHECK,0,0)==BST_CHECKED,"automatic screenshot editor checkbox defaults on");
|
require(SendDlgItemMessageW(settings,209,BM_GETCHECK,0,0)==BST_UNCHECKED,"automatic screenshot editor checkbox defaults off");
|
||||||
require(settings&&!IsWindowVisible(settings),"settings layout tested without changing user focus");
|
require(settings&&!IsWindowVisible(settings),"settings layout tested without changing user focus");
|
||||||
for(auto pair:{std::pair{209,215},std::pair{209,207},std::pair{209,220},std::pair{209,232},std::pair{207,215},std::pair{207,232},std::pair{207,220},std::pair{232,230},std::pair{230,231},std::pair{231,253}}) {
|
for(auto pair:{std::pair{209,215},std::pair{209,207},std::pair{209,220},std::pair{209,232},std::pair{207,215},std::pair{207,232},std::pair{207,220},std::pair{232,230},std::pair{230,231},std::pair{231,253}}) {
|
||||||
RECT first{},second{},overlap{};
|
RECT first{},second{},overlap{};
|
||||||
|
|||||||
@@ -165,8 +165,12 @@ int main()
|
|||||||
require(!IsWindow(window),"copied screenshot closes without confirmation");
|
require(!IsWindow(window),"copied screenshot closes without confirmation");
|
||||||
static bool published=false;
|
static bool published=false;
|
||||||
static bool notificationAccepted=false;
|
static bool notificationAccepted=false;
|
||||||
|
static HWND notificationWindow{};
|
||||||
|
static bool expectHidden=false;
|
||||||
app.notify=[](const ks::Clip &) {
|
app.notify=[](const ks::Clip &) {
|
||||||
if(!published) throw std::runtime_error("notification preceded clipboard publication");
|
if(!published) throw std::runtime_error("notification preceded clipboard publication");
|
||||||
|
if(expectHidden && IsWindowVisible(notificationWindow))
|
||||||
|
throw std::runtime_error("selection overlay is still visible when notification is sent");
|
||||||
return notificationAccepted;
|
return notificationAccepted;
|
||||||
};
|
};
|
||||||
for(bool autoOpen : {true,false}) for (bool accepted : {true, false}) {
|
for(bool autoOpen : {true,false}) for (bool accepted : {true, false}) {
|
||||||
@@ -178,6 +182,8 @@ int main()
|
|||||||
PatBlt(selection.image->dc,0,0,100,100,WHITENESS);
|
PatBlt(selection.image->dc,0,0,100,100,WHITENESS);
|
||||||
selection.start={10,20}; selection.end={70,60};
|
selection.start={10,20}; selection.end={70,60};
|
||||||
auto overlay=CreateWindowW(cls.lpszClassName,L"Selection test",WS_POPUP,0,0,100,100,app.window,nullptr,app.instance,&selection);
|
auto overlay=CreateWindowW(cls.lpszClassName,L"Selection test",WS_POPUP,0,0,100,100,app.window,nullptr,app.instance,&selection);
|
||||||
|
notificationWindow=overlay; expectHidden=!autoOpen;
|
||||||
|
ShowWindow(overlay,SW_SHOWNOACTIVATE);
|
||||||
ks::finishSelection(overlay,selection,[](HWND,const ks::Clip &clip)->DWORD {
|
ks::finishSelection(overlay,selection,[](HWND,const ks::Clip &clip)->DWORD {
|
||||||
auto pixels=ks::decodeImage(clip);
|
auto pixels=ks::decodeImage(clip);
|
||||||
if(pixels.width!=60 || pixels.height!=40) throw std::runtime_error("automatic copy did not crop selection");
|
if(pixels.width!=60 || pixels.height!=40) throw std::runtime_error("automatic copy did not crop selection");
|
||||||
|
|||||||
+4
-1
@@ -430,7 +430,10 @@ int main(int argc, char **argv)
|
|||||||
auto invalid = settings;
|
auto invalid = settings;
|
||||||
auto captureSettings = settings;
|
auto captureSettings = settings;
|
||||||
captureSettings.screenshot = L"Ctrl+Shift+F9";
|
captureSettings.screenshot = L"Ctrl+Shift+F9";
|
||||||
require(captureSettings.screenshotAutoOpenEditor,"editor opens by default");
|
require(!captureSettings.screenshotAutoOpenEditor,"notification-first capture is the default");
|
||||||
|
captureSettings.screenshotAutoOpenEditor=true;
|
||||||
|
require(ks::decodeSettings(ks::encodeSettings(captureSettings), {}).screenshotAutoOpenEditor,
|
||||||
|
"explicit automatic editor preference survives settings roundtrip");
|
||||||
captureSettings.screenshotAutoOpenEditor=false;
|
captureSettings.screenshotAutoOpenEditor=false;
|
||||||
require(!ks::decodeSettings(ks::encodeSettings(captureSettings), {}).screenshotAutoOpenEditor,
|
require(!ks::decodeSettings(ks::encodeSettings(captureSettings), {}).screenshotAutoOpenEditor,
|
||||||
"notification-first preference survives settings roundtrip");
|
"notification-first preference survives settings roundtrip");
|
||||||
|
|||||||
Reference in New Issue
Block a user