PowerToys/src/modules/shortcut_guide/shortcut_guide.cpp

259 lines
6.6 KiB
C++
Raw Normal View History

#include "pch.h"
#include "shortcut_guide.h"
#include "target_state.h"
#include "trace.h"
#include "resource.h"
#include <common/common.h>
#include <common/settings_objects.h>
extern "C" IMAGE_DOS_HEADER __ImageBase;
OverlayWindow* instance = nullptr;
namespace
{
LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
LowlevelKeyboardEvent event;
if (nCode == HC_ACTION)
{
event.lParam = reinterpret_cast<KBDLLHOOKSTRUCT*>(lParam);
event.wParam = wParam;
if (instance->signal_event(&event) != 0)
{
return 1;
}
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
}
OverlayWindow::OverlayWindow()
{
app_name = GET_RESOURCE_STRING(IDS_SHORTCUT_GUIDE);
init_settings();
}
const wchar_t* OverlayWindow::get_name()
{
return app_name.c_str();
}
const wchar_t** OverlayWindow::get_events()
{
return nullptr;
}
bool OverlayWindow::get_config(wchar_t* buffer, int* buffer_size)
{
HINSTANCE hinstance = reinterpret_cast<HINSTANCE>(&__ImageBase);
PowerToysSettings::Settings settings(hinstance, get_name());
settings.set_description(GET_RESOURCE_STRING(IDS_SETTINGS_DESCRIPTION));
settings.set_overview_link(L"https://github.com/microsoft/PowerToys/blob/master/src/modules/shortcut_guide/README.md");
settings.set_icon_key(L"pt-shortcut-guide");
settings.add_int_spinner(
pressTime.name,
pressTime.resourceId,
pressTime.value,
100,
10000,
100);
settings.add_int_spinner(
overlayOpacity.name,
overlayOpacity.resourceId,
overlayOpacity.value,
0,
100,
1);
settings.add_choice_group(
theme.name,
theme.resourceId,
theme.value,
theme.keys_and_texts);
return settings.serialize_to_buffer(buffer, buffer_size);
}
void OverlayWindow::set_config(const wchar_t* config)
{
try
{
// save configuration
PowerToysSettings::PowerToyValues _values =
PowerToysSettings::PowerToyValues::from_json_string(config);
_values.save_to_settings_file();
Trace::SettingsChanged(pressTime.value, overlayOpacity.value, theme.value);
// apply new settings if powertoy is enabled
if (_enabled)
{
if (const auto press_delay_time = _values.get_int_value(pressTime.name))
{
pressTime.value = *press_delay_time;
if (target_state)
{
target_state->set_delay(*press_delay_time);
}
}
if (const auto overlay_opacity = _values.get_int_value(overlayOpacity.name))
{
overlayOpacity.value = *overlay_opacity;
if (winkey_popup)
{
winkey_popup->apply_overlay_opacity(((float)overlayOpacity.value) / 100.0f);
}
}
if (auto val = _values.get_string_value(theme.name))
{
theme.value = std::move(*val);
if (winkey_popup)
{
winkey_popup->set_theme(theme.value);
}
}
}
}
catch (...)
{
// Improper JSON. TODO: handle the error.
}
}
void OverlayWindow::enable()
{
if (!_enabled)
{
Trace::EnableShortcutGuide(true);
winkey_popup = std::make_unique<D2DOverlayWindow>();
winkey_popup->apply_overlay_opacity(((float)overlayOpacity.value) / 100.0f);
winkey_popup->set_theme(theme.value);
target_state = std::make_unique<TargetState>(pressTime.value);
winkey_popup->initialize();
hook_handle = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, GetModuleHandle(NULL), NULL);
if (!hook_handle)
{
MessageBoxW(NULL, L"Cannot install keyboard listener.", L"PowerToys - Shortcut Guide", MB_OK | MB_ICONERROR);
}
}
_enabled = true;
}
void OverlayWindow::disable(bool trace_event)
{
if (_enabled)
{
_enabled = false;
if (trace_event)
{
Trace::EnableShortcutGuide(false);
}
winkey_popup->hide();
target_state->exit();
target_state.reset();
winkey_popup.reset();
if (hook_handle)
{
bool success = UnhookWindowsHookEx(hook_handle);
if (success)
{
hook_handle = nullptr;
}
}
}
}
void OverlayWindow::disable()
{
this->disable(true);
}
bool OverlayWindow::is_enabled()
{
return _enabled;
}
intptr_t OverlayWindow::signal_event(const wchar_t* name, intptr_t data)
{
return 0;
}
intptr_t OverlayWindow::signal_event(LowlevelKeyboardEvent* event)
{
if (!_enabled)
{
return 0;
}
if (event->wParam == WM_KEYDOWN ||
event->wParam == WM_SYSKEYDOWN ||
event->wParam == WM_KEYUP ||
event->wParam == WM_SYSKEYUP)
{
bool suppress = target_state->signal_event(event->lParam->vkCode,
event->wParam == WM_KEYDOWN || event->wParam == WM_SYSKEYDOWN);
return suppress ? 1 : 0;
}
else
{
return 0;
}
}
void OverlayWindow::on_held()
{
auto filter = get_shortcutguide_filtered_window();
winkey_popup->show(filter.hwnd, filter.snappable);
}
void OverlayWindow::on_held_press(DWORD vkCode)
{
winkey_popup->animate(vkCode);
}
void OverlayWindow::quick_hide()
{
winkey_popup->quick_hide();
}
void OverlayWindow::was_hidden()
{
target_state->was_hiden();
}
void OverlayWindow::destroy()
{
this->disable(false);
delete this;
instance = nullptr;
}
void OverlayWindow::init_settings()
{
try
{
PowerToysSettings::PowerToyValues settings =
PowerToysSettings::PowerToyValues::load_from_settings_file(OverlayWindow::get_name());
if (const auto val = settings.get_int_value(pressTime.name))
{
pressTime.value = *val;
}
if (const auto val = settings.get_int_value(overlayOpacity.name))
{
overlayOpacity.value = *val;
}
if (auto val = settings.get_string_value(theme.name))
{
theme.value = std::move(*val);
}
}
catch (std::exception&)
{
// Error while loading from the settings file. Just let default values stay as they are.
}
}