2009-07-25 5 views
2

Ich hätte gerne drei Mausaktionen über ein Steuerelement: links, rechts und BEIDE.Wie erkenne ich, ob die linken und rechten Tasten gedrückt werden?

Ich habe links und rechts und verwende derzeit die mittlere Taste für die dritte, bin aber gespannt, wie ich die linke und rechte Taste zusammen drücken könnte, für die Situationen, in denen der Benutzer eine Maus ohne hat mittlerer Knopf. Dies würde in der OnMouseDown-Methode eines benutzerdefinierten Steuerelements behandelt werden.

UPDATE Nach den vorgeschlagenen Antworten bewerten, muss ich das klären, was ich versuchte, in dem Mousedown-Ereignis Aktion auf der per Mausklick zu ergreifen, um zu tun war (eigentlich OnMouseDown Methode der Kontrolle). Da es so aussieht, als würde .NET immer zwei MouseDown-Ereignisse auslösen, wenn sowohl die linke als auch die rechte Maustaste geklickt wird (eine für jede Schaltfläche), würde ich wahrscheinlich nur eine Low-Level-Windows-Nachricht machen Management oder um eine Art verzögerte Ausführung einer Aktion nach MouseDown zu implementieren. Am Ende ist es einfacher, die mittlere Maustaste zu verwenden.

Nun, wenn die Aktion auf MouseUp stattfand, würden die Vorschläge von Gary oder Nos gut funktionieren.

Weitere Erkenntnisse zu diesem Problem wären willkommen. Vielen Dank!

+3

Mann. Geh nicht dorthin. UI-Standards gibt es aus gutem Grund. Ihre Benutzerfreundlichkeit wird leiden. Das klingt schlimmer als der "Triple Click" – JohnFx

+0

@ JohnFx Jeder anständige Minesweeper-Klon benötigt beide für das Akkordklopfen. Das ist ein Beispiel, wo es nützlich ist. – mbomb007

Antwort

0

Basierend auf dem, was ich aus den anderen Antworten gelernt habe, konnte ich das funktionieren. Ich poste hier die Lösung für den Fall, dass es jemand anderes braucht.

Ich erstellte eine Komponente, MouseDownManager, die ich während des MouseDown-Ereignisses aufrufen. Er verfolgt die Taste, die gerade gedrückt wurde, bestimmt, auf welche Taste wir warten, um ein "beide" Tasten herunterzufahren, und startet dann einen Timer, um auf diese Taste zu warten. Wenn innerhalb der vorgegebenen Zeit die richtige Taste gedrückt wird, löst der MouseDownManager das entsprechende "bottom button down" -Ereignis aus. Andernfalls wird das entsprechende Einzelknopf-Ereignis ausgelöst. Auf dem Formular bearbeite ich das MouseDown-Ereignis des MouseDownManagers, um auf den übersetzten Mausklick einzugehen.

Ich kann jetzt nur diese Komponente auf ein Formular/Steuerelement fallen lassen und ich kann auf einen "beide" klicken.

Vielen Dank für die Hilfe, dies herauszufinden.

/// <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

Nicht sicher, ob es einen nativen .Net Art und Weise, es zu tun, aber wenn Sie mit P zufrieden sind/Invoke Sie GetKeyState oder GetAsyncKeyState wie diese verwenden:

