Skip to content

Commit fc571ab

Browse files
committed
Shortcut key to select easings.
1 parent cb7ff87 commit fc571ab

File tree

2 files changed

+165
-24
lines changed

2 files changed

+165
-24
lines changed

assets/reactive_dlg.ini

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ keys_boost=alt
8989
rate_boost=10
9090
updown_clamp=0
9191
escape=1
92+
easing_menu.vkey=0
93+
easing_menu.mkeys=none
9294
; トラックバーの数値ボックスにフォーカスがあるとき,
9395
; 一部キーボード入力による動作を変更します.
9496
; updown:
@@ -129,6 +131,16 @@ escape=1
129131
; 既に変更前と同じ場合は拡張編集タイムラインウィンドウにフォーカスを移します.
130132
; escape が 0 のとき無効,それ以外の整数で有効です.
131133
; 初期値は 1 で有効.
134+
; easing_menu.vkey:
135+
; 数値入力ボックス上で指定したショートカットキーを押すと,
136+
; トラックバーの変化方法を選択するメニューを表示できます.
137+
; 指定キーは仮想キーコードで指定します (詳細は [TextBox.Focus] の項目参照).
138+
; 初期値は 0 で無効.
139+
; easing_menu.mkeys:
140+
; トラックバーの変化方法選択のメニュー表示の
141+
; ショートカットキーに必要な修飾キーを指定します.
142+
; "ctrl", "shift", "alt" の組み合わせを "+" で区切って指定します.
143+
; 初期値は "none" で修飾キーなし.
132144

133145

134146
[Track.Mouse]

reactive_dlg.cpp

Lines changed: 153 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -125,9 +125,10 @@ inline constinit struct ExEdit092 {
125125
uint8_t* easing_specs_script; // 0x231d90
126126

127127
uintptr_t cmp_shift_state_easing; // 0x02ca90
128+
byte* call_easing_popup_menu; // 0x02d4b5
128129

129130
// index: index of the script; zero1, zero2: zero, unknown otherwise.
130-
void(*load_easing_spec)(int32_t index, int32_t zero1, int32_t zero2); // 0x087940;
131+
void(*load_easing_spec)(int32_t index, int32_t zero1, int32_t zero2); // 0x087940
131132

132133
private:
133134
void init_pointers()
@@ -160,6 +161,7 @@ inline constinit struct ExEdit092 {
160161
pick_addr(easing_specs_script, 0x231d90);
161162

162163
pick_addr(cmp_shift_state_easing, 0x02ca90);
164+
pick_addr(call_easing_popup_menu, 0x02d4b5);
163165
pick_addr(load_easing_spec, 0x087940);
164166
}
165167
} exedit;
@@ -205,7 +207,7 @@ bool check_window_class(HWND hwnd, const wchar_t(&classname)[N])
205207
{
206208
wchar_t buf[N + 1];
207209
return ::GetClassNameW(hwnd, buf, N + 1) == N - 1
208-
&& std::memcmp(buf, classname, sizeof(wchar_t) * (N - 1)) == 0;
210+
&& std::wmemcmp(buf, classname, N - 1) == 0;
209211
}
210212

211213
inline auto get_edit_selection(HWND edit_box)
@@ -227,6 +229,15 @@ inline bool key_pressed_any(auto... vkeys) {
227229
return ((::GetKeyState(vkeys) < 0) || ...);
228230
}
229231

