AcceleratorKeyActivated 事件参数 KeyStatus.WasKeyDown 键按下时字段始终为 false

AcceleratorKeyActivated event args KeyStatus.WasKeyDown field is always false when key is down

当按下并按住一个键时 CoreDispatcher::AcceleratorKeyActivated 事件被触发并且 KeyStatus.WasKeyDown 字段始终为 false。 CoreWindow::KeyDown 事件已正确设置 WasKeyDown。实际上,最近似乎行为发生了变化。以前按住一个键会导致 KeyDown / KeyUp 事件,但现在它只会导致 KeyDown。有人可以证实这一点吗?

这里有一些例子:

//  IFrameworkView::SetWindow implementation
public: virtual void
SetWindow(::Windows::UI::Core::CoreWindow ^ h_window)
{
    h_window->Dispatcher->AcceleratorKeyActivated += ref new ::Windows::Foundation::TypedEventHandler
    <
        ::Windows::UI::Core::CoreDispatcher ^
    ,   ::Windows::UI::Core::AcceleratorKeyEventArgs ^
    >
    (this, &CView::On_Key);
    h_window->KeyDown += ref new ::Windows::Foundation::TypedEventHandler
    <
        ::Windows::UI::Core::CoreWindow ^
    ,   ::Windows::UI::Core::KeyEventArgs ^
    >
    (this, &CView::On_KeyDown);
    h_window->KeyUp += ref new ::Windows::Foundation::TypedEventHandler
    <
        ::Windows::UI::Core::CoreWindow ^
    ,   ::Windows::UI::Core::KeyEventArgs ^
    >
    (this, &CView::On_KeyUp);
}

private: static void
Trace_InputEvent
(
    wchar_t const *                     psz_description
,   ::Windows::System::VirtualKey const virtual_key
,   bool const                          was_down
,   bool const                          is_released
,   unsigned int const                  repeats_count
)
{
    ::std::wstringstream ss;
    ss << psz_description;
    ss << L" " << static_cast< int >(virtual_key);
    if(was_down)
    {
        ss << L" was down";
    }
    if(is_released)
    {
        ss << L" is released";
    }
    if(1 < repeats_count)
    {
        ss << L" repeats for " << repeats_count;
    }
    ss << L"\n";
    ss.flush();
    ::OutputDebugStringW(ss.str().c_str());
}

private: void
On_Key
(
    ::Windows::UI::Core::CoreDispatcher ^          h_dispatcher
,   ::Windows::UI::Core::AcceleratorKeyEventArgs ^ h_args
)
{
    auto const key_down
    {
        (::Windows::UI::Core::CoreAcceleratorKeyEventType::SystemKeyDown == h_args->EventType)
        ||
        (::Windows::UI::Core::CoreAcceleratorKeyEventType::KeyDown       == h_args->EventType)
    };
    auto const key_up
    {
        (::Windows::UI::Core::CoreAcceleratorKeyEventType::SystemKeyUp == h_args->EventType)
        ||
        (::Windows::UI::Core::CoreAcceleratorKeyEventType::KeyUp       == h_args->EventType)
    };
    if(key_down || key_up)
    {
        Trace_InputEvent
        (
            (key_down ? L"On_Key(Down)" : L"On_Key(Up)")
        ,   h_args->VirtualKey
        ,   h_args->KeyStatus.WasKeyDown
        ,   h_args->KeyStatus.IsKeyReleased
        ,   h_args->KeyStatus.RepeatCount
        );
    }
    //h_args->Handled = true; // Marking event as handled prevents On_KeyDown / On_KeyUp events from being emmitted.
}

private: void
On_KeyDown
(
    ::Windows::UI::Core::CoreWindow ^   h_dispatcher
,   ::Windows::UI::Core::KeyEventArgs ^ h_args
)
{
    Trace_InputEvent
    (
        L"On_KeyDown"
    ,   h_args->VirtualKey
    ,   h_args->KeyStatus.WasKeyDown
    ,   h_args->KeyStatus.IsKeyReleased
    ,   h_args->KeyStatus.RepeatCount
    );
}

private: void
On_KeyUp
(
    ::Windows::UI::Core::CoreWindow ^   h_dispatcher
,   ::Windows::UI::Core::KeyEventArgs ^ h_args
)
{
    Trace_InputEvent
    (
        L"On_KeyUp"
    ,   h_args->VirtualKey
    ,   h_args->KeyStatus.WasKeyDown
    ,   h_args->KeyStatus.IsKeyReleased
    ,   h_args->KeyStatus.RepeatCount
    );
}

按住空格键输出:

On_Key(Down) 32
On_KeyDown 32
On_Key(Down) 32
On_KeyDown 32 was down
On_Key(Down) 32
On_KeyDown 32 was down
...
On_Key(Down) 32
On_KeyDown 32 was down
On_Key(Up) 32 was down is released
On_KeyUp 32 was down is released

RS1 中存在一个已知问题。 MSDN论坛也有报道:CoreDispatcher.AcceleratorKeyActivated event: WasKeyDown property behaves differently on 10586.753 and 14393.693 (anniversary edition)

在使用XAML的过程中,AcceleratorKeyEventArgs里面的KeyStatus被忽略了,所以WasKeyDown不正确。

作为解决方法,请改用 GetKeyState(VirtualKey) 方法。

private void Dispatcher_AcceleratorKeyActivated(CoreDispatcher sender, AcceleratorKeyEventArgs args)
{
            var corewindow = CoreWindow.GetForCurrentThread();

            System.Diagnostics.Debug.WriteLine("AcceleratorKeyActivated-VirtualKey: " + 
            args.VirtualKey
            + " -- KeyState: " + 
            corewindow.GetKeyState(VirtualKey.Space));//Here
}

输出:

AcceleratorKeyActivated-VirtualKey: Space -- KeyState: Down, Locked
AcceleratorKeyActivated-VirtualKey: Space -- KeyState: Down, Locked
AcceleratorKeyActivated-VirtualKey: Space -- KeyState: Down, Locked
AcceleratorKeyActivated-VirtualKey: Space -- KeyState: Down, Locked
AcceleratorKeyActivated-VirtualKey: Space -- KeyState: Down, Locked
AcceleratorKeyActivated-VirtualKey: Space -- KeyState: Locked