2009-07-25 119 views
2

我想在控件上有三个鼠标动作:left,right和BOTH。如何检测左右按钮是否被按下?

我已经得到了左侧和右侧,目前正在使用第三个中间按钮,但我很好奇如何使用左右按钮被按在一起,对于那些用户没有鼠标的情况中间按钮。这将在自定义控件的OnMouseDown方法中处理。

UPDATE 审查建议的答复后,我需要澄清的是什么,我试图做的是采取在MouseDown事件的鼠标点击动作(实际上onmousedown事件控制的方法)。因为看起来,当鼠标左键和右键都被点击(每个按钮一个)时,.NET总是会引发两个MouseDown事件,我猜测唯一的方法是做一些低级别的Windows消息管理或在MouseDown后执行某种操作的延迟执行。最后,使用鼠标中键只是简单一些。

现在,如果动作发生在MouseUp上,那么Gary或nos的建议将会奏效。

对这个问题的任何进一步的见解将不胜感激。谢谢!

+3

伙计。不要去那里。 UI标准的存在是有原因的。你的可用性会受到影响。这听起来比“三重点击”更糟糕 – JohnFx 2009-07-25 21:48:27

+0

@JohnFx任何体面的扫雷克隆都需要双击chording。这是一个有用的例子。 – mbomb007 2016-06-03 15:29:43

回答

0

根据我从其他答案中学到的知识,我能够做到这一点。我在这里发布解决方案,以防其他人需要它。

我创建了一个组件MouseDownManager,我在MouseDown事件期间调用它。它跟踪刚刚按下的按钮,确定我们正在等待的按钮,以便拥有“两个”按钮按下事件,然后启动一个定时器以等待该按钮。如果在分配的时间内,按下了正确的按钮,则MouseDownManager引发相应的“两个”按钮向下事件。否则,它会引发相应的单个按钮事件。在窗体上,我正在处理MouseDownManager的MouseDown事件以对翻译的鼠标单击进行操作。

我现在可以将这个组件放在窗体/控件上,然后我可以对“双方”单击作出反应。

感谢您的帮助解决这个问题。

/// <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.... 
    } 
} 
1

不知道是否有一个本地.NET的方式来做到这一点,但如果你满意的P/Invoke,您可以使用GetKeyStateGetAsyncKeyState这样的:

[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. 
} 
+0

谢谢。我不确定“开心”是否合适,但我认为我可以鼓起勇气在这种情况下使用它。 :D – 2009-07-25 21:32:47

+0

查看我的回答以避免p/invoke。 – 2009-07-25 21:44:13

+0

经过一番测试,结果不是很可靠。使用此功能时,大约有四分之一被抓到。不知道为什么,有些事情我可以做些改进,但我不知道是什么。 – 2009-07-26 06:44:01

0

不是“中间的”同“左右”在一起?至少这是我从什么地方还记得,但那是从遥想当年我有两个按钮,鼠标没有滚轮按钮...

+0

这是Xorg上的一个标志,用来模拟像我这样蹩脚的笔记本电脑上的中间点击(在X11上,当您选择文本时,它会自动复制,而中间的点击也可以用作粘贴,当我使用Windows时,我真的很想念它)。 – elcuco 2009-07-25 20:04:04

+0

有趣,因为我记得它从Windows。好吧。 – Kawa 2009-07-26 11:35:59

2

总是有“自己动手”的方法:

只要记住状态按钮按下并释放。在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; 

} 
+0

我目前正在尝试处理MouseDown上的操作,所以这会变得复杂(请参阅评论Gary Willoughby的答案)。但是,我将重新访问代码,以查看是否可以通过鼠标移动来完成此操作。谢谢! – 2009-07-26 06:47:04

+0

我已经编辑好我的代码来做你现在需要的东西。 :) – 2009-07-26 11:51:36

+0

我认为这个解决方案是最好的。它使用现有的'MouseEventArgs'和'e.Button'来完成所需的工作。但是你的代码可以变得更简单。你不需要'doneAction',因为这个'OnMouseUp'是所有相关的mouseUp事件的处理器。只需使用'Select Case buttonPressed'和每个类型的case语句来处理:'Case MouseButtons.Left','Case MouseButtons.Middle,MouseButtons.Left或MouseButtons.Right'等... – mbomb007 2016-06-03 17:16:35

2

我会亲自使用MouseUpMouseDown事件更清洁的方式来处理它,避免互操作。基本上,这段代码使用一个静态类来保存两个按钮的状态,并通过检查确定两者实际上是否关闭。

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); 
     } 



    } 
} 
+0

这种方法的问题在于,.NET会发送两个鼠标下移,一个用于左侧,另一个用于右侧(取决于哪一个被认为先被点击过。如果我只需要处理两者,这将工作,但如果我只需要处理左边,仅右边或两者,然后这变得真实复杂,我想,因为我必须设置某种计时器来跟踪点击之间的间隔,然后我必须推迟要采取行动,直到我确定它不是两个按钮,尽管如此,它最终仍然可能比Interop更可靠 – 2009-07-26 06:42:07

+0

我已经编辑了上面的代码,将解决方案应用于您的问题,您只需要使用方法处理点击并更新它每个MouseUp和MouseDown。检查出来:) – 2009-07-26 11:50:23

+0

你永远不会解决这个事实,即当你按下一个按钮它会触发一个事件。所以,如果你想处理两个按钮点击,你将不得不先处理一个右键点击事件,然后左键点击事件。这可能是为什么没有程序使用两个按钮单击的用户界面。 – 2009-07-26 11:58:53