Formatting chores (#1441)

* format_sources: exclude 3rd party sources

* format common project

* format leftovers in runner & settings projects

* move source formatting-related files according to #939
This commit is contained in:
Andrey Nekrasov 2020-03-05 13:07:06 +03:00 committed by GitHub
parent 92f64188d5
commit cf1b53831f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
42 changed files with 2602 additions and 2220 deletions

View File

@ -20,7 +20,9 @@ $sourceExtensions.Add(".cpp") | Out-Null
$sourceExtensions.Add(".h") | Out-Null $sourceExtensions.Add(".h") | Out-Null
function Get-Dirty-Files-From-Git() { function Get-Dirty-Files-From-Git() {
$staged = & git diff --name-only --diff-filter=d --cached $repo_root = & git rev-parse --show-toplevel
$staged = & git diff --name-only --diff-filter=d --cached | % { $repo_root + "/" + $_ }
$unstaged = & git ls-files -m $unstaged = & git ls-files -m
$untracked = & git ls-files --others --exclude-standard $untracked = & git ls-files --others --exclude-standard
$result = New-Object System.Collections.Generic.List[string] $result = New-Object System.Collections.Generic.List[string]
@ -34,9 +36,10 @@ function Get-Dirty-Files-From-Git() {
if($all) { if($all) {
$filesToFormat = $filesToFormat =
Get-ChildItem -Recurse -File src | Get-ChildItem -Recurse -File ..\src |
Resolve-Path -Relative | Resolve-Path -Relative |
where {$sourceExtensions.Contains((Get-Item $_).Extension)} where { (Get-Item $_).Directory -notmatch "(Generated Files)|node_modules" -And
$sourceExtensions.Contains((Get-Item $_).Extension)}
} }
else { else {
$filesToFormat = Get-Dirty-Files-From-Git $filesToFormat = Get-Dirty-Files-From-Git

View File

@ -65,7 +65,8 @@ IndentPPDirectives: None
IndentWidth: 4 IndentWidth: 4
IndentWrappedFunctionNames: false IndentWrappedFunctionNames: false
KeepEmptyLinesAtTheStartOfBlocks: false KeepEmptyLinesAtTheStartOfBlocks: false
MacroBlockBegin: "BEGIN_TEST_METHOD_PROPERTIES|BEGIN_MODULE|BEGIN_TEST_CLASS|BEGIN_TEST_METHOD" ForEachMacros: ['TEST_CLASS', 'TEST_METHOD']
MacroBlockBegin: "TEST_METHOD|TEST_CLASS|BEGIN_TEST_METHOD_PROPERTIES|BEGIN_MODULE|BEGIN_TEST_CLASS|BEGIN_TEST_METHOD"
MacroBlockEnd: "END_TEST_METHOD_PROPERTIES|END_MODULE|END_TEST_CLASS|END_TEST_METHOD" MacroBlockEnd: "END_TEST_METHOD_PROPERTIES|END_MODULE|END_TEST_CLASS|END_TEST_METHOD"
MaxEmptyLinesToKeep: 1 MaxEmptyLinesToKeep: 1
NamespaceIndentation: All NamespaceIndentation: All

View File

@ -48,14 +48,14 @@ namespace UnitTestsCommonLib
} }
} }
TEST_CLASS(PowerToyValuesUnitTests) TEST_CLASS (PowerToyValuesUnitTests)
{ {
private: private:
const std::wstring m_json = L"{\"name\":\"Module Name\",\"properties\" : {\"bool_toggle_true\":{\"value\":true},\"bool_toggle_false\":{\"value\":false},\"color_picker\" : {\"value\":\"#ff8d12\"},\"int_spinner\" : {\"value\":10},\"string_text\" : {\"value\":\"a quick fox\"}},\"version\" : \"1.0\" }"; const std::wstring m_json = L"{\"name\":\"Module Name\",\"properties\" : {\"bool_toggle_true\":{\"value\":true},\"bool_toggle_false\":{\"value\":false},\"color_picker\" : {\"value\":\"#ff8d12\"},\"int_spinner\" : {\"value\":10},\"string_text\" : {\"value\":\"a quick fox\"}},\"version\" : \"1.0\" }";
const std::wstring m_moduleName = L"Module Name"; const std::wstring m_moduleName = L"Module Name";
public: public:
TEST_METHOD(LoadFromJsonBoolTrue) TEST_METHOD (LoadFromJsonBoolTrue)
{ {
PowerToyValues values = PowerToyValues::from_json_string(m_json); PowerToyValues values = PowerToyValues::from_json_string(m_json);
auto value = values.get_bool_value(L"bool_toggle_true"); auto value = values.get_bool_value(L"bool_toggle_true");
@ -63,7 +63,7 @@ namespace UnitTestsCommonLib
Assert::AreEqual(true, *value); Assert::AreEqual(true, *value);
} }
TEST_METHOD(LoadFromJsonBoolFalse) TEST_METHOD (LoadFromJsonBoolFalse)
{ {
PowerToyValues values = PowerToyValues::from_json_string(m_json); PowerToyValues values = PowerToyValues::from_json_string(m_json);
auto value = values.get_bool_value(L"bool_toggle_false"); auto value = values.get_bool_value(L"bool_toggle_false");
@ -71,7 +71,7 @@ namespace UnitTestsCommonLib
Assert::AreEqual(false, *value); Assert::AreEqual(false, *value);
} }
TEST_METHOD(LoadFromJsonInt) TEST_METHOD (LoadFromJsonInt)
{ {
PowerToyValues values = PowerToyValues::from_json_string(m_json); PowerToyValues values = PowerToyValues::from_json_string(m_json);
auto value = values.get_int_value(L"int_spinner"); auto value = values.get_int_value(L"int_spinner");
@ -79,7 +79,7 @@ namespace UnitTestsCommonLib
Assert::AreEqual(10, *value); Assert::AreEqual(10, *value);
} }
TEST_METHOD(LoadFromJsonString) TEST_METHOD (LoadFromJsonString)
{ {
PowerToyValues values = PowerToyValues::from_json_string(m_json); PowerToyValues values = PowerToyValues::from_json_string(m_json);
auto value = values.get_string_value(L"string_text"); auto value = values.get_string_value(L"string_text");
@ -89,7 +89,7 @@ namespace UnitTestsCommonLib
Assert::AreEqual(expected, *value); Assert::AreEqual(expected, *value);
} }
TEST_METHOD(LoadFromJsonColorPicker) TEST_METHOD (LoadFromJsonColorPicker)
{ {
PowerToyValues values = PowerToyValues::from_json_string(m_json); PowerToyValues values = PowerToyValues::from_json_string(m_json);
auto value = values.get_string_value(L"color_picker"); auto value = values.get_string_value(L"color_picker");
@ -99,19 +99,19 @@ namespace UnitTestsCommonLib
Assert::AreEqual(expected, *value); Assert::AreEqual(expected, *value);
} }
TEST_METHOD(LoadFromEmptyString) TEST_METHOD (LoadFromEmptyString)
{ {
auto func = [] { PowerToyValues values = PowerToyValues::from_json_string(L""); }; auto func = [] { PowerToyValues values = PowerToyValues::from_json_string(L""); };
Assert::ExpectException<winrt::hresult_error>(func); Assert::ExpectException<winrt::hresult_error>(func);
} }
TEST_METHOD(LoadFromInvalidString_NameMissed) TEST_METHOD (LoadFromInvalidString_NameMissed)
{ {
auto func = [] { PowerToyValues values = PowerToyValues::from_json_string(L"{\"properties\" : {\"bool_toggle_true\":{\"value\":true},\"bool_toggle_false\":{\"value\":false},\"color_picker\" : {\"value\":\"#ff8d12\"},\"int_spinner\" : {\"value\":10},\"string_text\" : {\"value\":\"a quick fox\"}},\"version\" : \"1.0\" }"); }; auto func = [] { PowerToyValues values = PowerToyValues::from_json_string(L"{\"properties\" : {\"bool_toggle_true\":{\"value\":true},\"bool_toggle_false\":{\"value\":false},\"color_picker\" : {\"value\":\"#ff8d12\"},\"int_spinner\" : {\"value\":10},\"string_text\" : {\"value\":\"a quick fox\"}},\"version\" : \"1.0\" }"); };
Assert::ExpectException<winrt::hresult_error>(func); Assert::ExpectException<winrt::hresult_error>(func);
} }
TEST_METHOD(LoadFromInvalidString_VersionMissed) TEST_METHOD (LoadFromInvalidString_VersionMissed)
{ {
PowerToyValues values = PowerToyValues::from_json_string(L"{\"name\":\"Module Name\",\"properties\" : {}}"); PowerToyValues values = PowerToyValues::from_json_string(L"{\"name\":\"Module Name\",\"properties\" : {}}");
const std::wstring expectedStr = L"{\"name\" : \"Module Name\", \"properties\" : {},\"version\" : \"1.0\"}"; const std::wstring expectedStr = L"{\"name\" : \"Module Name\", \"properties\" : {},\"version\" : \"1.0\"}";
@ -121,7 +121,7 @@ namespace UnitTestsCommonLib
compareJsons(expected, actual); compareJsons(expected, actual);
} }
TEST_METHOD(LoadFromInvalidString_PropertiesMissed) TEST_METHOD (LoadFromInvalidString_PropertiesMissed)
{ {
PowerToyValues values = PowerToyValues::from_json_string(L"{\"name\":\"Module Name\",\"version\" : \"1.0\" }"); PowerToyValues values = PowerToyValues::from_json_string(L"{\"name\":\"Module Name\",\"version\" : \"1.0\" }");
const std::wstring expectedStr = L"{\"name\":\"Module Name\",\"version\" : \"1.0\" }"; const std::wstring expectedStr = L"{\"name\":\"Module Name\",\"version\" : \"1.0\" }";
@ -131,7 +131,7 @@ namespace UnitTestsCommonLib
compareJsons(expected, actual); compareJsons(expected, actual);
} }
TEST_METHOD(LoadFromValidString_EmptyProperties) TEST_METHOD (LoadFromValidString_EmptyProperties)
{ {
PowerToyValues values = PowerToyValues::from_json_string(L"{\"name\":\"Module Name\",\"properties\" : {}, \"version\" : \"1.0\" }"); PowerToyValues values = PowerToyValues::from_json_string(L"{\"name\":\"Module Name\",\"properties\" : {}, \"version\" : \"1.0\" }");
const std::wstring expectedStr = L"{\"name\":\"Module Name\",\"properties\" : {},\"version\" : \"1.0\" }"; const std::wstring expectedStr = L"{\"name\":\"Module Name\",\"properties\" : {},\"version\" : \"1.0\" }";
@ -141,7 +141,7 @@ namespace UnitTestsCommonLib
compareJsons(expected, actual); compareJsons(expected, actual);
} }
TEST_METHOD(LoadFromValidString_ChangedVersion) TEST_METHOD (LoadFromValidString_ChangedVersion)
{ {
PowerToyValues values = PowerToyValues::from_json_string(L"{\"name\":\"Module Name\",\"properties\" : {},\"version\" : \"2.0\"}"); PowerToyValues values = PowerToyValues::from_json_string(L"{\"name\":\"Module Name\",\"properties\" : {},\"version\" : \"2.0\"}");
const std::wstring expectedStr = L"{\"name\" : \"Module Name\", \"properties\" : {},\"version\" : \"1.0\"}"; //version from input json is ignored const std::wstring expectedStr = L"{\"name\" : \"Module Name\", \"properties\" : {},\"version\" : \"1.0\"}"; //version from input json is ignored
@ -152,7 +152,7 @@ namespace UnitTestsCommonLib
compareJsons(expected, actual); compareJsons(expected, actual);
} }
TEST_METHOD(CreateWithName) TEST_METHOD (CreateWithName)
{ {
PowerToyValues values(m_moduleName); PowerToyValues values(m_moduleName);
const std::wstring expectedStr = L"{\"name\":\"Module Name\",\"properties\" : {},\"version\" : \"1.0\" }"; const std::wstring expectedStr = L"{\"name\":\"Module Name\",\"properties\" : {},\"version\" : \"1.0\" }";
@ -163,7 +163,7 @@ namespace UnitTestsCommonLib
compareJsons(expected, actual); compareJsons(expected, actual);
} }
TEST_METHOD(AddPropertyBoolPositive) TEST_METHOD (AddPropertyBoolPositive)
{ {
PowerToyValues values(m_moduleName); PowerToyValues values(m_moduleName);
values.add_property<bool>(L"positive_bool_value", true); values.add_property<bool>(L"positive_bool_value", true);
@ -173,7 +173,7 @@ namespace UnitTestsCommonLib
Assert::AreEqual(true, *value); Assert::AreEqual(true, *value);
} }
TEST_METHOD(AddPropertyBoolNegative) TEST_METHOD (AddPropertyBoolNegative)
{ {
PowerToyValues values(m_moduleName); PowerToyValues values(m_moduleName);
values.add_property<bool>(L"negative_bool_value", false); values.add_property<bool>(L"negative_bool_value", false);
@ -183,7 +183,7 @@ namespace UnitTestsCommonLib
Assert::AreEqual(false, *value); Assert::AreEqual(false, *value);
} }
TEST_METHOD(AddPropertyIntPositive) TEST_METHOD (AddPropertyIntPositive)
{ {
PowerToyValues values(m_moduleName); PowerToyValues values(m_moduleName);
const int intVal = 4392854; const int intVal = 4392854;
@ -194,7 +194,7 @@ namespace UnitTestsCommonLib
Assert::AreEqual(intVal, *value); Assert::AreEqual(intVal, *value);
} }
TEST_METHOD(AddPropertyIntNegative) TEST_METHOD (AddPropertyIntNegative)
{ {
PowerToyValues values(m_moduleName); PowerToyValues values(m_moduleName);
const int intVal = -4392854; const int intVal = -4392854;
@ -205,7 +205,7 @@ namespace UnitTestsCommonLib
Assert::AreEqual(intVal, *value); Assert::AreEqual(intVal, *value);
} }
TEST_METHOD(AddPropertyIntZero) TEST_METHOD (AddPropertyIntZero)
{ {
PowerToyValues values(m_moduleName); PowerToyValues values(m_moduleName);
const int intVal = 0; const int intVal = 0;
@ -216,7 +216,7 @@ namespace UnitTestsCommonLib
Assert::AreEqual(intVal, *value); Assert::AreEqual(intVal, *value);
} }
TEST_METHOD(AddPropertyStringEmpty) TEST_METHOD (AddPropertyStringEmpty)
{ {
PowerToyValues values(m_moduleName); PowerToyValues values(m_moduleName);
const std::wstring stringVal = L""; const std::wstring stringVal = L"";
@ -227,7 +227,7 @@ namespace UnitTestsCommonLib
Assert::AreEqual(stringVal, *value); Assert::AreEqual(stringVal, *value);
} }
TEST_METHOD(AddPropertyString) TEST_METHOD (AddPropertyString)
{ {
PowerToyValues values(m_moduleName); PowerToyValues values(m_moduleName);
const std::wstring stringVal = L"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."; const std::wstring stringVal = L"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.";
@ -238,7 +238,7 @@ namespace UnitTestsCommonLib
Assert::AreEqual(stringVal, *value); Assert::AreEqual(stringVal, *value);
} }
TEST_METHOD(AddPropertyJsonEmpty) TEST_METHOD (AddPropertyJsonEmpty)
{ {
PowerToyValues values(m_moduleName); PowerToyValues values(m_moduleName);
const auto json = json::JsonObject(); const auto json = json::JsonObject();
@ -249,7 +249,7 @@ namespace UnitTestsCommonLib
compareJsons(json, *value); compareJsons(json, *value);
} }
TEST_METHOD(AddPropertyJsonObject) TEST_METHOD (AddPropertyJsonObject)
{ {
PowerToyValues values(m_moduleName); PowerToyValues values(m_moduleName);
const auto json = json::JsonObject::Parse(m_json); const auto json = json::JsonObject::Parse(m_json);
@ -261,7 +261,7 @@ namespace UnitTestsCommonLib
} }
}; };
TEST_CLASS(SettingsUnitTests) TEST_CLASS (SettingsUnitTests)
{ {
private: private:
const std::wstring m_moduleName = L"Module Name"; const std::wstring m_moduleName = L"Module Name";
@ -279,7 +279,7 @@ namespace UnitTestsCommonLib
} }
public: public:
TEST_METHOD(SettingsSerialization) TEST_METHOD (SettingsSerialization)
{ {
Settings settings(nullptr, m_moduleName); Settings settings(nullptr, m_moduleName);
@ -288,7 +288,7 @@ namespace UnitTestsCommonLib
compareJsons(expected, actual); compareJsons(expected, actual);
} }
TEST_METHOD(SettingsSerializationToBuffer) TEST_METHOD (SettingsSerializationToBuffer)
{ {
Settings settings(nullptr, m_moduleName); Settings settings(nullptr, m_moduleName);
@ -307,7 +307,7 @@ namespace UnitTestsCommonLib
compareJsons(m_defaultSettingsJson, actualJson); compareJsons(m_defaultSettingsJson, actualJson);
} }
TEST_METHOD(SettingsSetDescription) TEST_METHOD (SettingsSetDescription)
{ {
const auto value = L"description value"; const auto value = L"description value";
Settings settings(nullptr, m_moduleName); Settings settings(nullptr, m_moduleName);
@ -320,7 +320,7 @@ namespace UnitTestsCommonLib
compareJsons(expected, actual); compareJsons(expected, actual);
} }
TEST_METHOD(SettingsSetIconKey) TEST_METHOD (SettingsSetIconKey)
{ {
const auto value = L"icon key"; const auto value = L"icon key";
Settings settings(nullptr, m_moduleName); Settings settings(nullptr, m_moduleName);
@ -333,7 +333,7 @@ namespace UnitTestsCommonLib
compareJsons(expected, actual); compareJsons(expected, actual);
} }
TEST_METHOD(SettingsSetOverviewLink) TEST_METHOD (SettingsSetOverviewLink)
{ {
const auto value = L"overview link"; const auto value = L"overview link";
Settings settings(nullptr, m_moduleName); Settings settings(nullptr, m_moduleName);
@ -346,7 +346,7 @@ namespace UnitTestsCommonLib
compareJsons(expected, actual); compareJsons(expected, actual);
} }
TEST_METHOD(SettingsSetVideoLink) TEST_METHOD (SettingsSetVideoLink)
{ {
const auto value = L"video link"; const auto value = L"video link";
Settings settings(nullptr, m_moduleName); Settings settings(nullptr, m_moduleName);
@ -359,7 +359,7 @@ namespace UnitTestsCommonLib
compareJsons(expected, actual); compareJsons(expected, actual);
} }
TEST_METHOD(SettingsAddBoolTogglePositive) TEST_METHOD (SettingsAddBoolTogglePositive)
{ {
const auto value = true; const auto value = true;
@ -376,7 +376,7 @@ namespace UnitTestsCommonLib
compareJsons(expected, actual); compareJsons(expected, actual);
} }
TEST_METHOD(SettingsAddBoolToggleNegative) TEST_METHOD (SettingsAddBoolToggleNegative)
{ {
const auto value = false; const auto value = false;
@ -393,7 +393,7 @@ namespace UnitTestsCommonLib
compareJsons(expected, actual); compareJsons(expected, actual);
} }
TEST_METHOD(SettingsAddSpinner) TEST_METHOD (SettingsAddSpinner)
{ {
const int value = 738543; const int value = 738543;
const int min = 0; const int min = 0;
@ -416,7 +416,7 @@ namespace UnitTestsCommonLib
compareJsons(expected, actual); compareJsons(expected, actual);
} }
TEST_METHOD(SettingsAddString) TEST_METHOD (SettingsAddString)
{ {
const auto value = L"string text "; const auto value = L"string text ";
@ -433,7 +433,7 @@ namespace UnitTestsCommonLib
compareJsons(expected, actual); compareJsons(expected, actual);
} }
TEST_METHOD(SettingsAddStringMultiline) TEST_METHOD (SettingsAddStringMultiline)
{ {
const auto value = L"Lorem ipsum dolor sit amet,\nconsectetur adipiscing elit,\nsed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\nUt enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\nDuis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.\nExcepteur sint occaecat cupidatat non proident,\nsunt in culpa qui officia deserunt mollit anim id est laborum."; const auto value = L"Lorem ipsum dolor sit amet,\nconsectetur adipiscing elit,\nsed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\nUt enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\nDuis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.\nExcepteur sint occaecat cupidatat non proident,\nsunt in culpa qui officia deserunt mollit anim id est laborum.";
@ -451,7 +451,7 @@ namespace UnitTestsCommonLib
compareJsons(expected, actual); compareJsons(expected, actual);
} }
TEST_METHOD(SettingsAddColorPicker) TEST_METHOD (SettingsAddColorPicker)
{ {
const auto value = L"#ffffff"; const auto value = L"#ffffff";
@ -468,7 +468,7 @@ namespace UnitTestsCommonLib
compareJsons(expected, actual); compareJsons(expected, actual);
} }
TEST_METHOD(SettingsAddHotkey) TEST_METHOD (SettingsAddHotkey)
{ {
const auto value = PowerToysSettings::HotkeyObject::from_settings(true, true, true, true, 0); const auto value = PowerToysSettings::HotkeyObject::from_settings(true, true, true, true, 0);
@ -485,7 +485,7 @@ namespace UnitTestsCommonLib
compareJsons(expected, actual); compareJsons(expected, actual);
} }
TEST_METHOD(SettingsAddChoiceGroup) TEST_METHOD (SettingsAddChoiceGroup)
{ {
const auto value = L"choice group value"; const auto value = L"choice group value";
const auto keysAndTexts = { const auto keysAndTexts = {
@ -516,7 +516,7 @@ namespace UnitTestsCommonLib
compareJsons(expected, actual); compareJsons(expected, actual);
} }
TEST_METHOD(SettingsAddChoiceGroupEmpty) TEST_METHOD (SettingsAddChoiceGroupEmpty)
{ {
const auto value = L"choice group value"; const auto value = L"choice group value";
@ -534,7 +534,7 @@ namespace UnitTestsCommonLib
compareJsons(expected, actual); compareJsons(expected, actual);
} }
TEST_METHOD(SettingsAddDropdown) TEST_METHOD (SettingsAddDropdown)
{ {
const auto value = L"dropdown value"; const auto value = L"dropdown value";
const auto keysAndTexts = { const auto keysAndTexts = {
@ -565,7 +565,7 @@ namespace UnitTestsCommonLib
compareJsons(expected, actual); compareJsons(expected, actual);
} }
TEST_METHOD(SettingsAddDropdownEmpty) TEST_METHOD (SettingsAddDropdownEmpty)
{ {
const auto value = L"dropdown value"; const auto value = L"dropdown value";
@ -582,7 +582,7 @@ namespace UnitTestsCommonLib
compareJsons(expected, actual); compareJsons(expected, actual);
} }
TEST_METHOD(SettingsAddCustomAction) TEST_METHOD (SettingsAddCustomAction)
{ {
const auto value = L"custom action value"; const auto value = L"custom action value";
const std::wstring buttonText = L"button text"; const std::wstring buttonText = L"button text";
@ -602,17 +602,17 @@ namespace UnitTestsCommonLib
} }
}; };
TEST_CLASS(CustomActionObjectUnitTests) TEST_CLASS (CustomActionObjectUnitTests)
{ {
public: public:
TEST_METHOD(CustomActionObjectName) TEST_METHOD (CustomActionObjectName)
{ {
const std::wstring json = L"{\"action_name\": \"action name\", \"value\": \"action value\"}"; const std::wstring json = L"{\"action_name\": \"action name\", \"value\": \"action value\"}";
CustomActionObject obj = CustomActionObject::from_json_string(json); CustomActionObject obj = CustomActionObject::from_json_string(json);
Assert::AreEqual(std::wstring(L"action name"), obj.get_name()); Assert::AreEqual(std::wstring(L"action name"), obj.get_name());
} }
TEST_METHOD(CustomActionObjectValue) TEST_METHOD (CustomActionObjectValue)
{ {
const std::wstring json = L"{\"action_name\": \"action name\", \"value\": \"action value\"}"; const std::wstring json = L"{\"action_name\": \"action name\", \"value\": \"action value\"}";
CustomActionObject obj = CustomActionObject::from_json_string(json); CustomActionObject obj = CustomActionObject::from_json_string(json);
@ -620,44 +620,44 @@ namespace UnitTestsCommonLib
} }
}; };
TEST_CLASS(HotkeyObjectUnitTests) TEST_CLASS (HotkeyObjectUnitTests)
{ {
private: private:
json::JsonObject m_defaultHotkeyJson = json::JsonObject::Parse(L"{\"key\":\"(Key 0)\", \"code\": 123, \"win\": true, \"ctrl\": true, \"alt\": true, \"shift\": true}"); json::JsonObject m_defaultHotkeyJson = json::JsonObject::Parse(L"{\"key\":\"(Key 0)\", \"code\": 123, \"win\": true, \"ctrl\": true, \"alt\": true, \"shift\": true}");
json::JsonObject m_defaultHotkeyJsonAlternative = json::JsonObject::Parse(L"{\"key\":\"(Key 0)\", \"code\": 123, \"win\": false, \"ctrl\": false, \"alt\": false, \"shift\": false}"); json::JsonObject m_defaultHotkeyJsonAlternative = json::JsonObject::Parse(L"{\"key\":\"(Key 0)\", \"code\": 123, \"win\": false, \"ctrl\": false, \"alt\": false, \"shift\": false}");
public: public:
TEST_METHOD(GetKeyFromJson) TEST_METHOD (GetKeyFromJson)
{ {
HotkeyObject object = HotkeyObject::from_json(m_defaultHotkeyJson); HotkeyObject object = HotkeyObject::from_json(m_defaultHotkeyJson);
Assert::AreEqual(std::wstring(L"(Key 0)"), object.get_key()); Assert::AreEqual(std::wstring(L"(Key 0)"), object.get_key());
} }
TEST_METHOD(GetKeyFromJsonString) TEST_METHOD (GetKeyFromJsonString)
{ {
HotkeyObject object = HotkeyObject::from_json_string(m_defaultHotkeyJson.Stringify()); HotkeyObject object = HotkeyObject::from_json_string(m_defaultHotkeyJson.Stringify());
Assert::AreEqual(std::wstring(L"(Key 0)"), object.get_key()); Assert::AreEqual(std::wstring(L"(Key 0)"), object.get_key());
} }
TEST_METHOD(GetCodeFromJson) TEST_METHOD (GetCodeFromJson)
{ {
HotkeyObject object = HotkeyObject::from_json(m_defaultHotkeyJson); HotkeyObject object = HotkeyObject::from_json(m_defaultHotkeyJson);
Assert::AreEqual(UINT(123), object.get_code()); Assert::AreEqual(UINT(123), object.get_code());
} }
TEST_METHOD(GetCodeFromJsonString) TEST_METHOD (GetCodeFromJsonString)
{ {
HotkeyObject object = HotkeyObject::from_json_string(m_defaultHotkeyJson.Stringify()); HotkeyObject object = HotkeyObject::from_json_string(m_defaultHotkeyJson.Stringify());
Assert::AreEqual(UINT(123), object.get_code()); Assert::AreEqual(UINT(123), object.get_code());
} }
TEST_METHOD(GetCodeFromSettings) TEST_METHOD (GetCodeFromSettings)
{ {
HotkeyObject object = HotkeyObject::from_settings(true, true, true, true, 123); HotkeyObject object = HotkeyObject::from_settings(true, true, true, true, 123);
Assert::AreEqual(UINT(123), object.get_code()); Assert::AreEqual(UINT(123), object.get_code());
} }
TEST_METHOD(GetWinPressedFromJson) TEST_METHOD (GetWinPressedFromJson)
{ {
HotkeyObject object = HotkeyObject::from_json(m_defaultHotkeyJson); HotkeyObject object = HotkeyObject::from_json(m_defaultHotkeyJson);
Assert::AreEqual(true, object.win_pressed()); Assert::AreEqual(true, object.win_pressed());
@ -666,7 +666,7 @@ namespace UnitTestsCommonLib
Assert::AreEqual(false, objectNegativeValues.win_pressed()); Assert::AreEqual(false, objectNegativeValues.win_pressed());
} }
TEST_METHOD(GetWinPressedFromJsonString) TEST_METHOD (GetWinPressedFromJsonString)
{ {
HotkeyObject object = HotkeyObject::from_json_string(m_defaultHotkeyJson.Stringify()); HotkeyObject object = HotkeyObject::from_json_string(m_defaultHotkeyJson.Stringify());
Assert::AreEqual(true, object.win_pressed()); Assert::AreEqual(true, object.win_pressed());
@ -675,7 +675,7 @@ namespace UnitTestsCommonLib
Assert::AreEqual(false, objectNegativeValues.win_pressed()); Assert::AreEqual(false, objectNegativeValues.win_pressed());
} }
TEST_METHOD(GetWinPressedFromSettings) TEST_METHOD (GetWinPressedFromSettings)
{ {
HotkeyObject object = HotkeyObject::from_settings(true, true, true, true, 123); HotkeyObject object = HotkeyObject::from_settings(true, true, true, true, 123);
Assert::AreEqual(true, object.win_pressed()); Assert::AreEqual(true, object.win_pressed());
@ -684,7 +684,7 @@ namespace UnitTestsCommonLib
Assert::AreEqual(false, objectNegativeValues.win_pressed()); Assert::AreEqual(false, objectNegativeValues.win_pressed());
} }
TEST_METHOD(GetCtrlPressedFromJson) TEST_METHOD (GetCtrlPressedFromJson)
{ {
HotkeyObject object = HotkeyObject::from_json(m_defaultHotkeyJson); HotkeyObject object = HotkeyObject::from_json(m_defaultHotkeyJson);
Assert::AreEqual(true, object.ctrl_pressed()); Assert::AreEqual(true, object.ctrl_pressed());
@ -693,7 +693,7 @@ namespace UnitTestsCommonLib
Assert::AreEqual(false, objectNegativeValues.ctrl_pressed()); Assert::AreEqual(false, objectNegativeValues.ctrl_pressed());
} }
TEST_METHOD(GetCtrlPressedFromJsonString) TEST_METHOD (GetCtrlPressedFromJsonString)
{ {
HotkeyObject object = HotkeyObject::from_json_string(m_defaultHotkeyJson.Stringify()); HotkeyObject object = HotkeyObject::from_json_string(m_defaultHotkeyJson.Stringify());
Assert::AreEqual(true, object.ctrl_pressed()); Assert::AreEqual(true, object.ctrl_pressed());
@ -702,7 +702,7 @@ namespace UnitTestsCommonLib
Assert::AreEqual(false, objectNegativeValues.ctrl_pressed()); Assert::AreEqual(false, objectNegativeValues.ctrl_pressed());
} }
TEST_METHOD(GetCtrlPressedFromSettings) TEST_METHOD (GetCtrlPressedFromSettings)
{ {
HotkeyObject object = HotkeyObject::from_settings(true, true, true, true, 123); HotkeyObject object = HotkeyObject::from_settings(true, true, true, true, 123);
Assert::AreEqual(true, object.ctrl_pressed()); Assert::AreEqual(true, object.ctrl_pressed());
@ -711,7 +711,7 @@ namespace UnitTestsCommonLib
Assert::AreEqual(false, objectNegativeValues.ctrl_pressed()); Assert::AreEqual(false, objectNegativeValues.ctrl_pressed());
} }
TEST_METHOD(GetAltPressedFromJson) TEST_METHOD (GetAltPressedFromJson)
{ {
HotkeyObject object = HotkeyObject::from_json(m_defaultHotkeyJson); HotkeyObject object = HotkeyObject::from_json(m_defaultHotkeyJson);
Assert::AreEqual(true, object.alt_pressed()); Assert::AreEqual(true, object.alt_pressed());
@ -720,7 +720,7 @@ namespace UnitTestsCommonLib
Assert::AreEqual(false, objectNegativeValues.alt_pressed()); Assert::AreEqual(false, objectNegativeValues.alt_pressed());
} }
TEST_METHOD(GetAltPressedFromJsonString) TEST_METHOD (GetAltPressedFromJsonString)
{ {
HotkeyObject object = HotkeyObject::from_json_string(m_defaultHotkeyJson.Stringify()); HotkeyObject object = HotkeyObject::from_json_string(m_defaultHotkeyJson.Stringify());
Assert::AreEqual(true, object.alt_pressed()); Assert::AreEqual(true, object.alt_pressed());
@ -729,7 +729,7 @@ namespace UnitTestsCommonLib
Assert::AreEqual(false, objectNegativeValues.alt_pressed()); Assert::AreEqual(false, objectNegativeValues.alt_pressed());
} }
TEST_METHOD(GetAltPressedFromSettings) TEST_METHOD (GetAltPressedFromSettings)
{ {
HotkeyObject object = HotkeyObject::from_settings(true, true, true, true, 123); HotkeyObject object = HotkeyObject::from_settings(true, true, true, true, 123);
Assert::AreEqual(true, object.alt_pressed()); Assert::AreEqual(true, object.alt_pressed());
@ -738,7 +738,7 @@ namespace UnitTestsCommonLib
Assert::AreEqual(false, objectNegativeValues.alt_pressed()); Assert::AreEqual(false, objectNegativeValues.alt_pressed());
} }
TEST_METHOD(GetShiftPressedFromJson) TEST_METHOD (GetShiftPressedFromJson)
{ {
HotkeyObject object = HotkeyObject::from_json(m_defaultHotkeyJson); HotkeyObject object = HotkeyObject::from_json(m_defaultHotkeyJson);
Assert::AreEqual(true, object.shift_pressed()); Assert::AreEqual(true, object.shift_pressed());
@ -747,7 +747,7 @@ namespace UnitTestsCommonLib
Assert::AreEqual(false, objectNegativeValues.shift_pressed()); Assert::AreEqual(false, objectNegativeValues.shift_pressed());
} }
TEST_METHOD(GetShiftPressedFromJsonString) TEST_METHOD (GetShiftPressedFromJsonString)
{ {
HotkeyObject object = HotkeyObject::from_json_string(m_defaultHotkeyJson.Stringify()); HotkeyObject object = HotkeyObject::from_json_string(m_defaultHotkeyJson.Stringify());
Assert::AreEqual(true, object.shift_pressed()); Assert::AreEqual(true, object.shift_pressed());
@ -756,7 +756,7 @@ namespace UnitTestsCommonLib
Assert::AreEqual(false, objectNegativeValues.shift_pressed()); Assert::AreEqual(false, objectNegativeValues.shift_pressed());
} }
TEST_METHOD(GetShiftPressedFromSettings) TEST_METHOD (GetShiftPressedFromSettings)
{ {
HotkeyObject object = HotkeyObject::from_settings(true, true, true, true, 123); HotkeyObject object = HotkeyObject::from_settings(true, true, true, true, 123);
Assert::AreEqual(true, object.shift_pressed()); Assert::AreEqual(true, object.shift_pressed());
@ -765,7 +765,7 @@ namespace UnitTestsCommonLib
Assert::AreEqual(false, objectNegativeValues.shift_pressed()); Assert::AreEqual(false, objectNegativeValues.shift_pressed());
} }
TEST_METHOD(GetModifiersRepeat) TEST_METHOD (GetModifiersRepeat)
{ {
std::map<UINT, HotkeyObject> expectedMap = { std::map<UINT, HotkeyObject> expectedMap = {
std::make_pair(0x0000, HotkeyObject::from_settings(false, false, false, false, 0)), std::make_pair(0x0000, HotkeyObject::from_settings(false, false, false, false, 0)),
@ -792,7 +792,7 @@ namespace UnitTestsCommonLib
} }
} }
TEST_METHOD(GetModifiers) TEST_METHOD (GetModifiers)
{ {
std::map<UINT, HotkeyObject> expectedMap = { std::map<UINT, HotkeyObject> expectedMap = {
std::make_pair(0x4000, HotkeyObject::from_settings(false, false, false, false, 0)), std::make_pair(0x4000, HotkeyObject::from_settings(false, false, false, false, 0)),

View File

@ -10,10 +10,10 @@ namespace UnitTestsVersionHelper
const int MINOR_VERSION_12 = 12; const int MINOR_VERSION_12 = 12;
const int REVISION_VERSION_0 = 0; const int REVISION_VERSION_0 = 0;
TEST_CLASS(UnitTestsVersionHelper) TEST_CLASS (UnitTestsVersionHelper)
{ {
public: public:
TEST_METHOD(integerConstructorShouldProprelyInitializateVersionNumbers) TEST_METHOD (integerConstructorShouldProprelyInitializateVersionNumbers)
{ {
VersionHelper sut(MAJOR_VERSION_0, MINOR_VERSION_12, REVISION_VERSION_0); VersionHelper sut(MAJOR_VERSION_0, MINOR_VERSION_12, REVISION_VERSION_0);
@ -21,7 +21,7 @@ namespace UnitTestsVersionHelper
Assert::AreEqual(MINOR_VERSION_12, sut.minor); Assert::AreEqual(MINOR_VERSION_12, sut.minor);
Assert::AreEqual(REVISION_VERSION_0, sut.revision); Assert::AreEqual(REVISION_VERSION_0, sut.revision);
} }
TEST_METHOD(integerConstructorShouldProprelyInitializateWithDifferentVersionNumbers) TEST_METHOD (integerConstructorShouldProprelyInitializateWithDifferentVersionNumbers)
{ {
const int testcaseMajor = 2; const int testcaseMajor = 2;
const int testcaseMinor = 25; const int testcaseMinor = 25;
@ -32,16 +32,15 @@ namespace UnitTestsVersionHelper
Assert::AreEqual(testcaseMinor, sut.minor); Assert::AreEqual(testcaseMinor, sut.minor);
Assert::AreEqual(testcaseRevision, sut.revision); Assert::AreEqual(testcaseRevision, sut.revision);
} }
TEST_METHOD(stringConstructorShouldProprelyInitializateVersionNumbers) TEST_METHOD (stringConstructorShouldProprelyInitializateVersionNumbers)
{ {
VersionHelper sut("v0.12.3"); VersionHelper sut("v0.12.3");
Assert::AreEqual(0, sut.major); Assert::AreEqual(0, sut.major);
Assert::AreEqual(12, sut.minor); Assert::AreEqual(12, sut.minor);
Assert::AreEqual(3, sut.revision); Assert::AreEqual(3, sut.revision);
} }
TEST_METHOD(stringConstructorShouldProprelyInitializateWithDifferentVersionNumbers) TEST_METHOD (stringConstructorShouldProprelyInitializateWithDifferentVersionNumbers)
{ {
VersionHelper sut("v2.25.1"); VersionHelper sut("v2.25.1");
@ -49,21 +48,21 @@ namespace UnitTestsVersionHelper
Assert::AreEqual(25, sut.minor); Assert::AreEqual(25, sut.minor);
Assert::AreEqual(1, sut.revision); Assert::AreEqual(1, sut.revision);
} }
TEST_METHOD(whenMajorVersionIsGreaterComparationOperatorShouldReturnProperValue) TEST_METHOD (whenMajorVersionIsGreaterComparationOperatorShouldReturnProperValue)
{ {
VersionHelper rhs(MAJOR_VERSION_0, MINOR_VERSION_12, REVISION_VERSION_0); VersionHelper rhs(MAJOR_VERSION_0, MINOR_VERSION_12, REVISION_VERSION_0);
VersionHelper lhs(MAJOR_VERSION_0 + 1, MINOR_VERSION_12, REVISION_VERSION_0); VersionHelper lhs(MAJOR_VERSION_0 + 1, MINOR_VERSION_12, REVISION_VERSION_0);
Assert::IsTrue(lhs > rhs); Assert::IsTrue(lhs > rhs);
} }
TEST_METHOD(whenMajorVersionIsLesserComparationOperatorShouldReturnProperValue) TEST_METHOD (whenMajorVersionIsLesserComparationOperatorShouldReturnProperValue)
{ {
VersionHelper rhs(MAJOR_VERSION_0 + 1, MINOR_VERSION_12, REVISION_VERSION_0); VersionHelper rhs(MAJOR_VERSION_0 + 1, MINOR_VERSION_12, REVISION_VERSION_0);
VersionHelper lhs(MAJOR_VERSION_0, MINOR_VERSION_12, REVISION_VERSION_0); VersionHelper lhs(MAJOR_VERSION_0, MINOR_VERSION_12, REVISION_VERSION_0);
Assert::IsFalse(lhs > rhs); Assert::IsFalse(lhs > rhs);
} }
TEST_METHOD(whenMajorVersionIsEqualComparationOperatorShouldCompareMinorVersionValue) TEST_METHOD (whenMajorVersionIsEqualComparationOperatorShouldCompareMinorVersionValue)
{ {
VersionHelper rhs(MAJOR_VERSION_0, MINOR_VERSION_12 - 1, REVISION_VERSION_0); VersionHelper rhs(MAJOR_VERSION_0, MINOR_VERSION_12 - 1, REVISION_VERSION_0);
@ -71,7 +70,7 @@ namespace UnitTestsVersionHelper
Assert::IsTrue(lhs > rhs); Assert::IsTrue(lhs > rhs);
} }
TEST_METHOD(whenMajorVersionIsEqualComparationOperatorShouldCompareMinorVersionValue2) TEST_METHOD (whenMajorVersionIsEqualComparationOperatorShouldCompareMinorVersionValue2)
{ {
VersionHelper rhs(MAJOR_VERSION_0, MINOR_VERSION_12, REVISION_VERSION_0); VersionHelper rhs(MAJOR_VERSION_0, MINOR_VERSION_12, REVISION_VERSION_0);
VersionHelper lhs(MAJOR_VERSION_0, MINOR_VERSION_12 - 1, REVISION_VERSION_0); VersionHelper lhs(MAJOR_VERSION_0, MINOR_VERSION_12 - 1, REVISION_VERSION_0);
@ -79,14 +78,14 @@ namespace UnitTestsVersionHelper
Assert::IsFalse(lhs > rhs); Assert::IsFalse(lhs > rhs);
} }
TEST_METHOD(whenMajorAndMinorVersionIsEqualComparationOperatorShouldCompareRevisionValue) TEST_METHOD (whenMajorAndMinorVersionIsEqualComparationOperatorShouldCompareRevisionValue)
{ {
VersionHelper rhs(MAJOR_VERSION_0, MINOR_VERSION_12, REVISION_VERSION_0); VersionHelper rhs(MAJOR_VERSION_0, MINOR_VERSION_12, REVISION_VERSION_0);
VersionHelper lhs(MAJOR_VERSION_0, MINOR_VERSION_12, REVISION_VERSION_0 + 1); VersionHelper lhs(MAJOR_VERSION_0, MINOR_VERSION_12, REVISION_VERSION_0 + 1);
Assert::IsTrue(lhs > rhs); Assert::IsTrue(lhs > rhs);
} }
TEST_METHOD(whenMajorAndMinorVersionIsEqualComparationOperatorShouldCompareRevisionValue2) TEST_METHOD (whenMajorAndMinorVersionIsEqualComparationOperatorShouldCompareRevisionValue2)
{ {
VersionHelper rhs(MAJOR_VERSION_0, MINOR_VERSION_12, REVISION_VERSION_0 + 1); VersionHelper rhs(MAJOR_VERSION_0, MINOR_VERSION_12, REVISION_VERSION_0 + 1);
VersionHelper lhs(MAJOR_VERSION_0, MINOR_VERSION_12, REVISION_VERSION_0); VersionHelper lhs(MAJOR_VERSION_0, MINOR_VERSION_12, REVISION_VERSION_0);

View File

@ -2,42 +2,50 @@
#include "animation.h" #include "animation.h"
Animation::Animation(double duration, double start, double stop) : Animation::Animation(double duration, double start, double stop) :
duration(duration), start_value(start), end_value(stop), start(std::chrono::high_resolution_clock::now()) { } duration(duration), start_value(start), end_value(stop), start(std::chrono::high_resolution_clock::now()) {}
void Animation::reset() { void Animation::reset()
start = std::chrono::high_resolution_clock::now(); {
start = std::chrono::high_resolution_clock::now();
} }
void Animation::reset(double duration) { void Animation::reset(double duration)
this->duration = duration; {
reset(); this->duration = duration;
reset();
} }
void Animation::reset(double duration, double start, double stop) { void Animation::reset(double duration, double start, double stop)
start_value = start; {
end_value = stop; start_value = start;
reset(duration); end_value = stop;
reset(duration);
} }
static double ease_out_expo(double t) { static double ease_out_expo(double t)
return 1 - pow(2, -8 * t); {
return 1 - pow(2, -8 * t);
} }
double Animation::apply_animation_function(double t, AnimFunctions apply_function) { double Animation::apply_animation_function(double t, AnimFunctions apply_function)
switch (apply_function) { {
case EASE_OUT_EXPO: switch (apply_function)
return ease_out_expo(t); {
case LINEAR: case EASE_OUT_EXPO:
default: return ease_out_expo(t);
return t; case LINEAR:
} default:
return t;
}
} }
double Animation::value(AnimFunctions apply_function) const { double Animation::value(AnimFunctions apply_function) const
auto anim_duration = std::chrono::high_resolution_clock::now() - start; {
double t = std::chrono::duration<double>(anim_duration).count() / duration; auto anim_duration = std::chrono::high_resolution_clock::now() - start;
if (t >= 1) double t = std::chrono::duration<double>(anim_duration).count() / duration;
return end_value; if (t >= 1)
return start_value + (end_value - start_value) * apply_animation_function(t, apply_function); return end_value;
return start_value + (end_value - start_value) * apply_animation_function(t, apply_function);
} }
bool Animation::done() const { bool Animation::done() const
return std::chrono::high_resolution_clock::now() - start >= std::chrono::duration<double>(duration); {
return std::chrono::high_resolution_clock::now() - start >= std::chrono::duration<double>(duration);
} }

View File

@ -11,21 +11,24 @@
When redering, call value() to get value from 0 to 1 - depending on animation When redering, call value() to get value from 0 to 1 - depending on animation
progress. progress.
*/ */
class Animation { class Animation
{
public: public:
enum AnimFunctions { enum AnimFunctions
LINEAR = 0, {
EASE_OUT_EXPO LINEAR = 0,
}; EASE_OUT_EXPO
};
Animation(double duration = 1, double start = 0, double stop = 1);
void reset();
void reset(double duration);
void reset(double duration, double start, double stop);
double value(AnimFunctions apply_function) const;
bool done() const;
Animation(double duration = 1, double start = 0, double stop = 1);
void reset();
void reset(double duration);
void reset(double duration, double start, double stop);
double value(AnimFunctions apply_function) const;
bool done() const;
private: private:
static double apply_animation_function(double t, AnimFunctions apply_function); static double apply_animation_function(double t, AnimFunctions apply_function);
std::chrono::high_resolution_clock::time_point start; std::chrono::high_resolution_clock::time_point start;
double start_value, end_value, duration; double start_value, end_value, duration;
}; };

View File

@ -5,43 +5,50 @@
#include <condition_variable> #include <condition_variable>
#include <string> #include <string>
class AsyncMessageQueue { class AsyncMessageQueue
{
private: private:
std::mutex queue_mutex; std::mutex queue_mutex;
std::queue<std::wstring> message_queue; std::queue<std::wstring> message_queue;
std::condition_variable message_ready; std::condition_variable message_ready;
bool interrupted = false; bool interrupted = false;
//Disable copy //Disable copy
AsyncMessageQueue(const AsyncMessageQueue&); AsyncMessageQueue(const AsyncMessageQueue&);
AsyncMessageQueue& operator=(const AsyncMessageQueue&); AsyncMessageQueue& operator=(const AsyncMessageQueue&);
public: public:
AsyncMessageQueue() { AsyncMessageQueue()
} {
void queue_message(std::wstring message) {
this->queue_mutex.lock();
this->message_queue.push(message);
this->queue_mutex.unlock();
this->message_ready.notify_one();
}
std::wstring pop_message() {
std::unique_lock<std::mutex> lock(this->queue_mutex);
while (message_queue.empty() && !this->interrupted) {
this->message_ready.wait(lock);
} }
if (this->interrupted) { void queue_message(std::wstring message)
//Just returns a empty string if the queue was interrupted. {
return std::wstring(L""); this->queue_mutex.lock();
this->message_queue.push(message);
this->queue_mutex.unlock();
this->message_ready.notify_one();
}
std::wstring pop_message()
{
std::unique_lock<std::mutex> lock(this->queue_mutex);
while (message_queue.empty() && !this->interrupted)
{
this->message_ready.wait(lock);
}
if (this->interrupted)
{
//Just returns a empty string if the queue was interrupted.
return std::wstring(L"");
}
std::wstring message = this->message_queue.front();
this->message_queue.pop();
return message;
}
void interrupt()
{
this->queue_mutex.lock();
this->interrupted = true;
this->queue_mutex.unlock();
this->message_ready.notify_all();
} }
std::wstring message = this->message_queue.front();
this->message_queue.pop();
return message;
}
void interrupt() {
this->queue_mutex.lock();
this->interrupted = true;
this->queue_mutex.unlock();
this->message_ready.notify_all();
}
}; };

View File

@ -8,7 +8,7 @@ template<typename T>
class com_object_factory : public IClassFactory class com_object_factory : public IClassFactory
{ {
public: public:
HRESULT __stdcall QueryInterface(const IID & riid, void** ppv) override HRESULT __stdcall QueryInterface(const IID& riid, void** ppv) override
{ {
static const QITAB qit[] = { static const QITAB qit[] = {
QITABENT(com_object_factory, IClassFactory), QITABENT(com_object_factory, IClassFactory),
@ -28,7 +28,7 @@ public:
return refCount; return refCount;
} }
HRESULT __stdcall CreateInstance(IUnknown* punkOuter, const IID & riid, void** ppv) HRESULT __stdcall CreateInstance(IUnknown* punkOuter, const IID& riid, void** ppv)
{ {
*ppv = nullptr; *ppv = nullptr;
HRESULT hr; HRESULT hr;

File diff suppressed because it is too large Load Diff

View File

@ -14,18 +14,20 @@ std::optional<RECT> get_window_pos(HWND hwnd);
std::optional<POINT> get_mouse_pos(); std::optional<POINT> get_mouse_pos();
// Test if window can be zoned by FancyZones // Test if window can be zoned by FancyZones
struct FancyZonesFilter { struct FancyZonesFilter
bool zonable = false; // If the window is zonable by FancyZones by default - true when both standard_window and no_visible_owner are also true {
bool standard_window = false; // True if from the styles the window looks like a standard window bool zonable = false; // If the window is zonable by FancyZones by default - true when both standard_window and no_visible_owner are also true
bool no_visible_owner = false; // True if the window is a top-level window that does not have a visible owner bool standard_window = false; // True if from the styles the window looks like a standard window
std::wstring process_path; // Path to the executable owning the window bool no_visible_owner = false; // True if the window is a top-level window that does not have a visible owner
std::wstring process_path; // Path to the executable owning the window
}; };
FancyZonesFilter get_fancyzones_filtered_window(HWND window); FancyZonesFilter get_fancyzones_filtered_window(HWND window);
// Gets active foreground window, filtering out all "non standard" windows like the taskbar, etc. // Gets active foreground window, filtering out all "non standard" windows like the taskbar, etc.
struct ShortcutGuideFilter { struct ShortcutGuideFilter
HWND hwnd = nullptr; // Handle to the top-level foreground window or nullptr if there is no such window {
bool snappable = false; // True, if the window can react to Windows Snap keys HWND hwnd = nullptr; // Handle to the top-level foreground window or nullptr if there is no such window
bool snappable = false; // True, if the window can react to Windows Snap keys
}; };
ShortcutGuideFilter get_shortcutguide_filtered_window(); ShortcutGuideFilter get_shortcutguide_filtered_window();
@ -42,17 +44,18 @@ int run_message_loop();
std::optional<std::wstring> get_last_error_message(const DWORD dw); std::optional<std::wstring> get_last_error_message(const DWORD dw);
void show_last_error_message(LPCWSTR lpszFunction, DWORD dw); void show_last_error_message(LPCWSTR lpszFunction, DWORD dw);
enum WindowState { enum WindowState
UNKNONW, {
MINIMIZED, UNKNONW,
MAXIMIZED, MINIMIZED,
SNAPED_TOP_LEFT, MAXIMIZED,
SNAPED_LEFT, SNAPED_TOP_LEFT,
SNAPED_BOTTOM_LEFT, SNAPED_LEFT,
SNAPED_TOP_RIGHT, SNAPED_BOTTOM_LEFT,
SNAPED_RIGHT, SNAPED_TOP_RIGHT,
SNAPED_BOTTOM_RIGHT, SNAPED_RIGHT,
RESTORED SNAPED_BOTTOM_RIGHT,
RESTORED
}; };
WindowState get_window_state(HWND hwnd); WindowState get_window_state(HWND hwnd);

View File

@ -1,105 +1,117 @@
#include "pch.h" #include "pch.h"
#include "d2d_svg.h" #include "d2d_svg.h"
D2DSVG& D2DSVG::load(const std::wstring& filename, ID2D1DeviceContext5* d2d_dc) { D2DSVG& D2DSVG::load(const std::wstring& filename, ID2D1DeviceContext5* d2d_dc)
svg = nullptr; {
winrt::com_ptr<IStream> svg_stream; svg = nullptr;
winrt::check_hresult(SHCreateStreamOnFileEx(filename.c_str(), winrt::com_ptr<IStream> svg_stream;
STGM_READ, FILE_ATTRIBUTE_NORMAL, FALSE, winrt::check_hresult(SHCreateStreamOnFileEx(filename.c_str(),
nullptr, STGM_READ,
svg_stream.put())); FILE_ATTRIBUTE_NORMAL,
FALSE,
nullptr,
svg_stream.put()));
winrt::check_hresult(d2d_dc->CreateSvgDocument( winrt::check_hresult(d2d_dc->CreateSvgDocument(
svg_stream.get(), svg_stream.get(),
D2D1::SizeF(1, 1), D2D1::SizeF(1, 1),
svg.put())); svg.put()));
winrt::com_ptr<ID2D1SvgElement> root; winrt::com_ptr<ID2D1SvgElement> root;
svg->GetRoot(root.put()); svg->GetRoot(root.put());
float tmp; float tmp;
winrt::check_hresult(root->GetAttributeValue(L"width", &tmp)); winrt::check_hresult(root->GetAttributeValue(L"width", &tmp));
svg_width = (int)tmp; svg_width = (int)tmp;
winrt::check_hresult(root->GetAttributeValue(L"height", &tmp)); winrt::check_hresult(root->GetAttributeValue(L"height", &tmp));
svg_height = (int)tmp; svg_height = (int)tmp;
return *this; return *this;
} }
D2DSVG& D2DSVG::resize(int x, int y, int width, int height, float fill, float max_scale) { D2DSVG& D2DSVG::resize(int x, int y, int width, int height, float fill, float max_scale)
// Center {
transform = D2D1::Matrix3x2F::Identity(); // Center
transform = transform * D2D1::Matrix3x2F::Translation((width - svg_width) / 2.0f, (height - svg_height) / 2.0f); transform = D2D1::Matrix3x2F::Identity();
float h_scale = fill * height / svg_height; transform = transform * D2D1::Matrix3x2F::Translation((width - svg_width) / 2.0f, (height - svg_height) / 2.0f);
float v_scale = fill * width / svg_width; float h_scale = fill * height / svg_height;
used_scale = min(h_scale, v_scale); float v_scale = fill * width / svg_width;
if (max_scale > 0) { used_scale = min(h_scale, v_scale);
used_scale = min(used_scale, max_scale); if (max_scale > 0)
} {
transform = transform * D2D1::Matrix3x2F::Scale(used_scale, used_scale, D2D1::Point2F(width / 2.0f, height / 2.0f)); used_scale = min(used_scale, max_scale);
transform = transform * D2D1::Matrix3x2F::Translation((float)x, (float)y); }
return *this; transform = transform * D2D1::Matrix3x2F::Scale(used_scale, used_scale, D2D1::Point2F(width / 2.0f, height / 2.0f));
transform = transform * D2D1::Matrix3x2F::Translation((float)x, (float)y);
return *this;
} }
D2DSVG& D2DSVG::recolor(uint32_t oldcolor, uint32_t newcolor) { D2DSVG& D2DSVG::recolor(uint32_t oldcolor, uint32_t newcolor)
auto new_color = D2D1::ColorF(newcolor & 0xFFFFFF, 1); {
auto old_color = D2D1::ColorF(oldcolor & 0xFFFFFF, 1); auto new_color = D2D1::ColorF(newcolor & 0xFFFFFF, 1);
std::function<void(ID2D1SvgElement* element)> recurse = [&](ID2D1SvgElement* element) { auto old_color = D2D1::ColorF(oldcolor & 0xFFFFFF, 1);
std::function<void(ID2D1SvgElement * element)> recurse = [&](ID2D1SvgElement* element) {
if (!element)
return;
if (element->IsAttributeSpecified(L"fill"))
{
D2D1_COLOR_F elem_fill;
winrt::com_ptr<ID2D1SvgPaint> paint;
element->GetAttributeValue(L"fill", paint.put());
paint->GetColor(&elem_fill);
if (elem_fill.r == old_color.r && elem_fill.g == old_color.g && elem_fill.b == old_color.b)
{
winrt::check_hresult(element->SetAttributeValue(L"fill", new_color));
}
}
winrt::com_ptr<ID2D1SvgElement> sub;
element->GetFirstChild(sub.put());
while (sub)
{
recurse(sub.get());
winrt::com_ptr<ID2D1SvgElement> next;
element->GetNextChild(sub.get(), next.put());
sub = next;
}
};
winrt::com_ptr<ID2D1SvgElement> root;
svg->GetRoot(root.put());
recurse(root.get());
return *this;
}
D2DSVG& D2DSVG::render(ID2D1DeviceContext5* d2d_dc)
{
D2D1_MATRIX_3X2_F current;
d2d_dc->GetTransform(&current);
d2d_dc->SetTransform(transform * current);
d2d_dc->DrawSvgDocument(svg.get());
d2d_dc->SetTransform(current);
return *this;
}
D2DSVG& D2DSVG::toggle_element(const wchar_t* id, bool visible)
{
winrt::com_ptr<ID2D1SvgElement> element;
if (svg->FindElementById(id, element.put()) != S_OK)
return *this;
if (!element) if (!element)
return; return *this;
if (element->IsAttributeSpecified(L"fill")) { element->SetAttributeValue(L"display", visible ? D2D1_SVG_DISPLAY::D2D1_SVG_DISPLAY_INLINE : D2D1_SVG_DISPLAY::D2D1_SVG_DISPLAY_NONE);
D2D1_COLOR_F elem_fill;
winrt::com_ptr<ID2D1SvgPaint> paint;
element->GetAttributeValue(L"fill", paint.put());
paint->GetColor(&elem_fill);
if (elem_fill.r == old_color.r && elem_fill.g == old_color.g && elem_fill.b == old_color.b) {
winrt::check_hresult(element->SetAttributeValue(L"fill", new_color));
}
}
winrt::com_ptr<ID2D1SvgElement> sub;
element->GetFirstChild(sub.put());
while (sub) {
recurse(sub.get());
winrt::com_ptr<ID2D1SvgElement> next;
element->GetNextChild(sub.get(), next.put());
sub = next;
}
};
winrt::com_ptr<ID2D1SvgElement> root;
svg->GetRoot(root.put());
recurse(root.get());
return *this;
}
D2DSVG& D2DSVG::render(ID2D1DeviceContext5* d2d_dc) {
D2D1_MATRIX_3X2_F current;
d2d_dc->GetTransform(&current);
d2d_dc->SetTransform(transform * current);
d2d_dc->DrawSvgDocument(svg.get());
d2d_dc->SetTransform(current);
return *this;
}
D2DSVG& D2DSVG::toggle_element(const wchar_t* id, bool visible) {
winrt::com_ptr<ID2D1SvgElement> element;
if (svg->FindElementById(id, element.put()) != S_OK)
return *this; return *this;
if (!element)
return *this;
element->SetAttributeValue(L"display", visible ? D2D1_SVG_DISPLAY::D2D1_SVG_DISPLAY_INLINE : D2D1_SVG_DISPLAY::D2D1_SVG_DISPLAY_NONE);
return *this;
} }
winrt::com_ptr<ID2D1SvgElement> D2DSVG::find_element(const std::wstring& id) { winrt::com_ptr<ID2D1SvgElement> D2DSVG::find_element(const std::wstring& id)
winrt::com_ptr< ID2D1SvgElement> element; {
winrt::check_hresult(svg->FindElementById(id.c_str(), element.put())); winrt::com_ptr<ID2D1SvgElement> element;
return element; winrt::check_hresult(svg->FindElementById(id.c_str(), element.put()));
return element;
} }
D2D1_RECT_F D2DSVG::rescale(D2D1_RECT_F rect) { D2D1_RECT_F D2DSVG::rescale(D2D1_RECT_F rect)
D2D1_RECT_F result; {
auto src = reinterpret_cast<D2D1_POINT_2F*>(&rect); D2D1_RECT_F result;
auto dst = reinterpret_cast<D2D1_POINT_2F*>(&result); auto src = reinterpret_cast<D2D1_POINT_2F*>(&rect);
dst[0] = src[0] * transform; auto dst = reinterpret_cast<D2D1_POINT_2F*>(&result);
dst[1] = src[1] * transform; dst[0] = src[0] * transform;
return result; dst[1] = src[1] * transform;
return result;
} }

View File

@ -4,21 +4,23 @@
#include <winrt/base.h> #include <winrt/base.h>
#include <string> #include <string>
class D2DSVG { class D2DSVG
{
public: public:
D2DSVG& load(const std::wstring& filename, ID2D1DeviceContext5* d2d_dc); D2DSVG& load(const std::wstring& filename, ID2D1DeviceContext5* d2d_dc);
D2DSVG& resize(int x, int y, int width, int height, float fill, float max_scale = -1.0f); D2DSVG& resize(int x, int y, int width, int height, float fill, float max_scale = -1.0f);
D2DSVG& render(ID2D1DeviceContext5* d2d_dc); D2DSVG& render(ID2D1DeviceContext5* d2d_dc);
D2DSVG& recolor(uint32_t oldcolor, uint32_t newcolor); D2DSVG& recolor(uint32_t oldcolor, uint32_t newcolor);
float get_scale() const { return used_scale; } float get_scale() const { return used_scale; }
int width() const { return svg_width; } int width() const { return svg_width; }
int height() const { return svg_height; } int height() const { return svg_height; }
D2DSVG& toggle_element(const wchar_t* id, bool visible); D2DSVG& toggle_element(const wchar_t* id, bool visible);
winrt::com_ptr<ID2D1SvgElement> find_element(const std::wstring& id); winrt::com_ptr<ID2D1SvgElement> find_element(const std::wstring& id);
D2D1_RECT_F rescale(D2D1_RECT_F rect); D2D1_RECT_F rescale(D2D1_RECT_F rect);
protected: protected:
float used_scale = 1.0f; float used_scale = 1.0f;
winrt::com_ptr<ID2D1SvgDocument> svg; winrt::com_ptr<ID2D1SvgDocument> svg;
int svg_width = -1, svg_height = -1; int svg_width = -1, svg_height = -1;
D2D1::Matrix3x2F transform; D2D1::Matrix3x2F transform;
}; };

View File

@ -1,48 +1,54 @@
#include "pch.h" #include "pch.h"
#include "d2d_text.h" #include "d2d_text.h"
D2DText::D2DText(float text_size, float scale) { D2DText::D2DText(float text_size, float scale)
winrt::check_hresult(DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(factory), reinterpret_cast<IUnknown**>(factory.put_void()))); {
resize(text_size, scale); winrt::check_hresult(DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(factory), reinterpret_cast<IUnknown**>(factory.put_void())));
winrt::check_hresult(format->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER)); resize(text_size, scale);
winrt::check_hresult(format->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER)); winrt::check_hresult(format->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER));
winrt::check_hresult(format->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER));
} }
D2DText & D2DText::resize(float text_size, float scale) { D2DText& D2DText::resize(float text_size, float scale)
format = nullptr; {
winrt::check_hresult(factory->CreateTextFormat(L"Segoe UI", format = nullptr;
nullptr, winrt::check_hresult(factory->CreateTextFormat(L"Segoe UI",
DWRITE_FONT_WEIGHT_NORMAL, nullptr,
DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_WEIGHT_NORMAL,
DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL,
text_size * scale, DWRITE_FONT_STRETCH_NORMAL,
L"en-us", text_size * scale,
format.put())); L"en-us",
winrt::check_hresult(format->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER)); format.put()));
return *this; winrt::check_hresult(format->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER));
return *this;
} }
D2DText & D2DText::set_aligment_left() { D2DText& D2DText::set_aligment_left()
winrt::check_hresult(format->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING)); {
return *this; winrt::check_hresult(format->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING));
return *this;
} }
D2DText & D2DText::set_aligment_center() { D2DText& D2DText::set_aligment_center()
winrt::check_hresult(format->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER)); {
return *this; winrt::check_hresult(format->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER));
return *this;
} }
D2DText & D2DText::set_aligment_right() { D2DText& D2DText::set_aligment_right()
winrt::check_hresult(format->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_TRAILING)); {
return *this; winrt::check_hresult(format->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_TRAILING));
return *this;
} }
void D2DText::write(ID2D1DeviceContext5 * d2d_dc, D2D1_COLOR_F color, D2D1_RECT_F rect, std::wstring text) { void D2DText::write(ID2D1DeviceContext5* d2d_dc, D2D1_COLOR_F color, D2D1_RECT_F rect, std::wstring text)
winrt::com_ptr<ID2D1SolidColorBrush> brush; {
d2d_dc->CreateSolidColorBrush(color, brush.put()); winrt::com_ptr<ID2D1SolidColorBrush> brush;
d2d_dc->DrawText(text.c_str(), d2d_dc->CreateSolidColorBrush(color, brush.put());
(UINT32)text.length(), d2d_dc->DrawText(text.c_str(),
format.get(), (UINT32)text.length(),
rect, format.get(),
brush.get()); rect,
brush.get());
} }

View File

@ -2,15 +2,17 @@
#include <winrt/base.h> #include <winrt/base.h>
#include <dwrite.h> #include <dwrite.h>
class D2DText { class D2DText
{
public: public:
D2DText(float text_size = 15.0f, float scale = 1.0f); D2DText(float text_size = 15.0f, float scale = 1.0f);
D2DText& resize(float text_size, float scale); D2DText& resize(float text_size, float scale);
D2DText& set_aligment_left(); D2DText& set_aligment_left();
D2DText& set_aligment_center(); D2DText& set_aligment_center();
D2DText& set_aligment_right(); D2DText& set_aligment_right();
void write(ID2D1DeviceContext5* d2d_dc, D2D1_COLOR_F color, D2D1_RECT_F rect, std::wstring text); void write(ID2D1DeviceContext5* d2d_dc, D2D1_COLOR_F color, D2D1_RECT_F rect, std::wstring text);
private: private:
winrt::com_ptr<IDWriteFactory> factory; winrt::com_ptr<IDWriteFactory> factory;
winrt::com_ptr<IDWriteTextFormat> format; winrt::com_ptr<IDWriteTextFormat> format;
}; };

View File

@ -3,182 +3,204 @@
extern "C" IMAGE_DOS_HEADER __ImageBase; extern "C" IMAGE_DOS_HEADER __ImageBase;
D2DWindow::D2DWindow() { D2DWindow::D2DWindow()
static const WCHAR* class_name = L"PToyD2DPopup"; {
WNDCLASS wc = {}; static const WCHAR* class_name = L"PToyD2DPopup";
wc.hCursor = LoadCursor(nullptr, IDC_ARROW); WNDCLASS wc = {};
wc.hInstance = reinterpret_cast<HINSTANCE>(&__ImageBase); wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
wc.lpszClassName = class_name; wc.hInstance = reinterpret_cast<HINSTANCE>(&__ImageBase);
wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpszClassName = class_name;
wc.lpfnWndProc = d2d_window_proc; wc.style = CS_HREDRAW | CS_VREDRAW;
RegisterClass(&wc); wc.lpfnWndProc = d2d_window_proc;
hwnd = CreateWindowExW(WS_EX_TOOLWINDOW | WS_EX_TOPMOST | WS_EX_NOREDIRECTIONBITMAP | WS_EX_LAYERED, RegisterClass(&wc);
wc.lpszClassName, hwnd = CreateWindowExW(WS_EX_TOOLWINDOW | WS_EX_TOPMOST | WS_EX_NOREDIRECTIONBITMAP | WS_EX_LAYERED,
L"PToyD2DPopup", wc.lpszClassName,
WS_POPUP| WS_VISIBLE, L"PToyD2DPopup",
CW_USEDEFAULT, CW_USEDEFAULT, WS_POPUP | WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
nullptr, nullptr, wc.hInstance, this); CW_USEDEFAULT,
WINRT_VERIFY(hwnd); CW_USEDEFAULT,
CW_USEDEFAULT,
nullptr,
nullptr,
wc.hInstance,
this);
WINRT_VERIFY(hwnd);
} }
void D2DWindow::show(UINT x, UINT y, UINT width, UINT height) { void D2DWindow::show(UINT x, UINT y, UINT width, UINT height)
if (!initialized) { {
if (!initialized)
{
base_init();
}
base_resize(width, height);
render_empty();
on_show();
SetWindowPos(hwnd, HWND_TOPMOST, x, y, width, height, 0);
ShowWindow(hwnd, SW_SHOWNORMAL);
UpdateWindow(hwnd);
}
void D2DWindow::hide()
{
ShowWindow(hwnd, SW_HIDE);
on_hide();
}
void D2DWindow::initialize()
{
base_init(); base_init();
}
base_resize(width, height);
render_empty();
on_show();
SetWindowPos(hwnd, HWND_TOPMOST, x, y, width, height, 0);
ShowWindow(hwnd, SW_SHOWNORMAL);
UpdateWindow(hwnd);
} }
void D2DWindow::hide() { void D2DWindow::base_init()
ShowWindow(hwnd, SW_HIDE); {
on_hide(); std::unique_lock lock(mutex);
} // D2D1Factory is independent from the device, no need to recreate it if we need to recreate the device.
if (!d2d_factory)
void D2DWindow::initialize() { {
base_init();
}
void D2DWindow::base_init() {
std::unique_lock lock(mutex);
// D2D1Factory is independent from the device, no need to recreate it if we need to recreate the device.
if (!d2d_factory) {
#ifdef _DEBUG #ifdef _DEBUG
D2D1_FACTORY_OPTIONS options = { D2D1_DEBUG_LEVEL_INFORMATION }; D2D1_FACTORY_OPTIONS options = { D2D1_DEBUG_LEVEL_INFORMATION };
#else #else
D2D1_FACTORY_OPTIONS options = {}; D2D1_FACTORY_OPTIONS options = {};
#endif #endif
winrt::check_hresult(D2D1CreateFactory(D2D1_FACTORY_TYPE_MULTI_THREADED, winrt::check_hresult(D2D1CreateFactory(D2D1_FACTORY_TYPE_MULTI_THREADED,
__uuidof(d2d_factory), __uuidof(d2d_factory),
&options, &options,
d2d_factory.put_void())); d2d_factory.put_void()));
} }
// For all other stuff - assing nullptr first to release the object, to reset the com_ptr. // For all other stuff - assing nullptr first to release the object, to reset the com_ptr.
d2d_dc = nullptr; d2d_dc = nullptr;
d2d_device = nullptr; d2d_device = nullptr;
dxgi_factory = nullptr; dxgi_factory = nullptr;
dxgi_device = nullptr; dxgi_device = nullptr;
d3d_device = nullptr; d3d_device = nullptr;
winrt::check_hresult(D3D11CreateDevice(nullptr, winrt::check_hresult(D3D11CreateDevice(nullptr,
D3D_DRIVER_TYPE_HARDWARE, D3D_DRIVER_TYPE_HARDWARE,
nullptr, nullptr,
D3D11_CREATE_DEVICE_BGRA_SUPPORT, D3D11_CREATE_DEVICE_BGRA_SUPPORT,
nullptr, nullptr,
0, 0,
D3D11_SDK_VERSION, D3D11_SDK_VERSION,
d3d_device.put(), d3d_device.put(),
nullptr, nullptr,
nullptr)); nullptr));
winrt::check_hresult(d3d_device->QueryInterface(__uuidof(dxgi_device), dxgi_device.put_void())); winrt::check_hresult(d3d_device->QueryInterface(__uuidof(dxgi_device), dxgi_device.put_void()));
winrt::check_hresult(CreateDXGIFactory2(0, __uuidof(dxgi_factory), dxgi_factory.put_void())); winrt::check_hresult(CreateDXGIFactory2(0, __uuidof(dxgi_factory), dxgi_factory.put_void()));
winrt::check_hresult(d2d_factory->CreateDevice(dxgi_device.get(), d2d_device.put())); winrt::check_hresult(d2d_factory->CreateDevice(dxgi_device.get(), d2d_device.put()));
winrt::check_hresult(d2d_device->CreateDeviceContext(D2D1_DEVICE_CONTEXT_OPTIONS_NONE, d2d_dc.put())); winrt::check_hresult(d2d_device->CreateDeviceContext(D2D1_DEVICE_CONTEXT_OPTIONS_NONE, d2d_dc.put()));
init(); init();
initialized = true; initialized = true;
} }
void D2DWindow::base_resize(UINT width, UINT height) { void D2DWindow::base_resize(UINT width, UINT height)
std::unique_lock lock(mutex); {
if (!initialized) { std::unique_lock lock(mutex);
return; if (!initialized)
} {
window_width = width; return;
window_height = height; }
if (window_width == 0 || window_height == 0) { window_width = width;
return; window_height = height;
} if (window_width == 0 || window_height == 0)
DXGI_SWAP_CHAIN_DESC1 sc_description = {}; {
sc_description.Format = DXGI_FORMAT_B8G8R8A8_UNORM; return;
sc_description.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; }
sc_description.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; DXGI_SWAP_CHAIN_DESC1 sc_description = {};
sc_description.BufferCount = 2; sc_description.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
sc_description.SampleDesc.Count = 1; sc_description.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
sc_description.AlphaMode = DXGI_ALPHA_MODE_PREMULTIPLIED; sc_description.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
sc_description.Width = window_width; sc_description.BufferCount = 2;
sc_description.Height = window_height; sc_description.SampleDesc.Count = 1;
dxgi_swap_chain = nullptr; sc_description.AlphaMode = DXGI_ALPHA_MODE_PREMULTIPLIED;
winrt::check_hresult(dxgi_factory->CreateSwapChainForComposition(dxgi_device.get(), sc_description.Width = window_width;
&sc_description, sc_description.Height = window_height;
nullptr, dxgi_swap_chain = nullptr;
dxgi_swap_chain.put())); winrt::check_hresult(dxgi_factory->CreateSwapChainForComposition(dxgi_device.get(),
composition_device = nullptr; &sc_description,
winrt::check_hresult(DCompositionCreateDevice(dxgi_device.get(), nullptr,
__uuidof(composition_device), dxgi_swap_chain.put()));
composition_device.put_void())); composition_device = nullptr;
winrt::check_hresult(DCompositionCreateDevice(dxgi_device.get(),
__uuidof(composition_device),
composition_device.put_void()));
composition_target = nullptr; composition_target = nullptr;
winrt::check_hresult(composition_device->CreateTargetForHwnd(hwnd, true, composition_target.put())); winrt::check_hresult(composition_device->CreateTargetForHwnd(hwnd, true, composition_target.put()));
composition_visual = nullptr; composition_visual = nullptr;
winrt::check_hresult(composition_device->CreateVisual(composition_visual.put())); winrt::check_hresult(composition_device->CreateVisual(composition_visual.put()));
winrt::check_hresult(composition_visual->SetContent(dxgi_swap_chain.get())); winrt::check_hresult(composition_visual->SetContent(dxgi_swap_chain.get()));
winrt::check_hresult(composition_target->SetRoot(composition_visual.get())); winrt::check_hresult(composition_target->SetRoot(composition_visual.get()));
dxgi_surface = nullptr; dxgi_surface = nullptr;
winrt::check_hresult(dxgi_swap_chain->GetBuffer(0, __uuidof(dxgi_surface), dxgi_surface.put_void())); winrt::check_hresult(dxgi_swap_chain->GetBuffer(0, __uuidof(dxgi_surface), dxgi_surface.put_void()));
D2D1_BITMAP_PROPERTIES1 properties = {}; D2D1_BITMAP_PROPERTIES1 properties = {};
properties.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED; properties.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED;
properties.pixelFormat.format = DXGI_FORMAT_B8G8R8A8_UNORM; properties.pixelFormat.format = DXGI_FORMAT_B8G8R8A8_UNORM;
properties.bitmapOptions = D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW; properties.bitmapOptions = D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW;
d2d_bitmap = nullptr; d2d_bitmap = nullptr;
winrt::check_hresult(d2d_dc->CreateBitmapFromDxgiSurface(dxgi_surface.get(), winrt::check_hresult(d2d_dc->CreateBitmapFromDxgiSurface(dxgi_surface.get(),
properties, properties,
d2d_bitmap.put())); d2d_bitmap.put()));
d2d_dc->SetTarget(d2d_bitmap.get()); d2d_dc->SetTarget(d2d_bitmap.get());
resize(); resize();
} }
void D2DWindow::base_render() { void D2DWindow::base_render()
std::unique_lock lock(mutex); {
if (!initialized || !d2d_dc || !d2d_bitmap) std::unique_lock lock(mutex);
return; if (!initialized || !d2d_dc || !d2d_bitmap)
d2d_dc->BeginDraw(); return;
render(d2d_dc.get()); d2d_dc->BeginDraw();
winrt::check_hresult(d2d_dc->EndDraw()); render(d2d_dc.get());
winrt::check_hresult(dxgi_swap_chain->Present(1, 0)); winrt::check_hresult(d2d_dc->EndDraw());
winrt::check_hresult(composition_device->Commit()); winrt::check_hresult(dxgi_swap_chain->Present(1, 0));
winrt::check_hresult(composition_device->Commit());
} }
void D2DWindow::render_empty() { void D2DWindow::render_empty()
std::unique_lock lock(mutex); {
if (!initialized || !d2d_dc || !d2d_bitmap) std::unique_lock lock(mutex);
return; if (!initialized || !d2d_dc || !d2d_bitmap)
d2d_dc->BeginDraw(); return;
d2d_dc->Clear(); d2d_dc->BeginDraw();
winrt::check_hresult(d2d_dc->EndDraw()); d2d_dc->Clear();
winrt::check_hresult(dxgi_swap_chain->Present(1, 0)); winrt::check_hresult(d2d_dc->EndDraw());
winrt::check_hresult(composition_device->Commit()); winrt::check_hresult(dxgi_swap_chain->Present(1, 0));
winrt::check_hresult(composition_device->Commit());
} }
D2DWindow::~D2DWindow() { D2DWindow::~D2DWindow()
ShowWindow(hwnd, SW_HIDE); {
DestroyWindow(hwnd); ShowWindow(hwnd, SW_HIDE);
DestroyWindow(hwnd);
} }
D2DWindow* D2DWindow::this_from_hwnd(HWND window) { D2DWindow* D2DWindow::this_from_hwnd(HWND window)
return reinterpret_cast<D2DWindow*>(GetWindowLongPtr(window, GWLP_USERDATA)); {
return reinterpret_cast<D2DWindow*>(GetWindowLongPtr(window, GWLP_USERDATA));
} }
LRESULT __stdcall D2DWindow::d2d_window_proc(HWND window, UINT message, WPARAM wparam, LPARAM lparam) { LRESULT __stdcall D2DWindow::d2d_window_proc(HWND window, UINT message, WPARAM wparam, LPARAM lparam)
switch (message) { {
case WM_NCCREATE: { switch (message)
auto create_struct = reinterpret_cast<CREATESTRUCT*>(lparam); {
SetWindowLongPtr(window, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(create_struct->lpCreateParams)); case WM_NCCREATE:
return TRUE; {
} auto create_struct = reinterpret_cast<CREATESTRUCT*>(lparam);
case WM_MOVE: SetWindowLongPtr(window, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(create_struct->lpCreateParams));
case WM_SIZE: return TRUE;
this_from_hwnd(window)->base_resize((unsigned)lparam & 0xFFFF, (unsigned)lparam >> 16); }
// Fall through to call 'base_render()' case WM_MOVE:
case WM_PAINT: case WM_SIZE:
this_from_hwnd(window)->base_render(); this_from_hwnd(window)->base_resize((unsigned)lparam & 0xFFFF, (unsigned)lparam >> 16);
return 0; // Fall through to call 'base_render()'
default: case WM_PAINT:
return DefWindowProc(window, message, wparam, lparam); this_from_hwnd(window)->base_render();
} return 0;
default:
return DefWindowProc(window, message, wparam, lparam);
}
} }

View File

@ -14,47 +14,48 @@
class D2DWindow class D2DWindow
{ {
public: public:
D2DWindow(); D2DWindow();
void show(UINT x, UINT y, UINT width, UINT height); void show(UINT x, UINT y, UINT width, UINT height);
void hide(); void hide();
void initialize(); void initialize();
virtual ~D2DWindow(); virtual ~D2DWindow();
protected: protected:
// Implement this: // Implement this:
// Initialization - called when D2D device needs to be created. // Initialization - called when D2D device needs to be created.
// When called all D2DWindow members will be initialized, including d2d_dc // When called all D2DWindow members will be initialized, including d2d_dc
virtual void init() = 0; virtual void init() = 0;
// resize - when called, window_width and window_height will have current window size // resize - when called, window_width and window_height will have current window size
virtual void resize() = 0; virtual void resize() = 0;
// render - called on WM_PAIT, BeginPaint/EndPaint is handled by D2DWindow // render - called on WM_PAIT, BeginPaint/EndPaint is handled by D2DWindow
virtual void render(ID2D1DeviceContext5* d2d_dc) = 0; virtual void render(ID2D1DeviceContext5* d2d_dc) = 0;
// on_show, on_hide - called when the window is about to be shown or about to be hidden // on_show, on_hide - called when the window is about to be shown or about to be hidden
virtual void on_show() = 0; virtual void on_show() = 0;
virtual void on_hide() = 0; virtual void on_hide() = 0;
static LRESULT __stdcall d2d_window_proc(HWND window, UINT message, WPARAM wparam, LPARAM lparam); static LRESULT __stdcall d2d_window_proc(HWND window, UINT message, WPARAM wparam, LPARAM lparam);
static D2DWindow* this_from_hwnd(HWND window); static D2DWindow* this_from_hwnd(HWND window);
void base_init();
void base_resize(UINT width, UINT height);
void base_render();
void render_empty();
std::recursive_mutex mutex; void base_init();
bool initialized = false; void base_resize(UINT width, UINT height);
HWND hwnd; void base_render();
UINT window_width, window_height; void render_empty();
winrt::com_ptr<ID3D11Device> d3d_device;
winrt::com_ptr<IDXGIDevice> dxgi_device; std::recursive_mutex mutex;
winrt::com_ptr<IDXGIFactory2> dxgi_factory; bool initialized = false;
winrt::com_ptr<IDXGISwapChain1> dxgi_swap_chain; HWND hwnd;
winrt::com_ptr<IDCompositionDevice> composition_device; UINT window_width, window_height;
winrt::com_ptr<IDCompositionTarget> composition_target; winrt::com_ptr<ID3D11Device> d3d_device;
winrt::com_ptr<IDCompositionVisual> composition_visual; winrt::com_ptr<IDXGIDevice> dxgi_device;
winrt::com_ptr<IDXGISurface2> dxgi_surface; winrt::com_ptr<IDXGIFactory2> dxgi_factory;
winrt::com_ptr<ID2D1Bitmap1> d2d_bitmap; winrt::com_ptr<IDXGISwapChain1> dxgi_swap_chain;
winrt::com_ptr<ID2D1Factory6> d2d_factory; winrt::com_ptr<IDCompositionDevice> composition_device;
winrt::com_ptr<ID2D1Device5> d2d_device; winrt::com_ptr<IDCompositionTarget> composition_target;
winrt::com_ptr<ID2D1DeviceContext5> d2d_dc; winrt::com_ptr<IDCompositionVisual> composition_visual;
winrt::com_ptr<IDXGISurface2> dxgi_surface;
winrt::com_ptr<ID2D1Bitmap1> d2d_bitmap;
winrt::com_ptr<ID2D1Factory6> d2d_factory;
winrt::com_ptr<ID2D1Device5> d2d_device;
winrt::com_ptr<ID2D1DeviceContext5> d2d_dc;
}; };

View File

@ -5,22 +5,22 @@
namespace json namespace json
{ {
std::optional<JsonObject> from_file(std::wstring_view file_name) std::optional<JsonObject> from_file(std::wstring_view file_name)
{
try
{ {
std::wifstream file(file_name.data(), std::ios::binary); try
using isbi = std::istreambuf_iterator<wchar_t>; {
return JsonValue::Parse(std::wstring{isbi{file}, isbi{}}).GetObjectW(); std::wifstream file(file_name.data(), std::ios::binary);
using isbi = std::istreambuf_iterator<wchar_t>;
return JsonValue::Parse(std::wstring{ isbi{ file }, isbi{} }).GetObjectW();
}
catch (...)
{
return std::nullopt;
}
} }
catch(...)
{
return std::nullopt;
}
}
void to_file(std::wstring_view file_name, const JsonObject & obj) void to_file(std::wstring_view file_name, const JsonObject& obj)
{ {
std::wofstream{file_name.data(), std::ios::binary} << obj.Stringify().c_str(); std::wofstream{ file_name.data(), std::ios::binary } << obj.Stringify().c_str();
} }
} }

View File

@ -7,44 +7,44 @@
namespace json namespace json
{ {
using namespace winrt::Windows::Data::Json; using namespace winrt::Windows::Data::Json;
std::optional<JsonObject> from_file(std::wstring_view file_name); std::optional<JsonObject> from_file(std::wstring_view file_name);
void to_file(std::wstring_view file_name, const JsonObject& obj); void to_file(std::wstring_view file_name, const JsonObject& obj);
inline bool has( inline bool has(
const json::JsonObject & o, const json::JsonObject& o,
std::wstring_view name, std::wstring_view name,
const json::JsonValueType type = JsonValueType::Object) const json::JsonValueType type = JsonValueType::Object)
{ {
return o.HasKey(name) && o.GetNamedValue(name).ValueType() == type; return o.HasKey(name) && o.GetNamedValue(name).ValueType() == type;
} }
template<typename T> template<typename T>
inline std::enable_if_t<std::is_arithmetic_v<T>, JsonValue> value(const T arithmetic) inline std::enable_if_t<std::is_arithmetic_v<T>, JsonValue> value(const T arithmetic)
{ {
return json::JsonValue::CreateNumberValue(arithmetic); return json::JsonValue::CreateNumberValue(arithmetic);
} }
template<typename T> template<typename T>
inline std::enable_if_t<!std::is_arithmetic_v<T>, JsonValue> value(T s) inline std::enable_if_t<!std::is_arithmetic_v<T>, JsonValue> value(T s)
{ {
return json::JsonValue::CreateStringValue(s); return json::JsonValue::CreateStringValue(s);
} }
inline JsonValue value(const bool boolean) inline JsonValue value(const bool boolean)
{ {
return json::JsonValue::CreateBooleanValue(boolean); return json::JsonValue::CreateBooleanValue(boolean);
} }
inline JsonValue value(JsonObject value) inline JsonValue value(JsonObject value)
{ {
return value.as<JsonValue>(); return value.as<JsonValue>();
} }
inline JsonValue value(JsonValue value) inline JsonValue value(JsonValue value)
{ {
return value; // identity function overload for convenience return value; // identity function overload for convenience
} }
} }

View File

@ -3,67 +3,77 @@
#include "common.h" #include "common.h"
#include "monitors.h" #include "monitors.h"
bool operator==(const ScreenSize& lhs, const ScreenSize& rhs) { bool operator==(const ScreenSize& lhs, const ScreenSize& rhs)
auto lhs_tuple = std::make_tuple(lhs.rect.left, lhs.rect.right, lhs.rect.top, lhs.rect.bottom); {
auto rhs_tuple = std::make_tuple(rhs.rect.left, rhs.rect.right, rhs.rect.top, rhs.rect.bottom); auto lhs_tuple = std::make_tuple(lhs.rect.left, lhs.rect.right, lhs.rect.top, lhs.rect.bottom);
return lhs_tuple == rhs_tuple; auto rhs_tuple = std::make_tuple(rhs.rect.left, rhs.rect.right, rhs.rect.top, rhs.rect.bottom);
return lhs_tuple == rhs_tuple;
} }
static BOOL CALLBACK get_displays_enum_cb(HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM data) { static BOOL CALLBACK get_displays_enum_cb(HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM data)
MONITORINFOEX monitor_info; {
monitor_info.cbSize = sizeof(MONITORINFOEX); MONITORINFOEX monitor_info;
GetMonitorInfo(monitor, &monitor_info); monitor_info.cbSize = sizeof(MONITORINFOEX);
reinterpret_cast<std::vector<MonitorInfo>*>(data)->emplace_back(monitor, monitor_info.rcWork); GetMonitorInfo(monitor, &monitor_info);
return true; reinterpret_cast<std::vector<MonitorInfo>*>(data)->emplace_back(monitor, monitor_info.rcWork);
return true;
}; };
static BOOL CALLBACK get_displays_enum_cb_with_toolbar(HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM data) { static BOOL CALLBACK get_displays_enum_cb_with_toolbar(HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM data)
MONITORINFOEX monitor_info; {
monitor_info.cbSize = sizeof(MONITORINFOEX); MONITORINFOEX monitor_info;
GetMonitorInfo(monitor, &monitor_info); monitor_info.cbSize = sizeof(MONITORINFOEX);
reinterpret_cast<std::vector<MonitorInfo>*>(data)->emplace_back(monitor, monitor_info.rcMonitor); GetMonitorInfo(monitor, &monitor_info);
return true; reinterpret_cast<std::vector<MonitorInfo>*>(data)->emplace_back(monitor, monitor_info.rcMonitor);
return true;
}; };
std::vector<MonitorInfo> MonitorInfo::GetMonitors(bool include_toolbar) { std::vector<MonitorInfo> MonitorInfo::GetMonitors(bool include_toolbar)
std::vector<MonitorInfo> monitors; {
EnumDisplayMonitors(NULL, NULL, include_toolbar ? get_displays_enum_cb_with_toolbar : get_displays_enum_cb, reinterpret_cast<LPARAM>(&monitors)); std::vector<MonitorInfo> monitors;
std::sort(begin(monitors), end(monitors), [](const MonitorInfo& lhs, const MonitorInfo& rhs) { EnumDisplayMonitors(NULL, NULL, include_toolbar ? get_displays_enum_cb_with_toolbar : get_displays_enum_cb, reinterpret_cast<LPARAM>(&monitors));
return lhs.rect < rhs.rect; std::sort(begin(monitors), end(monitors), [](const MonitorInfo& lhs, const MonitorInfo& rhs) {
return lhs.rect < rhs.rect;
}); });
return monitors; return monitors;
} }
static BOOL CALLBACK get_primary_display_enum_cb(HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM data) { static BOOL CALLBACK get_primary_display_enum_cb(HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM data)
MONITORINFOEX monitor_info; {
monitor_info.cbSize = sizeof(MONITORINFOEX); MONITORINFOEX monitor_info;
GetMonitorInfo(monitor, &monitor_info); monitor_info.cbSize = sizeof(MONITORINFOEX);
if (monitor_info.dwFlags & MONITORINFOF_PRIMARY) { GetMonitorInfo(monitor, &monitor_info);
reinterpret_cast<MonitorInfo*>(data)->handle = monitor; if (monitor_info.dwFlags & MONITORINFOF_PRIMARY)
reinterpret_cast<MonitorInfo*>(data)->rect = monitor_info.rcWork; {
} reinterpret_cast<MonitorInfo*>(data)->handle = monitor;
return true; reinterpret_cast<MonitorInfo*>(data)->rect = monitor_info.rcWork;
}
return true;
}; };
MonitorInfo MonitorInfo::GetPrimaryMonitor() { MonitorInfo MonitorInfo::GetPrimaryMonitor()
MonitorInfo primary({}, {}); {
EnumDisplayMonitors(NULL, NULL, get_primary_display_enum_cb, reinterpret_cast<LPARAM>(&primary)); MonitorInfo primary({}, {});
return primary; EnumDisplayMonitors(NULL, NULL, get_primary_display_enum_cb, reinterpret_cast<LPARAM>(&primary));
return primary;
} }
MonitorInfo MonitorInfo::GetFromWindow(HWND hwnd) { MonitorInfo MonitorInfo::GetFromWindow(HWND hwnd)
auto monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST); {
return GetFromHandle(monitor); auto monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
return GetFromHandle(monitor);
} }
MonitorInfo MonitorInfo::GetFromPoint(POINT p) { MonitorInfo MonitorInfo::GetFromPoint(POINT p)
auto monitor = MonitorFromPoint(p, MONITOR_DEFAULTTONEAREST); {
return GetFromHandle(monitor); auto monitor = MonitorFromPoint(p, MONITOR_DEFAULTTONEAREST);
return GetFromHandle(monitor);
} }
MonitorInfo MonitorInfo::GetFromHandle(HMONITOR monitor) { MonitorInfo MonitorInfo::GetFromHandle(HMONITOR monitor)
MONITORINFOEX monitor_info; {
monitor_info.cbSize = sizeof(MONITORINFOEX); MONITORINFOEX monitor_info;
GetMonitorInfo(monitor, &monitor_info); monitor_info.cbSize = sizeof(MONITORINFOEX);
return MonitorInfo(monitor, monitor_info.rcWork); GetMonitorInfo(monitor, &monitor_info);
return MonitorInfo(monitor, monitor_info.rcWork);
} }

View File

@ -2,40 +2,44 @@
#include <Windows.h> #include <Windows.h>
#include <vector> #include <vector>
struct ScreenSize { struct ScreenSize
explicit ScreenSize(RECT rect) : rect(rect) {} {
RECT rect; explicit ScreenSize(RECT rect) :
int left() const { return rect.left; } rect(rect) {}
int right() const { return rect.right; } RECT rect;
int top() const { return rect.top; } int left() const { return rect.left; }
int bottom() const { return rect.bottom; } int right() const { return rect.right; }
int height() const { return rect.bottom - rect.top; }; int top() const { return rect.top; }
int width() const { return rect.right - rect.left; }; int bottom() const { return rect.bottom; }
POINT top_left() const { return { rect.left, rect.top }; }; int height() const { return rect.bottom - rect.top; };
POINT top_middle() const { return { rect.left + width() / 2, rect.top }; }; int width() const { return rect.right - rect.left; };
POINT top_right() const { return { rect.right, rect.top }; }; POINT top_left() const { return { rect.left, rect.top }; };
POINT middle_left() const { return { rect.left, rect.top + height() / 2 }; }; POINT top_middle() const { return { rect.left + width() / 2, rect.top }; };
POINT middle() const { return { rect.left + width() / 2, rect.top + height() / 2 }; }; POINT top_right() const { return { rect.right, rect.top }; };
POINT middle_right() const { return { rect.right, rect.top + height() / 2 }; }; POINT middle_left() const { return { rect.left, rect.top + height() / 2 }; };
POINT bottom_left() const { return { rect.left, rect.bottom }; }; POINT middle() const { return { rect.left + width() / 2, rect.top + height() / 2 }; };
POINT bottm_midle() const { return { rect.left + width() / 2, rect.bottom }; }; POINT middle_right() const { return { rect.right, rect.top + height() / 2 }; };
POINT bottom_right() const { return { rect.right, rect.bottom }; }; POINT bottom_left() const { return { rect.left, rect.bottom }; };
POINT bottm_midle() const { return { rect.left + width() / 2, rect.bottom }; };
POINT bottom_right() const { return { rect.right, rect.bottom }; };
}; };
struct MonitorInfo : ScreenSize { struct MonitorInfo : ScreenSize
explicit MonitorInfo(HMONITOR monitor, RECT rect) : handle(monitor), ScreenSize(rect) {} {
HMONITOR handle; explicit MonitorInfo(HMONITOR monitor, RECT rect) :
handle(monitor), ScreenSize(rect) {}
HMONITOR handle;
// Returns monitor rects ordered from left to right // Returns monitor rects ordered from left to right
static std::vector<MonitorInfo> GetMonitors(bool include_toolbar); static std::vector<MonitorInfo> GetMonitors(bool include_toolbar);
// Return primary display // Return primary display
static MonitorInfo GetPrimaryMonitor(); static MonitorInfo GetPrimaryMonitor();
// Return monitor on which hwnd window is displayed // Return monitor on which hwnd window is displayed
static MonitorInfo GetFromWindow(HWND hwnd); static MonitorInfo GetFromWindow(HWND hwnd);
// Return monitor nearest to a point // Return monitor nearest to a point
static MonitorInfo GetFromPoint(POINT p); static MonitorInfo GetFromPoint(POINT p);
// Return monitor info given a HMONITOR // Return monitor info given a HMONITOR
static MonitorInfo GetFromHandle(HMONITOR monitor); static MonitorInfo GetFromHandle(HMONITOR monitor);
}; };
bool operator==(const ScreenSize& lhs, const ScreenSize& rhs); bool operator==(const ScreenSize& lhs, const ScreenSize& rhs);

View File

@ -1,2 +1 @@
#include "pch.h" #include "pch.h"

View File

@ -189,7 +189,7 @@ void notifications::show_toast_with_activations(std::wstring_view message, std::
std::wstring toast_xml; std::wstring toast_xml;
toast_xml.reserve(1024); toast_xml.reserve(1024);
std::wstring title{L"PowerToys"}; std::wstring title{ L"PowerToys" };
if (winstore::running_as_packaged()) if (winstore::running_as_packaged())
{ {
title += L" (Experimental)"; title += L" (Experimental)";

View File

@ -2,38 +2,42 @@
#include "on_thread_executor.h" #include "on_thread_executor.h"
OnThreadExecutor::OnThreadExecutor() OnThreadExecutor::OnThreadExecutor() :
: _shutdown_request{false} _shutdown_request{ false }, _worker_thread{ [this] { worker_thread(); } }
, _worker_thread{[this] { worker_thread(); }} {
{}
std::future<void> OnThreadExecutor::submit(task_t task) {
auto future = task.get_future();
std::lock_guard lock{_task_mutex};
_task_queue.emplace(std::move(task));
_task_cv.notify_one();
return future;
} }
void OnThreadExecutor::worker_thread() { std::future<void> OnThreadExecutor::submit(task_t task)
while(!_shutdown_request) { {
task_t task; auto future = task.get_future();
std::lock_guard lock{ _task_mutex };
_task_queue.emplace(std::move(task));
_task_cv.notify_one();
return future;
}
void OnThreadExecutor::worker_thread()
{
while (!_shutdown_request)
{ {
std::unique_lock task_lock{_task_mutex}; task_t task;
_task_cv.wait(task_lock, [this] { return !_task_queue.empty() || _shutdown_request; }); {
if(_shutdown_request) { std::unique_lock task_lock{ _task_mutex };
return; _task_cv.wait(task_lock, [this] { return !_task_queue.empty() || _shutdown_request; });
} if (_shutdown_request)
task = std::move(_task_queue.front()); {
_task_queue.pop(); return;
}
task = std::move(_task_queue.front());
_task_queue.pop();
}
task();
} }
task();
}
} }
OnThreadExecutor::~OnThreadExecutor() { OnThreadExecutor::~OnThreadExecutor()
_shutdown_request = true; {
_task_cv.notify_one(); _shutdown_request = true;
_worker_thread.join(); _task_cv.notify_one();
_worker_thread.join();
} }

View File

@ -10,21 +10,22 @@
// This might come in handy if you use the API which sets thread-wide global state and the state needs // This might come in handy if you use the API which sets thread-wide global state and the state needs
// to be isolated. // to be isolated.
class OnThreadExecutor final { class OnThreadExecutor final
{
public: public:
using task_t = std::packaged_task<void()>; using task_t = std::packaged_task<void()>;
OnThreadExecutor(); OnThreadExecutor();
~OnThreadExecutor(); ~OnThreadExecutor();
std::future<void> submit(task_t task); std::future<void> submit(task_t task);
private: private:
void worker_thread(); void worker_thread();
std::thread _worker_thread; std::thread _worker_thread;
std::mutex _task_mutex; std::mutex _task_mutex;
std::condition_variable _task_cv; std::condition_variable _task_cv;
std::atomic_bool _shutdown_request; std::atomic_bool _shutdown_request;
std::queue<std::packaged_task<void()>> _task_queue; std::queue<std::packaged_task<void()>> _task_queue;
}; };

View File

@ -22,4 +22,3 @@
#include <unordered_set> #include <unordered_set>
#include <string> #include <string>
#include <vector> #include <vector>

View File

@ -3,62 +3,72 @@
#include <filesystem> #include <filesystem>
#include <fstream> #include <fstream>
namespace PTSettingsHelper { namespace PTSettingsHelper
{
constexpr inline const wchar_t* settings_filename = L"\\settings.json";
constexpr inline const wchar_t * settings_filename = L"\\settings.json"; std::wstring get_root_save_folder_location()
{
PWSTR local_app_path;
winrt::check_hresult(SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, NULL, &local_app_path));
std::wstring result{ local_app_path };
CoTaskMemFree(local_app_path);
std::wstring get_root_save_folder_location() { result += L"\\Microsoft\\PowerToys";
PWSTR local_app_path; std::filesystem::path save_path(result);
winrt::check_hresult(SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, NULL, &local_app_path)); if (!std::filesystem::exists(save_path))
std::wstring result{local_app_path}; {
CoTaskMemFree(local_app_path); std::filesystem::create_directories(save_path);
}
result += L"\\Microsoft\\PowerToys"; return result;
std::filesystem::path save_path(result);
if (!std::filesystem::exists(save_path)) {
std::filesystem::create_directories(save_path);
} }
return result;
}
std::wstring get_module_save_folder_location(std::wstring_view powertoy_name) { std::wstring get_module_save_folder_location(std::wstring_view powertoy_name)
std::wstring result = get_root_save_folder_location(); {
result += L"\\"; std::wstring result = get_root_save_folder_location();
result += powertoy_name; result += L"\\";
std::filesystem::path save_path(result); result += powertoy_name;
if (!std::filesystem::exists(save_path)) { std::filesystem::path save_path(result);
std::filesystem::create_directories(save_path); if (!std::filesystem::exists(save_path))
{
std::filesystem::create_directories(save_path);
}
return result;
} }
return result;
}
std::wstring get_module_save_file_location(std::wstring_view powertoy_name) { std::wstring get_module_save_file_location(std::wstring_view powertoy_name)
return get_module_save_folder_location(powertoy_name) + settings_filename; {
} return get_module_save_folder_location(powertoy_name) + settings_filename;
}
std::wstring get_powertoys_general_save_file_location() { std::wstring get_powertoys_general_save_file_location()
return get_root_save_folder_location() + settings_filename; {
} return get_root_save_folder_location() + settings_filename;
}
void save_module_settings(std::wstring_view powertoy_name, json::JsonObject& settings) { void save_module_settings(std::wstring_view powertoy_name, json::JsonObject& settings)
const std::wstring save_file_location = get_module_save_file_location(powertoy_name); {
json::to_file(save_file_location, settings); const std::wstring save_file_location = get_module_save_file_location(powertoy_name);
} json::to_file(save_file_location, settings);
}
json::JsonObject load_module_settings(std::wstring_view powertoy_name) { json::JsonObject load_module_settings(std::wstring_view powertoy_name)
const std::wstring save_file_location = get_module_save_file_location(powertoy_name); {
auto saved_settings = json::from_file(save_file_location); const std::wstring save_file_location = get_module_save_file_location(powertoy_name);
return saved_settings.has_value() ? std::move(*saved_settings) : json::JsonObject{}; auto saved_settings = json::from_file(save_file_location);
} return saved_settings.has_value() ? std::move(*saved_settings) : json::JsonObject{};
}
void save_general_settings(const json::JsonObject& settings) { void save_general_settings(const json::JsonObject& settings)
const std::wstring save_file_location = get_powertoys_general_save_file_location(); {
json::to_file(save_file_location, settings); const std::wstring save_file_location = get_powertoys_general_save_file_location();
} json::to_file(save_file_location, settings);
}
json::JsonObject load_general_settings() { json::JsonObject load_general_settings()
const std::wstring save_file_location = get_powertoys_general_save_file_location(); {
auto saved_settings = json::from_file(save_file_location); const std::wstring save_file_location = get_powertoys_general_save_file_location();
return saved_settings.has_value() ? std::move(*saved_settings) : json::JsonObject{}; auto saved_settings = json::from_file(save_file_location);
} return saved_settings.has_value() ? std::move(*saved_settings) : json::JsonObject{};
}
} }

View File

@ -4,14 +4,14 @@
#include "json.h" #include "json.h"
namespace PTSettingsHelper { namespace PTSettingsHelper
{
std::wstring get_module_save_folder_location(std::wstring_view powertoy_name);
std::wstring get_root_save_folder_location();
std::wstring get_module_save_folder_location(std::wstring_view powertoy_name); void save_module_settings(std::wstring_view powertoy_name, json::JsonObject& settings);
std::wstring get_root_save_folder_location(); json::JsonObject load_module_settings(std::wstring_view powertoy_name);
void save_general_settings(const json::JsonObject& settings);
void save_module_settings(std::wstring_view powertoy_name, json::JsonObject& settings); json::JsonObject load_general_settings();
json::JsonObject load_module_settings(std::wstring_view powertoy_name);
void save_general_settings(const json::JsonObject& settings);
json::JsonObject load_general_settings();
} }

View File

@ -2,298 +2,350 @@
#include "settings_objects.h" #include "settings_objects.h"
#include "settings_helpers.h" #include "settings_helpers.h"
namespace PowerToysSettings { namespace PowerToysSettings
{
Settings::Settings(const HINSTANCE hinstance, std::wstring_view powertoy_name) { Settings::Settings(const HINSTANCE hinstance, std::wstring_view powertoy_name)
m_instance = hinstance; {
m_json.SetNamedValue(L"version", json::value(L"1.0")); m_instance = hinstance;
m_json.SetNamedValue(L"name", json::value(powertoy_name)); m_json.SetNamedValue(L"version", json::value(L"1.0"));
m_json.SetNamedValue(L"properties", json::JsonObject{}); m_json.SetNamedValue(L"name", json::value(powertoy_name));
} m_json.SetNamedValue(L"properties", json::JsonObject{});
void Settings::set_description(UINT resource_id) {
m_json.SetNamedValue(L"description", json::value(get_resource(resource_id)));
}
void Settings::set_description(std::wstring_view description) {
m_json.SetNamedValue(L"description", json::value(description));
}
void Settings::set_icon_key(std::wstring_view icon_key) {
m_json.SetNamedValue(L"icon_key", json::value(icon_key));
}
void Settings::set_overview_link(std::wstring_view overview_link) {
m_json.SetNamedValue(L"overview_link", json::value(overview_link));
}
void Settings::set_video_link(std::wstring_view video_link) {
m_json.SetNamedValue(L"video_link", json::value(video_link));
}
// add_bool_toogle overloads.
void Settings::add_bool_toogle(std::wstring_view name, UINT description_resource_id, bool value) {
add_bool_toogle(name, get_resource(description_resource_id), value);
}
void Settings::add_bool_toogle(std::wstring_view name, std::wstring_view description, bool value) {
json::JsonObject toggle;
toggle.SetNamedValue(L"display_name", json::value(description));
toggle.SetNamedValue(L"editor_type", json::value(L"bool_toggle"));
toggle.SetNamedValue(L"value", json::value(value));
toggle.SetNamedValue(L"order", json::value(++m_curr_priority));
m_json.GetNamedObject(L"properties").SetNamedValue(name, toggle);
}
// add_int_spinner overloads.
void Settings::add_int_spinner(std::wstring_view name, UINT description_resource_id, int value, int min, int max, int step) {
add_int_spinner(name, get_resource(description_resource_id), value, min, max, step);
}
void Settings::add_int_spinner(std::wstring_view name, std::wstring_view description, int value, int min, int max, int step) {
json::JsonObject spinner;
spinner.SetNamedValue(L"display_name", json::value(description));
spinner.SetNamedValue(L"editor_type", json::value(L"int_spinner"));
spinner.SetNamedValue(L"value", json::value(value));
spinner.SetNamedValue(L"min", json::value(min));
spinner.SetNamedValue(L"max", json::value(max));
spinner.SetNamedValue(L"step", json::value(step));
spinner.SetNamedValue(L"order", json::value(++m_curr_priority));
m_json.GetNamedObject(L"properties").SetNamedValue(name, spinner);
}
// add_string overloads.
void Settings::add_string(std::wstring_view name, UINT description_resource_id, std::wstring_view value) {
add_string(name, get_resource(description_resource_id), value);
}
void Settings::add_string(std::wstring_view name, std::wstring_view description, std::wstring_view value) {
json::JsonObject string;
string.SetNamedValue(L"display_name", json::value(description));
string.SetNamedValue(L"editor_type", json::value(L"string_text"));
string.SetNamedValue(L"value", json::value(value));
string.SetNamedValue(L"order", json::value(++m_curr_priority));
m_json.GetNamedObject(L"properties").SetNamedValue(name, string);
}
// add_multiline_string overloads.
void Settings::add_multiline_string(std::wstring_view name, UINT description_resource_id, std::wstring_view value) {
add_multiline_string(name, get_resource(description_resource_id), value);
}
void Settings::add_multiline_string(std::wstring_view name, std::wstring_view description, std::wstring_view value) {
json::JsonObject ml_string;
ml_string.SetNamedValue(L"display_name", json::value(description));
ml_string.SetNamedValue(L"editor_type", json::value(L"string_text"));
ml_string.SetNamedValue(L"value", json::value(value));
ml_string.SetNamedValue(L"order", json::value(++m_curr_priority));
ml_string.SetNamedValue(L"multiline", json::value(true));
m_json.GetNamedObject(L"properties").SetNamedValue(name, ml_string);
}
// add_color_picker overloads.
void Settings::add_color_picker(std::wstring_view name, UINT description_resource_id, std::wstring_view value) {
add_color_picker(name, get_resource(description_resource_id), value);
}
void Settings::add_color_picker(std::wstring_view name, std::wstring_view description, std::wstring_view value) {
json::JsonObject picker;
picker.SetNamedValue(L"display_name", json::value(description));
picker.SetNamedValue(L"editor_type", json::value(L"color_picker"));
picker.SetNamedValue(L"value", json::value(value));
picker.SetNamedValue(L"order", json::value(++m_curr_priority));
m_json.GetNamedObject(L"properties").SetNamedValue(name, picker);
}
void Settings::add_hotkey(std::wstring_view name, UINT description_resource_id, const HotkeyObject& hotkey) {
add_hotkey(name, get_resource(description_resource_id), hotkey);
}
void Settings::add_hotkey(std::wstring_view name, std::wstring_view description, const HotkeyObject& hotkey_obj) {
json::JsonObject hotkey;
hotkey.SetNamedValue(L"display_name", json::value(description));
hotkey.SetNamedValue(L"editor_type", json::value(L"hotkey"));
hotkey.SetNamedValue(L"value", hotkey_obj.get_json());
hotkey.SetNamedValue(L"order", json::value(++m_curr_priority));
m_json.GetNamedObject(L"properties").SetNamedValue(name, hotkey);
}
void Settings::add_choice_group(std::wstring_view name, UINT description_resource_id, std::wstring_view value, const std::vector<std::pair<std::wstring, UINT>>& keys_and_text_ids) {
std::vector<std::pair<std::wstring, std::wstring>> keys_and_texts;
keys_and_texts.reserve(keys_and_text_ids.size());
for (const auto& kv : keys_and_text_ids) {
keys_and_texts.emplace_back(kv.first, get_resource(kv.second));
}
add_choice_group(name, get_resource(description_resource_id), value, keys_and_texts);
}
void Settings::add_choice_group(std::wstring_view name, std::wstring_view description, std::wstring_view value, const std::vector<std::pair<std::wstring, std::wstring>>& keys_and_texts) {
json::JsonObject choice_group;
choice_group.SetNamedValue(L"display_name", json::value(description));
choice_group.SetNamedValue(L"editor_type", json::value(L"choice_group"));
json::JsonArray options;
for(const auto & [key, text] : keys_and_texts) {
json::JsonObject entry;
entry.SetNamedValue(L"key", json::value(key));
entry.SetNamedValue(L"text", json::value(text));
options.Append(std::move(entry));
}
choice_group.SetNamedValue(L"options", std::move(options));
choice_group.SetNamedValue(L"value", json::value(value));
choice_group.SetNamedValue(L"order", json::value(++m_curr_priority));
m_json.GetNamedObject(L"properties").SetNamedValue(name, choice_group);
}
void Settings::add_dropdown(std::wstring_view name, UINT description_resource_id, std::wstring_view value, const std::vector<std::pair<std::wstring, UINT>>& keys_and_text_ids) {
std::vector<std::pair<std::wstring, std::wstring>> keys_and_texts;
keys_and_texts.reserve(keys_and_text_ids.size());
for (const auto& kv : keys_and_text_ids) {
keys_and_texts.emplace_back(kv.first, get_resource(kv.second));
}
add_dropdown(name, get_resource(description_resource_id), value, keys_and_texts);
}
void Settings::add_dropdown(std::wstring_view name, std::wstring_view description, std::wstring_view value, const std::vector<std::pair<std::wstring, std::wstring>>& keys_and_texts) {
json::JsonObject dropdown;
dropdown.SetNamedValue(L"display_name", json::value(description));
dropdown.SetNamedValue(L"editor_type", json::value(L"dropdown"));
json::JsonArray options;
for(const auto & [key, text] : keys_and_texts) {
json::JsonObject entry;
entry.SetNamedValue(L"key", json::value(key));
entry.SetNamedValue(L"text", json::value(text));
options.Append(std::move(entry));
}
dropdown.SetNamedValue(L"options", std::move(options));
dropdown.SetNamedValue(L"value", json::value(value));
dropdown.SetNamedValue(L"order", json::value(++m_curr_priority));
m_json.GetNamedObject(L"properties").SetNamedValue(name, dropdown);
}
// add_custom_action overloads.
void Settings::add_custom_action(std::wstring_view name, UINT description_resource_id, UINT button_text_resource_id, UINT ext_description_resource_id) {
add_custom_action(name, get_resource(description_resource_id), get_resource(button_text_resource_id), get_resource(ext_description_resource_id));
}
void Settings::add_custom_action(std::wstring_view name, UINT description_resource_id, UINT button_text_resource_id, std::wstring_view value) {
add_custom_action(name, get_resource(description_resource_id), get_resource(button_text_resource_id), value);
}
void Settings::add_custom_action(std::wstring_view name, std::wstring_view description, std::wstring_view button_text, std::wstring_view value) {
json::JsonObject custom_action;
custom_action.SetNamedValue(L"display_name", json::value(description));
custom_action.SetNamedValue(L"button_text", json::value(button_text));
custom_action.SetNamedValue(L"editor_type", json::value(L"custom_action"));
custom_action.SetNamedValue(L"value", json::value(value));
custom_action.SetNamedValue(L"order", json::value(++m_curr_priority));
m_json.GetNamedObject(L"properties").SetNamedValue(name, custom_action);
}
// Serialization methods.
std::wstring Settings::serialize() {
return m_json.Stringify().c_str();
}
bool Settings::serialize_to_buffer(wchar_t* buffer, int *buffer_size) {
auto result = m_json.Stringify();
const int result_len = (int)result.size() + 1;
if (buffer == nullptr || *buffer_size < result_len) {
*buffer_size = result_len;
return false;
} else {
wcscpy_s(buffer, *buffer_size, result.c_str());
return true;
}
}
// Resource helper.
std::wstring Settings::get_resource(UINT resource_id) {
if (resource_id != 0) {
wchar_t* res_ptr;
const size_t resource_length = LoadStringW(m_instance, resource_id, reinterpret_cast<wchar_t *>(&res_ptr), 0);
if (resource_length != 0) {
return {*reinterpret_cast<wchar_t **>(&res_ptr), resource_length};
}
} }
return L"RESOURCE ID NOT FOUND: " + std::to_wstring(resource_id); void Settings::set_description(UINT resource_id)
} {
m_json.SetNamedValue(L"description", json::value(get_resource(resource_id)));
PowerToyValues::PowerToyValues(std::wstring_view powertoy_name) {
_name = powertoy_name;
set_version();
m_json.SetNamedValue(L"name", json::value(powertoy_name));
m_json.SetNamedValue(L"properties", json::JsonObject{});
}
PowerToyValues PowerToyValues::from_json_string(std::wstring_view json) {
PowerToyValues result = PowerToyValues();
result.m_json = json::JsonValue::Parse(json).GetObjectW();
result._name = result.m_json.GetNamedString(L"name");
return result;
}
PowerToyValues PowerToyValues::load_from_settings_file(std::wstring_view powertoy_name) {
PowerToyValues result = PowerToyValues();
result.m_json = PTSettingsHelper::load_module_settings(powertoy_name);
result._name = powertoy_name;
return result;
}
inline bool has_property(const json::JsonObject& o, std::wstring_view name, const json::JsonValueType type) {
const json::JsonObject props = o.GetNamedObject(L"properties", json::JsonObject{});
return json::has(props, name) && json::has(props.GetNamedObject(name), L"value", type);
}
std::optional<bool> PowerToyValues::get_bool_value(std::wstring_view property_name) {
if (!has_property(m_json, property_name, json::JsonValueType::Boolean)) {
return std::nullopt;
} }
return m_json.GetNamedObject(L"properties").GetNamedObject(property_name).GetNamedBoolean(L"value");
}
std::optional<int> PowerToyValues::get_int_value(std::wstring_view property_name) { void Settings::set_description(std::wstring_view description)
if (!has_property(m_json, property_name, json::JsonValueType::Number)) { {
return std::nullopt; m_json.SetNamedValue(L"description", json::value(description));
} }
return static_cast<int>(m_json.GetNamedObject(L"properties").GetNamedObject(property_name).GetNamedNumber(L"value"));
}
std::optional<std::wstring> PowerToyValues::get_string_value(std::wstring_view property_name) { void Settings::set_icon_key(std::wstring_view icon_key)
if (!has_property(m_json, property_name, json::JsonValueType::String)) { {
return std::nullopt; m_json.SetNamedValue(L"icon_key", json::value(icon_key));
} }
return m_json.GetNamedObject(L"properties").GetNamedObject(property_name).GetNamedString(L"value").c_str();
}
std::optional<json::JsonObject> PowerToyValues::get_json(std::wstring_view property_name) { void Settings::set_overview_link(std::wstring_view overview_link)
if (!has_property(m_json, property_name, json::JsonValueType::Object)) { {
return std::nullopt; m_json.SetNamedValue(L"overview_link", json::value(overview_link));
} }
return m_json.GetNamedObject(L"properties").GetNamedObject(property_name).GetNamedObject(L"value");
}
std::wstring PowerToyValues::serialize() { void Settings::set_video_link(std::wstring_view video_link)
set_version(); {
return m_json.Stringify().c_str(); m_json.SetNamedValue(L"video_link", json::value(video_link));
} }
void PowerToyValues::save_to_settings_file() { // add_bool_toogle overloads.
set_version(); void Settings::add_bool_toogle(std::wstring_view name, UINT description_resource_id, bool value)
PTSettingsHelper::save_module_settings(_name, m_json); {
} add_bool_toogle(name, get_resource(description_resource_id), value);
}
void PowerToyValues::set_version() { void Settings::add_bool_toogle(std::wstring_view name, std::wstring_view description, bool value)
m_json.SetNamedValue(L"version", json::value(m_version)); {
} json::JsonObject toggle;
toggle.SetNamedValue(L"display_name", json::value(description));
toggle.SetNamedValue(L"editor_type", json::value(L"bool_toggle"));
toggle.SetNamedValue(L"value", json::value(value));
toggle.SetNamedValue(L"order", json::value(++m_curr_priority));
m_json.GetNamedObject(L"properties").SetNamedValue(name, toggle);
}
// add_int_spinner overloads.
void Settings::add_int_spinner(std::wstring_view name, UINT description_resource_id, int value, int min, int max, int step)
{
add_int_spinner(name, get_resource(description_resource_id), value, min, max, step);
}
void Settings::add_int_spinner(std::wstring_view name, std::wstring_view description, int value, int min, int max, int step)
{
json::JsonObject spinner;
spinner.SetNamedValue(L"display_name", json::value(description));
spinner.SetNamedValue(L"editor_type", json::value(L"int_spinner"));
spinner.SetNamedValue(L"value", json::value(value));
spinner.SetNamedValue(L"min", json::value(min));
spinner.SetNamedValue(L"max", json::value(max));
spinner.SetNamedValue(L"step", json::value(step));
spinner.SetNamedValue(L"order", json::value(++m_curr_priority));
m_json.GetNamedObject(L"properties").SetNamedValue(name, spinner);
}
// add_string overloads.
void Settings::add_string(std::wstring_view name, UINT description_resource_id, std::wstring_view value)
{
add_string(name, get_resource(description_resource_id), value);
}
void Settings::add_string(std::wstring_view name, std::wstring_view description, std::wstring_view value)
{
json::JsonObject string;
string.SetNamedValue(L"display_name", json::value(description));
string.SetNamedValue(L"editor_type", json::value(L"string_text"));
string.SetNamedValue(L"value", json::value(value));
string.SetNamedValue(L"order", json::value(++m_curr_priority));
m_json.GetNamedObject(L"properties").SetNamedValue(name, string);
}
// add_multiline_string overloads.
void Settings::add_multiline_string(std::wstring_view name, UINT description_resource_id, std::wstring_view value)
{
add_multiline_string(name, get_resource(description_resource_id), value);
}
void Settings::add_multiline_string(std::wstring_view name, std::wstring_view description, std::wstring_view value)
{
json::JsonObject ml_string;
ml_string.SetNamedValue(L"display_name", json::value(description));
ml_string.SetNamedValue(L"editor_type", json::value(L"string_text"));
ml_string.SetNamedValue(L"value", json::value(value));
ml_string.SetNamedValue(L"order", json::value(++m_curr_priority));
ml_string.SetNamedValue(L"multiline", json::value(true));
m_json.GetNamedObject(L"properties").SetNamedValue(name, ml_string);
}
// add_color_picker overloads.
void Settings::add_color_picker(std::wstring_view name, UINT description_resource_id, std::wstring_view value)
{
add_color_picker(name, get_resource(description_resource_id), value);
}
void Settings::add_color_picker(std::wstring_view name, std::wstring_view description, std::wstring_view value)
{
json::JsonObject picker;
picker.SetNamedValue(L"display_name", json::value(description));
picker.SetNamedValue(L"editor_type", json::value(L"color_picker"));
picker.SetNamedValue(L"value", json::value(value));
picker.SetNamedValue(L"order", json::value(++m_curr_priority));
m_json.GetNamedObject(L"properties").SetNamedValue(name, picker);
}
void Settings::add_hotkey(std::wstring_view name, UINT description_resource_id, const HotkeyObject& hotkey)
{
add_hotkey(name, get_resource(description_resource_id), hotkey);
}
void Settings::add_hotkey(std::wstring_view name, std::wstring_view description, const HotkeyObject& hotkey_obj)
{
json::JsonObject hotkey;
hotkey.SetNamedValue(L"display_name", json::value(description));
hotkey.SetNamedValue(L"editor_type", json::value(L"hotkey"));
hotkey.SetNamedValue(L"value", hotkey_obj.get_json());
hotkey.SetNamedValue(L"order", json::value(++m_curr_priority));
m_json.GetNamedObject(L"properties").SetNamedValue(name, hotkey);
}
void Settings::add_choice_group(std::wstring_view name, UINT description_resource_id, std::wstring_view value, const std::vector<std::pair<std::wstring, UINT>>& keys_and_text_ids)
{
std::vector<std::pair<std::wstring, std::wstring>> keys_and_texts;
keys_and_texts.reserve(keys_and_text_ids.size());
for (const auto& kv : keys_and_text_ids)
{
keys_and_texts.emplace_back(kv.first, get_resource(kv.second));
}
add_choice_group(name, get_resource(description_resource_id), value, keys_and_texts);
}
void Settings::add_choice_group(std::wstring_view name, std::wstring_view description, std::wstring_view value, const std::vector<std::pair<std::wstring, std::wstring>>& keys_and_texts)
{
json::JsonObject choice_group;
choice_group.SetNamedValue(L"display_name", json::value(description));
choice_group.SetNamedValue(L"editor_type", json::value(L"choice_group"));
json::JsonArray options;
for (const auto& [key, text] : keys_and_texts)
{
json::JsonObject entry;
entry.SetNamedValue(L"key", json::value(key));
entry.SetNamedValue(L"text", json::value(text));
options.Append(std::move(entry));
}
choice_group.SetNamedValue(L"options", std::move(options));
choice_group.SetNamedValue(L"value", json::value(value));
choice_group.SetNamedValue(L"order", json::value(++m_curr_priority));
m_json.GetNamedObject(L"properties").SetNamedValue(name, choice_group);
}
void Settings::add_dropdown(std::wstring_view name, UINT description_resource_id, std::wstring_view value, const std::vector<std::pair<std::wstring, UINT>>& keys_and_text_ids)
{
std::vector<std::pair<std::wstring, std::wstring>> keys_and_texts;
keys_and_texts.reserve(keys_and_text_ids.size());
for (const auto& kv : keys_and_text_ids)
{
keys_and_texts.emplace_back(kv.first, get_resource(kv.second));
}
add_dropdown(name, get_resource(description_resource_id), value, keys_and_texts);
}
void Settings::add_dropdown(std::wstring_view name, std::wstring_view description, std::wstring_view value, const std::vector<std::pair<std::wstring, std::wstring>>& keys_and_texts)
{
json::JsonObject dropdown;
dropdown.SetNamedValue(L"display_name", json::value(description));
dropdown.SetNamedValue(L"editor_type", json::value(L"dropdown"));
json::JsonArray options;
for (const auto& [key, text] : keys_and_texts)
{
json::JsonObject entry;
entry.SetNamedValue(L"key", json::value(key));
entry.SetNamedValue(L"text", json::value(text));
options.Append(std::move(entry));
}
dropdown.SetNamedValue(L"options", std::move(options));
dropdown.SetNamedValue(L"value", json::value(value));
dropdown.SetNamedValue(L"order", json::value(++m_curr_priority));
m_json.GetNamedObject(L"properties").SetNamedValue(name, dropdown);
}
// add_custom_action overloads.
void Settings::add_custom_action(std::wstring_view name, UINT description_resource_id, UINT button_text_resource_id, UINT ext_description_resource_id)
{
add_custom_action(name, get_resource(description_resource_id), get_resource(button_text_resource_id), get_resource(ext_description_resource_id));
}
void Settings::add_custom_action(std::wstring_view name, UINT description_resource_id, UINT button_text_resource_id, std::wstring_view value)
{
add_custom_action(name, get_resource(description_resource_id), get_resource(button_text_resource_id), value);
}
void Settings::add_custom_action(std::wstring_view name, std::wstring_view description, std::wstring_view button_text, std::wstring_view value)
{
json::JsonObject custom_action;
custom_action.SetNamedValue(L"display_name", json::value(description));
custom_action.SetNamedValue(L"button_text", json::value(button_text));
custom_action.SetNamedValue(L"editor_type", json::value(L"custom_action"));
custom_action.SetNamedValue(L"value", json::value(value));
custom_action.SetNamedValue(L"order", json::value(++m_curr_priority));
m_json.GetNamedObject(L"properties").SetNamedValue(name, custom_action);
}
// Serialization methods.
std::wstring Settings::serialize()
{
return m_json.Stringify().c_str();
}
bool Settings::serialize_to_buffer(wchar_t* buffer, int* buffer_size)
{
auto result = m_json.Stringify();
const int result_len = (int)result.size() + 1;
if (buffer == nullptr || *buffer_size < result_len)
{
*buffer_size = result_len;
return false;
}
else
{
wcscpy_s(buffer, *buffer_size, result.c_str());
return true;
}
}
// Resource helper.
std::wstring Settings::get_resource(UINT resource_id)
{
if (resource_id != 0)
{
wchar_t* res_ptr;
const size_t resource_length = LoadStringW(m_instance, resource_id, reinterpret_cast<wchar_t*>(&res_ptr), 0);
if (resource_length != 0)
{
return { *reinterpret_cast<wchar_t**>(&res_ptr), resource_length };
}
}
return L"RESOURCE ID NOT FOUND: " + std::to_wstring(resource_id);
}
PowerToyValues::PowerToyValues(std::wstring_view powertoy_name)
{
_name = powertoy_name;
set_version();
m_json.SetNamedValue(L"name", json::value(powertoy_name));
m_json.SetNamedValue(L"properties", json::JsonObject{});
}
PowerToyValues PowerToyValues::from_json_string(std::wstring_view json)
{
PowerToyValues result = PowerToyValues();
result.m_json = json::JsonValue::Parse(json).GetObjectW();
result._name = result.m_json.GetNamedString(L"name");
return result;
}
PowerToyValues PowerToyValues::load_from_settings_file(std::wstring_view powertoy_name)
{
PowerToyValues result = PowerToyValues();
result.m_json = PTSettingsHelper::load_module_settings(powertoy_name);
result._name = powertoy_name;
return result;
}
inline bool has_property(const json::JsonObject& o, std::wstring_view name, const json::JsonValueType type)
{
const json::JsonObject props = o.GetNamedObject(L"properties", json::JsonObject{});
return json::has(props, name) && json::has(props.GetNamedObject(name), L"value", type);
}
std::optional<bool> PowerToyValues::get_bool_value(std::wstring_view property_name)
{
if (!has_property(m_json, property_name, json::JsonValueType::Boolean))
{
return std::nullopt;
}
return m_json.GetNamedObject(L"properties").GetNamedObject(property_name).GetNamedBoolean(L"value");
}
std::optional<int> PowerToyValues::get_int_value(std::wstring_view property_name)
{
if (!has_property(m_json, property_name, json::JsonValueType::Number))
{
return std::nullopt;
}
return static_cast<int>(m_json.GetNamedObject(L"properties").GetNamedObject(property_name).GetNamedNumber(L"value"));
}
std::optional<std::wstring> PowerToyValues::get_string_value(std::wstring_view property_name)
{
if (!has_property(m_json, property_name, json::JsonValueType::String))
{
return std::nullopt;
}
return m_json.GetNamedObject(L"properties").GetNamedObject(property_name).GetNamedString(L"value").c_str();
}
std::optional<json::JsonObject> PowerToyValues::get_json(std::wstring_view property_name)
{
if (!has_property(m_json, property_name, json::JsonValueType::Object))
{
return std::nullopt;
}
return m_json.GetNamedObject(L"properties").GetNamedObject(property_name).GetNamedObject(L"value");
}
std::wstring PowerToyValues::serialize()
{
set_version();
return m_json.Stringify().c_str();
}
void PowerToyValues::save_to_settings_file()
{
set_version();
PTSettingsHelper::save_module_settings(_name, m_json);
}
void PowerToyValues::set_version()
{
m_json.SetNamedValue(L"version", json::value(m_version));
}
} }

View File

@ -2,184 +2,220 @@
#include "json.h" #include "json.h"
namespace PowerToysSettings { namespace PowerToysSettings
{
class HotkeyObject;
class HotkeyObject; class Settings
class Settings {
public:
Settings(
const HINSTANCE hinstance, // Module handle of the PowerToy DLL 'IMAGE_DOS_HEADER __ImageBase'
std::wstring_view powertoy_name
);
// Add additional general information to the PowerToy settings.
void set_description(UINT resource_id);
void set_description(std::wstring_view description);
void set_icon_key(std::wstring_view icon_key);
void set_overview_link(std::wstring_view overview_link);
void set_video_link(std::wstring_view video_link);
// Add properties to the PowerToy settings.
void add_bool_toogle(std::wstring_view name, UINT description_resource_id, bool value);
void add_bool_toogle(std::wstring_view name, std::wstring_view description, bool value);
void add_int_spinner(std::wstring_view name, UINT description_resource_id, int value, int min, int max, int step);
void add_int_spinner(std::wstring_view name, std::wstring_view description, int value, int min, int max, int step);
void add_string(std::wstring_view name, UINT description_resource_id, std::wstring_view value);
void add_string(std::wstring_view name, std::wstring_view description, std::wstring_view value);
void add_multiline_string(std::wstring_view name, UINT description_resource_id, std::wstring_view value);
void add_multiline_string(std::wstring_view name, std::wstring_view description, std::wstring_view value);
void add_color_picker(std::wstring_view name, UINT description_resource_id, std::wstring_view value);
void add_color_picker(std::wstring_view name, std::wstring_view description, std::wstring_view value);
void add_hotkey(std::wstring_view name, UINT description_resource_id, const HotkeyObject& hotkey);
void add_hotkey(std::wstring_view name, std::wstring_view description, const HotkeyObject& hotkey);
void add_choice_group(std::wstring_view name, UINT description_resource_id, std::wstring_view value, const std::vector<std::pair<std::wstring, UINT>>& keys_and_text_ids);
void add_choice_group(std::wstring_view name, std::wstring_view description, std::wstring_view value, const std::vector<std::pair<std::wstring, std::wstring>>& keys_and_texts);
void add_dropdown(std::wstring_view name, UINT description_resource_id, std::wstring_view value, const std::vector<std::pair<std::wstring, UINT>>& keys_and_text_ids);
void add_dropdown(std::wstring_view name, std::wstring_view description, std::wstring_view value, const std::vector<std::pair<std::wstring, std::wstring>>& keys_and_texts);
void add_custom_action(std::wstring_view name, UINT description_resource_id, UINT button_text_resource_id, UINT ext_description_resource_id);
void add_custom_action(std::wstring_view name, UINT description_resource_id, UINT button_text_resource_id, std::wstring_view value);
void add_custom_action(std::wstring_view name, std::wstring_view description, std::wstring_view button_text, std::wstring_view value);
// Serialize the internal json to a string.
std::wstring serialize();
// Serialize the internal json to the input buffer.
bool serialize_to_buffer(wchar_t* buffer, int* buffer_size);
private:
json::JsonObject m_json;
int m_curr_priority = 0; // For keeping order when adding elements.
HINSTANCE m_instance;
std::wstring get_resource(UINT resource_id);
};
class PowerToyValues {
public:
PowerToyValues(std::wstring_view powertoy_name);
static PowerToyValues from_json_string(std::wstring_view json);
static PowerToyValues load_from_settings_file(std::wstring_view powertoy_name);
template <typename T>
inline void add_property(std::wstring_view name, T value)
{ {
json::JsonObject prop_value; public:
prop_value.SetNamedValue(L"value", json::value(value)); Settings(
m_json.GetNamedObject(L"properties").SetNamedValue(name, prop_value); const HINSTANCE hinstance, // Module handle of the PowerToy DLL 'IMAGE_DOS_HEADER __ImageBase'
} std::wstring_view powertoy_name);
std::optional<bool> get_bool_value(std::wstring_view property_name); // Add additional general information to the PowerToy settings.
std::optional<int> get_int_value(std::wstring_view property_name); void set_description(UINT resource_id);
std::optional<std::wstring> get_string_value(std::wstring_view property_name); void set_description(std::wstring_view description);
std::optional<json::JsonObject> get_json(std::wstring_view property_name);
std::wstring serialize(); void set_icon_key(std::wstring_view icon_key);
void save_to_settings_file(); void set_overview_link(std::wstring_view overview_link);
void set_video_link(std::wstring_view video_link);
private: // Add properties to the PowerToy settings.
const std::wstring m_version = L"1.0"; void add_bool_toogle(std::wstring_view name, UINT description_resource_id, bool value);
void set_version(); void add_bool_toogle(std::wstring_view name, std::wstring_view description, bool value);
json::JsonObject m_json;
std::wstring _name;
PowerToyValues() {}
};
class CustomActionObject { void add_int_spinner(std::wstring_view name, UINT description_resource_id, int value, int min, int max, int step);
public: void add_int_spinner(std::wstring_view name, std::wstring_view description, int value, int min, int max, int step);
static CustomActionObject from_json_string(std::wstring_view json) {
return CustomActionObject(json::JsonValue::Parse(json).GetObjectW());
}
std::wstring get_name() { return m_json.GetNamedString(L"action_name").c_str(); } void add_string(std::wstring_view name, UINT description_resource_id, std::wstring_view value);
std::wstring get_value() { return m_json.GetNamedString(L"value").c_str(); } void add_string(std::wstring_view name, std::wstring_view description, std::wstring_view value);
protected: void add_multiline_string(std::wstring_view name, UINT description_resource_id, std::wstring_view value);
CustomActionObject(json::JsonObject action_json) : m_json(std::move(action_json)) {}; void add_multiline_string(std::wstring_view name, std::wstring_view description, std::wstring_view value);
json::JsonObject m_json;
};
class HotkeyObject {
public:
static HotkeyObject from_json(json::JsonObject json) {
return HotkeyObject(std::move(json));
}
static HotkeyObject from_json_string(std::wstring_view json) {
return HotkeyObject(json::JsonValue::Parse(json).GetObjectW());
}
static HotkeyObject from_settings(bool win_pressed, bool ctrl_pressed, bool alt_pressed, bool shift_pressed, UINT vk_code) {
json::JsonObject json;
json.SetNamedValue(L"win", json::value(win_pressed));
json.SetNamedValue(L"ctrl", json::value(ctrl_pressed));
json.SetNamedValue(L"alt", json::value(alt_pressed));
json.SetNamedValue(L"shift", json::value(shift_pressed));
json.SetNamedValue(L"code", json::value(vk_code));
json.SetNamedValue(L"key", json::value(key_from_code(vk_code)));
return std::move(json);
}
const json::JsonObject& get_json() const { return m_json; }
std::wstring get_key() const { return m_json.GetNamedString(L"key").c_str(); } void add_color_picker(std::wstring_view name, UINT description_resource_id, std::wstring_view value);
UINT get_code() const { return static_cast<UINT>(m_json.GetNamedNumber(L"code")); } void add_color_picker(std::wstring_view name, std::wstring_view description, std::wstring_view value);
bool win_pressed() const { return m_json.GetNamedBoolean(L"win"); }
bool ctrl_pressed() const { return m_json.GetNamedBoolean(L"ctrl"); } void add_hotkey(std::wstring_view name, UINT description_resource_id, const HotkeyObject& hotkey);
bool alt_pressed() const { return m_json.GetNamedBoolean(L"alt"); } void add_hotkey(std::wstring_view name, std::wstring_view description, const HotkeyObject& hotkey);
bool shift_pressed() const { return m_json.GetNamedBoolean(L"shift"); }
UINT get_modifiers_repeat() const { void add_choice_group(std::wstring_view name, UINT description_resource_id, std::wstring_view value, const std::vector<std::pair<std::wstring, UINT>>& keys_and_text_ids);
return (win_pressed() ? MOD_WIN : 0) | void add_choice_group(std::wstring_view name, std::wstring_view description, std::wstring_view value, const std::vector<std::pair<std::wstring, std::wstring>>& keys_and_texts);
(ctrl_pressed() ? MOD_CONTROL : 0) |
(alt_pressed() ? MOD_ALT : 0) | void add_dropdown(std::wstring_view name, UINT description_resource_id, std::wstring_view value, const std::vector<std::pair<std::wstring, UINT>>& keys_and_text_ids);
(shift_pressed() ? MOD_SHIFT : 0); void add_dropdown(std::wstring_view name, std::wstring_view description, std::wstring_view value, const std::vector<std::pair<std::wstring, std::wstring>>& keys_and_texts);
}
UINT get_modifiers() const { void add_custom_action(std::wstring_view name, UINT description_resource_id, UINT button_text_resource_id, UINT ext_description_resource_id);
return get_modifiers_repeat() | MOD_NOREPEAT; void add_custom_action(std::wstring_view name, UINT description_resource_id, UINT button_text_resource_id, std::wstring_view value);
} void add_custom_action(std::wstring_view name, std::wstring_view description, std::wstring_view button_text, std::wstring_view value);
protected:
static std::wstring key_from_code(UINT key_code) { // Serialize the internal json to a string.
auto layout = GetKeyboardLayout(0); std::wstring serialize();
auto scan_code = MapVirtualKeyExW(key_code, MAPVK_VK_TO_VSC_EX, layout); // Serialize the internal json to the input buffer.
// Determinate if vk is an extended key. Unfortunatly MAPVK_VK_TO_VSC_EX bool serialize_to_buffer(wchar_t* buffer, int* buffer_size);
// does not return correct values.
static std::vector<UINT> extended_keys = { private:
VK_APPS, VK_CANCEL, VK_SNAPSHOT, VK_DIVIDE, VK_NUMLOCK, VK_LWIN, VK_RWIN, VK_RMENU, json::JsonObject m_json;
VK_RCONTROL, VK_RSHIFT, VK_RETURN, VK_INSERT, VK_DELETE, VK_PRIOR, VK_NEXT, int m_curr_priority = 0; // For keeping order when adding elements.
VK_HOME, VK_END, VK_UP, VK_DOWN, VK_LEFT, VK_RIGHT, HINSTANCE m_instance;
};
if (find(begin(extended_keys), end(extended_keys), key_code) != end(extended_keys)) { std::wstring get_resource(UINT resource_id);
scan_code |= 0x100; };
}
std::array<BYTE, 256> key_states{}; // Zero-initialize class PowerToyValues
std::array<wchar_t, 256> output; {
auto output_bytes = ToUnicodeEx(key_code, scan_code, key_states.data(), output.data(), (int)output.size() - 1, 0, layout); public:
if (output_bytes <= 0) { PowerToyValues(std::wstring_view powertoy_name);
// If ToUnicodeEx fails (e.g. for F1-F12 keys) use GetKeyNameTextW static PowerToyValues from_json_string(std::wstring_view json);
output_bytes = GetKeyNameTextW(scan_code << 16, output.data(), static_cast<int>(output.size())); static PowerToyValues load_from_settings_file(std::wstring_view powertoy_name);
}
if (output_bytes > 0) { template<typename T>
output[output_bytes] = 0; inline void add_property(std::wstring_view name, T value)
if (output_bytes == 1 && output[0] >= 'a' && output[0] <= 'z') { {
// Make Latin letters keys capital, as it looks better json::JsonObject prop_value;
output[0] = toupper(output[0]); prop_value.SetNamedValue(L"value", json::value(value));
} m_json.GetNamedObject(L"properties").SetNamedValue(name, prop_value);
return output.data(); }
}
return L"(Key " + std::to_wstring(key_code) + L")"; std::optional<bool> get_bool_value(std::wstring_view property_name);
} std::optional<int> get_int_value(std::wstring_view property_name);
HotkeyObject(json::JsonObject hotkey_json) : m_json(std::move(hotkey_json)) { std::optional<std::wstring> get_string_value(std::wstring_view property_name);
if (get_key() == L"~" && get_modifiers_repeat() == MOD_WIN) { std::optional<json::JsonObject> get_json(std::wstring_view property_name);
m_json.SetNamedValue(L"key", json::value(key_from_code(get_code())));
} std::wstring serialize();
void save_to_settings_file();
private:
const std::wstring m_version = L"1.0";
void set_version();
json::JsonObject m_json;
std::wstring _name;
PowerToyValues() {}
};
class CustomActionObject
{
public:
static CustomActionObject from_json_string(std::wstring_view json)
{
return CustomActionObject(json::JsonValue::Parse(json).GetObjectW());
}
std::wstring get_name() { return m_json.GetNamedString(L"action_name").c_str(); }
std::wstring get_value() { return m_json.GetNamedString(L"value").c_str(); }
protected:
CustomActionObject(json::JsonObject action_json) :
m_json(std::move(action_json)){};
json::JsonObject m_json;
};
class HotkeyObject
{
public:
static HotkeyObject from_json(json::JsonObject json)
{
return HotkeyObject(std::move(json));
}
static HotkeyObject from_json_string(std::wstring_view json)
{
return HotkeyObject(json::JsonValue::Parse(json).GetObjectW());
}
static HotkeyObject from_settings(bool win_pressed, bool ctrl_pressed, bool alt_pressed, bool shift_pressed, UINT vk_code)
{
json::JsonObject json;
json.SetNamedValue(L"win", json::value(win_pressed));
json.SetNamedValue(L"ctrl", json::value(ctrl_pressed));
json.SetNamedValue(L"alt", json::value(alt_pressed));
json.SetNamedValue(L"shift", json::value(shift_pressed));
json.SetNamedValue(L"code", json::value(vk_code));
json.SetNamedValue(L"key", json::value(key_from_code(vk_code)));
return std::move(json);
}
const json::JsonObject& get_json() const { return m_json; }
std::wstring get_key() const { return m_json.GetNamedString(L"key").c_str(); }
UINT get_code() const { return static_cast<UINT>(m_json.GetNamedNumber(L"code")); }
bool win_pressed() const { return m_json.GetNamedBoolean(L"win"); }
bool ctrl_pressed() const { return m_json.GetNamedBoolean(L"ctrl"); }
bool alt_pressed() const { return m_json.GetNamedBoolean(L"alt"); }
bool shift_pressed() const { return m_json.GetNamedBoolean(L"shift"); }
UINT get_modifiers_repeat() const
{
return (win_pressed() ? MOD_WIN : 0) |
(ctrl_pressed() ? MOD_CONTROL : 0) |
(alt_pressed() ? MOD_ALT : 0) |
(shift_pressed() ? MOD_SHIFT : 0);
}
UINT get_modifiers() const
{
return get_modifiers_repeat() | MOD_NOREPEAT;
}
protected:
static std::wstring key_from_code(UINT key_code)
{
auto layout = GetKeyboardLayout(0);
auto scan_code = MapVirtualKeyExW(key_code, MAPVK_VK_TO_VSC_EX, layout);
// Determinate if vk is an extended key. Unfortunatly MAPVK_VK_TO_VSC_EX
// does not return correct values.
static std::vector<UINT> extended_keys = {
VK_APPS,
VK_CANCEL,
VK_SNAPSHOT,
VK_DIVIDE,
VK_NUMLOCK,
VK_LWIN,
VK_RWIN,
VK_RMENU,
VK_RCONTROL,
VK_RSHIFT,
VK_RETURN,
VK_INSERT,
VK_DELETE,
VK_PRIOR,
VK_NEXT,
VK_HOME,
VK_END,
VK_UP,
VK_DOWN,
VK_LEFT,
VK_RIGHT,
};
if (find(begin(extended_keys), end(extended_keys), key_code) != end(extended_keys))
{
scan_code |= 0x100;
}
std::array<BYTE, 256> key_states{}; // Zero-initialize
std::array<wchar_t, 256> output;
auto output_bytes = ToUnicodeEx(key_code, scan_code, key_states.data(), output.data(), (int)output.size() - 1, 0, layout);
if (output_bytes <= 0)
{
// If ToUnicodeEx fails (e.g. for F1-F12 keys) use GetKeyNameTextW
output_bytes = GetKeyNameTextW(scan_code << 16, output.data(), static_cast<int>(output.size()));
}
if (output_bytes > 0)
{
output[output_bytes] = 0;
if (output_bytes == 1 && output[0] >= 'a' && output[0] <= 'z')
{
// Make Latin letters keys capital, as it looks better
output[0] = toupper(output[0]);
}
return output.data();
}
return L"(Key " + std::to_wstring(key_code) + L")";
}
HotkeyObject(json::JsonObject hotkey_json) :
m_json(std::move(hotkey_json))
{
if (get_key() == L"~" && get_modifiers_repeat() == MOD_WIN)
{
m_json.SetNamedValue(L"key", json::value(key_from_code(get_code())));
}
};
json::JsonObject m_json;
}; };
json::JsonObject m_json;
};
} }

View File

@ -1,16 +1,18 @@
#include "pch.h" #include "pch.h"
#include "start_visible.h" #include "start_visible.h"
bool is_start_visible() { bool is_start_visible()
static winrt::com_ptr<IAppVisibility> app_visibility; {
if (!app_visibility) { static winrt::com_ptr<IAppVisibility> app_visibility;
winrt::check_hresult(CoCreateInstance(CLSID_AppVisibility, if (!app_visibility)
nullptr, {
CLSCTX_INPROC_SERVER, winrt::check_hresult(CoCreateInstance(CLSID_AppVisibility,
__uuidof(app_visibility), nullptr,
app_visibility.put_void())); CLSCTX_INPROC_SERVER,
} __uuidof(app_visibility),
BOOL visible; app_visibility.put_void()));
auto result = app_visibility->IsLauncherVisible(&visible); }
return SUCCEEDED(result) && visible; BOOL visible;
auto result = app_visibility->IsLauncherVisible(&visible);
return SUCCEEDED(result) && visible;
} }

View File

@ -1,4 +1,3 @@
#pragma once #pragma once
bool is_start_visible(); bool is_start_visible();

View File

@ -1,93 +1,116 @@
#include "pch.h" #include "pch.h"
#include "tasklist_positions.h" #include "tasklist_positions.h"
void Tasklist::update() { void Tasklist::update()
// Get HWND of the tasklist {
auto tasklist_hwnd = FindWindowA("Shell_TrayWnd", nullptr); // Get HWND of the tasklist
if (!tasklist_hwnd) return; auto tasklist_hwnd = FindWindowA("Shell_TrayWnd", nullptr);
tasklist_hwnd = FindWindowExA(tasklist_hwnd, 0, "ReBarWindow32", nullptr); if (!tasklist_hwnd)
if (!tasklist_hwnd) return; return;
tasklist_hwnd = FindWindowExA(tasklist_hwnd, 0, "MSTaskSwWClass", nullptr); tasklist_hwnd = FindWindowExA(tasklist_hwnd, 0, "ReBarWindow32", nullptr);
if (!tasklist_hwnd) return; if (!tasklist_hwnd)
tasklist_hwnd = FindWindowExA(tasklist_hwnd, 0, "MSTaskListWClass", nullptr); return;
if (!tasklist_hwnd) return; tasklist_hwnd = FindWindowExA(tasklist_hwnd, 0, "MSTaskSwWClass", nullptr);
if (!automation) { if (!tasklist_hwnd)
winrt::check_hresult(CoCreateInstance(CLSID_CUIAutomation, return;
nullptr, tasklist_hwnd = FindWindowExA(tasklist_hwnd, 0, "MSTaskListWClass", nullptr);
CLSCTX_INPROC_SERVER, if (!tasklist_hwnd)
IID_IUIAutomation, return;
automation.put_void())); if (!automation)
winrt::check_hresult(automation->CreateTrueCondition(true_condition.put())); {
} winrt::check_hresult(CoCreateInstance(CLSID_CUIAutomation,
element = nullptr; nullptr,
winrt::check_hresult(automation->ElementFromHandle(tasklist_hwnd, element.put())); CLSCTX_INPROC_SERVER,
IID_IUIAutomation,
automation.put_void()));
winrt::check_hresult(automation->CreateTrueCondition(true_condition.put()));
}
element = nullptr;
winrt::check_hresult(automation->ElementFromHandle(tasklist_hwnd, element.put()));
} }
bool Tasklist::update_buttons(std::vector<TasklistButton>& buttons) { bool Tasklist::update_buttons(std::vector<TasklistButton>& buttons)
if (!automation || !element) { {
return false; if (!automation || !element)
} {
winrt::com_ptr<IUIAutomationElementArray> elements; return false;
if (element->FindAll(TreeScope_Children, true_condition.get(), elements.put()) < 0)
return false;
if (!elements)
return false;
int count;
if (elements->get_Length(&count) < 0)
return false;
winrt::com_ptr<IUIAutomationElement> child;
std::vector<TasklistButton> found_butttons;
found_butttons.reserve(count);
for (int i = 0; i < count; ++i) {
child = nullptr;
if (elements->GetElement(i, child.put()) < 0)
return false;
TasklistButton button;
if (VARIANT var_rect; child->GetCurrentPropertyValue(UIA_BoundingRectanglePropertyId, &var_rect) >= 0) {
if (var_rect.vt == (VT_R8 | VT_ARRAY)) {
LONG pos;
double value;
pos = 0; SafeArrayGetElement(var_rect.parray, &pos, &value);
button.x = (long)value;
pos = 1; SafeArrayGetElement(var_rect.parray, &pos, &value);
button.y = (long)value;
pos = 2; SafeArrayGetElement(var_rect.parray, &pos, &value);
button.width = (long)value;
pos = 3; SafeArrayGetElement(var_rect.parray, &pos, &value);
button.height = (long)value;
}
VariantClear(&var_rect);
} else {
return false;
} }
if (BSTR automation_id; child->get_CurrentAutomationId(&automation_id) >= 0) { winrt::com_ptr<IUIAutomationElementArray> elements;
button.name = automation_id; if (element->FindAll(TreeScope_Children, true_condition.get(), elements.put()) < 0)
SysFreeString(automation_id); return false;
if (!elements)
return false;
int count;
if (elements->get_Length(&count) < 0)
return false;
winrt::com_ptr<IUIAutomationElement> child;
std::vector<TasklistButton> found_butttons;
found_butttons.reserve(count);
for (int i = 0; i < count; ++i)
{
child = nullptr;
if (elements->GetElement(i, child.put()) < 0)
return false;
TasklistButton button;
if (VARIANT var_rect; child->GetCurrentPropertyValue(UIA_BoundingRectanglePropertyId, &var_rect) >= 0)
{
if (var_rect.vt == (VT_R8 | VT_ARRAY))
{
LONG pos;
double value;
pos = 0;
SafeArrayGetElement(var_rect.parray, &pos, &value);
button.x = (long)value;
pos = 1;
SafeArrayGetElement(var_rect.parray, &pos, &value);
button.y = (long)value;
pos = 2;
SafeArrayGetElement(var_rect.parray, &pos, &value);
button.width = (long)value;
pos = 3;
SafeArrayGetElement(var_rect.parray, &pos, &value);
button.height = (long)value;
}
VariantClear(&var_rect);
}
else
{
return false;
}
if (BSTR automation_id; child->get_CurrentAutomationId(&automation_id) >= 0)
{
button.name = automation_id;
SysFreeString(automation_id);
}
found_butttons.push_back(button);
} }
found_butttons.push_back(button); // assign keynums
} buttons.clear();
// assign keynums for (auto& button : found_butttons)
buttons.clear(); {
for (auto& button : found_butttons) { if (buttons.empty())
if (buttons.empty()) { {
button.keynum = 1; button.keynum = 1;
buttons.push_back(std::move(button)); buttons.push_back(std::move(button));
} else { }
if (button.x < buttons.back().x || button.y < buttons.back().y) // skip 2nd row else
break; {
if (button.name == buttons.back().name) if (button.x < buttons.back().x || button.y < buttons.back().y) // skip 2nd row
continue; // skip buttons from the same app break;
button.keynum = buttons.back().keynum + 1; if (button.name == buttons.back().name)
buttons.push_back(std::move(button)); continue; // skip buttons from the same app
if (buttons.back().keynum == 10) button.keynum = buttons.back().keynum + 1;
break; // no more than 10 buttons buttons.push_back(std::move(button));
if (buttons.back().keynum == 10)
break; // no more than 10 buttons
}
} }
} return true;
return true;
} }
std::vector<TasklistButton> Tasklist::get_buttons() { std::vector<TasklistButton> Tasklist::get_buttons()
std::vector<TasklistButton> buttons; {
update_buttons(buttons); std::vector<TasklistButton> buttons;
return buttons; update_buttons(buttons);
return buttons;
} }

View File

@ -5,18 +5,21 @@
#include <Windows.h> #include <Windows.h>
#include <UIAutomationClient.h> #include <UIAutomationClient.h>
struct TasklistButton { struct TasklistButton
std::wstring name; {
long x, y, width, height, keynum; std::wstring name;
long x, y, width, height, keynum;
}; };
class Tasklist { class Tasklist
{
public: public:
void update(); void update();
std::vector<TasklistButton> get_buttons(); std::vector<TasklistButton> get_buttons();
bool update_buttons(std::vector<TasklistButton>& buttons); bool update_buttons(std::vector<TasklistButton>& buttons);
private: private:
winrt::com_ptr<IUIAutomation> automation; winrt::com_ptr<IUIAutomation> automation;
winrt::com_ptr<IUIAutomationElement> element; winrt::com_ptr<IUIAutomationElement> element;
winrt::com_ptr<IUIAutomationCondition> true_condition; winrt::com_ptr<IUIAutomationCondition> true_condition;
}; };

View File

@ -6,424 +6,471 @@
#include <accctrl.h> #include <accctrl.h>
#include <aclapi.h> #include <aclapi.h>
class TwoWayPipeMessageIPC { class TwoWayPipeMessageIPC
{
public: public:
typedef void(*callback_function)(const std::wstring&); typedef void (*callback_function)(const std::wstring&);
void send(std::wstring msg) { void send(std::wstring msg)
output_queue.queue_message(msg); {
} output_queue.queue_message(msg);
TwoWayPipeMessageIPC(std::wstring _input_pipe_name, std::wstring _output_pipe_name, callback_function p_func) { }
input_pipe_name = _input_pipe_name; TwoWayPipeMessageIPC(std::wstring _input_pipe_name, std::wstring _output_pipe_name, callback_function p_func)
output_pipe_name = _output_pipe_name; {
dispatch_inc_message_function = p_func; input_pipe_name = _input_pipe_name;
} output_pipe_name = _output_pipe_name;
void start(HANDLE _restricted_pipe_token) { dispatch_inc_message_function = p_func;
output_queue_thread = std::thread(&TwoWayPipeMessageIPC::consume_output_queue_thread, this); }
input_queue_thread = std::thread(&TwoWayPipeMessageIPC::consume_input_queue_thread, this); void start(HANDLE _restricted_pipe_token)
input_pipe_thread = std::thread(&TwoWayPipeMessageIPC::start_named_pipe_server, this, _restricted_pipe_token); {
} output_queue_thread = std::thread(&TwoWayPipeMessageIPC::consume_output_queue_thread, this);
input_queue_thread = std::thread(&TwoWayPipeMessageIPC::consume_input_queue_thread, this);
void end() { input_pipe_thread = std::thread(&TwoWayPipeMessageIPC::start_named_pipe_server, this, _restricted_pipe_token);
closed = true; }
input_queue.interrupt();
input_queue_thread.join(); void end()
output_queue.interrupt(); {
output_queue_thread.join(); closed = true;
pipe_connect_handle_mutex.lock(); input_queue.interrupt();
if (current_connect_pipe_handle != NULL) { input_queue_thread.join();
//Cancels the Pipe currently waiting for a connection. output_queue.interrupt();
CancelIoEx(current_connect_pipe_handle,NULL); output_queue_thread.join();
pipe_connect_handle_mutex.lock();
if (current_connect_pipe_handle != NULL)
{
//Cancels the Pipe currently waiting for a connection.
CancelIoEx(current_connect_pipe_handle, NULL);
}
pipe_connect_handle_mutex.unlock();
input_pipe_thread.join();
} }
pipe_connect_handle_mutex.unlock();
input_pipe_thread.join();
}
private: private:
AsyncMessageQueue input_queue; AsyncMessageQueue input_queue;
AsyncMessageQueue output_queue; AsyncMessageQueue output_queue;
std::wstring output_pipe_name; std::wstring output_pipe_name;
std::wstring input_pipe_name; std::wstring input_pipe_name;
std::thread input_queue_thread; std::thread input_queue_thread;
std::thread output_queue_thread; std::thread output_queue_thread;
std::thread input_pipe_thread; std::thread input_pipe_thread;
std::mutex pipe_connect_handle_mutex; // For manipulating the current_connect_pipe std::mutex pipe_connect_handle_mutex; // For manipulating the current_connect_pipe
HANDLE current_connect_pipe_handle = NULL; HANDLE current_connect_pipe_handle = NULL;
bool closed = false; bool closed = false;
TwoWayPipeMessageIPC::callback_function dispatch_inc_message_function; TwoWayPipeMessageIPC::callback_function dispatch_inc_message_function;
const DWORD BUFSIZE = 1024; const DWORD BUFSIZE = 1024;
void send_pipe_message(std::wstring message) { void send_pipe_message(std::wstring message)
// Adapted from https://docs.microsoft.com/en-us/windows/win32/ipc/named-pipe-client {
HANDLE output_pipe_handle; // Adapted from https://docs.microsoft.com/en-us/windows/win32/ipc/named-pipe-client
const wchar_t* message_send = message.c_str(); HANDLE output_pipe_handle;
BOOL fSuccess = FALSE; const wchar_t* message_send = message.c_str();
DWORD cbToWrite, cbWritten, dwMode; BOOL fSuccess = FALSE;
const wchar_t* lpszPipename = output_pipe_name.c_str(); DWORD cbToWrite, cbWritten, dwMode;
const wchar_t* lpszPipename = output_pipe_name.c_str();
// Try to open a named pipe; wait for it, if necessary. // Try to open a named pipe; wait for it, if necessary.
while (1) { while (1)
output_pipe_handle = CreateFile( {
lpszPipename, // pipe name output_pipe_handle = CreateFile(
GENERIC_READ | // read and write access lpszPipename, // pipe name
GENERIC_WRITE, GENERIC_READ | // read and write access
0, // no sharing GENERIC_WRITE,
NULL, // default security attributes 0, // no sharing
OPEN_EXISTING, // opens existing pipe NULL, // default security attributes
0, // default attributes OPEN_EXISTING, // opens existing pipe
NULL); // no template file 0, // default attributes
NULL); // no template file
// Break if the pipe handle is valid. // Break if the pipe handle is valid.
if (output_pipe_handle != INVALID_HANDLE_VALUE) if (output_pipe_handle != INVALID_HANDLE_VALUE)
break; break;
// Exit if an error other than ERROR_PIPE_BUSY occurs. // Exit if an error other than ERROR_PIPE_BUSY occurs.
DWORD curr_error = 0; DWORD curr_error = 0;
if ((curr_error = GetLastError()) != ERROR_PIPE_BUSY) { if ((curr_error = GetLastError()) != ERROR_PIPE_BUSY)
{
return;
}
// All pipe instances are busy, so wait for 20 seconds.
if (!WaitNamedPipe(lpszPipename, 20000))
{
return;
}
}
dwMode = PIPE_READMODE_MESSAGE;
fSuccess = SetNamedPipeHandleState(
output_pipe_handle, // pipe handle
&dwMode, // new pipe mode
NULL, // don't set maximum bytes
NULL); // don't set maximum time
if (!fSuccess)
{
return;
}
// Send a message to the pipe server.
cbToWrite = (lstrlen(message_send)) * sizeof(WCHAR); // no need to send final '\0'. Pipe is in message mode.
fSuccess = WriteFile(
output_pipe_handle, // pipe handle
message_send, // message
cbToWrite, // message length
&cbWritten, // bytes written
NULL); // not overlapped
if (!fSuccess)
{
return;
}
CloseHandle(output_pipe_handle);
return; return;
}
// All pipe instances are busy, so wait for 20 seconds.
if (!WaitNamedPipe(lpszPipename, 20000)) {
return;
}
}
dwMode = PIPE_READMODE_MESSAGE;
fSuccess = SetNamedPipeHandleState(
output_pipe_handle, // pipe handle
&dwMode, // new pipe mode
NULL, // don't set maximum bytes
NULL); // don't set maximum time
if (!fSuccess) {
return;
} }
// Send a message to the pipe server. void consume_output_queue_thread()
{
cbToWrite = (lstrlen(message_send)) * sizeof(WCHAR); // no need to send final '\0'. Pipe is in message mode. while (!closed)
{
fSuccess = WriteFile( std::wstring message = output_queue.pop_message();
output_pipe_handle, // pipe handle if (message.length() == 0)
message_send, // message {
cbToWrite, // message length break;
&cbWritten, // bytes written }
NULL); // not overlapped send_pipe_message(message);
if (!fSuccess) {
return;
}
CloseHandle(output_pipe_handle);
return;
}
void consume_output_queue_thread() {
while (!closed) {
std::wstring message = output_queue.pop_message();
if (message.length() == 0) {
break;
}
send_pipe_message(message);
}
}
BOOL GetLogonSID(HANDLE hToken, PSID *ppsid) {
// From https://docs.microsoft.com/en-us/previous-versions/aa446670(v=vs.85)
BOOL bSuccess = FALSE;
DWORD dwIndex;
DWORD dwLength = 0;
PTOKEN_GROUPS ptg = NULL;
// Verify the parameter passed in is not NULL.
if (NULL == ppsid)
goto Cleanup;
// Get required buffer size and allocate the TOKEN_GROUPS buffer.
if (!GetTokenInformation(
hToken, // handle to the access token
TokenGroups, // get information about the token's groups
(LPVOID)ptg, // pointer to TOKEN_GROUPS buffer
0, // size of buffer
&dwLength // receives required buffer size
)) {
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
goto Cleanup;
ptg = (PTOKEN_GROUPS)HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY, dwLength);
if (ptg == NULL)
goto Cleanup;
}
// Get the token group information from the access token.
if (!GetTokenInformation(
hToken, // handle to the access token
TokenGroups, // get information about the token's groups
(LPVOID)ptg, // pointer to TOKEN_GROUPS buffer
dwLength, // size of buffer
&dwLength // receives required buffer size
)) {
goto Cleanup;
}
// Loop through the groups to find the logon SID.
for (dwIndex = 0; dwIndex < ptg->GroupCount; dwIndex++)
if ((ptg->Groups[dwIndex].Attributes & SE_GROUP_LOGON_ID)
== SE_GROUP_LOGON_ID) {
// Found the logon SID; make a copy of it.
dwLength = GetLengthSid(ptg->Groups[dwIndex].Sid);
*ppsid = (PSID)HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY, dwLength);
if (*ppsid == NULL)
goto Cleanup;
if (!CopySid(dwLength, *ppsid, ptg->Groups[dwIndex].Sid)) {
HeapFree(GetProcessHeap(), 0, (LPVOID)*ppsid);
goto Cleanup;
} }
break;
}
bSuccess = TRUE;
Cleanup:
// Free the buffer for the token groups.
if (ptg != NULL)
HeapFree(GetProcessHeap(), 0, (LPVOID)ptg);
return bSuccess;
}
VOID FreeLogonSID(PSID *ppsid) {
// From https://docs.microsoft.com/en-us/previous-versions/aa446670(v=vs.85)
HeapFree(GetProcessHeap(), 0, (LPVOID)*ppsid);
}
int change_pipe_security_allow_restricted_token(HANDLE handle, HANDLE token) {
PACL old_dacl, new_dacl;
PSECURITY_DESCRIPTOR sd;
EXPLICIT_ACCESS ea;
PSID user_restricted;
int error;
if (!GetLogonSID(token, &user_restricted)) {
error = 5; // No access error.
goto Ldone;
} }
if (GetSecurityInfo(handle, BOOL GetLogonSID(HANDLE hToken, PSID* ppsid)
SE_KERNEL_OBJECT, {
DACL_SECURITY_INFORMATION, // From https://docs.microsoft.com/en-us/previous-versions/aa446670(v=vs.85)
NULL, BOOL bSuccess = FALSE;
NULL, DWORD dwIndex;
&old_dacl, DWORD dwLength = 0;
NULL, PTOKEN_GROUPS ptg = NULL;
&sd)) {
error = GetLastError();
goto Lclean_sid;
}
memset(&ea, 0, sizeof(EXPLICIT_ACCESS)); // Verify the parameter passed in is not NULL.
ea.grfAccessPermissions |= GENERIC_READ | FILE_WRITE_ATTRIBUTES; if (NULL == ppsid)
ea.grfAccessPermissions |= GENERIC_WRITE | FILE_READ_ATTRIBUTES; goto Cleanup;
ea.grfAccessPermissions |= SYNCHRONIZE;
ea.grfAccessMode = SET_ACCESS;
ea.grfInheritance = NO_INHERITANCE;
ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
ea.Trustee.TrusteeType = TRUSTEE_IS_USER;
ea.Trustee.ptstrName = (LPTSTR)user_restricted;
if (SetEntriesInAcl(1, &ea, old_dacl, &new_dacl)) { // Get required buffer size and allocate the TOKEN_GROUPS buffer.
error = GetLastError();
goto Lclean_sd;
}
if (SetSecurityInfo(handle, if (!GetTokenInformation(
SE_KERNEL_OBJECT, hToken, // handle to the access token
DACL_SECURITY_INFORMATION, TokenGroups, // get information about the token's groups
NULL, (LPVOID)ptg, // pointer to TOKEN_GROUPS buffer
NULL, 0, // size of buffer
new_dacl, &dwLength // receives required buffer size
NULL)) { ))
error = GetLastError(); {
goto Lclean_dacl; if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
} goto Cleanup;
error = 0; ptg = (PTOKEN_GROUPS)HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
dwLength);
Lclean_dacl: if (ptg == NULL)
LocalFree((HLOCAL)new_dacl); goto Cleanup;
Lclean_sd:
LocalFree((HLOCAL)sd);
Lclean_sid:
FreeLogonSID(&user_restricted);
Ldone:
return error;
}
HANDLE create_medium_integrity_token() {
HANDLE restricted_token_handle;
SAFER_LEVEL_HANDLE level_handle = NULL;
DWORD sid_size = SECURITY_MAX_SID_SIZE;
BYTE medium_sid[SECURITY_MAX_SID_SIZE];
if (!SaferCreateLevel(SAFER_SCOPEID_USER, SAFER_LEVELID_NORMALUSER, SAFER_LEVEL_OPEN, &level_handle, NULL)) {
return NULL;
}
if (!SaferComputeTokenFromLevel(level_handle, NULL, &restricted_token_handle, 0, NULL)) {
SaferCloseLevel(level_handle);
return NULL;
}
SaferCloseLevel(level_handle);
if (!CreateWellKnownSid(WinMediumLabelSid, nullptr, medium_sid, &sid_size)) {
CloseHandle(restricted_token_handle);
return NULL;
}
TOKEN_MANDATORY_LABEL integrity_level = { 0 };
integrity_level.Label.Attributes = SE_GROUP_INTEGRITY;
integrity_level.Label.Sid = reinterpret_cast<PSID>(medium_sid);
if (!SetTokenInformation(restricted_token_handle, TokenIntegrityLevel, &integrity_level, sizeof(integrity_level))) {
CloseHandle(restricted_token_handle);
return NULL;
}
return restricted_token_handle;
}
void handle_pipe_connection(HANDLE input_pipe_handle) {
//Adapted from https://docs.microsoft.com/en-us/windows/win32/ipc/multithreaded-pipe-server
HANDLE hHeap = GetProcessHeap();
uint8_t* pchRequest = (uint8_t*)HeapAlloc(hHeap, 0, BUFSIZE * sizeof(uint8_t));
DWORD cbBytesRead = 0, cbReplyBytes = 0, cbWritten = 0;
BOOL fSuccess = FALSE;
// Do some extra error checking since the app will keep running even if this thread fails.
std::list<std::vector<uint8_t>> message_parts;
if (input_pipe_handle == NULL) {
if (pchRequest != NULL) HeapFree(hHeap, 0, pchRequest);
return;
}
if (pchRequest == NULL) {
return;
}
// Loop until done reading
do {
// Read client requests from the pipe. This simplistic code only allows messages
// up to BUFSIZE characters in length.
ZeroMemory(pchRequest, BUFSIZE * sizeof(uint8_t));
fSuccess = ReadFile(
input_pipe_handle, // handle to pipe
pchRequest, // buffer to receive data
BUFSIZE * sizeof(uint8_t), // size of buffer
&cbBytesRead, // number of bytes read
NULL); // not overlapped I/O
if (!fSuccess && GetLastError() != ERROR_MORE_DATA) {
break;
}
std::vector<uint8_t> part_vector;
part_vector.reserve(cbBytesRead);
std::copy(pchRequest, pchRequest + cbBytesRead, std::back_inserter(part_vector));
message_parts.push_back(part_vector);
} while (!fSuccess);
if (fSuccess) {
// Reconstruct the total_message.
std::vector<uint8_t> reconstructed_message;
size_t total_size = 0;
for (auto& part_vector : message_parts) {
total_size += part_vector.size();
}
reconstructed_message.reserve(total_size);
for (auto& part_vector : message_parts) {
std::move(part_vector.begin(), part_vector.end(), std::back_inserter(reconstructed_message));
}
std::wstring unicode_msg;
unicode_msg.assign(reinterpret_cast<std::wstring::const_pointer>(reconstructed_message.data()), reconstructed_message.size() / sizeof(std::wstring::value_type));
input_queue.queue_message(unicode_msg);
}
// Flush the pipe to allow the client to read the pipe's contents
// before disconnecting. Then disconnect the pipe, and close the
// handle to this pipe instance.
FlushFileBuffers(input_pipe_handle);
DisconnectNamedPipe(input_pipe_handle);
CloseHandle(input_pipe_handle);
HeapFree(hHeap, 0, pchRequest);
printf("InstanceThread exitting.\n");
}
void start_named_pipe_server(HANDLE token) {
// Adapted from https://docs.microsoft.com/en-us/windows/win32/ipc/multithreaded-pipe-server
const wchar_t* pipe_name = input_pipe_name.c_str();
BOOL connected = FALSE;
HANDLE connect_pipe_handle = INVALID_HANDLE_VALUE;
while(!closed) {
{
std::unique_lock lock(pipe_connect_handle_mutex);
connect_pipe_handle = CreateNamedPipe(
pipe_name,
PIPE_ACCESS_DUPLEX |
WRITE_DAC,
PIPE_TYPE_MESSAGE |
PIPE_READMODE_MESSAGE |
PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES,
BUFSIZE,
BUFSIZE,
0,
NULL
);
if (connect_pipe_handle == INVALID_HANDLE_VALUE) {
return;
} }
if (token != NULL) { // Get the token group information from the access token.
int err = change_pipe_security_allow_restricted_token(connect_pipe_handle, token);
if (!GetTokenInformation(
hToken, // handle to the access token
TokenGroups, // get information about the token's groups
(LPVOID)ptg, // pointer to TOKEN_GROUPS buffer
dwLength, // size of buffer
&dwLength // receives required buffer size
))
{
goto Cleanup;
} }
current_connect_pipe_handle = connect_pipe_handle;
}
connected = ConnectNamedPipe(connect_pipe_handle, NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
{
std::unique_lock lock(pipe_connect_handle_mutex);
current_connect_pipe_handle = NULL;
}
if (connected) {
std::thread(&TwoWayPipeMessageIPC::handle_pipe_connection, this, connect_pipe_handle).detach();
} else {
// Client could not connect.
CloseHandle(connect_pipe_handle);
}
}
}
void consume_input_queue_thread() { // Loop through the groups to find the logon SID.
while (!closed) {
std::wstring message = input_queue.pop_message();
if (message.length() == 0) {
break;
}
dispatch_inc_message_function(message);
}
}
for (dwIndex = 0; dwIndex < ptg->GroupCount; dwIndex++)
if ((ptg->Groups[dwIndex].Attributes & SE_GROUP_LOGON_ID) == SE_GROUP_LOGON_ID)
{
// Found the logon SID; make a copy of it.
dwLength = GetLengthSid(ptg->Groups[dwIndex].Sid);
*ppsid = (PSID)HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
dwLength);
if (*ppsid == NULL)
goto Cleanup;
if (!CopySid(dwLength, *ppsid, ptg->Groups[dwIndex].Sid))
{
HeapFree(GetProcessHeap(), 0, (LPVOID)*ppsid);
goto Cleanup;
}
break;
}
bSuccess = TRUE;
Cleanup:
// Free the buffer for the token groups.
if (ptg != NULL)
HeapFree(GetProcessHeap(), 0, (LPVOID)ptg);
return bSuccess;
}
VOID FreeLogonSID(PSID* ppsid)
{
// From https://docs.microsoft.com/en-us/previous-versions/aa446670(v=vs.85)
HeapFree(GetProcessHeap(), 0, (LPVOID)*ppsid);
}
int change_pipe_security_allow_restricted_token(HANDLE handle, HANDLE token)
{
PACL old_dacl, new_dacl;
PSECURITY_DESCRIPTOR sd;
EXPLICIT_ACCESS ea;
PSID user_restricted;
int error;
if (!GetLogonSID(token, &user_restricted))
{
error = 5; // No access error.
goto Ldone;
}
if (GetSecurityInfo(handle,
SE_KERNEL_OBJECT,
DACL_SECURITY_INFORMATION,
NULL,
NULL,
&old_dacl,
NULL,
&sd))
{
error = GetLastError();
goto Lclean_sid;
}
memset(&ea, 0, sizeof(EXPLICIT_ACCESS));
ea.grfAccessPermissions |= GENERIC_READ | FILE_WRITE_ATTRIBUTES;
ea.grfAccessPermissions |= GENERIC_WRITE | FILE_READ_ATTRIBUTES;
ea.grfAccessPermissions |= SYNCHRONIZE;
ea.grfAccessMode = SET_ACCESS;
ea.grfInheritance = NO_INHERITANCE;
ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
ea.Trustee.TrusteeType = TRUSTEE_IS_USER;
ea.Trustee.ptstrName = (LPTSTR)user_restricted;
if (SetEntriesInAcl(1, &ea, old_dacl, &new_dacl))
{
error = GetLastError();
goto Lclean_sd;
}
if (SetSecurityInfo(handle,
SE_KERNEL_OBJECT,
DACL_SECURITY_INFORMATION,
NULL,
NULL,
new_dacl,
NULL))
{
error = GetLastError();
goto Lclean_dacl;
}
error = 0;
Lclean_dacl:
LocalFree((HLOCAL)new_dacl);
Lclean_sd:
LocalFree((HLOCAL)sd);
Lclean_sid:
FreeLogonSID(&user_restricted);
Ldone:
return error;
}
HANDLE create_medium_integrity_token()
{
HANDLE restricted_token_handle;
SAFER_LEVEL_HANDLE level_handle = NULL;
DWORD sid_size = SECURITY_MAX_SID_SIZE;
BYTE medium_sid[SECURITY_MAX_SID_SIZE];
if (!SaferCreateLevel(SAFER_SCOPEID_USER, SAFER_LEVELID_NORMALUSER, SAFER_LEVEL_OPEN, &level_handle, NULL))
{
return NULL;
}
if (!SaferComputeTokenFromLevel(level_handle, NULL, &restricted_token_handle, 0, NULL))
{
SaferCloseLevel(level_handle);
return NULL;
}
SaferCloseLevel(level_handle);
if (!CreateWellKnownSid(WinMediumLabelSid, nullptr, medium_sid, &sid_size))
{
CloseHandle(restricted_token_handle);
return NULL;
}
TOKEN_MANDATORY_LABEL integrity_level = { 0 };
integrity_level.Label.Attributes = SE_GROUP_INTEGRITY;
integrity_level.Label.Sid = reinterpret_cast<PSID>(medium_sid);
if (!SetTokenInformation(restricted_token_handle, TokenIntegrityLevel, &integrity_level, sizeof(integrity_level)))
{
CloseHandle(restricted_token_handle);
return NULL;
}
return restricted_token_handle;
}
void handle_pipe_connection(HANDLE input_pipe_handle)
{
//Adapted from https://docs.microsoft.com/en-us/windows/win32/ipc/multithreaded-pipe-server
HANDLE hHeap = GetProcessHeap();
uint8_t* pchRequest = (uint8_t*)HeapAlloc(hHeap, 0, BUFSIZE * sizeof(uint8_t));
DWORD cbBytesRead = 0, cbReplyBytes = 0, cbWritten = 0;
BOOL fSuccess = FALSE;
// Do some extra error checking since the app will keep running even if this thread fails.
std::list<std::vector<uint8_t>> message_parts;
if (input_pipe_handle == NULL)
{
if (pchRequest != NULL)
HeapFree(hHeap, 0, pchRequest);
return;
}
if (pchRequest == NULL)
{
return;
}
// Loop until done reading
do
{
// Read client requests from the pipe. This simplistic code only allows messages
// up to BUFSIZE characters in length.
ZeroMemory(pchRequest, BUFSIZE * sizeof(uint8_t));
fSuccess = ReadFile(
input_pipe_handle, // handle to pipe
pchRequest, // buffer to receive data
BUFSIZE * sizeof(uint8_t), // size of buffer
&cbBytesRead, // number of bytes read
NULL); // not overlapped I/O
if (!fSuccess && GetLastError() != ERROR_MORE_DATA)
{
break;
}
std::vector<uint8_t> part_vector;
part_vector.reserve(cbBytesRead);
std::copy(pchRequest, pchRequest + cbBytesRead, std::back_inserter(part_vector));
message_parts.push_back(part_vector);
} while (!fSuccess);
if (fSuccess)
{
// Reconstruct the total_message.
std::vector<uint8_t> reconstructed_message;
size_t total_size = 0;
for (auto& part_vector : message_parts)
{
total_size += part_vector.size();
}
reconstructed_message.reserve(total_size);
for (auto& part_vector : message_parts)
{
std::move(part_vector.begin(), part_vector.end(), std::back_inserter(reconstructed_message));
}
std::wstring unicode_msg;
unicode_msg.assign(reinterpret_cast<std::wstring::const_pointer>(reconstructed_message.data()), reconstructed_message.size() / sizeof(std::wstring::value_type));
input_queue.queue_message(unicode_msg);
}
// Flush the pipe to allow the client to read the pipe's contents
// before disconnecting. Then disconnect the pipe, and close the
// handle to this pipe instance.
FlushFileBuffers(input_pipe_handle);
DisconnectNamedPipe(input_pipe_handle);
CloseHandle(input_pipe_handle);
HeapFree(hHeap, 0, pchRequest);
printf("InstanceThread exitting.\n");
}
void start_named_pipe_server(HANDLE token)
{
// Adapted from https://docs.microsoft.com/en-us/windows/win32/ipc/multithreaded-pipe-server
const wchar_t* pipe_name = input_pipe_name.c_str();
BOOL connected = FALSE;
HANDLE connect_pipe_handle = INVALID_HANDLE_VALUE;
while (!closed)
{
{
std::unique_lock lock(pipe_connect_handle_mutex);
connect_pipe_handle = CreateNamedPipe(
pipe_name,
PIPE_ACCESS_DUPLEX |
WRITE_DAC,
PIPE_TYPE_MESSAGE |
PIPE_READMODE_MESSAGE |
PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES,
BUFSIZE,
BUFSIZE,
0,
NULL);
if (connect_pipe_handle == INVALID_HANDLE_VALUE)
{
return;
}
if (token != NULL)
{
int err = change_pipe_security_allow_restricted_token(connect_pipe_handle, token);
}
current_connect_pipe_handle = connect_pipe_handle;
}
connected = ConnectNamedPipe(connect_pipe_handle, NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
{
std::unique_lock lock(pipe_connect_handle_mutex);
current_connect_pipe_handle = NULL;
}
if (connected)
{
std::thread(&TwoWayPipeMessageIPC::handle_pipe_connection, this, connect_pipe_handle).detach();
}
else
{
// Client could not connect.
CloseHandle(connect_pipe_handle);
}
}
}
void consume_input_queue_thread()
{
while (!closed)
{
std::wstring message = input_queue.pop_message();
if (message.length() == 0)
{
break;
}
dispatch_inc_message_function(message);
}
}
}; };

