Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
54c3604
Save to Disk + Bug fixes
Aemony Mar 20, 2026
262eba5
Sort from File Explorer + Delete + menu changes
Aemony Mar 22, 2026
8488d0d
Improved sort handling (esp. with network shares)
Aemony Mar 22, 2026
63dffaf
Added native context menu
Aemony Mar 22, 2026
7b26d53
Improvements to reduce overhead on folder changes
Aemony Mar 22, 2026
0b6a681
Prune temporary files, leaving only the 10 latest
Aemony Mar 23, 2026
152938d
Offload folder scan/refresh to a background thread
Aemony Mar 23, 2026
9251ac3
Optimized background folder refresh a bit
Aemony Mar 24, 2026
65834d3
Added toggles for hotkeys w/o unbinding keys
Aemony Mar 24, 2026
085f99d
Added context menu to Settings tab
Aemony Mar 24, 2026
e81bf4e
Added save to disk toggle to the region toolbar
Aemony Mar 24, 2026
8ba6b1a
Snipping Toolbar: Select File + Hotkeys!
Aemony Mar 25, 2026
c3e6168
Fixed Snip: Select File being persistent
Aemony Mar 25, 2026
4d27383
Minor improvements to notification toasts
Aemony Mar 25, 2026
8dc8c24
Bump SDK to stop GitHub Actions from failing
Aemony Mar 25, 2026
ecc0d7e
Disable Viewer hotkeys while on the Settings tab
Aemony Mar 25, 2026
881c6b2
Added configurable naming scheme for screenshots
Aemony Mar 25, 2026
4eb001a
Vista-style folder picker!
Aemony Mar 26, 2026
9b3a998
Added support for retrieving alternate names
Aemony Mar 26, 2026
4817acc
Fixed path bug when trying to delete a paste
Aemony Mar 27, 2026
cd1d748
I dunno know what I'm doing or where we're heading
Aemony Mar 27, 2026
e082dca
Implement manually managed window size + position
Aemony Apr 7, 2026
f06b1c0
Changed setting name to match SKIF
Aemony Apr 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion SKIV.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
<ProjectGuid>{93301458-CC3B-4924-B659-EB190D6EF9EB}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>SKIV</RootNamespace>
<WindowsTargetPlatformVersion>10.0.22621.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
Expand Down
2 changes: 1 addition & 1 deletion include/tabs/viewer.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,4 @@ enum ImageScaling {
};

