diff --git a/IntelPresentMon/AppCef/CefNano.vcxproj b/IntelPresentMon/AppCef/CefNano.vcxproj
index 835029e3..8464054f 100644
--- a/IntelPresentMon/AppCef/CefNano.vcxproj
+++ b/IntelPresentMon/AppCef/CefNano.vcxproj
@@ -23,7 +23,6 @@
-
@@ -44,6 +43,7 @@
+
@@ -60,8 +60,6 @@
-
-
@@ -75,7 +73,6 @@
-
diff --git a/IntelPresentMon/AppCef/ipm-ui-vue/src/core/api.ts b/IntelPresentMon/AppCef/ipm-ui-vue/src/core/api.ts
index b9ad66dc..c00fe5ea 100644
--- a/IntelPresentMon/AppCef/ipm-ui-vue/src/core/api.ts
+++ b/IntelPresentMon/AppCef/ipm-ui-vue/src/core/api.ts
@@ -81,13 +81,10 @@ export class Api {
return adapters;
}
static async bindHotkey(binding: Binding): Promise {
- await this.invokeEndpointFuture('bindHotkey', binding);
+ await this.invokeEndpointFuture('BindHotkey', binding);
}
static async clearHotkey(action: Action): Promise {
- await this.invokeEndpointFuture('clearHotkey', {action});
- }
- static async launchKernel(): Promise {
- await this.invokeEndpointFuture('launchKernel', {});
+ await this.invokeEndpointFuture('ClearHotkey', {action});
}
static async pushSpecification(spec: Spec): Promise {
await this.invokeEndpointFuture('PushSpecification', spec);
diff --git a/IntelPresentMon/AppCef/source/DataBindAccessor.cpp b/IntelPresentMon/AppCef/source/DataBindAccessor.cpp
index abe7bb5f..0812d780 100644
--- a/IntelPresentMon/AppCef/source/DataBindAccessor.cpp
+++ b/IntelPresentMon/AppCef/source/DataBindAccessor.cpp
@@ -20,14 +20,7 @@ namespace p2c::client::cef
:
pBrowser{ std::move(pBrowser) },
pKernelWrapper{ pKernelWrapper_ }
- {
- pKernelWrapper->pHotkeys = std::make_unique();
- // set the hotkey listener component to call hotkey signal on the signal manager when a hotkey chord is detected
- pKernelWrapper->pHotkeys->SetHandler([this](Action action) {
- CefPostTask(TID_RENDERER, base::BindOnce(&util::SignalManager::SignalHotkeyFired,
- base::Unretained(&pKernelWrapper->signals), uint32_t(action)));
- });
- }
+ {}
bool DataBindAccessor::Execute(const CefString& name, CefRefPtr object, const CefV8ValueList& arguments, CefRefPtr& retval, CefString& exception)
{
@@ -88,44 +81,6 @@ namespace p2c::client::cef
}
}
- bool DataBindAccessor::BindHotkey(CefValue& pArgObj)
- {
- // {action:int, combination: {modifiers:[], key:int}}
-
- std::shared_lock lk{ kernelMtx };
- if (pKernelWrapper) {
- const auto payload = pArgObj.GetDictionary();
- const auto comboJs = payload->GetDictionary("combination");
- const auto modsJs = comboJs->GetList("modifiers");
-
- auto mods = win::Mod::Null;
- for (int i = 0; i < modsJs->GetSize(); i++) {
- const auto modCode = modsJs->GetValue(i)->GetInt();
- mods = mods | *win::ModSet::SingleModFromCode(modCode);
- }
-
- return pKernelWrapper->pHotkeys->BindAction(
- (Action)payload->GetInt("action"),
- win::Key{ (win::Key::Code)comboJs->GetInt("key") },
- mods
- );
- }
- return false;
- }
-
- bool DataBindAccessor::ClearHotkey(CefValue& pArgObj)
- {
- // {action:int}
-
- std::shared_lock lk{ kernelMtx };
- if (pKernelWrapper) {
- return pKernelWrapper->pHotkeys->ClearAction(
- (Action)pArgObj.GetDictionary()->GetInt("action")
- );
- }
- return false;
- }
-
void DataBindAccessor::ClearKernelWrapper()
{
std::lock_guard lk{ kernelMtx };
diff --git a/IntelPresentMon/AppCef/source/DataBindAccessor.h b/IntelPresentMon/AppCef/source/DataBindAccessor.h
index f2584a47..ced6059f 100644
--- a/IntelPresentMon/AppCef/source/DataBindAccessor.h
+++ b/IntelPresentMon/AppCef/source/DataBindAccessor.h
@@ -19,8 +19,6 @@ namespace p2c::client::cef
CefRefPtr& retval,
CefString& exception) override;
void ResolveAsyncEndpoint(uint64_t uid, bool success, CefRefPtr pArgs);
- bool BindHotkey(CefValue& pArgObj);
- bool ClearHotkey(CefValue& pArgObj);
void ClearKernelWrapper();
private:
// data
diff --git a/IntelPresentMon/AppCef/source/util/AsyncEndpointCollection.cpp b/IntelPresentMon/AppCef/source/util/AsyncEndpointCollection.cpp
index ebcfa3ac..bc638ca1 100644
--- a/IntelPresentMon/AppCef/source/util/AsyncEndpointCollection.cpp
+++ b/IntelPresentMon/AppCef/source/util/AsyncEndpointCollection.cpp
@@ -6,8 +6,6 @@
#include "async/BrowseReadSpec.h"
#include "async/BrowseStoreSpec.h"
-#include "async/BindHotkey.h"
-#include "async/ClearHotkey.h"
#include "async/EnumerateProcesses.h"
#include "async/EnumerateKeys.h"
#include "async/EnumerateModifiers.h"
@@ -34,8 +32,6 @@ namespace p2c::client::util
using namespace async;
AddEndpoint();
AddEndpoint();
- AddEndpoint();
- AddEndpoint();
AddEndpoint();
AddEndpoint();
AddEndpoint();
diff --git a/IntelPresentMon/AppCef/source/util/KernelActionRegistration.cpp b/IntelPresentMon/AppCef/source/util/KernelActionRegistration.cpp
index 2b5ba9f0..55e8ca22 100644
--- a/IntelPresentMon/AppCef/source/util/KernelActionRegistration.cpp
+++ b/IntelPresentMon/AppCef/source/util/KernelActionRegistration.cpp
@@ -11,5 +11,7 @@ namespace p2c::client::util::kact {
IpcActionRegistrator reg_ibind_PushSpecification_;
IpcActionRegistrator reg_ibind_SetAdapter_;
IpcActionRegistrator reg_ibind_SetCapture_;
+ IpcActionRegistrator reg_ibind_BindHotkey_;
+ IpcActionRegistrator reg_ibind_ClearHotkey_;
}
diff --git a/IntelPresentMon/AppCef/source/util/KernelWrapper.h b/IntelPresentMon/AppCef/source/util/KernelWrapper.h
index 7f997c64..874c86fb 100644
--- a/IntelPresentMon/AppCef/source/util/KernelWrapper.h
+++ b/IntelPresentMon/AppCef/source/util/KernelWrapper.h
@@ -1,6 +1,5 @@
#pragma once
#include
-#include "HotkeyListener.h"
#include "SignalManager.h"
#include "AsyncEndpointManager.h"
#include "ActionClientServer.h"
@@ -11,7 +10,6 @@ namespace p2c::client::util
{
struct KernelWrapper
{
- std::unique_ptr pHotkeys;
util::SignalManager signals;
util::AsyncEndpointManager asyncEndpoints;
std::unique_ptr pClient;
diff --git a/IntelPresentMon/AppCef/source/util/async/BindHotkey.h b/IntelPresentMon/AppCef/source/util/async/BindHotkey.h
deleted file mode 100644
index 5f835e44..00000000
--- a/IntelPresentMon/AppCef/source/util/async/BindHotkey.h
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright (C) 2022 Intel Corporation
-// SPDX-License-Identifier: MIT
-#pragma once
-#include "../AsyncEndpoint.h"
-#include
-#include "include/base/cef_callback.h"
-#include "include/wrapper/cef_closure_task.h"
-#include "../../DataBindAccessor.h"
-#include "../CefValues.h"
-
-namespace p2c::client::util::async
-{
- class BindHotkey : public AsyncEndpoint
- {
- public:
- static constexpr std::string GetKey() { return "bindHotkey"; }
- BindHotkey() : AsyncEndpoint{ AsyncEndpoint::Environment::RenderProcess } {}
- // {combination: {modifiers:[], hotkey:int}, action:int} => null
- Result ExecuteOnRenderer(uint64_t uid, CefRefPtr pArgObj, cef::DataBindAccessor& accessor) const override
- {
- return Result{ accessor.BindHotkey(*pArgObj), CefValueNull() };
- }
- };
-}
\ No newline at end of file
diff --git a/IntelPresentMon/AppCef/source/util/async/ClearHotkey.h b/IntelPresentMon/AppCef/source/util/async/ClearHotkey.h
deleted file mode 100644
index 53f12d9b..00000000
--- a/IntelPresentMon/AppCef/source/util/async/ClearHotkey.h
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright (C) 2022 Intel Corporation
-// SPDX-License-Identifier: MIT
-#pragma once
-#include "../AsyncEndpoint.h"
-#include
-#include "include/base/cef_callback.h"
-#include "include/wrapper/cef_closure_task.h"
-#include "../../DataBindAccessor.h"
-#include "../CefValues.h"
-
-namespace p2c::client::util::async
-{
- class ClearHotkey : public AsyncEndpoint
- {
- public:
- static constexpr std::string GetKey() { return "clearHotkey"; }
- ClearHotkey() : AsyncEndpoint{ AsyncEndpoint::Environment::RenderProcess } {}
- // {action:int} => null
- Result ExecuteOnRenderer(uint64_t uid, CefRefPtr pArgObj, cef::DataBindAccessor& accessor) const override
- {
- return Result{ accessor.ClearHotkey(*pArgObj), CefValueNull() };
- }
- };
-}
\ No newline at end of file
diff --git a/IntelPresentMon/AppCef/source/util/async/EnumerateKeys.h b/IntelPresentMon/AppCef/source/util/async/EnumerateKeys.h
index 28e23a5d..bcd2b40c 100644
--- a/IntelPresentMon/AppCef/source/util/async/EnumerateKeys.h
+++ b/IntelPresentMon/AppCef/source/util/async/EnumerateKeys.h
@@ -3,6 +3,8 @@
#pragma once
#include "../AsyncEndpoint.h"
#include "../CefValues.h"
+#include
+#include
namespace p2c::client::util::async
{
diff --git a/IntelPresentMon/AppCef/source/util/async/EnumerateProcesses.h b/IntelPresentMon/AppCef/source/util/async/EnumerateProcesses.h
index 1cfa04ba..fd86304d 100644
--- a/IntelPresentMon/AppCef/source/util/async/EnumerateProcesses.h
+++ b/IntelPresentMon/AppCef/source/util/async/EnumerateProcesses.h
@@ -2,8 +2,11 @@
// SPDX-License-Identifier: MIT
#pragma once
#include
+#include
+#include
#include "../AsyncEndpoint.h"
#include "../CefValues.h"
+#include
namespace p2c::client::util::async
{
@@ -15,6 +18,7 @@ namespace p2c::client::util::async
// {} => {processes: [{name: string, pid: uint}]}
Result ExecuteOnRenderer(uint64_t uid, CefRefPtr pArgObj, cef::DataBindAccessor&) const override
{
+ namespace vi = std::views;
// enumerate processes on system
win::ProcessMapBuilder builder;
builder.FillWindowHandles();
diff --git a/IntelPresentMon/AppCef/source/util/cact/CefActionRegistration.cpp b/IntelPresentMon/AppCef/source/util/cact/CefActionRegistration.cpp
index 78e44eda..51b01979 100644
--- a/IntelPresentMon/AppCef/source/util/cact/CefActionRegistration.cpp
+++ b/IntelPresentMon/AppCef/source/util/cact/CefActionRegistration.cpp
@@ -2,4 +2,5 @@
#include "OverlayDiedAction.h"
#include "PresentmonInitFailedAction.h"
#include "StalePidAction.h"
-#include "TargetLostAction.h"
\ No newline at end of file
+#include "TargetLostAction.h"
+#include "HotkeyFiredAction.h"
\ No newline at end of file
diff --git a/IntelPresentMon/AppCef/source/util/cact/HotkeyFiredAction.h b/IntelPresentMon/AppCef/source/util/cact/HotkeyFiredAction.h
new file mode 100644
index 00000000..1d6edd03
--- /dev/null
+++ b/IntelPresentMon/AppCef/source/util/cact/HotkeyFiredAction.h
@@ -0,0 +1,59 @@
+#pragma once
+#include
+#include "CefExecutionContext.h"
+#include "../../Action.h"
+#include
+
+#define ACT_NAME HotkeyFiredAction
+#define ACT_EXEC_CTX CefExecutionContext
+#define ACT_TYPE AsyncEventActionBase_
+#define ACT_NS ::p2c::client::util::cact
+
+namespace p2c::client::util::cact
+{
+ using namespace ::pmon::ipc::act;
+
+ class ACT_NAME : public ACT_TYPE
+ {
+ public:
+ static constexpr const char* Identifier = STRINGIFY(ACT_NAME);
+ struct Params
+ {
+ int32_t actionId;
+
+ template void serialize(A& ar) {
+ ar(actionId);
+ }
+ };
+ private:
+ friend class ACT_TYPE;
+ static void Execute_(const ACT_EXEC_CTX& ctx, SessionContext& stx, Params&& in);
+ };
+}
+
+#ifdef PM_ASYNC_ACTION_REGISTRATION_
+#include
+#include
+#include
+#include "../SignalManager.h"
+namespace p2c::client::util::cact
+{
+ ACTION_REG();
+ // need to put this function definition only in the cef-server-side since it contains
+ // references to CEF types we do not want to pollute other projects with
+ // TODO: consider a better approach to maintaining single-file actions like this
+ // while also enabling dependency decoupling more easily
+ void ACT_NAME::Execute_(const ACT_EXEC_CTX& ctx, SessionContext& stx, Params&& in)
+ {
+ CefPostTask(TID_RENDERER, base::BindOnce(&SignalManager::SignalHotkeyFired,
+ base::Unretained(ctx.pSignalManager), in.actionId));
+ }
+}
+#endif
+
+ACTION_TRAITS_DEF();
+
+#undef ACT_NAME
+#undef ACT_EXEC_CTX
+#undef ACT_NS
+#undef ACT_TYPE
\ No newline at end of file
diff --git a/IntelPresentMon/Core/Core.vcxproj b/IntelPresentMon/Core/Core.vcxproj
index 979b91ef..b866f46b 100644
--- a/IntelPresentMon/Core/Core.vcxproj
+++ b/IntelPresentMon/Core/Core.vcxproj
@@ -85,6 +85,7 @@
+
@@ -147,6 +148,7 @@
+
diff --git a/IntelPresentMon/Core/Core.vcxproj.filters b/IntelPresentMon/Core/Core.vcxproj.filters
index 0701ec39..fed77fa8 100644
--- a/IntelPresentMon/Core/Core.vcxproj.filters
+++ b/IntelPresentMon/Core/Core.vcxproj.filters
@@ -91,6 +91,7 @@
+
@@ -150,6 +151,7 @@
+
diff --git a/IntelPresentMon/Core/source/infra/Logging.h b/IntelPresentMon/Core/source/infra/Logging.h
index 1a8bb8d2..8016b9ca 100644
--- a/IntelPresentMon/Core/source/infra/Logging.h
+++ b/IntelPresentMon/Core/source/infra/Logging.h
@@ -26,4 +26,5 @@ namespace p2c::v
#else
inline constexpr bool metric = true;
#endif
+ inline constexpr bool hotkey2 = false;
}
\ No newline at end of file
diff --git a/IntelPresentMon/AppCef/source/util/HotkeyListener.cpp b/IntelPresentMon/Core/source/win/HotkeyListener.cpp
similarity index 76%
rename from IntelPresentMon/AppCef/source/util/HotkeyListener.cpp
rename to IntelPresentMon/Core/source/win/HotkeyListener.cpp
index 5dec741c..b01ca2b0 100644
--- a/IntelPresentMon/AppCef/source/util/HotkeyListener.cpp
+++ b/IntelPresentMon/Core/source/win/HotkeyListener.cpp
@@ -1,13 +1,10 @@
// Copyright (C) 2022 Intel Corporation
// SPDX-License-Identifier: MIT
#include "HotkeyListener.h"
-#include "Logging.h"
+#include
#include
#include
#include
-#include
-#include "include/base/cef_callback.h"
-#include "include/wrapper/cef_closure_task.h"
namespace rn = std::ranges;
namespace vi = rn::views;
@@ -15,24 +12,24 @@ using namespace pmon::util;
// TODO: general logging in this codebase (winapi calls like PostThreadMessage etc.)
-namespace p2c::client::util
+namespace p2c::win
{
Hotkeys::Hotkeys()
:
- thread_{ "hotkey", & Hotkeys::Kernel_, this}
+ thread_{ "hotkey", &Hotkeys::Kernel_, this }
{
startupSemaphore_.acquire();
- pmlog_verb(v::hotkey)("Hotkey process ctor complete");
+ pmlog_verb(v::hotkey2)("Hotkey process ctor complete");
}
Hotkeys::~Hotkeys()
{
- pmlog_verb(v::hotkey)("Destroying hotkey processor");
+ pmlog_verb(v::hotkey2)("Destroying hotkey processor");
PostThreadMessageA(threadId_, WM_QUIT, 0, 0);
}
void Hotkeys::Kernel_() noexcept
{
try {
- pmlog_verb(v::hotkey)("Hotkey processor kernel start");
+ pmlog_verb(v::hotkey2)("Hotkey processor kernel start");
// capture thread id
threadId_ = GetCurrentThreadId();
@@ -44,17 +41,17 @@ namespace p2c::client::util
.hInstance = GetModuleHandle(nullptr),
.lpszClassName = "$PresentmonMessageWindowClass$",
};
- const auto atom = RegisterClassEx(&wx);
+ const auto atom = RegisterClassExA(&wx);
if (!atom) {
pmlog_error().hr();
return;
}
- pmlog_verb(v::hotkey)(std::format("Hotkey processor wndclass registered: {:X}", atom));
+ pmlog_verb(v::hotkey2)(std::format("Hotkey processor wndclass registered: {:X}", atom));
// create message window
- messageWindowHandle_ = CreateWindowExA(
- 0, MAKEINTATOM(atom), "$PresentmonMessageWindow$",
+ messageWindowHandle_ = CreateWindowExW(
+ 0, MAKEINTATOM(atom), L"$PresentmonMessageWindow$",
0, 0, 0, 0, 0, HWND_MESSAGE, nullptr, nullptr, nullptr
);
if (!messageWindowHandle_) {
@@ -62,7 +59,7 @@ namespace p2c::client::util
return;
}
- pmlog_verb(v::hotkey)(std::format("Hotkey processor wnd created: {:X}",
+ pmlog_verb(v::hotkey2)(std::format("Hotkey processor wnd created: {:X}",
reinterpret_cast(messageWindowHandle_)));
// register to receive raw keyboard input
@@ -77,7 +74,7 @@ namespace p2c::client::util
return;
}
- pmlog_verb(v::hotkey)("Raw input registered");
+ pmlog_verb(v::hotkey2)("Raw input registered");
// signal that constuction is complete
startupSemaphore_.release();
@@ -85,7 +82,7 @@ namespace p2c::client::util
MSG msg;
while (GetMessageA(&msg, nullptr, 0, 0)) {
if (msg.message == WM_INPUT) {
- pmlog_verb(v::hotkey)("WM_INPUT received");
+ pmlog_verb(v::hotkey2)("WM_INPUT received");
auto& lParam = msg.lParam;
// allocate memory for raw input data
@@ -109,16 +106,16 @@ namespace p2c::client::util
{
const auto& keyboard = input.data.keyboard;
- pmlog_verb(v::hotkey)(std::format("KBD| vk:{} msg:{}", keyboard.VKey, keyboard.Message));
+ pmlog_verb(v::hotkey2)(std::format("KBD| vk:{} msg:{}", keyboard.VKey, keyboard.Message));
// check for keycode outside of range of our table
if (keyboard.VKey >= win::Key::virtualKeyTableSize) {
- pmlog_verb(v::hotkey)("KBD| vk out of range");
+ pmlog_verb(v::hotkey2)("KBD| vk out of range");
continue;
}
// key presses
if (keyboard.Message == WM_KEYDOWN || keyboard.Message == WM_SYSKEYDOWN) {
- pmlog_verb(v::hotkey)("key press");
+ pmlog_verb(v::hotkey2)("key press");
// don't handle autorepeat presses
if (!pressedKeys_[keyboard.VKey]) {
// mark key as in down state
@@ -133,19 +130,19 @@ namespace p2c::client::util
if (auto i = registeredHotkeys_.find({ *key, mods });
i != registeredHotkeys_.cend()) {
// if match found dispatch action on renderer thread
- pmlog_verb(v::hotkey)("hotkey dispatching");
+ pmlog_verb(v::hotkey2)("hotkey dispatching");
DispatchHotkey_(i->second);
}
}
}
}
else {
- pmlog_verb(v::hotkey)("key repeat");
+ pmlog_verb(v::hotkey2)("key repeat");
}
}
// key releases
else if (keyboard.Message == WM_KEYUP || keyboard.Message == WM_SYSKEYUP) {
- pmlog_verb(v::hotkey)("Key up");
+ pmlog_verb(v::hotkey2)("Key up");
pressedKeys_[keyboard.VKey] = false;
}
}
@@ -162,37 +159,37 @@ namespace p2c::client::util
pmlog_warn("failed unreg class").hr();
}
- pmlog_verb(v::hotkey)();
+ pmlog_verb(v::hotkey2)();
}
catch (...) {
pmlog_error(ReportException());
}
}
- void Hotkeys::DispatchHotkey_(Action action) const
+ void Hotkeys::DispatchHotkey_(int action) const
{
if (Handler_) {
- pmlog_dbg("hotkey action dispatched to handler").pmwatch(reflect::enum_name(action));
+ pmlog_dbg("hotkey action dispatched to handler").pmwatch(action);
Handler_(action);
}
else {
pmlog_warn("Hotkey handler not set");
}
}
- void Hotkeys::SetHandler(std::function handler)
+ void Hotkeys::SetHandler(std::function handler)
{
std::lock_guard lk{ mtx_ };
- pmlog_verb(v::hotkey)("Hotkey handler set");
+ pmlog_verb(v::hotkey2)("Hotkey handler set");
Handler_ = std::move(handler);
}
- bool Hotkeys::BindAction(Action action, win::Key key, win::ModSet mods)
+ bool Hotkeys::BindAction(int action, win::Key key, win::ModSet mods)
{
- pmlog_verb(v::hotkey)("Hotkey action binding");
+ pmlog_verb(v::hotkey2)("Hotkey action binding");
std::lock_guard lk{ mtx_ };
// if action is already bound, remove it
if (const auto i = rn::find_if(registeredHotkeys_, [action](const auto& i) {
return i.second == action;
}); i != registeredHotkeys_.cend()) {
- pmlog_verb(v::hotkey)("Hotkey action binding remove existing action");
+ pmlog_verb(v::hotkey2)("Hotkey action binding remove existing action");
registeredHotkeys_.erase(i);
}
// if hotkey combination is already bound, remove it
@@ -205,14 +202,14 @@ namespace p2c::client::util
// signal success
return true;
}
- bool Hotkeys::ClearAction(Action action)
+ bool Hotkeys::ClearAction(int action)
{
- pmlog_verb(v::hotkey)("Hotkey action clearing");
+ pmlog_verb(v::hotkey2)("Hotkey action clearing");
std::lock_guard lk{ mtx_ };
// if action is bound, remove it
if (const auto i = rn::find_if(registeredHotkeys_, [action](const auto& i) {
return i.second == action;
- }); i != registeredHotkeys_.cend()) {
+ }); i != registeredHotkeys_.cend()) {
registeredHotkeys_.erase(i);
}
else {
diff --git a/IntelPresentMon/AppCef/source/util/HotkeyListener.h b/IntelPresentMon/Core/source/win/HotkeyListener.h
similarity index 70%
rename from IntelPresentMon/AppCef/source/util/HotkeyListener.h
rename to IntelPresentMon/Core/source/win/HotkeyListener.h
index 10caf036..1420a71d 100644
--- a/IntelPresentMon/AppCef/source/util/HotkeyListener.h
+++ b/IntelPresentMon/Core/source/win/HotkeyListener.h
@@ -12,20 +12,19 @@
#include
#include
#include
-#include "../Action.h"
-namespace p2c::client::util
+namespace p2c::win
{
class Hotkeys
{
public:
Hotkeys();
- Hotkeys(const Hotkeys&) = delete;
- Hotkeys& operator=(const Hotkeys&) = delete;
+ Hotkeys(const Hotkeys&) = delete;
+ Hotkeys& operator=(const Hotkeys&) = delete;
~Hotkeys();
- bool BindAction(Action action, win::Key key, win::ModSet mods);
- bool ClearAction(Action action);
- void SetHandler(std::function handler);
+ bool BindAction(int action, win::Key key, win::ModSet mods);
+ bool ClearAction(int action);
+ void SetHandler(std::function handler);
private:
// types
struct Hotkey
@@ -37,10 +36,10 @@ namespace p2c::client::util
private:
win::Key key;
win::ModSet mods;
- };
+ };
// functions
void Kernel_() noexcept;
- void DispatchHotkey_(Action action) const;
+ void DispatchHotkey_(int action) const;
win::ModSet GatherModifiers_() const;
// data
std::binary_semaphore startupSemaphore_{ 0 };
@@ -50,7 +49,7 @@ namespace p2c::client::util
std::bitset pressedKeys_;
// control access to concurrent memory for key map / handler
mutable std::mutex mtx_;
- std::function Handler_;
- std::map registeredHotkeys_;
+ std::function Handler_;
+ std::map registeredHotkeys_;
};
}
\ No newline at end of file
diff --git a/IntelPresentMon/Core/source/win/ModSet.cpp b/IntelPresentMon/Core/source/win/ModSet.cpp
index 413254e4..39743310 100644
--- a/IntelPresentMon/Core/source/win/ModSet.cpp
+++ b/IntelPresentMon/Core/source/win/ModSet.cpp
@@ -140,4 +140,13 @@ namespace p2c::win
{
return Registry::Get().EnumerateMods();
}
+
+ ModSet ModSet::FromCodes(const std::vector& codes)
+ {
+ uint32_t combined = 0;
+ for (auto& code : codes) {
+ combined |= code;
+ }
+ return { combined };
+ }
}
\ No newline at end of file
diff --git a/IntelPresentMon/Core/source/win/ModSet.h b/IntelPresentMon/Core/source/win/ModSet.h
index e9150521..07f2db88 100644
--- a/IntelPresentMon/Core/source/win/ModSet.h
+++ b/IntelPresentMon/Core/source/win/ModSet.h
@@ -30,6 +30,7 @@ namespace p2c::win
std::vector GetModStrings();
static std::optional FromString(const std::string& s);
static std::optional SingleModFromCode(uint32_t p);
+ static ModSet FromCodes(const std::vector& codes);
static std::vector EnumerateMods();
private:
// types
diff --git a/IntelPresentMon/KernelProcess/KernelProcess.vcxproj b/IntelPresentMon/KernelProcess/KernelProcess.vcxproj
index ea9ca498..eab27aae 100644
--- a/IntelPresentMon/KernelProcess/KernelProcess.vcxproj
+++ b/IntelPresentMon/KernelProcess/KernelProcess.vcxproj
@@ -158,6 +158,8 @@
+
+
diff --git a/IntelPresentMon/KernelProcess/KernelProcess.vcxproj.filters b/IntelPresentMon/KernelProcess/KernelProcess.vcxproj.filters
index cfbbb7c1..9a313d17 100644
--- a/IntelPresentMon/KernelProcess/KernelProcess.vcxproj.filters
+++ b/IntelPresentMon/KernelProcess/KernelProcess.vcxproj.filters
@@ -56,6 +56,12 @@
Header Files
+
+ Header Files
+
+
+ Header Files
+
diff --git a/IntelPresentMon/KernelProcess/kact/AllActions.h b/IntelPresentMon/KernelProcess/kact/AllActions.h
index f4a4c95a..f3baf7df 100644
--- a/IntelPresentMon/KernelProcess/kact/AllActions.h
+++ b/IntelPresentMon/KernelProcess/kact/AllActions.h
@@ -4,4 +4,6 @@
#include "SetCapture.h"
#include "EnumerateAdapters.h"
#include "Introspect.h"
-#include "PushSpecification.h"
\ No newline at end of file
+#include "PushSpecification.h"
+#include "BindHotkey.h"
+#include "ClearHotkey.h"
\ No newline at end of file
diff --git a/IntelPresentMon/KernelProcess/kact/BindHotkey.h b/IntelPresentMon/KernelProcess/kact/BindHotkey.h
new file mode 100644
index 00000000..ccfcc048
--- /dev/null
+++ b/IntelPresentMon/KernelProcess/kact/BindHotkey.h
@@ -0,0 +1,60 @@
+#pragma once
+#include "../../Interprocess/source/act/ActionHelper.h"
+#include "KernelExecutionContext.h"
+#include
+#include "../../Core/source/kernel/Kernel.h"
+
+#define ACT_NAME BindHotkey
+#define ACT_EXEC_CTX KernelExecutionContext
+#define ACT_TYPE AsyncActionBase_
+#define ACT_NS kproc::kact
+
+namespace ACT_NS
+{
+ using namespace ::pmon::ipc::act;
+
+ class ACT_NAME : public ACT_TYPE
+ {
+ public:
+ static constexpr const char* Identifier = STRINGIFY(ACT_NAME);
+ struct Params
+ {
+ struct Combination {
+ uint32_t key;
+ std::vector modifiers;
+ template void serialize(A& ar) {
+ ar(key, modifiers);
+ }
+ } combination;
+ int action;
+
+ template void serialize(A& ar) {
+ ar(combination, action);
+ }
+ };
+ struct Response {
+ template void serialize(A& ar) {
+ }
+ };
+ private:
+ friend class ACT_TYPE;
+ static Response Execute_(const ACT_EXEC_CTX& ctx, SessionContext& stx, Params&& in)
+ {
+ ctx.pHotkeys->BindAction(in.action,
+ p2c::win::Key::Code(in.combination.key),
+ p2c::win::ModSet::FromCodes(in.combination.modifiers));
+ return {};
+ }
+ };
+
+#ifdef PM_ASYNC_ACTION_REGISTRATION_
+ ACTION_REG();
+#endif
+}
+
+ACTION_TRAITS_DEF();
+
+#undef ACT_NAME
+#undef ACT_EXEC_CTX
+#undef ACT_NS
+#undef ACT_TYPE
\ No newline at end of file
diff --git a/IntelPresentMon/KernelProcess/kact/ClearHotkey.h b/IntelPresentMon/KernelProcess/kact/ClearHotkey.h
new file mode 100644
index 00000000..3041ba70
--- /dev/null
+++ b/IntelPresentMon/KernelProcess/kact/ClearHotkey.h
@@ -0,0 +1,52 @@
+#pragma once
+#include "../../Interprocess/source/act/ActionHelper.h"
+#include "KernelExecutionContext.h"
+#include
+#include "../../Core/source/kernel/Kernel.h"
+
+#define ACT_NAME ClearHotkey
+#define ACT_EXEC_CTX KernelExecutionContext
+#define ACT_TYPE AsyncActionBase_
+#define ACT_NS kproc::kact
+
+namespace ACT_NS
+{
+ using namespace ::pmon::ipc::act;
+
+ class ACT_NAME : public ACT_TYPE
+ {
+ public:
+ static constexpr const char* Identifier = STRINGIFY(ACT_NAME);
+
+ struct Params
+ {
+ int action;
+
+ template void serialize(A& ar) {
+ ar(action);
+ }
+ };
+ struct Response {
+ template void serialize(A& ar) {
+ }
+ };
+ private:
+ friend class ACT_TYPE;
+ static Response Execute_(const ACT_EXEC_CTX& ctx, SessionContext& stx, Params&& in)
+ {
+ ctx.pHotkeys->ClearAction(in.action);
+ return {};
+ }
+ };
+
+#ifdef PM_ASYNC_ACTION_REGISTRATION_
+ ACTION_REG();
+#endif
+}
+
+ACTION_TRAITS_DEF();
+
+#undef ACT_NAME
+#undef ACT_EXEC_CTX
+#undef ACT_NS
+#undef ACT_TYPE
\ No newline at end of file
diff --git a/IntelPresentMon/KernelProcess/kact/KernelExecutionContext.h b/IntelPresentMon/KernelProcess/kact/KernelExecutionContext.h
index 995b0d6c..b3abcdca 100644
--- a/IntelPresentMon/KernelProcess/kact/KernelExecutionContext.h
+++ b/IntelPresentMon/KernelProcess/kact/KernelExecutionContext.h
@@ -9,6 +9,7 @@
#include
#include
#include "../../Core/source/kernel/Kernel.h"
+#include "../../Core/source/win/HotkeyListener.h"
namespace kproc::kact
{
@@ -32,5 +33,6 @@ namespace kproc::kact
std::optional responseWriteTimeoutMs;
p2c::kern::Kernel** ppKernel = nullptr;
+ p2c::win::Hotkeys* pHotkeys = nullptr;
};
}
\ No newline at end of file
diff --git a/IntelPresentMon/KernelProcess/winmain.cpp b/IntelPresentMon/KernelProcess/winmain.cpp
index b75b1fdf..2c202f5b 100644
--- a/IntelPresentMon/KernelProcess/winmain.cpp
+++ b/IntelPresentMon/KernelProcess/winmain.cpp
@@ -7,6 +7,7 @@
#include "../AppCef/source/util/cact/OverlayDiedAction.h"
#include "../AppCef/source/util/cact/PresentmonInitFailedAction.h"
#include "../AppCef/source/util/cact/StalePidAction.h"
+#include "../AppCef/source/util/cact/HotkeyFiredAction.h"
#include
#include
#include
@@ -149,9 +150,17 @@ int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLi
// this pointer serves as a way to set the kernel on the server exec context after the server is created
p2c::kern::Kernel* pKernel = nullptr;
+ // active object that creates a window and sinks raw input messages to listen for hotkey presses
+ p2c::win::Hotkeys hotkeys;
// this server receives a connection from the CEF render process
const auto actName = std::format(R"(\\.\pipe\ipm-cef-channel-{})", GetCurrentProcessId());
- KernelServer server{ kact::KernelExecutionContext{.ppKernel = &pKernel }, actName, 1, "D:(A;;GA;;;WD)S:(ML;;NW;;;ME)" };
+ KernelServer server{ kact::KernelExecutionContext{ .ppKernel = &pKernel, .pHotkeys = &hotkeys },
+ actName, 1, "D:(A;;GA;;;WD)S:(ML;;NW;;;ME)" };
+ // set the hotkey manager to send notifications via the action server
+ hotkeys.SetHandler([&](int action) {
+ pmlog_info("hey hot");
+ server.DispatchDetached(p2c::client::util::cact::HotkeyFiredAction::Params{ .actionId = action });
+ });
// this handler receives events from the kernel and transmits them to the render process via the server
KernelHandler kernHandler{ server };
// the kernel manages the PresentMon data collection and the overlay rendering