Skip to content

Commit

Permalink
Updated ForceKeyState class.
Browse files Browse the repository at this point in the history
  • Loading branch information
sigma-axis committed May 2, 2024
1 parent 5c0823a commit ddc01fa
Show file tree
Hide file tree
Showing 4 changed files with 144 additions and 34 deletions.
129 changes: 129 additions & 0 deletions key_states.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/*
The MIT License (MIT)
Copyright (c) 2024 sigma-axis
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#pragma once

#include <cstdint>
#include <tuple>

#define NOMINMAX
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>

////////////////////////////////
// Windows API 利用の補助関数.
////////////////////////////////
namespace sigma_lib::W32::UI
{
enum class flag_map : uint8_t {
id = 0,
off = 1,
on = 2,
inv = 3,
};

// キー入力認識をちょろまかす補助クラス.
template<size_t N>
class ForceKeyState {
template<size_t i, class... TArgs>
using arg_at = std::decay_t<std::tuple_element_t<i, std::tuple<TArgs...>>>;

template<class... TArgs>
static consteval bool check_requirements() {
constexpr auto check_arg = []<size_t i>() {
return std::convertible_to<arg_at<i, TArgs...>, int>;
};
constexpr auto check_result = []<size_t i>() {
using result = arg_at<i, TArgs...>;
return std::same_as<result, bool>
|| std::same_as<result, flag_map>
|| std::convertible_to<result, uint8_t>;
};

if (!([]<size_t... I>(std::index_sequence<I...>) {
if constexpr (!(check_arg.operator() < 2 * I > () && ...)) return false;
if constexpr (!(check_result.operator() < 2 * I + 1 > () && ...)) return false;
return true;
}(std::make_index_sequence<N>{}))) return false;

return true;
}

constexpr static size_t num_keys = 256;
uint8_t key[N], rew[N];

static constexpr uint8_t coerce_key(int val) {
if (val < 0 || val >= num_keys) return 0;
return static_cast<uint8_t>(val);
}
struct modifier {
uint8_t a, b;
constexpr modifier(bool mod) : modifier{ mod ? flag_map::on : flag_map::off } {}
constexpr modifier(flag_map mod) {
using enum flag_map;
switch (mod) {
case off: a = 0x80, b = 0x80; break;
case on: a = 0x80, b = 0x00; break;
case inv: a = 0x00, b = 0x80; break;
case id: default: a = b = 0x00; break;
}
}
constexpr modifier(uint8_t mod) : a{ 0xff }, b{ ~mod } {}

constexpr uint8_t operator()(uint8_t& state) const {
auto ret = state;
state = (state | a) ^ b;
return ret;
}
constexpr operator bool() const { return a != 0 || b != 0; }
};

template<size_t... I>
ForceKeyState(std::index_sequence<I...>, const auto&& data) noexcept
: key{ coerce_key(std::get<2 * I>(data))... }
{
modifier m[]{ { std::get<2 * I + 1>(data) }... };
if (((key[I] > 0 && m) || ...)) {
// overwrite the state.
uint8_t state[num_keys]; std::ignore = ::GetKeyboardState(state);
((key[I] > 0 && m ? (rew[I] = m[I](state[key[I]])) : (key[I] = 0)), ...);
::SetKeyboardState(state);
}
}

public:
template<class... TArgs>
requires(sizeof...(TArgs) == 2 * N && check_requirements<TArgs...>())
ForceKeyState(TArgs const... args) noexcept
: ForceKeyState{ std::make_index_sequence<N>{}, std::make_tuple(args...) } {}

ForceKeyState(const ForceKeyState&) = delete;
ForceKeyState(ForceKeyState&&) = delete;

~ForceKeyState() noexcept {
size_t i = 0;
for (; i < N; i++) { if (key[i] > 0) goto rewind; }
return;

rewind:
// rewind the state.
uint8_t state[num_keys]; std::ignore = ::GetKeyboardState(state);
do {
if (key[i] > 0) state[key[i]] = rew[i];
} while (++i < N);
::SetKeyboardState(state);
}
};
template<class... TArgs>
ForceKeyState(TArgs...)->ForceKeyState<sizeof...(TArgs) / 2>;
template<> struct ForceKeyState<0> {};
}
41 changes: 7 additions & 34 deletions tl_walkaround.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ using byte = uint8_t;
using namespace AviUtl;
using namespace ExEdit;

#include "key_states.hpp"
using namespace sigma_lib::W32::UI;

////////////////////////////////
// 主要情報源の変数アドレス.
////////////////////////////////
Expand Down Expand Up @@ -368,34 +371,6 @@ struct BPM_Grid {
// Windows API 利用の補助関数.
////////////////////////////////

// キー入力認識をちょろまかす補助クラス.
class ForceKeyState {
static auto force_key_state(short vkey, uint8_t state)
{
uint8_t states[256]; std::ignore = ::GetKeyboardState(states);
std::swap(state, states[vkey]); ::SetKeyboardState(states);
return state;
}

constexpr static auto state(bool pressed) { return pressed ? key_pressed : key_released; }

const short vkey;
const uint8_t prev;

public:
constexpr static uint8_t key_released = 0, key_pressed = 0x80;
constexpr static int vkey_invalid = -1;

ForceKeyState(short vkey, bool pressed) : ForceKeyState(vkey, state(pressed)) {}
ForceKeyState(short vkey, uint8_t state) :
vkey{ 0 <= vkey && vkey < 256 ? vkey : vkey_invalid },
prev{ this->vkey != vkey_invalid ? force_key_state(this->vkey, state) : uint8_t{} } {}
~ForceKeyState() { if (vkey != vkey_invalid) force_key_state(vkey, prev); }

ForceKeyState(const ForceKeyState&) = delete;
ForceKeyState& operator=(const ForceKeyState&) = delete;
};

// タイムラインのスクロールバー操作.
class TimelineScrollBar {
HWND* const& phwnd;
Expand Down Expand Up @@ -724,8 +699,7 @@ class Drag {
std::abs(moveto_x - mouse_x) > settings.mouse.snap_range)) return false;

// Then, move to the desired destination, forcing Shift key state if necessary.
ForceKeyState shift(settings.mouse.suppress_shift ?
VK_SHIFT : ForceKeyState::vkey_invalid, false);
ForceKeyState shift{ settings.mouse.suppress_shift ? VK_SHIFT : 0, false };
fp->exfunc->set_frame(editp, moveto);
return true;
}
Expand Down Expand Up @@ -1217,8 +1191,7 @@ inline bool menu_seek_obj_handler(Menu::ID id, EditHandle* editp, FilterPlugin*
if (pos == moveto) return false;

// disable SHIFT key
ForceKeyState shift(settings.keyboard.suppress_shift ?
VK_SHIFT : ForceKeyState::vkey_invalid, false);
ForceKeyState shift{ settings.keyboard.suppress_shift ? VK_SHIFT : 0, false };
if (pos == fp->exfunc->set_frame(editp, moveto)) return false; // 実質移動なし.

// 拡張編集のバグで,「カーソル移動時に自動でスクロール」を設定していても,
Expand All @@ -1242,7 +1215,7 @@ inline bool menu_select_obj_handler(Menu::ID id, EditHandle* editp)
}

// fake shift key state.
ForceKeyState k(VK_SHIFT, shift);
ForceKeyState k{ VK_SHIFT, shift };

// 拡張編集にコマンドメッセージ送信.
return exedit.fp->func_WndProc(exedit.fp->hwnd, FilterPlugin::WindowMessage::Command,
Expand Down Expand Up @@ -1368,7 +1341,7 @@ BOOL WINAPI DllMain(HINSTANCE hinst, DWORD fdwReason, LPVOID lpvReserved)
// 看板.
////////////////////////////////
#define PLUGIN_NAME "TLショトカ移動"
#define PLUGIN_VERSION "v1.22"
#define PLUGIN_VERSION "v1.23-beta1"
#define PLUGIN_AUTHOR "sigma-axis"
#define PLUGIN_INFO_FMT(name, ver, author) (name##" "##ver##" by "##author)
#define PLUGIN_INFO PLUGIN_INFO_FMT(PLUGIN_NAME, PLUGIN_VERSION, PLUGIN_AUTHOR)
Expand Down
3 changes: 3 additions & 0 deletions tl_walkaround.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,9 @@
<None Include="assets\tl_walkaround.ini" />
<None Include="tl_walkaround.def" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="key_states.hpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
Expand Down
5 changes: 5 additions & 0 deletions tl_walkaround.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,9 @@
<Filter>assets</Filter>
</None>
</ItemGroup>
<ItemGroup>
<ClInclude Include="key_states.hpp">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

0 comments on commit ddc01fa

Please sign in to comment.