Skip to content

Commit

Permalink
Working "core code". With "RefreshConfig".
Browse files Browse the repository at this point in the history
  • Loading branch information
jefflord committed Oct 16, 2023
1 parent 51279ee commit dd463b7
Show file tree
Hide file tree
Showing 4 changed files with 206 additions and 39 deletions.
161 changes: 142 additions & 19 deletions src/runner/centralized_kb_hook.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include "centralized_kb_hook.h"
#include <common/debug_control.h>
#include <common/utils/winapi_error.h>
#include <common/utils/json.h>
#include <common/logger/logger.h>
#include <common/interop/shared_constants.h>

Expand Down Expand Up @@ -39,7 +40,7 @@ namespace CentralizedKeyboardHook
};
std::multiset<PressedKeyDescriptor> pressedKeyDescriptors;
std::mutex pressedKeyMutex;
long LastKeyInChord = 0;
long lastKeyInChord = 0;

// keep track of last pressed key, to detect repeated keys and if there are more keys pressed.
const DWORD VK_DISABLED = CommonSharedConstants::VK_DISABLED;
Expand Down Expand Up @@ -159,7 +160,7 @@ namespace CentralizedKeyboardHook
.key = static_cast<unsigned char>(keyPressInfo.vkCode)
};

handleCreateProcessHotKeysAndChords(hotkey, keyPressInfo, wParam);
handleCreateProcessHotKeysAndChords(hotkey);

std::function<bool()> action;
{
Expand Down Expand Up @@ -192,41 +193,163 @@ namespace CentralizedKeyboardHook
return CallNextHookEx(hHook, nCode, wParam, lParam);
}

void handleCreateProcessHotKeysAndChords(CentralizedKeyboardHook::Hotkey& hotkey, const KBDLLHOOKSTRUCT& keyPressInfo, WPARAM& wParam)
class RunProgramSpec
{
if (hotkey.win || hotkey.shift || hotkey.ctrl)
public:
bool win = false;
bool shift = false;
bool alt = false;
bool ctrl = false;
std::wstring path = L"";
std::vector<UCHAR> keys;

//RunProgramSpec()
//{
// // Initialization
//}
};

bool getConfigInit = false;
std::vector<RunProgramSpec> runProgramSpecs;

void RefreshConfig()
{
getConfigInit = false;
runProgramSpecs.clear();
}

void setupConfig()
{
if (!getConfigInit)
{
if ((keyPressInfo.vkCode != 79 && keyPressInfo.vkCode != 80))
auto jsonData = json::from_file(L"c:\\Temp\\keyboardManagerConfig.json");

if (!jsonData)
{
return;
}

auto keyboardManagerConfig = jsonData->GetNamedObject(L"runProgramShortcuts");

if (keyboardManagerConfig)
{
LastKeyInChord = 0;
auto global = keyboardManagerConfig.GetNamedArray(L"global");
for (const auto& it : global)
{
try
{
// auto isChord = it.GetObjectW().GetNamedBoolean(L"isChord");
RunProgramSpec runProgramSpec;
runProgramSpec.win = true;

runProgramSpec.win = it.GetObjectW().GetNamedBoolean(L"win");
runProgramSpec.shift = it.GetObjectW().GetNamedBoolean(L"shift");
runProgramSpec.alt = it.GetObjectW().GetNamedBoolean(L"alt");
runProgramSpec.ctrl = it.GetObjectW().GetNamedBoolean(L"control");

auto keys = it.GetObjectW().GetNamedArray(L"keys");
auto program = it.GetObjectW().GetNamedObject(L"program");
auto path = program.GetObjectW().GetNamedString(L"path");

runProgramSpec.path = path;

for (const auto& key : keys)
{
runProgramSpec.keys.push_back(static_cast<UCHAR>(key.GetNumber()));
}

runProgramSpecs.push_back(runProgramSpec);
}
catch (...)
{
Logger::error(L"Improper Key Data JSON. Try the next remap.");
}
}
}

getConfigInit = true;
}
}

if (hotkey.win && hotkey.shift && hotkey.ctrl)
bool isPartOfAnyRunProgramSpec(UCHAR key)
{
for (RunProgramSpec runProgramSpec : runProgramSpecs)
{
if ((keyPressInfo.vkCode != 79 && keyPressInfo.vkCode != 80))
for (unsigned char c : runProgramSpec.keys)
{
LastKeyInChord = 0;
if (c == key)
{
return true;
}
}
else
}
return false;
}

bool isPartOfThisRunProgramSpec(RunProgramSpec runProgramSpec, UCHAR key)
{
for (unsigned char c : runProgramSpec.keys)
{
if (c == key)
{
return true;
}
}
return false;
}

