Как определить, нажаты ли левая и правая кнопки?

StackOverflow https://stackoverflow.com/questions/1182893

  •  19-09-2019
  •  | 
  •  

Вопрос

Я хотел бы иметь три действия мыши над элементом управления:влево, вправо и ОБА.

У меня есть левая и правая кнопки, и в настоящее время я использую среднюю кнопку для третьей, но мне любопытно, как я мог бы использовать левую и правую кнопки, нажимая вместе, в тех ситуациях, когда у пользователя есть мышь без средней кнопки.Это будет обрабатываться в методе OnMouseDown пользовательского элемента управления.

ОБНОВЛЯТЬИзучив предложенные ответы, мне нужно уточнить, что я пытался выполнить действие по щелчку мыши в событии MouseDown (на самом деле это метод элемента управления OnMouseDown).Поскольку кажется, что .NET всегда будет вызывать два события MouseDown при нажатии левой и правой кнопок мыши (по одному на каждую кнопку), я предполагаю, что единственный способ сделать это - либо выполнить какое-нибудь низкоуровневое сообщение Windows управление или реализовать какое-то отложенное выполнение действия после MouseDown.В конце концов, гораздо проще использовать среднюю кнопку мыши.

Теперь, если бы действие происходило на MouseUp, то предложения Гэри или нет сработали бы хорошо.

Будем признательны за любые дополнительные сведения по этой проблеме.Спасибо!

Это было полезно?

Решение 5

Основываясь на том, что я узнал из других ответов, мне удалось заставить это работать.Я публикую решение здесь на случай, если оно понадобится кому-то еще.

Я создал компонент MouseDownManager, который вызываю во время события MouseDown.Он отслеживает только что нажатую кнопку, определяет, какую кнопку мы ждем, чтобы произошло событие «обе кнопки нажаты», а затем запускает таймер для ожидания этой кнопки.Если в течение отведенного времени нажата правильная кнопка, MouseDownManager вызывает соответствующее событие нажатия обеих кнопок.В противном случае он вызывает соответствующее событие одной кнопки.В форме я обрабатываю событие MouseDown MouseDownManager, чтобы выполнить действие по переведенному щелчку мыши.

Теперь я могу просто поместить этот компонент в форму/элемент управления и отреагировать на щелчок «оба».

Спасибо за помощь в выяснении этого.

/// <summary>
/// Manage mouse down event to enable using both buttons at once.
/// I.e. allowing the pressing of the right and left mouse
/// buttons together.
/// </summary>
public partial class MouseDownManager : Component
{

  /// <summary>
  /// Raised when a mouse down event is triggered by this
  /// component.
  /// </summary>
  public event EventHandler<MouseEventArgs> MouseDown;

  protected virtual void OnMouseDown( MouseEventArgs e )
  {
    if (this.MouseDown != null)
    {
      this.MouseDown( this, e );
    }
  }

  public MouseDownManager()
  { 
    //-- the timer was dropped on the designer, so it
    //   is initialized by InitializeComponent.
    InitializeComponent();
  }

  /// <summary>
  /// Defines the interval that the timer will wait for the other
  /// click, in milliseconds.
  /// </summary>
  public int BothClickInterval
  {
    get
    {
      return this.tmrBothInterval.Interval;
    }
    set
    {
      this.tmrBothInterval.Interval = value;
    }
  }

  private MouseButtons _virtualButton = MouseButtons.Middle;

  /// <summary>
  /// Defines the button that is sent when both buttons are
  /// pressed. This can be either a single button (like a middle
  /// button) or more than one button (like both the left and
  /// right buttons.
  /// </summary>
  public MouseButtons VirtualButton
  {
    get
    {
      return _virtualButton;
    }
    set
    {
      _virtualButton = value;
    }
  }

  private MouseEventArgs _originalArgs;

  /// <summary>
  /// Defines the original mouse event arguments that is associated
  /// with the original press.
  /// </summary>
  private MouseEventArgs OriginalArgs
  {
    get
    {
      return _originalArgs;
    }
    set
    {
      _originalArgs = value;
    }
  }