[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

Danke. Ich bin mir nicht sicher "glücklich" ist das richtige Wort, aber ich denke, ich kann den Mut aufbringen, es in dieser Situation zu verwenden. : D –

+0

Siehe meine Antwort, um p/invoke zu vermeiden. –

+0

Nach einigen Tests erweist sich dies als nicht sehr zuverlässig. Ungefähr 1 in 4 werden gefangen, wenn Sie dies verwenden. Ich weiß nicht warum und vielleicht kann ich etwas tun, um das zu verbessern, aber ich habe keine Ahnung was. –

0

War das nicht „Mitte“ die wie "links und rechts zusammen"? Zumindest ist das, was ich von irgendwo erinnern, aber das war aus dem Rückweg, als ich zwei Tasten-Mäuse hatten ohne Scrollrad Tasten ...

+0

Dies ist eine Flagge auf Xorg, um den mittleren Klick auf beschissene Laptops wie meinen zu emulieren (auf X11, wenn Sie Text auswählen, wird es automatisch kopiert, und der mittlere Klick fungiert auch als Paste, was ich wirklich vermisse, wenn ich Windows verwende). – elcuco

+0

Lustig, weil ich es von Windows erinnere. Naja. – Kawa

2

Es gibt immer die „do it yourself“ -Ansatz:

Denken Sie daran, den Zustand der Der Knopf drückt und lässt los. In OnMouseDown merken Sie sich einfach die gedrückte Taste, und in OnMouseUp überprüfen Sie einfach, welche Tasten gespeichert wurden, und löschen Sie den Status für die Taste.

Sie benötigen eine Logik, um nicht mehrere Aktionen auszuführen, wenn Tasten losgelassen werden. So etwas wie

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

Ich versuche gerade mit der Aktion auf MouseDown umzugehen, das würde kompliziert werden (siehe Kommentar zu Gary Willoughbys Antwort). Allerdings werde ich den Code noch einmal überprüfen, um zu sehen, ob ich es in mouse machen kann, wo dies sinnvoll wäre. Vielen Dank! –

+0

Ich habe meinen Code bearbeitet, um zu tun, was Sie jetzt brauchen. :) –

+0

Ich denke, diese Lösung ist die beste. Es verwendet die vorhandenen 'MouseEventArgs' und' e.Button', um zu tun, was benötigt wird. Aber Ihr Code könnte einfacher gemacht werden. Sie brauchen 'doneAction' nicht, da' OnMouseUp' der Handler für * all * der relevanten mouseUp-Ereignisse ist. Verwenden Sie einfach "Select Case buttonPressed" mit einer case-Anweisung für jeden zu handhabenden Typ: 'Case MouseButtons.Left',' Case MouseButtons.Middle, MouseButtons.Left oder MouseButtons.Right', etc ... – mbomb007

2

würde ich persönlich benutze die MouseUp und MouseDown Ereignisse für eine sauberere Art und Weise zu handhaben und Interop zu vermeiden. Im Grunde verwendet dieser Code eine statische Klasse, um den Status der beiden Schaltflächen zu halten und um zu überprüfen, ob beide tatsächlich inaktiv sind.

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

Das Problem bei diesem Ansatz ist, dass .NET zwei Maus-Downs sendet, eine für die linke und eine für die rechte (je nachdem, welche zuerst als angeklickt betrachtet wurde. Das würde funktionieren, wenn ich nur beide, aber wenn Ich muss nur mit links, nur mit rechts oder mit beiden umgehen, dann wird das sehr kompliziert, denke ich, da ich eine Art Timer einstellen müsste, um das Intervall zwischen den Klicks zu verfolgen und dann müsste ich das verschieben Ich musste etwas unternehmen, bis ich sicher war, dass es nicht beide Tasten waren. Das könnte am Ende immer noch zuverlässiger als Interop sein. –

+0

Ich habe den obigen Code bearbeitet, um eine Lösung für Ihr Problem zu finden. Sie müssen nur eine Methode verwenden um die Klicks zu bearbeiten und jedes MouseUp und MouseDown zu aktualisieren. Überprüfen Sie es. :) –

+0

Sie werden nie die Tatsache umgehen, dass wenn Sie einen Knopf drücken, es ein Ereignis auslöst. Wenn Sie also mit beiden Schaltflächen klickern wollen, müssen Sie zuerst ein Rechtsklick-Ereignis und dann ein Linksklick-Ereignis behandeln. Dies ist wahrscheinlich der Grund, warum keine Programme einen Klick auf beide Schaltflächen für die Benutzeroberfläche verwenden. –

Verwandte Themen