You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MAUI中左右点击按压/释放事件的检测问题

区分MAUI中Windows和macOS的左右点击手势并追踪按压状态

要同时实现左右点击区分、按压状态追踪的需求,最直接的方案是基于平台原生事件封装自定义手势识别器,绕开MAUI内置手势的局限性。以下是具体实现步骤:

自定义手势识别器(推荐)

通过封装平台原生的指针/鼠标事件,我们可以同时获取按键类型和按压状态变化。

1. 共享项目中定义核心手势类

创建跨平台的手势抽象,包含按压/释放事件和按键类型枚举:

using System;

namespace YourAppNamespace
{
    public class CustomPointerGestureRecognizer : GestureRecognizer
    {
        public event EventHandler<PointerButtonEventArgs> PointerDown;
        public event EventHandler<PointerButtonEventArgs> PointerUp;

        internal void RaisePointerDown(PointerButton button)
        {
            PointerDown?.Invoke(this, new PointerButtonEventArgs(button));
        }

        internal void RaisePointerUp(PointerButton button)
        {
            PointerUp?.Invoke(this, new PointerButtonEventArgs(button));
        }
    }

    public enum PointerButton
    {
        Left,
        Right,
        Other
    }

    public class PointerButtonEventArgs : EventArgs
    {
        public PointerButton Button { get; }
        public PointerButtonEventArgs(PointerButton button) => Button = button;
    }
}

2. Windows平台实现手势Handler

在Platforms/Windows目录下创建平台特定的Handler,对接WinUI的指针事件:

using Microsoft.Maui.Handlers;
using Microsoft.UI.Xaml.Input;
using YourAppNamespace;

namespace YourAppNamespace.Platforms.Windows
{
    public class CustomPointerGestureHandler : GestureHandler<CustomPointerGestureRecognizer, Microsoft.UI.Xaml.UIElement>
    {
        protected override void ConnectHandler(Microsoft.UI.Xaml.UIElement platformView)
        {
            base.ConnectHandler(platformView);
            platformView.PointerPressed += OnPointerPressed;
            platformView.PointerReleased += OnPointerReleased;
        }

        protected override void DisconnectHandler(Microsoft.UI.Xaml.UIElement platformView)
        {
            platformView.PointerPressed -= OnPointerPressed;
            platformView.PointerReleased -= OnPointerReleased;
            base.DisconnectHandler(platformView);
        }

        private void OnPointerPressed(object sender, PointerRoutedEventArgs e)
        {
            var point = e.GetCurrentPoint((Microsoft.UI.Xaml.UIElement)sender);
            var button = point.Properties.IsRightPressed ? PointerButton.Right :
                         point.Properties.IsLeftPressed ? PointerButton.Left : PointerButton.Other;
            GestureRecognizer.RaisePointerDown(button);
        }

        private void OnPointerReleased(object sender, PointerRoutedEventArgs e)
        {
            var point = e.GetCurrentPoint((Microsoft.UI.Xaml.UIElement)sender);
            var button = point.Properties.IsRightPressed ? PointerButton.Right :
                         point.Properties.IsLeftPressed ? PointerButton.Left : PointerButton.Other;
            GestureRecognizer.RaisePointerUp(button);
        }
    }
}

3. macOS平台实现手势Handler

在Platforms/MacCatalyst目录下创建对接AppKit鼠标事件的Handler:

using AppKit;
using Microsoft.Maui.Handlers;
using YourAppNamespace;

namespace YourAppNamespace.Platforms.MacCatalyst
{
    public class CustomPointerGestureHandler : GestureHandler<CustomPointerGestureRecognizer, NSView>
    {
        protected override void ConnectHandler(NSView platformView)
        {
            base.ConnectHandler(platformView);
            platformView.MouseDown += OnMouseDown;
            platformView.MouseUp += OnMouseUp;
        }

        protected override void DisconnectHandler(NSView platformView)
        {
            platformView.MouseDown -= OnMouseDown;
            platformView.MouseUp -= OnMouseUp;
            base.DisconnectHandler(platformView);
        }

        private void OnMouseDown(object sender, NSEventEventArgs e)
        {
            var button = e.Event.ButtonNumber switch
            {
                0 => PointerButton.Left,
                2 => PointerButton.Right,
                _ => PointerButton.Other
            };
            GestureRecognizer.RaisePointerDown(button);
        }

        private void OnMouseUp(object sender, NSEventEventArgs e)
        {
            var button = e.Event.ButtonNumber switch
            {
                0 => PointerButton.Left,
                2 => PointerButton.Right,
                _ => PointerButton.Other
            };
            GestureRecognizer.RaisePointerUp(button);
        }
    }
}

4. 注册手势Handler并使用

在MauiProgram.cs中注册平台Handler:

using YourAppNamespace.Platforms.MacCatalyst;
using YourAppNamespace.Platforms.Windows;

var builder = MauiApp.CreateBuilder();
builder
    .UseMauiApp<App>()
    .ConfigureMauiHandlers(handlers =>
    {
#if WINDOWS
        handlers.AddHandler<CustomPointerGestureRecognizer, CustomPointerGestureHandler>();
#endif
#if MACCATALYST
        handlers.AddHandler<CustomPointerGestureRecognizer, CustomPointerGestureHandler>();
#endif
    });

在XAML中绑定手势并处理事件:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:YourAppNamespace"
             x:Class="YourAppNamespace.MainPage">

    <Frame WidthRequest="300" HeightRequest="300" BackgroundColor="LightSkyBlue">
        <Frame.GestureRecognizers>
            <local:CustomPointerGestureRecognizer 
                PointerDown="OnPointerDown" 
                PointerUp="OnPointerUp"/>
        </Frame.GestureRecognizers>
        <Label Text="Click with Left/Right Button" HorizontalOptions="Center" VerticalOptions="Center"/>
    </Frame>

</ContentPage>

后台代码处理按压/释放逻辑:

private void OnPointerDown(object sender, PointerButtonEventArgs e)
{
    switch (e.Button)
    {
        case PointerButton.Left:
            // 左键按下时的逻辑,比如高亮控件
            break;
        case PointerButton.Right:
            // 右键按下时的逻辑,比如显示上下文菜单前置状态
            break;
    }
}

private void OnPointerUp(object sender, PointerButtonEventArgs e)
{
    switch (e.Button)
    {
        case PointerButton.Left:
            // 左键释放完成点击的逻辑
            break;
        case PointerButton.Right:
            // 右键释放完成点击的逻辑
            break;
    }
}

注意事项

  • macOS上,无论是物理右键按钮还是Control+左键模拟右键,都会被识别为PointerButton.Right
  • 可以根据需求扩展自定义手势,比如添加指针位置、按压压力等额外信息

内容的提问来源于stack exchange,提问作者GMachine

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 23:30:59