  private MouseButtons _waitButton = MouseButtons.None;

  /// <summary>
  /// Defines the button that we are waiting on, for there to be a
  /// both button click.
  /// </summary>
  private MouseButtons WaitButton
  {
    get
    {
      return _waitButton;
    }
    set
    {
      _waitButton = value;
    }
  }

  /// <summary>
  /// Manage a mouse button being depressed.
  /// </summary>
  /// <remarks>
  /// This will instigate one of two actions.  If there is no
  /// current wait button, this will set the appropriate wait
  /// button (if the button pressed was the left button, then we
  /// are waiting on the right button) and start a timer. If the
  /// wait button is set, but this isn't that button, then the wait
  /// button is updated and the timer restarted.  Also, this will
  /// trigger the waiting event.  If it is the wait button, then
  /// the appropriate event is raised for a "both" button press.
  /// </remarks>
  public void ManageMouseDown( MouseEventArgs mouseArgs )
  {
    //-- Is the the button we are waiting for?
    if (mouseArgs.Button == this.WaitButton)
    {
      //-- Turn off timer.
      this.ClearTimer();

      //-- Create new mouse event args for our virtual event.
      MouseEventArgs bothArgs = new MouseEventArgs( this.VirtualButton
                                                  , mouseArgs.Clicks
                                                  , mouseArgs.X
                                                  , mouseArgs.Y
                                                  , mouseArgs.Delta );

      //-- Raise the mouse down event.
      this.OnMouseDown( bothArgs );
    }
    else
    {
      //-- Clear timer
      this.ClearTimer();

      //-- If we were waiting for a button, then
      //   fire the event for the original button.
      if (this.WaitButton != MouseButtons.None)
      {
        this.OnMouseDown( this.OriginalArgs );
      }

      //-- Cache the original mouse event args.
      MouseEventArgs newMouseArgs = new MouseEventArgs( mouseArgs.Button
                                                      , mouseArgs.Clicks
                                                      , mouseArgs.X
                                                      , mouseArgs.Y
                                                      , mouseArgs.Delta );
      this.OriginalArgs = newMouseArgs;

      //-- Reset to wait for the appropriate next button.
      switch (mouseArgs.Button)
      {
        case MouseButtons.Left:
          this.WaitButton = MouseButtons.Right;
          break;
        case MouseButtons.Right:
          this.WaitButton = MouseButtons.Left;
          break;
        default:
          this.WaitButton = MouseButtons.None;
          break;
      }

      //-- Start timer
      this.tmrBothInterval.Enabled = true;
    }
  }

  /// <summary>
  /// Raise the event for the button that was pressed initially
  /// and turn off the timer.
  /// </summary>
  private void tmrBothInterval_Tick( object sender, EventArgs e )
  {
    //-- Turn off the timer.
    this.tmrBothInterval.Enabled = false;

    //-- Based on the original button pressed, raise
    //   the appropriate mouse down event.
    this.OnMouseDown( this.OriginalArgs );

    //-- Clear timer.
    this.ClearTimer();
  }

  /// <summary>
  /// Clear the timer and associated variables so we aren't waiting
  /// for the second click.
  /// </summary>
  private void ClearTimer()
  {
    //-- Turn off the timer.
    this.tmrBothInterval.Enabled = false;

    //-- Clear the wait button.
    this.WaitButton = MouseButtons.None;

    //-- Clear the original args
    this.OriginalArgs = null;
  }
}

/// <summary>
/// Just the mouse code from the control needing the functionality.
/// </summary>
public class MyControl: Control
{
  /// <summary>
  /// Handle the mouse down event. This delegates the actual event
  /// to the MouseDownManager, so we can capture the situation
  /// where both buttons are clicked.
  /// </summary>
  protected override void OnMouseDown( MouseEventArgs e )
  {
    this.mdmMain.ManageMouseDown( e );
  }