void handleCreateProcessHotKeysAndChords(CentralizedKeyboardHook::Hotkey& hotkey)
{
if (hotkey.win || hotkey.shift || hotkey.ctrl || hotkey.alt)
{
setupConfig();

if (!isPartOfAnyRunProgramSpec(hotkey.key))
{
if ((keyPressInfo.vkCode == 79 || keyPressInfo.vkCode == 80) && hotkey.win && hotkey.shift && hotkey.ctrl)
lastKeyInChord = 0;
return;
}
}
else
{
return;
}

for (RunProgramSpec runProgramSpec : runProgramSpecs)
{
if (runProgramSpec.win == hotkey.win && runProgramSpec.shift == hotkey.shift && runProgramSpec.ctrl == hotkey.ctrl && runProgramSpec.alt == hotkey.alt)
{
auto runProgram = false;
if (runProgramSpec.keys.size() == 1 && runProgramSpec.keys[0] == hotkey.key)
{
runProgram = true;
}
else if (runProgramSpec.keys.size() == 2 && runProgramSpec.keys[0] == lastKeyInChord && runProgramSpec.keys[1] == hotkey.key)
{
runProgram = true;
}
else
{
Logger::trace(L"wParam {}", wParam);
lastKeyInChord = hotkey.key;
}

if (LastKeyInChord == 79 && keyPressInfo.vkCode == 80)
if (runProgram)
{
Logger::trace(L"runProgram {}", runProgram);
lastKeyInChord = 0;

if (runProgramSpec.path.compare(L"RefreshConfig") == 0)
{
RefreshConfig();
}
else
{
LastKeyInChord = 0;
std::wstring executable_path = L"C:\\Program Files\\ActualHideDesktopIcons\\ActualHideDesktopIcons.exe";
std::wstring executable_path = runProgramSpec.path;
std::wstring executable_args = fmt::format(L"\"{}\"", executable_path);
STARTUPINFO startup_info = { sizeof(startup_info) };
PROCESS_INFORMATION process_info = { 0 };
CreateProcessW(executable_path.c_str(), executable_args.data(), nullptr, nullptr, FALSE, 0, nullptr, nullptr, &startup_info, &process_info);
}
else
{
LastKeyInChord = keyPressInfo.vkCode;
}
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/runner/centralized_kb_hook.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ namespace CentralizedKeyboardHook
void Start() noexcept;
void Stop() noexcept;
void SetHotkeyAction(const std::wstring& moduleName, const Hotkey& hotkey, std::function<bool()>&& action) noexcept;
void handleCreateProcessHotKeysAndChords(CentralizedKeyboardHook::Hotkey& hotkey, const KBDLLHOOKSTRUCT& keyPressInfo, WPARAM& wParam);
void handleCreateProcessHotKeysAndChords(CentralizedKeyboardHook::Hotkey& hotkey);
void AddPressedKeyAction(const std::wstring& moduleName, const DWORD vk, const UINT milliseconds, std::function<bool()>&& action) noexcept;
void ClearModuleHotkeys(const std::wstring& moduleName) noexcept;
void RegisterWindow(HWND hwnd) noexcept;
void RefreshConfig();
};
79 changes: 61 additions & 18 deletions src/runner/powertoy_module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,26 +69,70 @@ void PowertoyModule::update_hotkeys()
});
}

PowertoyModuleIface::Hotkey hotkey;
// Add reg for run program shortuts

Check failure on line 72 in src/runner/powertoy_module.cpp

View workflow job for this annotation

GitHub Actions / Spell checking

`shortuts` is not a recognized word. (unrecognized-spelling)
add_run_program_shortcuts();

CentralizedKeyboardHook::RefreshConfig();
}

void PowertoyModule::add_run_program_shortcuts()
{
long emptyValue = 0;
auto modulePtr = pt_module.get();
PowertoyModuleIface::Hotkey hotkey;
hotkey.alt = false;
hotkey.win = true;
hotkey.shift = true;
hotkey.ctrl = true;
hotkey.key = 79;

long emptyValue = 0;

CentralizedKeyboardHook::SetHotkeyAction(pt_module->get_key(), hotkey, [modulePtr, emptyValue] {
Logger::trace(L"{} hotkey is invoked from Centralized keyboard hook", modulePtr->get_key());
return true;
});

hotkey.key = 80;
CentralizedKeyboardHook::SetHotkeyAction(pt_module->get_key(), hotkey, [modulePtr, emptyValue] {
Logger::trace(L"{} hotkey is invoked from Centralized keyboard hook", modulePtr->get_key());
return true;
});
try
{
auto jsonData = json::from_file(L"c:\\Temp\\keyboardManagerConfig.json");

if (!jsonData)
{
return;
}

auto keyboardManagerConfig = jsonData->GetNamedObject(L"runProgramShortcuts");

if (keyboardManagerConfig)
{
auto global = keyboardManagerConfig.GetNamedArray(L"global");
for (const auto& it : global)
{
try
{
// auto isChord = it.GetObjectW().GetNamedBoolean(L"isChord");
hotkey.win = it.GetObjectW().GetNamedBoolean(L"win");
hotkey.shift = it.GetObjectW().GetNamedBoolean(L"shift");
hotkey.alt = it.GetObjectW().GetNamedBoolean(L"alt");
hotkey.ctrl = it.GetObjectW().GetNamedBoolean(L"control");

auto keys = it.GetObjectW().GetNamedArray(L"keys");
auto program = it.GetObjectW().GetNamedObject(L"program");
auto path = program.GetObjectW().GetNamedString(L"path");

for (const auto& key : keys)
{
hotkey.key = static_cast<UCHAR>(key.GetNumber());
CentralizedKeyboardHook::SetHotkeyAction(pt_module->get_key(), hotkey, [modulePtr, emptyValue] {
Logger::trace(L"{} hotkey is invoked from Centralized keyboard hook", modulePtr->get_key());
return true;
});
}
}
catch (...)
{
Logger::error(L"Improper Key Data JSON. Try the next remap.");
}
}
}
}
catch (...)
{
Logger::error(L"Improper Key Data JSON. Try the next remap.");
}
}