uint32_t SKIV_Viewer_CycleVisualizationModes (void);
ImageScaling SKIV_Viewer_CycleScalingModes (void);
ImageScaling SKIV_Viewer_CycleScalingModes (void);
2 changes: 1 addition & 1 deletion include/utility/fsutil.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ struct SKIF_CommonPathsCache {
wchar_t skiv_install [MAX_PATH + 2] = { }; // Holds the install folder for SKIV
wchar_t skiv_userdata [MAX_PATH + 2] = { }; // Holds the user data folder for SKIV
wchar_t specialk_userdata [MAX_PATH + 2] = { }; // Holds the user data folder for SK (often lines up with its install folder)
wchar_t skiv_temp [MAX_PATH + 2] = { }; // Holds the temp data folder for SKIV (images downloaded from the web; cleared out on every launch): %APPDATA%\TEMP\SKIV
wchar_t skiv_temp [MAX_PATH + 2] = { }; // Holds the temp data folder for SKIV (images downloaded from the web; cleared out on every launch): "%APPDATA%\TEMP\SKIV\"
wchar_t skiv_screenshots [MAX_PATH + 2] = { }; // Holds the screenshot folder for SKIV
char skiv_screenshotsA [MAX_PATH + 2] = { }; // UTF-8

Expand Down
164 changes: 156 additions & 8 deletions include/utility/image.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <imgui/imgui_internal.h>
#include <ImGuiNotify.hpp>
#include <atlbase.h>
#include "utility.h"

#pragma warning( push )
#pragma warning( disable : 4305 )
Expand Down Expand Up @@ -134,14 +135,30 @@ static const ParamsPQ PQ =

#pragma warning( pop )

struct SKIV_Region {
ImRect _rect;
std::wstring _title;

SKIV_Region (ImRect r_ = ImRect(), std::wstring t_ = L"")
struct SKIV_CaptureData {
ImRect _rect;
struct Application {
std::wstring custom; // #1 - SK/SKIF profiles name
std::wstring product; // #2 - Product name from executable
std::wstring executable; // #3 - Executable filename
std::wstring window; // -optional-
} _names;
CaptureMode _mode;
bool _select = false;
HWND _hwnd = NULL;

SKIV_CaptureData (ImRect r_, Application n_, CaptureMode m_)
{
_rect = r_;
_title = t_;
_names = n_;
_mode = m_;
}

SKIV_CaptureData (ImRect r_, std::wstring t_, CaptureMode m_)
{
_rect = r_;
_mode = m_;
_names.custom = t_;
}
};

Expand All @@ -152,11 +169,11 @@ float SKIV_Image_LinearToPQY (float N);
DirectX::XMVECTOR SKIV_Image_Rec709toICtCp (DirectX::XMVECTOR N);
DirectX::XMVECTOR SKIV_Image_ICtCptoRec709 (DirectX::XMVECTOR N);

bool SKIV_Image_CopyToClipboard (const DirectX::Image* pImage, bool isHDR, bool isTemp, const wchar_t* wszFileName);
bool SKIV_Image_CopyToClipboard (const DirectX::Image* pImage, bool isHDR, SKIV_CaptureData capture_data);
HRESULT SKIV_Image_SaveToDisk_HDR (const DirectX::Image& image, const wchar_t* wszFileName);
HRESULT SKIV_Image_SaveToDisk_SDR (const DirectX::Image& image, const wchar_t* wszFileName, bool force_sRGB);
HRESULT SKIV_Image_CaptureDesktop (DirectX::ScratchImage& image, POINT pos, int flags = 0x0);
void SKIV_Image_CaptureRegion (SKIV_Region capture_area);
void SKIV_Image_CaptureRegion (SKIV_CaptureData capture_data);
HRESULT SKIV_Image_TonemapToSDR (const DirectX::Image& image, DirectX::ScratchImage& final_sdr, float mastering_max_nits, float mastering_sdr_nits);

bool SKIV_Image_IsUltraHDR (const wchar_t* wszFileName);
Expand Down Expand Up @@ -277,4 +294,135 @@ struct skiv_image_desktop_s {
_max_display_nits = 1000.0f;
_rotation = DXGI_MODE_ROTATION_UNSPECIFIED;
}
};

// Image Directory

#include <shobjidl_core.h>

struct skiv_image_directory_s {

class FileSystemBindData : public IFileSystemBindData
{
public:
FileSystemBindData() : _ref(1)
{
ZeroMemory(&_fd, sizeof(_fd));
}

// IUnknown
IFACEMETHODIMP QueryInterface(REFIID riid, void** ppv) override
{
if (riid == IID_IUnknown || riid == IID_IFileSystemBindData)
{
*ppv = static_cast<IFileSystemBindData*>(this);
AddRef();
return S_OK;
}
*ppv = nullptr;
return E_NOINTERFACE;
}

IFACEMETHODIMP_(ULONG) AddRef() override
{
return InterlockedIncrement(&_ref);
}

IFACEMETHODIMP_(ULONG) Release() override
{
ULONG r = InterlockedDecrement(&_ref);
if (r == 0) delete this;
return r;
}

// IFileSystemBindData
IFACEMETHODIMP SetFindData (const WIN32_FIND_DATAW* pfd) override
{
_fd = *pfd;
return S_OK;
}

IFACEMETHODIMP GetFindData (WIN32_FIND_DATAW* pfd) override
{
*pfd = _fd;
return S_OK;
}

private:
~FileSystemBindData() = default;

LONG _ref;
WIN32_FIND_DATAW _fd;
};

struct fd_s {
std::wstring filename; // Image filename
//std::wstring folder_path; // Parent folder path
std::wstring path; // Image path (full)
WIN32_FIND_DATA ffd;
};

struct fl_s {
fd_s* getActiveFile (void)
{
return (_ptr != nullptr) ? _ptr : nullptr;
}

std::vector<fd_s> getList (void)
{
return _list;
}

void setList (std::vector<fd_s> list)
{
_list = std::move(list);
_it = _list.end();
_ptr = _it._Ptr;
}

void clear (void)
{
_list.clear();
_it = _list.end();
_ptr = nullptr;
}

bool empty (void)
{
return _list.empty();
}

void setImage (const std::wstring& path);
std::wstring nextImage (void);
std::wstring prevImage (void);
std::wstring deleteImage (void);
void updateFileIterator (const std::wstring& path); // Find the position of the image in the current folder

bool fileDeleted = false;

private:
std::vector<fd_s> _list;
std::vector<fd_s>::iterator _it;
fd_s* _ptr;
} fileList;

//std::wstring orig_path; // Holds a cached copy of cover.path
//std::wstring filename; // Image filename
std::wstring folder_path; // Parent folder path
SKIF_DirectoryWatch watch;


std::vector<SORTCOLUMN> sortColumns; // File Explorer

void reset (void);

// Retrieve all files in the folder, and identify our current place among them...
int workerThread (bool runThread); // 0 = Not done, 1 = No change in sort order (i.e. same files as before) , 2 = Change in the sort order (i.e. new files/folder)

// Win32 File Explorer based sorting
private:
static bool updateFolderData (std::vector<fd_s>& list, std::vector<SORTCOLUMN>& sortColumns, const std::wstring& path);
static void updateSortOrder (std::vector<fd_s>& list, std::vector<SORTCOLUMN>& sortColumns, const std::wstring& path);
static void sortByColumns (std::vector<fd_s>& list, const std::vector<SORTCOLUMN>& sortColumns);
static void sortByFilename (std::vector<fd_s>& list);
};
67 changes: 49 additions & 18 deletions include/utility/registry.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#include <typeindex>
#include <sstream>
#include <vector>
#include "sk_utility.h"
#include "utility.h"

#ifndef RRF_SUBKEY_WOW6464KEY
#define RRF_SUBKEY_WOW6464KEY 0x00010000
Expand Down Expand Up @@ -265,10 +265,6 @@ struct SKIF_RegistrySettings {
SKIF_MakeRegKeyB ( LR"(SOFTWARE\Kaldaien\Special K\Viewer\)",
LR"(99th Percentile MaxCLL)" );

KeyValue <bool> regKVSaveScreenshots =
SKIF_MakeRegKeyB ( LR"(SOFTWARE\Kaldaien\Special K\Viewer\)",
LR"(Save Screenshots)" );

// Integers (DWORDs)

KeyValue <int> regKVImageScaling =
Expand Down Expand Up @@ -311,6 +307,22 @@ struct SKIF_RegistrySettings {
SKIF_MakeRegKeyI ( LR"(SOFTWARE\Kaldaien\Special K\Viewer\)",
LR"(UI Mode)" );

KeyValue <int> regKVUIWidth =
SKIF_MakeRegKeyI ( LR"(SOFTWARE\Kaldaien\Special K\Viewer\)",
LR"(UI Width)" );

KeyValue <int> regKVUIHeight =
SKIF_MakeRegKeyI ( LR"(SOFTWARE\Kaldaien\Special K\Viewer\)",
LR"(UI Height)" );

KeyValue <int> regKVUIPositionX =
SKIF_MakeRegKeyI ( LR"(SOFTWARE\Kaldaien\Special K\Viewer\)",
LR"(UI Position X)" );

KeyValue <int> regKVUIPositionY =
SKIF_MakeRegKeyI ( LR"(SOFTWARE\Kaldaien\Special K\Viewer\)",
LR"(UI Position Y)" );

KeyValue <int> regKVDiagnostics =
SKIF_MakeRegKeyI ( LR"(SOFTWARE\Kaldaien\Special K\Viewer\)",
LR"(Diagnostics)" );
Expand Down Expand Up @@ -347,6 +359,14 @@ struct SKIF_RegistrySettings {
SKIF_MakeRegKeyI ( LR"(SOFTWARE\Kaldaien\Special K\Viewer\PNG\)",
LR"(HDR BitDepth)" );

KeyValue <int> regKVScreenshotsAutosave =
SKIF_MakeRegKeyI ( LR"(SOFTWARE\Kaldaien\Special K\Viewer\)",
LR"(Screenshots Autosave)" );

KeyValue <int> regKVScreenshotsHotkeys =
SKIF_MakeRegKeyI ( LR"(SOFTWARE\Kaldaien\Special K\Viewer\)",
LR"(Screenshots Hotkeys)" );

// Wide Strings

KeyValue <std::wstring> regKVIgnoreUpdate =
Expand All @@ -365,6 +385,10 @@ struct SKIF_RegistrySettings {
SKIF_MakeRegKeyWS ( LR"(SOFTWARE\Kaldaien\Special K\Viewer\)",
LR"(Screenshots)" );

KeyValue <std::wstring> regKVScreenshotsPattern =
SKIF_MakeRegKeyWS ( LR"(SOFTWARE\Kaldaien\Special K\Viewer\)",
LR"(Screenshots Pattern)" );

KeyValue <std::wstring> regKVAutoUpdateVersion =
SKIF_MakeRegKeyWS ( LR"(SOFTWARE\Kaldaien\Special K\Viewer\)",
LR"(Auto-Update Version)" );
Expand Down Expand Up @@ -419,18 +443,24 @@ struct SKIF_RegistrySettings {
LR"(AppsUseLightTheme)" );

// Default settings (multiple options)
//int iImageScaling = 2; // 0 = None, 1 = Fill, 2 = Fit (default), 3 = Stretch
int iStyle = 0; // 0 = Dynamic, 1 = SKIF Dark, 2 = SKIF Light, 3 = ImGui Classic, 4 = ImGui Dark
int iStyleTemp = 0; // Used to temporary hold changes in the style during the current session
int iDarkenImages = 0; // 0 = Never, 1 = Always, 2 = On mouse hover
int iCheckForUpdates = 1; // 0 = Never, 1 = Weekly, 2 = On each launch
int iLogging = 4; // 0 = None, 1 = Fatal, 2 = Error, 3 = Warning, 4 = Info, 5 = Debug, 6 = Verbose
int iSDRMode = 0; // 0 = 8 bpc, 1 = 10 bpc, 2 = 16 bpc
int iHDRMode = 2; // 0 = Disabled, 1 = HDR10 (10 bpc), 2 = scRGB (16 bpc)
//int iImageScaling = 2; // 0 = None, 1 = Fill, 2 = Fit (default), 3 = Stretch
int iStyle = 0; // 0 = Dynamic, 1 = SKIF Dark, 2 = SKIF Light, 3 = ImGui Classic, 4 = ImGui Dark
int iStyleTemp = 0; // Used to temporary hold changes in the style during the current session
int iDarkenImages = 0; // 0 = Never, 1 = Always, 2 = On mouse hover
int iCheckForUpdates = 1; // 0 = Never, 1 = Weekly, 2 = On each launch
int iLogging = 4; // 0 = None, 1 = Fatal, 2 = Error, 3 = Warning, 4 = Info, 5 = Debug, 6 = Verbose
int iSDRMode = 0; // 0 = 8 bpc, 1 = 10 bpc, 2 = 16 bpc
int iHDRMode = 2; // 0 = Disabled, 1 = HDR10 (10 bpc), 2 = scRGB (16 bpc)
int iHDRBrightness = 203; // HDR reference white for BT.2408
int iHDRToneMapType = 8; // 0 = Do Nothing, 1 = Clip Luminance, 8 = Map to Display
int iUIMode = 1; // 0 = Safe Mode (BitBlt), 1 = Normal, 2 = VRR Compatibility
int iDiagnostics = 1; // 0 = None, 1 = Normal, 2 = Enhanced (not actually used yet)
int iHDRToneMapType = 8; // 0 = Do Nothing, 1 = Clip Luminance, 8 = Map to Display
int iUIMode = 1; // 0 = Safe Mode (BitBlt), 1 = Normal, 2 = VRR Compatibility
int iDiagnostics = 1; // 0 = None, 1 = Normal, 2 = Enhanced (not actually used yet)
int iUIWidth = 0; // 0 = None (default)
int iUIHeight = 0; // 0 = None (default)
int iUIPositionX = -1; // -1 = None (default)
int iUIPositionY = -1; // -1 = None (default)
CaptureMode eScreenshotsAutosave = CaptureMode_ALL, // Default to saving all types of screen captures
eScreenshotsHotkeys = CaptureMode_ALL; // Default to enabling all hotkeys

// Default settings (booleans)
bool bAdjustWindow = false; // Adjust window size based on the image size?
Expand Down Expand Up @@ -459,14 +489,14 @@ struct SKIF_RegistrySettings {
bool bFadeCovers = true;
bool bControllers = true; // Should SKIF support controller input ?
bool bLoggingDeveloper = false; // This is a log level "above" verbose logging that also includes stuff like window messages. Only useable for SKIF developers
bool bSaveScreenshots = true;

// Wide strings
std::wstring wsUpdateChannel = L"Website"; // Default to stable channel
std::wstring wsIgnoreUpdate;
std::wstring wsPathViewer;
std::wstring wsPathScreenshots;
std::wstring wsPathSpecialK;
std::wstring wsPathScreenshots;
std::wstring wsScreenshotsPattern = L"<app>_<date>_<time>";
std::wstring wsAutoUpdateVersion; // Holds the version the auto-updater is trying to install
std::wstring wsDefaultHDRExt = L".png";
std::wstring wsDefaultSDRExt = L".png";
Expand Down Expand Up @@ -511,6 +541,7 @@ struct SKIF_RegistrySettings {
bool _RendererHDREnabled = false; // HDR Enabled
bool _TouchDevice = false;
bool _SnippingMode = false;
bool _SnippingModeInit = true;
bool _SnippingModeExit = false;
bool _SnippingModeTempHDR = false;
int _SnippingTonemapsHDR = 2;
Expand Down
7 changes: 4 additions & 3 deletions include/utility/sk_utility.h
Original file line number Diff line number Diff line change
Expand Up @@ -806,15 +806,16 @@ struct SK_KeybindMultiState
const char* bind_name = nullptr;
bool assigning = false,
state = false;
SK_Keybind saved, pending;
SK_Keybind default, pending, saved;

// This empty object is used during assignment to disable hotkeys temporarily
static constexpr SK_Keybind disabled = { };

SK_KeybindMultiState (const char* _n, std::wstring _h) {
bind_name = _n;
pending.human_readable = _h;
pending.human_readable_utf8 = SK_WideCharToUTF8 (pending.human_readable);
default.human_readable = _h;
default.human_readable_utf8 = SK_WideCharToUTF8 (default.human_readable);
pending = default;
};

bool applyChanges (void); // This applies the pending changes
Expand Down
2 changes: 1 addition & 1 deletion include/utility/skif_imgui.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,4 +90,4 @@ static ImVec4 SKIF_ImGui_ImDerp (const ImVec4& a, const ImVec4& b, float t
extern PopupState PopupMessageInfo; // App Mode: show an informational message box with text set through SKIF_ImGui_InfoMessage

// Fonts
extern ImFont* fontConsolas;
extern ImFont* fontConsolas;
Loading
Loading