// Skill keys cast their combat-art slot. // // The game casts one art with the right mouse button: the one in the // "selected" art slot, which is always slot 0 now (src/mods/skillbar.cpp). // Slot 0's key presses the right mouse button; the keys of slots 1-6 first // make their slot the selected one. The button is pressed by posting // WM_RBUTTONDOWN to the game window, so the game handles it exactly like a // real right-click at the cursor (UI hit tests, target under the cursor, // cEvent_creature 0x105), and released with the key: holding the key is // holding the button. While no skill key is held, slot 0 is selected again // (checked every engine tick, which also covers saves loaded with another // selection). #include "mods/skillkeys.h" #include #include #include "game/engine/events.h" #include "mods/skillbar.h" namespace mods::skillkeys { namespace { // The game window, if it has the focus (it does while a skill key is used). HWND GameWindow() { HWND window = GetForegroundWindow(); DWORD process = 0; if (!window || !GetWindowThreadProcessId(window, &process) || process != GetCurrentProcessId()) { return nullptr; } return window; } LPARAM CursorClientPos(HWND window) { POINT cursor = {}; GetCursorPos(&cursor); ScreenToClient(window, &cursor); return MAKELPARAM(cursor.x, cursor.y); } // The key holding the right mouse button down, and the window it was pressed // in. Set on the window thread, read by the engine tick. std::atomic g_heldKey{0}; HWND g_window = nullptr; void OnTick(uint8_t*) { if (!g_heldKey.load() && mods::skillbar::SelectedSkillSlot() != 0) { mods::skillbar::SelectSkillSlot(0); } } struct Registration { Registration() { game::OnEngineTick(&OnTick); } } g_registration; } // namespace void KeyPressed(unsigned slot, int vk) { if (g_heldKey.load() || !mods::skillbar::SkillSlotHasArt(slot)) { return; } HWND window = GameWindow(); if (!window) { return; } g_window = window; g_heldKey = vk; // before selecting: the tick leaves the selection alone if (slot != 0) { mods::skillbar::SelectSkillSlot(slot); } PostMessageW(window, WM_RBUTTONDOWN, MK_RBUTTON, CursorClientPos(window)); } bool KeyHeld() { return g_heldKey.load() != 0; } void KeyReleased(int vk) { if (g_heldKey.load() != vk) { return; } PostMessageW(g_window, WM_RBUTTONUP, 0, CursorClientPos(g_window)); g_heldKey = 0; } } // namespace mods::skillkeys