232+
inline byte set_key_state(byte vkey, byte state)
233+
{
234+
byte states[0x100];
235+
std::ignore = ::GetKeyboardState(states);
236+
std::swap(state, states[vkey]);
237+
::SetKeyboardState(states);
238+
return state;
239+
}
240+
230241
inline void discard_message(HWND hwnd, UINT message) {
231242
MSG msg;
232243
while (::PeekMessageW(&msg, hwnd, message, message, PM_REMOVE));
@@ -369,18 +380,31 @@ struct TextBox : SettingDlg {
369380
struct TrackLabel : SettingDlg {
370381
private:
371382
// finding edit boxes for trackbars.
372-
constexpr static int id_label_left_base = 4100, id_label_right_base = 4200;
383+
constexpr static uint32_t id_button_base = 4000,
384+
id_label_left_base = 4100, id_label_right_base = 4200;
373385

374386
public:
375387
static uintptr_t hook_uid() { return SettingDlg::hook_uid() + 2; }
376388

377-
static std::pair<bool, int8_t> check_edit_box_id(uint32_t id)
389+
static constexpr int8_t check_button_id(uint32_t id)
390+
{
391+
auto idx = id - id_button_base;
392+
if (idx >= Object::MAX_TRACK) return -1;
393+
return static_cast<int8_t>(idx);
394+
}
395+
static constexpr uint32_t button_id(size_t idx) {
396+
return idx + id_button_base;
397+
}
398+
static constexpr std::pair<bool, int8_t> check_edit_box_id(uint32_t id)
378399
{
379400
bool left = id < id_label_right_base;
380401
id -= left ? id_label_left_base : id_label_right_base;
381402
if (id >= Object::MAX_TRACK) return { false, -1 };
382403
return { left , static_cast<int8_t>(id) };
383404
}
405+
static constexpr uint32_t label_id(bool left, size_t idx) {
406+
return idx + (left ? id_label_left_base : id_label_right_base);
407+
}
384408
static bool check_edit_box_style(HWND edit)
385409
{
386410
// check whether ...
@@ -479,17 +503,30 @@ struct TrackLabel : SettingDlg {
479503

480504
private:
481505
// manipulation of the currently selected trackbar.
482-
static inline constinit const TrackInfo* info = nullptr;
483-
static inline constinit wchar_t last_text[15] = L"";
506+
static inline constinit TrackInfo const* info = nullptr;
507+
static inline constinit wchar_t last_text[16] = L"";
484508

485509
public:
486510
static inline POINT mouse_pos_on_focused{};
487-
static const TrackInfo& curr_info() { return *info; }
488-
static void on_setfocus(const TrackInfo* track_info)
511+
static inline struct {
512+
uint16_t idx = ~0;
513+
byte alt_state = 0;
514+
constexpr bool is_active() const { return idx < Object::MAX_TRACK; }
515+
constexpr void activate(size_t idx) { this->idx = static_cast<decltype(this->idx)>(idx); }
516+
constexpr void deactivate() { idx = ~0; alt_state = 0; }
517+
} easing_menu;
518+
static TrackInfo const& curr_info() { return *info; }
519+
constexpr static size_t max_num_len = std::size(last_text);
520+
static size_t find_info_index(TrackInfo const* ptr_info) {
521+
return std::min<size_t>(ptr_info - exedit.trackinfo_left, ptr_info - exedit.trackinfo_right);
522+
}
523+
static void on_setfocus(TrackInfo const* track_info)
489524
{
490-
::GetCursorPos(&mouse_pos_on_focused);
491525
info = track_info;
492-
::GetWindowTextW(track_info->hwnd_label, last_text, std::size(last_text));
526+
if (!easing_menu.is_active()) {
527+
::GetCursorPos(&mouse_pos_on_focused);
528+
::GetWindowTextW(track_info->hwnd_label, last_text, std::size(last_text));
529+
}
493530
}
494531
static void on_killfocus() { info = nullptr; }
495532
static bool is_focused() { return info != nullptr; }
@@ -1178,15 +1215,17 @@ inline constinit struct Settings {
11781215
return (boost(keys) ? rate_boost : 1) * (decimal(keys) ? 1 : info.precision());
11791216
}
11801217
};
1218+
struct shortcut_key {
1219+
byte vkey;
1220+
modkeys mkeys;
1221+
constexpr bool match(byte code, modkeys keys) const {
1222+
return is_enabled() && code == vkey && mkeys == keys;
1223+
}
1224+
constexpr bool is_enabled() const { return vkey != 0; }
1225+
};
11811226

11821227
struct {
1183-
struct {
1184-
byte vkey;
1185-
modkeys mkeys;
1186-
constexpr bool match(byte code, modkeys keys) const {
1187-
return vkey != 0 && code == vkey && mkeys == keys;
1188-
}
1189-
} forward{ VK_TAB, modkeys::none }, backward{ VK_TAB, modkeys::shift };
1228+
shortcut_key forward{ VK_TAB, modkeys::none }, backward{ VK_TAB, modkeys::shift };
11901229
constexpr bool is_enabled() const { return forward.vkey != 0 || backward.vkey != 0; }
11911230
constexpr bool match(bool& is_forward, auto... args)
11921231
{
@@ -1214,14 +1253,15 @@ inline constinit struct Settings {
12141253

12151254
struct : modkey_set {
12161255
bool updown, updown_clamp, escape;
1217-
constexpr bool is_enabled() const { return updown || escape; }
1256+
shortcut_key easing_menu;
1257+
constexpr bool is_enabled() const { return updown || escape || easing_menu.is_enabled(); }
12181258
constexpr bool no_wrong_keys(modkeys keys) const
12191259
{
12201260
return keys <= (keys_decimal | keys_boost);
12211261
}
12221262
} trackKbd{
12231263
{ modkeys::shift, modkeys::alt, false, 10, },
1224-
true, false, true,
1264+
true, false, true, { 0, modkeys::none },
12251265
};
12261266

12271267
struct : modkey_set {
@@ -1335,6 +1375,8 @@ inline constinit struct Settings {
13351375
load_bool(trackKbd., def_decimal, "Track.Keyboard");
13361376
load_gen (trackKbd., rate_boost, "Track.Keyboard",
13371377
[](auto x) { return std::clamp(x, modkey_set::min_rate_boost, modkey_set::max_rate_boost); }, /* id */);
1378+
load_int (trackKbd., easing_menu.vkey, "Track.Keyboard");
1379+
load_key (trackKbd., easing_menu.mkeys, "Track.Keyboard");
13381380

13391381
load_bool(trackMouse., wheel, "Track.Mouse");
13401382
load_bool(trackMouse., reverse_wheel, "Track.Mouse");
@@ -1534,7 +1576,7 @@ inline bool delta_move_on_label(byte vkey)
15341576
}
15351577

15361578
// ESC キーで編集前に戻す / フォーカスを外す機能.
1537-
inline bool escape_from_label(HWND edit_box)
1579+
inline bool escape_from_label()
15381580
{
15391581
if (!TrackLabel::is_focused()) [[unlikely]] return false;
15401582

@@ -1545,6 +1587,62 @@ inline bool escape_from_label(HWND edit_box)
15451587
return ::SetFocus(exedit.fp->hwnd) != nullptr; // no need to revert, the focus moves away.
15461588
}
15471589

1590+
// トラックバー変化方法の選択メニューを表示する機能.
1591+
inline bool popup_easing_menu(byte vkey)
1592+
{
1593+
if (!settings.trackKbd.easing_menu.match(vkey, curr_modkeys()) ||
1594+
key_pressed_any(VK_LWIN, VK_RWIN)) return false;
1595+
1596+
if (!TrackLabel::is_focused()) [[unlikely]] return false;
1597+
1598+
auto& info = TrackLabel::curr_info();
1599+
auto const idx = TrackLabel::find_info_index(&info);
1600+
if (idx >= Object::MAX_TRACK) return false;
1601+
1602+
// suppress notification sound by discarding certain messages.
1603+
discard_message(info.hwnd_label, settings.trackKbd.easing_menu.mkeys
1604+
.has_flags(modkeys::alt) ? WM_SYSCHAR : WM_CHAR);
1605+
1606+
// save the index so it the hook is enabled.
1607+
TrackLabel::easing_menu.activate(idx);
1608+
1609+
// move off the focus form this edit box,
1610+
// otherwise it would swallow the input of Enter key.
1611+
auto [l_pos, r_pos] = get_edit_selection(info.hwnd_label);
1612+
wchar_t last_text[TrackLabel::max_num_len];
1613+
::GetWindowTextW(info.hwnd_label, last_text, std::size(last_text));
1614+
::SetFocus(*exedit.hwnd_setting_dlg);
1615+
1616+
if (settings.trackKbd.easing_menu.mkeys.has_flags(modkeys::alt))
1617+
// as alt+clicking the button has a different functionality,
1618+
// make the key recognized as released.
1619+
TrackLabel::easing_menu.alt_state = set_key_state(VK_MENU, 0);
1620+
// send the button-click notification.
1621+
::SendMessageW(*exedit.hwnd_setting_dlg, WM_COMMAND,
1622+
(BN_CLICKED << 16) | TrackLabel::button_id(idx),
1623+
reinterpret_cast<LPARAM>(exedit.hwnd_track_buttons[idx]));
1624+
1625+
// rewind the focus and other states.
1626+
if ((::GetWindowLongW(info.hwnd_label, GWL_STYLE) & WS_DISABLED) == 0) {
1627+
::SetFocus(info.hwnd_label);
1628+
::SetWindowTextW(info.hwnd_label, last_text);
1629+
set_edit_selection(info.hwnd_label, l_pos, r_pos);
1630+
1631+
// turn out of the hooking state.
1632+
TrackLabel::easing_menu.deactivate();
1633+
}
1634+
else {
1635+
// if it's right side and disabled now, focus on left instead.
1636+
auto left_one = exedit.trackinfo_left[idx].hwnd_label;
1637+
1638+
TrackLabel::easing_menu.deactivate(); // no more hooks.
1639+
::SetFocus(left_one);
1640+
set_edit_selection_all(left_one);
1641+
}
1642+
1643+
return true;
1644+
}
1645+
15481646
// ホイールでトラックバーの数値をテキストラベル上で増減する機能.
15491647
inline bool wheel_on_track(const TrackInfo& info, short wheel, modkeys keys)
15501648
{
@@ -1690,16 +1788,17 @@ LRESULT CALLBACK track_label_hook(HWND hwnd, UINT message, WPARAM wparam, LPARAM
16901788
case WM_KEYDOWN:
16911789
case WM_SYSKEYDOWN:
16921790
if (byte vkey = static_cast<byte>(wparam);
1693-
settings.trackKbd.updown &&
1694-
delta_move_on_label(vkey)) {
1791+
settings.trackKbd.updown && delta_move_on_label(vkey)) {
16951792
// prevent calling the default window procedure.
16961793
return 0;
16971794
}
1698-
else if (settings.trackKbd.escape && vkey == VK_ESCAPE && escape_from_label(hwnd)) {
1795+
else if (settings.trackKbd.escape && vkey == VK_ESCAPE && escape_from_label()) {
16991796
// needs to remove WM_CHAR messages to avoid the notification sound.
17001797
discard_message(hwnd, message == WM_KEYDOWN ? WM_CHAR : WM_SYSCHAR);
17011798
return 0;
17021799
}
1800+
else if (settings.trackKbd.easing_menu.is_enabled() && popup_easing_menu(vkey))
1801+
return 0;
17031802
break;
17041803
case WM_MOUSEMOVE:
17051804
if (settings.trackMouse.fixed_drag &&
@@ -1725,6 +1824,28 @@ LRESULT CALLBACK track_label_hook(HWND hwnd, UINT message, WPARAM wparam, LPARAM
17251824
return ::DefSubclassProc(hwnd, message, wparam, lparam);
17261825
}
17271826

1827+
// トラックバー変化方法のメニューをショートカットキーで表示させたときの座標調整.
1828+
BOOL WINAPI popup_easing_menu_hook(HMENU menu, UINT flags, int x, int y, int, HWND hwnd, RECT const*)
1829+
{
1830+
if (TrackLabel::easing_menu.is_active()) {
1831+
auto const btn = exedit.hwnd_track_buttons[TrackLabel::easing_menu.idx];
1832+
1833+
// Alt の状態を差し戻す.
1834+
set_key_state(VK_MENU, TrackLabel::easing_menu.alt_state);
1835+
1836+
// メニューの位置をボタンの矩形に合わせて調整.
1837+
TPMPARAMS p{ .cbSize = sizeof(p) };
1838+
::GetWindowRect(btn, &p.rcExclude);
1839+
1840+
// メニュー表示.
1841+
return ::TrackPopupMenuEx(menu, flags | TPM_VERTICAL,
1842+
p.rcExclude.left, p.rcExclude.top, hwnd, &p);
1843+
}
1844+
1845+
// 条件を満たさない場合は未介入のデフォルト処理.
1846+
return ::TrackPopupMenuEx(menu, flags, x, y, hwnd, nullptr);
1847+
}
1848+
17281849
LRESULT CALLBACK setting_dlg_hook(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam, auto id, auto data)
17291850
{
17301851
switch (message) {
@@ -2049,6 +2170,14 @@ BOOL func_init(FilterPlugin* fp)
20492170
conflict_warning("filter_name.auf", "[FilterName]\nanim_eff_fmt=\"\"");
20502171
}
20512172

2173+
// トラックバー変化方法のメニューをショートカットキーで表示させたときの座標調整.
2174+
if (settings.trackKbd.easing_menu.is_enabled())
2175+
// ff 15 48 a3 ff 2f call dword ptr ds:[TrackPopupMenu]
2176+
// V
2177+
// e8 yy yy yy yy call yyyyyyyy
2178+
// 90 nop
2179+
memory::hook_api_call(exedit.call_easing_popup_menu, popup_easing_menu_hook);
2180+
20522181
// トラックバーの変化方法の調整.
20532182
if (settings.easings.linked_track_invert_shift)
20542183
// 0f 8c 87 00 00 00 jl
@@ -2151,7 +2280,7 @@ BOOL WINAPI DllMain(HINSTANCE hinst, DWORD fdwReason, LPVOID lpvReserved)
21512280
// 看板.
21522281
////////////////////////////////
21532282
#define PLUGIN_NAME "Reactive Dialog"
2154-
#define PLUGIN_VERSION "v1.63-beta1"
2283+
#define PLUGIN_VERSION "v1.70-beta2"
21552284
#define PLUGIN_AUTHOR "sigma-axis"
21562285
#define PLUGIN_INFO_FMT(name, ver, author) (name##" "##ver##" by "##author)
21572286
#define PLUGIN_INFO PLUGIN_INFO_FMT(PLUGIN_NAME, PLUGIN_VERSION, PLUGIN_AUTHOR)

0 commit comments

Comments
 (0)