View File

@ -2,17 +2,18 @@
#define STRINGIZE2(s) #s #define STRINGIZE2(s) #s
#define STRINGIZE(s) STRINGIZE2(s) #define STRINGIZE(s) STRINGIZE2(s)
#define VERSION_MAJOR 0
#define VERSION_MINOR 15
#define VERSION_REVISION 2
#define FILE_VERSION VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION, 0
#define FILE_VERSION_STRING STRINGIZE(VERSION_MAJOR) "." STRINGIZE(VERSION_MINOR) "." STRINGIZE(VERSION_REVISION) ".0"
#define PRODUCT_VERSION FILE_VERSION #define VERSION_MAJOR 0
#define PRODUCT_VERSION_STRING FILE_VERSION_STRING #define VERSION_MINOR 15
#define VERSION_REVISION 2
#define COMPANY_NAME "Microsoft Corporation" #define FILE_VERSION VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION, 0
#define COPYRIGHT_NOTE "Copyright (C) 2019 Microsoft Corporation" #define FILE_VERSION_STRING \
STRINGIZE(VERSION_MAJOR) \
"." STRINGIZE(VERSION_MINOR) "." STRINGIZE(VERSION_REVISION) ".0"
#define PRODUCT_VERSION FILE_VERSION
#define PRODUCT_VERSION_STRING FILE_VERSION_STRING
#define COMPANY_NAME "Microsoft Corporation"
#define COPYRIGHT_NOTE "Copyright (C) 2019 Microsoft Corporation"