  /// <summary>
  /// Process the mouse down event.
  /// </summary>
  private void mdmMain_MouseDown( object sender, MouseEventArgs e )
  {
    //-- Get the reported button state.
    MouseButtons mouseButton = e.Button;

    //-- Execute logic based on button pressed, which now can include
    //   both the left and right together if needed....
  }
}

Другие советы

Всегда есть подход «сделай сам»:

Просто запомните состояние нажатия и отпускания кнопок.В OnMouseDown вы просто запоминаете нажатую кнопку, а в OnMouseUp просто проверяете, какие кнопки запомнились, а также очищаете состояние кнопки.

Вам нужна логика, чтобы не выполнять несколько действий при отпускании кнопок.Что-то вроде

MouseButtons buttonPressed;
..

void OnMouseDown(MouseEventArgs e) 
{
   buttonPressed |= e.Button;
}


void OnMouseUp(MouseEventArgs e) 
{
  if(!doneAction) {
    if((buttonPressed & MouseButtons.Right == MouseButtons.Right 
       && buttonPressed & MouseButtons.Left == MouseButtons.Left)
       || buttonPressed & MouseButtons.Middle== MouseButtons.Middle) {
       DoMiddleAction();
       doneAction = true;
    } else if(check Right button , etc.) {
       .... 
    }
  }

  buttonpressed &= ~e.Button;
  if(buttonpressed == None)
      doneAction = false;

}

Я бы лично использовал MouseUp и MouseDown события для более чистого способа обработки и предотвращения взаимодействия.По сути, этот код использует статический класс для хранения состояния двух кнопок и, проверяя, можно ли определить, действительно ли обе кнопки неактивны.

using System.Windows.Forms;

namespace WindowsFormsApplication1
{

    public static class MouseButtonStatus
    {
        static bool RightButton;
        static bool LeftButton;

        public static bool RightButtonPressed
        {
            get
            {
                return RightButton;
            }
            set
            {
                RightButton = value;
            }
        }

        public static bool LeftButtonPressed
        {
            get
            {
                return LeftButton;
            }
            set
            {
                LeftButton = value;
            }
        }


    }


    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        public void HandleButtons(bool LeftPressed, bool RightPressed)
        {
            if(LeftPressed && RightPressed)
            {
                //BOTH ARE PRESSED
            }
            else if(LeftPressed)
            {
                //LEFT IS PRESSED
            }
            else if(RightPressed)
            {
                //RIGHT IS PRESSED
            }
            else
            {
                //NONE ARE PRESSED
            }
        }

        private void Form1_MouseDown(object sender, MouseEventArgs e)
        {
            if(e.Button == MouseButtons.Left)
            {
                MouseButtonStatus.LeftButtonPressed = true;
            }
            if(e.Button == MouseButtons.Right)
            {
                MouseButtonStatus.RightButtonPressed = true;
            }

            HandleButtons(MouseButtonStatus.LeftButtonPressed, MouseButtonStatus.RightButtonPressed);
        }

        private void Form1_MouseUp(object sender, MouseEventArgs e)
        {
            if(e.Button == MouseButtons.Left)
            {
                MouseButtonStatus.LeftButtonPressed = false;
            }
            if(e.Button == MouseButtons.Right)
            {
                MouseButtonStatus.RightButtonPressed = false;
            }

            HandleButtons(MouseButtonStatus.LeftButtonPressed, MouseButtonStatus.RightButtonPressed);
        }



    }
}

Не уверен, что есть собственный способ сделать это в .Net, но если вас устраивает P/Invoke, вы можете использовать GetKeyState или GetAsyncKeyState так:

[DllImport("user32.dll")]
public static extern short GetKeyState(int nVirtKey);

if (GetKeyState((int)Keys.LButton) < 0 && GetKeyState((int)Keys.RButton) < 0)
{
    // Both buttons are pressed.
}

Разве «середина» не то же самое, что «лево и право вместе»?По крайней мере, я откуда-то это помню, но это было еще тогда, когда у меня была двухкнопочная мышь без колесика прокрутки...

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top