在 #351 的基础上收敛几处实现: - CloseContextMenu 里新增的 hover 清理和 Present 原本无条件执行,而 ShowFromGlobalState 和 Hide 每次按键都会调它。没有菜单时按键路径上会多出 一次整屏重绘,画的还是更新前的旧场景。改为只在确实有 popup 要销毁时才做。 - 分页与动态扩充的逻辑从键盘路径复制了一份。抽成 ExpandCandidatesKeepingPagePosition 和 MoveCandidatePage,键盘与滚轮共用。 - 每一格滚轮直接投一个任务,而每个任务都可能回引擎和用户词库。改为在队列里 合并成 page_steps,一次快速滚动只重绘一次。 - 窗口层不再直接调 EnqueueCandidateUiAction,改为与其它候选窗动作一致, PostMessage 到宿主 WndProc(WM_PAGE_CANDIDATE)。EnqueueCandidateUiAction 的序号校验随之恢复原样。 - 滚轮累加拆成纯函数 CandidateWheel::ConsumeWheelDelta 并补上单元测试; 候选窗隐藏时忽略迟到的滚轮消息。 滚轮翻页仍然把页内高亮重置为首项,键盘翻页仍然保留原有的页内索引。 Co-authored-by: Carry <xu762556@outlook.com>
77 lines
2.4 KiB
C++
77 lines
2.4 KiB
C++
#include "tests/includes/test_framework.h"
|
|
#include "window/candidate_wheel_paging.h"
|
|
|
|
namespace
|
|
{
|
|
constexpr int kNotch = 120; // WHEEL_DELTA
|
|
} // namespace
|
|
|
|
TEST_CASE(candidate_wheel_emits_one_step_per_full_notch)
|
|
{
|
|
int accumulator = 0;
|
|
|
|
const auto up = CandidateWheel::ConsumeWheelDelta(accumulator, kNotch, kNotch);
|
|
REQUIRE_EQ(up.page_up, 1);
|
|
REQUIRE_EQ(up.page_down, 0);
|
|
REQUIRE_EQ(accumulator, 0);
|
|
|
|
const auto down = CandidateWheel::ConsumeWheelDelta(accumulator, -kNotch, kNotch);
|
|
REQUIRE_EQ(down.page_up, 0);
|
|
REQUIRE_EQ(down.page_down, 1);
|
|
REQUIRE_EQ(accumulator, 0);
|
|
}
|
|
|
|
TEST_CASE(candidate_wheel_accumulates_high_precision_deltas_across_messages)
|
|
{
|
|
int accumulator = 0;
|
|
|
|
// A high-precision mouse reports fractions of a notch. None of these may
|
|
// page on their own; the sixth completes the first full notch.
|
|
for (int i = 0; i < 5; ++i)
|
|
{
|
|
const auto partial = CandidateWheel::ConsumeWheelDelta(accumulator, 20, kNotch);
|
|
REQUIRE_EQ(partial.page_up, 0);
|
|
REQUIRE_EQ(partial.page_down, 0);
|
|
}
|
|
const auto completing = CandidateWheel::ConsumeWheelDelta(accumulator, 20, kNotch);
|
|
REQUIRE_EQ(completing.page_up, 1);
|
|
REQUIRE_EQ(accumulator, 0);
|
|
}
|
|
|
|
TEST_CASE(candidate_wheel_reports_every_notch_of_a_single_burst)
|
|
{
|
|
int accumulator = 0;
|
|
|
|
// A flick can arrive as one oversized delta. Every notch in it has to be
|
|
// reported, or a fast scroll silently loses pages.
|
|
const auto burst = CandidateWheel::ConsumeWheelDelta(accumulator, -3 * kNotch - 40, kNotch);
|
|
REQUIRE_EQ(burst.page_down, 3);
|
|
REQUIRE_EQ(burst.page_up, 0);
|
|
REQUIRE_EQ(accumulator, -40);
|
|
}
|
|
|
|
TEST_CASE(candidate_wheel_drops_the_remainder_when_direction_reverses)
|
|
{
|
|
int accumulator = 0;
|
|
|
|
CandidateWheel::ConsumeWheelDelta(accumulator, 80, kNotch);
|
|
REQUIRE_EQ(accumulator, 80);
|
|
|
|
// Without the reset the leftover +80 would cancel most of the first notch
|
|
// back down, so the reversal would need an extra notch to take effect.
|
|
const auto reversed = CandidateWheel::ConsumeWheelDelta(accumulator, -kNotch, kNotch);
|
|
REQUIRE_EQ(reversed.page_down, 1);
|
|
REQUIRE_EQ(reversed.page_up, 0);
|
|
REQUIRE_EQ(accumulator, 0);
|
|
}
|
|
|
|
TEST_CASE(candidate_wheel_ignores_a_non_positive_notch)
|
|
{
|
|
int accumulator = 0;
|
|
|
|
const auto steps = CandidateWheel::ConsumeWheelDelta(accumulator, kNotch, 0);
|
|
REQUIRE_EQ(steps.page_up, 0);
|
|
REQUIRE_EQ(steps.page_down, 0);
|
|
REQUIRE_EQ(accumulator, 0);
|
|
}
|