View File

@ -4,7 +4,7 @@
HWND CreateMsgWindow(_In_ HINSTANCE hInst, _In_ WNDPROC pfnWndProc, _In_ void* p) HWND CreateMsgWindow(_In_ HINSTANCE hInst, _In_ WNDPROC pfnWndProc, _In_ void* p)
{ {
WNDCLASS wc = { 0 }; WNDCLASS wc = { 0 };
PCWSTR wndClassName = L"MsgWindow"; PCWSTR wndClassName = L"MsgWindow";
wc.lpfnWndProc = DefWindowProc; wc.lpfnWndProc = DefWindowProc;

View File

@ -1,75 +1,89 @@
#include "pch.h" #include "pch.h"
#include "windows_colors.h" #include "windows_colors.h"
DWORD WindowsColors::rgb_color(DWORD abgr_color) { DWORD WindowsColors::rgb_color(DWORD abgr_color)
// registry keeps the colors in ABGR format, we want RGB {
auto r = (abgr_color & 0xFF); // registry keeps the colors in ABGR format, we want RGB
auto g = (abgr_color & 0xFF00) >> 8; auto r = (abgr_color & 0xFF);
auto b = (abgr_color & 0xFF0000) >> 16; auto g = (abgr_color & 0xFF00) >> 8;
return (r << 16) | (g << 8) | b; auto b = (abgr_color & 0xFF0000) >> 16;
return (r << 16) | (g << 8) | b;
} }
DWORD WindowsColors::rgb_color(winrt::Windows::UI::Color color) { DWORD WindowsColors::rgb_color(winrt::Windows::UI::Color color)
return ((DWORD)color.R << 16) | ((DWORD)color.G << 8) | ((DWORD)color.B); {
return ((DWORD)color.R << 16) | ((DWORD)color.G << 8) | ((DWORD)color.B);
} }
WindowsColors::Color WindowsColors::get_button_face_color() { WindowsColors::Color WindowsColors::get_button_face_color()
winrt::Windows::UI::ViewManagement::UISettings uiSettings; {
return uiSettings.UIElementColor(winrt::Windows::UI::ViewManagement::UIElementType::ButtonFace); winrt::Windows::UI::ViewManagement::UISettings uiSettings;
return uiSettings.UIElementColor(winrt::Windows::UI::ViewManagement::UIElementType::ButtonFace);
} }
WindowsColors::Color WindowsColors::get_button_text_color() { WindowsColors::Color WindowsColors::get_button_text_color()
winrt::Windows::UI::ViewManagement::UISettings uiSettings; {
return uiSettings.UIElementColor(winrt::Windows::UI::ViewManagement::UIElementType::ButtonText); winrt::Windows::UI::ViewManagement::UISettings uiSettings;
return uiSettings.UIElementColor(winrt::Windows::UI::ViewManagement::UIElementType::ButtonText);
} }
WindowsColors::Color WindowsColors::get_highlight_color() { WindowsColors::Color WindowsColors::get_highlight_color()
winrt::Windows::UI::ViewManagement::UISettings uiSettings; {
return uiSettings.UIElementColor(winrt::Windows::UI::ViewManagement::UIElementType::Highlight); winrt::Windows::UI::ViewManagement::UISettings uiSettings;
return uiSettings.UIElementColor(winrt::Windows::UI::ViewManagement::UIElementType::Highlight);
} }
WindowsColors::Color WindowsColors::get_hotlight_color() { WindowsColors::Color WindowsColors::get_hotlight_color()
winrt::Windows::UI::ViewManagement::UISettings uiSettings; {
return uiSettings.UIElementColor(winrt::Windows::UI::ViewManagement::UIElementType::Hotlight); winrt::Windows::UI::ViewManagement::UISettings uiSettings;
return uiSettings.UIElementColor(winrt::Windows::UI::ViewManagement::UIElementType::Hotlight);
} }
WindowsColors::Color WindowsColors::get_highlight_text_color() { WindowsColors::Color WindowsColors::get_highlight_text_color()
winrt::Windows::UI::ViewManagement::UISettings uiSettings; {
return uiSettings.UIElementColor(winrt::Windows::UI::ViewManagement::UIElementType::HighlightText); winrt::Windows::UI::ViewManagement::UISettings uiSettings;
return uiSettings.UIElementColor(winrt::Windows::UI::ViewManagement::UIElementType::HighlightText);
} }
WindowsColors::Color WindowsColors::get_accent_light_1_color() { WindowsColors::Color WindowsColors::get_accent_light_1_color()
winrt::Windows::UI::ViewManagement::UISettings uiSettings; {
return uiSettings.GetColorValue(winrt::Windows::UI::ViewManagement::UIColorType::AccentLight1); winrt::Windows::UI::ViewManagement::UISettings uiSettings;
return uiSettings.GetColorValue(winrt::Windows::UI::ViewManagement::UIColorType::AccentLight1);
} }
WindowsColors::Color WindowsColors::get_accent_light_2_color() { WindowsColors::Color WindowsColors::get_accent_light_2_color()
winrt::Windows::UI::ViewManagement::UISettings uiSettings; {
return uiSettings.GetColorValue(winrt::Windows::UI::ViewManagement::UIColorType::AccentLight2); winrt::Windows::UI::ViewManagement::UISettings uiSettings;
return uiSettings.GetColorValue(winrt::Windows::UI::ViewManagement::UIColorType::AccentLight2);
} }
WindowsColors::Color WindowsColors::get_accent_dark_1_color() { WindowsColors::Color WindowsColors::get_accent_dark_1_color()
winrt::Windows::UI::ViewManagement::UISettings uiSettings; {
return uiSettings.GetColorValue(winrt::Windows::UI::ViewManagement::UIColorType::AccentDark1); winrt::Windows::UI::ViewManagement::UISettings uiSettings;
return uiSettings.GetColorValue(winrt::Windows::UI::ViewManagement::UIColorType::AccentDark1);
} }
WindowsColors::Color WindowsColors::get_accent_color() { WindowsColors::Color WindowsColors::get_accent_color()
winrt::Windows::UI::ViewManagement::UISettings uiSettings; {
return uiSettings.GetColorValue(winrt::Windows::UI::ViewManagement::UIColorType::Accent); winrt::Windows::UI::ViewManagement::UISettings uiSettings;
return uiSettings.GetColorValue(winrt::Windows::UI::ViewManagement::UIColorType::Accent);
} }
WindowsColors::Color WindowsColors::get_background_color() { WindowsColors::Color WindowsColors::get_background_color()
winrt::Windows::UI::ViewManagement::UISettings uiSettings; {
return uiSettings.GetColorValue(winrt::Windows::UI::ViewManagement::UIColorType::Background); winrt::Windows::UI::ViewManagement::UISettings uiSettings;
} return uiSettings.GetColorValue(winrt::Windows::UI::ViewManagement::UIColorType::Background);
bool WindowsColors::is_dark_mode() {
return rgb_color(get_background_color()) == 0;
} }
bool WindowsColors::update() { bool WindowsColors::is_dark_mode()
auto new_accent_color_menu = rgb_color(get_accent_color()); {
auto new_start_color_menu = new_accent_color_menu; return rgb_color(get_background_color()) == 0;
auto new_desktop_fill_color = rgb_color(GetSysColor(COLOR_DESKTOP)); }
auto new_light_mode = rgb_color(get_background_color()) != 0; //Dark mode will have black as the background color.
bool WindowsColors::update()
bool changed = new_accent_color_menu != accent_color_menu || {
new_start_color_menu != start_color_menu || auto new_accent_color_menu = rgb_color(get_accent_color());
new_light_mode != light_mode || auto new_start_color_menu = new_accent_color_menu;
new_desktop_fill_color != desktop_fill_color; auto new_desktop_fill_color = rgb_color(GetSysColor(COLOR_DESKTOP));
accent_color_menu = new_accent_color_menu; auto new_light_mode = rgb_color(get_background_color()) != 0; //Dark mode will have black as the background color.
start_color_menu = new_start_color_menu;
light_mode = new_light_mode; bool changed = new_accent_color_menu != accent_color_menu ||
desktop_fill_color = new_desktop_fill_color; new_start_color_menu != start_color_menu ||
new_light_mode != light_mode ||
return changed; new_desktop_fill_color != desktop_fill_color;
accent_color_menu = new_accent_color_menu;
start_color_menu = new_start_color_menu;
light_mode = new_light_mode;
desktop_fill_color = new_desktop_fill_color;
return changed;
} }

View File

@ -1,27 +1,28 @@
#pragma once #pragma once
#include <winrt/Windows.UI.ViewManagement.h> #include <winrt/Windows.UI.ViewManagement.h>
struct WindowsColors { struct WindowsColors
using Color = winrt::Windows::UI::Color; {
using Color = winrt::Windows::UI::Color;
static DWORD rgb_color(DWORD abgr_color);
static DWORD rgb_color(Color color);
static Color get_button_face_color();
static Color get_button_text_color();
static Color get_highlight_color();
static Color get_hotlight_color();
static Color get_highlight_text_color();
static Color get_accent_light_1_color();
static Color get_accent_light_2_color();
static Color get_accent_dark_1_color();
static Color get_accent_color();
static Color get_background_color();
static bool is_dark_mode();
// Update colors - returns true if the values where changed
bool update();
DWORD accent_color_menu = 0, static DWORD rgb_color(DWORD abgr_color);
start_color_menu = 0, static DWORD rgb_color(Color color);
desktop_fill_color = 0; static Color get_button_face_color();
bool light_mode = true; static Color get_button_text_color();
static Color get_highlight_color();
static Color get_hotlight_color();
static Color get_highlight_text_color();
static Color get_accent_light_1_color();
static Color get_accent_light_2_color();
static Color get_accent_dark_1_color();
static Color get_accent_color();
static Color get_background_color();
static bool is_dark_mode();
// Update colors - returns true if the values where changed
bool update();
DWORD accent_color_menu = 0,
start_color_menu = 0,
desktop_fill_color = 0;
bool light_mode = true;
}; };

View File

@ -4,7 +4,6 @@
#include <winrt/Windows.ApplicationModel.h> #include <winrt/Windows.ApplicationModel.h>
namespace winstore namespace winstore
{ {
using winrt::Windows::ApplicationModel::StartupTaskState; using winrt::Windows::ApplicationModel::StartupTaskState;

View File

@ -317,7 +317,6 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
int result = 0; int result = 0;
try try
{ {
std::thread{ [] { std::thread{ [] {
github_update_checking_worker(); github_update_checking_worker();
} }.detach(); } }.detach();

View File

@ -99,7 +99,8 @@ LRESULT __stdcall tray_icon_window_proc(HWND window, UINT message, WPARAM wparam
// Shell_NotifyIcon can fail when we invoke it during the time explorer.exe isn't present/ready to handle it. // Shell_NotifyIcon can fail when we invoke it during the time explorer.exe isn't present/ready to handle it.
// We'll also never receive wm_taskbar_restart message if the first call to Shell_NotifyIcon failed, so we use // We'll also never receive wm_taskbar_restart message if the first call to Shell_NotifyIcon failed, so we use
// WM_WINDOWPOSCHANGING which is always received on explorer startup sequence. // WM_WINDOWPOSCHANGING which is always received on explorer startup sequence.
case WM_WINDOWPOSCHANGING: { case WM_WINDOWPOSCHANGING:
{
if (!tray_icon_created) if (!tray_icon_created)
{ {
tray_icon_created = Shell_NotifyIcon(NIM_ADD, &tray_icon_data) == TRUE; tray_icon_created = Shell_NotifyIcon(NIM_ADD, &tray_icon_data) == TRUE;
@ -111,12 +112,14 @@ LRESULT __stdcall tray_icon_window_proc(HWND window, UINT message, WPARAM wparam
{ {
switch (lparam) switch (lparam)
{ {
case WM_LBUTTONUP: { case WM_LBUTTONUP:
{
open_settings_window(); open_settings_window();
break; break;
} }
case WM_RBUTTONUP: case WM_RBUTTONUP:
case WM_CONTEXTMENU: { case WM_CONTEXTMENU:
{
if (!h_menu) if (!h_menu)
{ {
h_menu = LoadMenu(reinterpret_cast<HINSTANCE>(&__ImageBase), MAKEINTRESOURCE(ID_TRAY_MENU)); h_menu = LoadMenu(reinterpret_cast<HINSTANCE>(&__ImageBase), MAKEINTRESOURCE(ID_TRAY_MENU));

View File

@ -248,7 +248,7 @@ void initialize_webview(int nShowCmd)
// WebView doesn't let us to open ms-settings:protocol links directly, so we translate it // WebView doesn't let us to open ms-settings:protocol links directly, so we translate it
// from a https placeholder // from a https placeholder
if (uri.AbsoluteUri() == L"https://ms_settings_startupapps/") if (uri.AbsoluteUri() == L"https://ms_settings_startupapps/")
uri = Uri{L"ms-settings:startupapps"}; uri = Uri{ L"ms-settings:startupapps" };
winrt::Windows::System::Launcher::LaunchUriAsync(uri); winrt::Windows::System::Launcher::LaunchUriAsync(uri);
}); });
@ -339,7 +339,8 @@ LRESULT CALLBACK wnd_proc_static(HWND hWnd, UINT message, WPARAM wParam, LPARAM
wm_data_for_webview = RegisterWindowMessageW(L"PTSettingsCopyDataWebView"); wm_data_for_webview = RegisterWindowMessageW(L"PTSettingsCopyDataWebView");
wm_destroy_window = RegisterWindowMessageW(L"PTSettingsParentTerminated"); wm_destroy_window = RegisterWindowMessageW(L"PTSettingsParentTerminated");
break; break;
case WM_DPICHANGED: { case WM_DPICHANGED:
{
// Resize the window using the suggested rect // Resize the window using the suggested rect
RECT* const prcNewWindow = (RECT*)lParam; RECT* const prcNewWindow = (RECT*)lParam;
SetWindowPos(hWnd, SetWindowPos(hWnd,
@ -351,7 +352,8 @@ LRESULT CALLBACK wnd_proc_static(HWND hWnd, UINT message, WPARAM wParam, LPARAM
SWP_NOZORDER | SWP_NOACTIVATE); SWP_NOZORDER | SWP_NOACTIVATE);
} }
break; break;
case WM_NCCREATE: { case WM_NCCREATE:
{
// Enable auto-resizing the title bar // Enable auto-resizing the title bar
EnableNonClientDpiScaling(hWnd); EnableNonClientDpiScaling(hWnd);
} }