void PowertoyModule::UpdateHotkeyEx()
Expand All @@ -107,6 +151,8 @@ void PowertoyModule::UpdateHotkeyEx()
CentralizedHotkeys::AddHotkeyAction({ hotkey.modifiersMask, hotkey.vkCode }, { pt_module->get_key(), action });
}

CentralizedKeyboardHook::RefreshConfig();

// Hotkey hotkey{
// .win = (GetAsyncKeyState(VK_LWIN) & 0x8000) || (GetAsyncKeyState(VK_RWIN) & 0x8000),
// .ctrl = static_cast<bool>(GetAsyncKeyState(VK_CONTROL) & 0x8000),
Expand All @@ -133,10 +179,7 @@ void PowertoyModule::UpdateHotkeyEx()
CentralizedKeyboardHook::AddPressedKeyAction(pt_module->get_key(), VK_LWIN, pt_module->milliseconds_win_key_must_be_pressed(), action);
CentralizedKeyboardHook::AddPressedKeyAction(pt_module->get_key(), VK_RWIN, pt_module->milliseconds_win_key_must_be_pressed(), action);


CentralizedKeyboardHook::AddPressedKeyAction(pt_module->get_key(), VK_LCONTROL, pt_module->milliseconds_win_key_must_be_pressed(), action);
CentralizedKeyboardHook::AddPressedKeyAction(pt_module->get_key(), VK_LSHIFT, pt_module->milliseconds_win_key_must_be_pressed(), action);
CentralizedKeyboardHook::AddPressedKeyAction(pt_module->get_key(), VK_LSHIFT, pt_module->milliseconds_win_key_must_be_pressed(), action);
}


}
2 changes: 1 addition & 1 deletion src/runner/powertoy_module.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class PowertoyModule
json::JsonObject json_config() const;

void update_hotkeys();

void add_run_program_shortcuts();
void UpdateHotkeyEx();

private:
Expand Down

1 comment on commit dd463b7

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@check-spelling-bot Report

🔴 Please review

See the 📜action log for details.

Unrecognized words (1)

shortuts

Previously acknowledged words that are now absent administra RSAT systemroot sysvol :arrow_right:
To accept ✔️ these unrecognized words as correct and remove the previously acknowledged and now absent words, run the following commands

... in a clone of the git@github.com:jefflord/PowerToys.git repository
on the run-program-shortcuts branch (ℹ️ how do I use this?):

curl -s -S -L 'https://raw.githubusercontent.com/check-spelling/check-spelling/v0.0.21/apply.pl' |
perl - 'https://github.com/jefflord/PowerToys/actions/runs/6532326520/attempts/1'
Available 📚 dictionaries could cover words not in the 📘 dictionary

This includes both expected items (2287) from .github/actions/spell-check/expect.txt and unrecognized words (1)

Dictionary Entries Covers
cspell:win32/src/win32.txt 53509 139
cspell:cpp/src/cpp.txt 30216 132
cspell:python/src/python/python-lib.txt 3873 29
cspell:php/php.txt 2597 20
cspell:node/node.txt 1768 15
cspell:typescript/typescript.txt 1211 13
cspell:java/java.txt 7642 12
cspell:python/src/python/python.txt 453 10
cspell:aws/aws.txt 218 9
cspell:python/src/common/extra.txt 741 8

Consider adding them using (in .github/workflows/spelling2.yml):

      with:
        extra_dictionaries:
          cspell:win32/src/win32.txt
          cspell:cpp/src/cpp.txt
          cspell:python/src/python/python-lib.txt
          cspell:php/php.txt
          cspell:node/node.txt
          cspell:typescript/typescript.txt
          cspell:java/java.txt
          cspell:python/src/python/python.txt
          cspell:aws/aws.txt
          cspell:python/src/common/extra.txt

To stop checking additional dictionaries, add:

      with:
        check_extra_dictionaries: ''
If the flagged items are 🤯 false positives

If items relate to a ...

  • binary file (or some other file you wouldn't want to check at all).

    Please add a file path to the excludes.txt file matching the containing file.

    File paths are Perl 5 Regular Expressions - you can test yours before committing to verify it will match your files.

    ^ refers to the file's path from the root of the repository, so ^README\.md$ would exclude README.md (on whichever branch you're using).

  • well-formed pattern.

    If you can write a pattern that would match it,
    try adding it to the patterns.txt file.

    Patterns are Perl 5 Regular Expressions - you can test yours before committing to verify it will match your lines.

    Note that patterns can't match multiline strings.

Please sign in to comment.