无法在鼠标事件处理程序中读取 WPF 中键的保持状态 - VMWare Fusion for Mac 上的 Windows 客户机中的行为不一致

Posted

技术标签:

【中文标题】无法在鼠标事件处理程序中读取 WPF 中键的保持状态 - VMWare Fusion for Mac 上的 Windows 客户机中的行为不一致【英文标题】:Cannot read held state of key in WPF inside mouse event handler - Inconsistent behaviour in Windows guest on VMWare Fusion for Mac 【发布时间】:2019-01-06 17:38:12 【问题描述】:

此问题是由 vmware fusion 中的设置不一致引起的 - 尽管在 vmware fusion 设置中配置为作为单独的键发送控制权。

我将把它留在这里,因为它概述了为隔离问题而采取的诊断步骤。

此行为可能存在于 MacOS 上的其他虚拟化解决方案中。

这不是重复的 - 我已经尝试过建议的方法 - 它们不起作用。需要真正的帮助。

我正在尝试在 WPF 画布中实现多选功能,并且需要能够检测在单击项目时何时按住任一控制键。

我已经尝试过使用记录在案和接受的方法来获取密钥(Keyboard.IsKeyDownKeyboard.Modifiers),虽然它们应该可以工作,但在这种情况下却不行。

我无法在应用程序的主窗口中放置密钥处理程序,因为此解决方案是在组件中实现的,因此我无法访问主窗口。

我无法创建键盘OnKeyDown 覆盖,因为它没有注册事件。我不知道为什么会这样,但我只想说,在对 Stack Overflow 进行广泛搜索后,我已经尝试了所有能找到的方法,但目前没有想法。

在当前逻辑中,单击画布中的项目将清除所有已选择的项目。如果按住控制键,我不会清除选定的项目。

我的应用结构如下:

主窗口 -> 停靠面板 -> ScrollViewer -> 主自定义组件(扩展 Canvas) -> ChildCanvas 对象(多个实例,都扩展 Canvas)。

组件不会有任何返回到主窗口的引用 - 这绝对是不可协商的。

组件必须不需要对主窗口的引用才能传递给它。

组件不能依赖于MainWindow 中放置的任何逻辑、属性、方法或其他功能代码 - 它必须是完全可重用的。

Canvas 派生的自定义对象 (ChildCanvas) 的多个实例被放置在同样扩展 Canvas 的基础自定义对象 (ExtendedCanvas) 上。

我正在自定义项中的鼠标事件处理程序中检测到鼠标单击。

虽然我理论上可以处理按键事件并在按键按下时设置一个布尔标志并在按键上升时清除它,但这不是一种可靠的做事方式,因为它需要将焦点放在任何一个组件正在处理密钥。

我看过的所有示例都需要特定的按键事件处理程序,但在这种情况下我不能应用这种方法,因为它似乎根本没有注册按键,即使事件处理程序所在的组件是实施有当时的重点。

如果在 WPF 中可行,我想找到一种方法来检查鼠标单击处理程序中是否按下了某个键。

编辑:我尝试使用Keyboard.Modifiers 方法,但这没有返回任何结果。

编辑:我也试过Keyboard.IsKeyDown(Key.LeftCtrl),它不返回任何值。

编辑:我试图通过在 EventManager 上注册来全局处理关键事件,如图所示。我发现按键向上和按键向下事件是快速连续触发的。第一个事件的属性e.IsRepeat 为false,所有后续事件的发生都将e.IsRepeat 设置为true。使用这些事件,我设置了一个布尔值,在第一个 keyDown 事件中设置为 truee.IsRepeat 为假(第一次初始按键),如果 e.IsRepeat 是,则在 keyUp 事件中设置为 false false(物理释放键时触发 keyUp 事件)。

这不起作用 - 按住键时单击画布上的项目会更改 bool 的状态,将其设置为 false。

此行为与 Microsoft 文档中关于键盘处理的工作方式完全不一致。

EventManager.RegisterClassHandler(typeof(Control),
    Keyboard.KeyDownEvent,new KeyEventHandler(keyDown),true);

我可以调用Keyboard.IsKeyToggled(Key.LeftCtrl),它确实显示了切换状态,但它会随着每次按键的按下而改变,并且不会显示在鼠标点击时按键是否被按住。

public class ExtendedCanvas:Canvas 
    public ExtendedCanvas() 
        MouseUp += thisMouseUp;
    


    void thisMouseUp(object sender,MouseButtonEventArgs e) 

        if ((Keyboard.Modifiers & ModifierKeys.Control) > 0) 
            //This does not work - no key is registered, as for some reason, Keyboard.Modifiers does not register that the key is held.
        

        //If CONTROL is held down 
        if (!ControlKeyHeldDown) 
            ClearSelectedItems();
        

        IsSelected = true;    
    

【问题讨论】:

Getting shift/ctrl/alt states from a mouse event?的可能重复 抱歉,已尝试Keyboard.Modifiers 方法,但没有成功。我最初忽略了将此添加到我的问题中。 How to detect modifier key states in WPF?的可能重复 不是重复的,修饰键状态解决方案在这种情况下不起作用。我添加了更多细节。 根据您为代码显示的内容,这对我有用。你得到了 MouseUp 事件吗? 【参考方案1】:

不一致的行为是 VMWare 选项的结果。

此 VM 正在 MacOS 上运行,尽管 VMWare Fusion 被配置为直接发送 Control 键,但 Control Click 仍会触发辅助鼠标按钮(即,在本例中为右键单击)。

解决办法是:

1) 关闭虚拟机。

2) 在 VMWare Fusion Preferences -> Keyboard And Mouse -> Mouse Shortcuts 中,启用(选中)“辅助按钮”选项(如果未选中)。

3) 关闭首选项窗口以保存设置。

4) 关闭 VMWare Fusion

5) 重启主机系统

6) 在 VMWare Fusion Preferences -> Keyboard And Mouse -> Mouse Shortcuts 中,禁用(取消选中)“辅助按钮”选项。

7) 启动虚拟机,并确认 Control Click 不再触发二次点击。

在将 VMWare Fusion 从 8 升级到 10 之前,此选项已配置为直接发送控制。

看来,虽然“次要功能”复选框未选中,但该属性设置为 true,并且其行为与设置建议的方式不一致。

【讨论】:

以上是关于无法在鼠标事件处理程序中读取 WPF 中键的保持状态 - VMWare Fusion for Mac 上的 Windows 客户机中的行为不一致的主要内容,如果未能解决你的问题,请参考以下文章

如何使 WPF ScrollViewer 中键单击滚动?

鼠标右键的WPF按钮命令?

在wpf中,处理鼠标Click事件的时候为啥火弹出这样的问题?如图!

Appsetting.json 读取控制器类中键的值,空白?

鼠标滚轮不能滑动都有哪些解决办法

如何在WPF中模拟鼠标点击