This blog has moved http://www.sharplogic.com/blogs/ed

This blog has moved here<!--meta http-equiv="refresh" content="0;url=http://www.sharplogic.com/blogs/ed"-->

February 2004 - Posts

Fun Fact Of The Day

It turns out that Starbucks owns the “Seattle Coffee Company”, which in turn owns “Seattle's Best Coffee”. “Seattle Coffee Company“ is a Georgia corporation. Go figure :-)

(PDF-->) http://ir.10kwizard.com/download.php?format=PDF&ipage=2489823 (Exhibit 21)

 

A Keyboard/Mouse Class

I noticed a post in a newsgroup asking about accessing keyboard state. I did a quick search on Google and found a useful article at http://www.developer.com/net/article.php/1489521. However, I do a lot of development across Windows platforms, and have found that staying as much on the managed platform as possible makes it easy to port, such as from desktop to device. I made a multi-purpose Windows Forms class for handling general input stuff, such as keyboard state, key combinations, and mouse movement. Unfortunately, I lost the app that used it when I repaved my system a few weeks ago. However, I was lucky enough to find an earlier version of the class I had backed up. It has a few shortcomings (such as if you Alt+Tab away, it doesn't track keys properly). Anyway, you can feel free to use whatever's useful.

Since the code is fairly long, I'll put the usage stuff up front, and then the code for the class at the end of this posting.

1. Setting up the class for usage.

First, add the “using Utilities;” directive at the top with the other namespaces.

Then, allocate a member variable for the Keyboard class. The class started off as an attempt to track the keyboard, although it does mouse stuff now too. “Keyboard“ stuck as the name, however. For example:

private Keyboard m_Keyboard;

Next, inside the Form's constructor, add these lines after InitializeComponent(). If you're only interested in the keyboard events, only subscribe to those. If you only want to use the mouse stuff, only use that.

this.m_Keyboard = new Keyboard();

this.KeyDown += new KeyEventHandler(this.m_Keyboard.KeyDown);

this.KeyUp += new KeyEventHandler(this.m_Keyboard.KeyUp);

this.MouseDown += new MouseEventHandler(this.m_Keyboard.MouseDown);

this.MouseUp += new MouseEventHandler(this.m_Keyboard.MouseUp);

this.MouseMove += new MouseEventHandler(this.m_Keyboard.MouseMove);

2. Checking for key state. Whenever you want to check the state of a key (such as the Return key), use code such as this:

this.m_Keyboard.IsKeyDown(Keys.Return);

There are three ways to check for key combos. First, you can do it by hand. Second, you can use CheckButtonCombo() to check manually. Finally, you can subscribe to specific combinations, which will fire when the combo is hit.

3. Checking for key press combos. To manually check for a key combo, you can use the following code, which checks for Ctrl+Space:

if (this.m_Keyboard.CheckButtonCombo(Keys.ControlKey, Keys.Space))

{

// Code to execute when this combo is found

}

4. Subscribing to key press combos. If you'd rather not poll the key states, you can subscribe to specific key combos. First, you'll need to make a handler, such as:

private void OnButtonCombo()

{

// Key combo code goes here

}

Then you can add this code after the keyboard setup code (or elsewhere if desired) to subscribe, such as for Ctrl+Q:

ButtonCombo.ButtonComboHandler buttonComboHandler = new ButtonCombo.ButtonComboHandler(OnButtonCombo);

ButtonCombo buttonCombo = new ButtonCombo(buttonComboHandler, Keys.ControlKey, Keys.Q);

this.m_Keyboard.TrackButtonCombo(buttonCombo);

5. Checking mouse location. You can get the mouse state and location by using IsMouseDown() and MousePoint, respectively. However, be aware that the class doesn't track different mouse buttons (feature hasn't yet been implemented because this class was originally used on the .NET Compact Framework for a Pocket PC game).

this.m_Keyboard.IsMouseDown();

this.m_Keyboard.MousePoint;

6. Getting the mouse drag points. When a mouse button is pressed, the trail it makes is tracked until a mouse button is released. You can get this through GetMouseTrail, such as:

Point[] points = this.m_Keyboard.GetMouseTrail();

foreach (Point point in points)

{

// Do something

}

Here is the class source:

using System;

using System.Drawing;

using System.Windows.Forms;

using System.Text;

using System.Collections;

namespace Utilities

{

/// <summary>

/// Summary description for Keyboard.

/// </summary>

public class Keyboard

{

/// <summary>

/// Enum for whether a given key is down or not

/// </summary>

private enum KeyState { Up, Down }

private bool m_bMouseDown;

private Point m_LastMousePoint;

private ArrayList m_MouseDragPoints;

 

/// <summary>

/// Tracks states of individual keys

/// </summary>

private Hashtable m_KeyStates;

private ArrayList m_ButtonCombos;

/// <summary>

/// Default constructor

/// </summary>

public Keyboard()

{

this.Reset();

}

/// <summary>

/// Resets the keyboard to all keys up

/// </summary>

public void Reset()

{

this.m_KeyStates = new Hashtable();

this.m_ButtonCombos = new ArrayList();

this.m_bMouseDown = false;

this.m_LastMousePoint = new Point(0, 0);

this.m_MouseDragPoints = new ArrayList();

}

public void TrackButtonCombo(ButtonCombo buttonCombo)

{

this.m_ButtonCombos.Add(buttonCombo);

}

/// <summary>

/// A form should have their KeyDown event point directly to this

/// </summary>

/// <param name="sender">The sender raised by the form</param>

/// <param name="e">The event raised by the form</param>

public void KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)

{

this.m_KeyStates[e.KeyCode] = KeyState.Down;

this.CheckButtonCombos();

}

/// <summary>

/// A form should have their KeyUp event point directly to this

///

/// </summary>

/// <param name="sender">The sender raised by the form</param>

/// <param name="e">The event raised by the form</param>

public void KeyUp(object sender, System.Windows.Forms.KeyEventArgs e)

{

this.m_KeyStates[e.KeyCode] = KeyState.Up;

}

/// <summary>

/// Returns the list of all keys currently down

/// </summary>

/// <returns>A newline-delimited list of currently down keys</returns>

public override string ToString()

{

StringBuilder state = new StringBuilder();

// Iterates through the hashtable and adds each down key to the list

IDictionaryEnumerator enumerator = this.m_KeyStates.GetEnumerator();

while (enumerator.MoveNext())

{

if (((KeyState) enumerator.Value) == KeyState.Down)

{

state.AppendFormat(System.Globalization.CultureInfo.InvariantCulture, "{0}\n", ((Keys) enumerator.Key).ToString());

}

}

return state.ToString();

}

/// <summary>

/// Returns the status of the key

/// </summary>

/// <param name="key">The key to check</param>

/// <returns>True if the key is down, false if it is up</returns>

public bool IsKeyDown(Keys key)

{

if (!this.m_KeyStates.ContainsKey(key))

{

this.m_KeyStates.Add(key, KeyState.Up);

return false;

}

return (((KeyState) this.m_KeyStates[key]) == KeyState.Down);

}

/// <summary>

/// Clears the state of the specified key

/// </summary>

/// <param name="key">The key to clear</param>

public void ClearKey(Keys key)

{

this.m_KeyStates[key] = KeyState.Up;

}

/// <summary>

/// Runs through the list of subscribed button combos and checks for success

/// </summary>

public void CheckButtonCombos()

{

foreach (ButtonCombo buttonCombo in this.m_ButtonCombos)

{

buttonCombo.HitTest(this);

}

}

/// <summary>

/// Checks a specific button combo (doesn't require subscription)

/// </summary>

/// <param name="keys">The array of keys to check</param>

/// <returns></returns>

public bool CheckButtonCombo(params Keys[] keys)

{

foreach (Keys key in keys)

{

if (!this.IsKeyDown(key))

{

return false;

}

}

return true;

}

public void MouseDown(object sender, MouseEventArgs e)

{

this.m_bMouseDown = true;

this.m_MouseDragPoints = new ArrayList();

this.m_LastMousePoint = new Point(e.X, e.Y);

this.m_MouseDragPoints.Add(this.m_LastMousePoint);

}

public void MouseUp(object sender, MouseEventArgs e)

{

this.m_MouseDragPoints.Clear();

this.m_LastMousePoint = new Point(0, 0);

this.m_bMouseDown = false;

}

public void MouseMove(object sender, MouseEventArgs e)

{

if (this.m_bMouseDown)

{

this.m_LastMousePoint = new Point(e.X, e.Y);

this.m_MouseDragPoints.Add(this.m_LastMousePoint);

}

}

/// <summary>

/// Returns the state of the mouse (up or down)

/// </summary>

/// <returns>Returns true if the mouse is down</returns>

public bool IsMouseDown()

{

return this.m_bMouseDown;

}

/// <summary>

/// Returns the mouse drag points (all points passed since mouse was down)

/// </summary>

/// <returns>An array of points that represents the mouse path while a button is down</returns>

public Point[] GetMouseTrail()

{

Point[] points = new Point[this.m_MouseDragPoints.Count];

this.m_MouseDragPoints.CopyTo(points);

return points;

}

/// <summary>

/// Gets the last mouse point

/// </summary>

public Point MousePoint { get { return this.m_LastMousePoint; } }

}

public class ButtonCombo

{

public delegate void ButtonComboHandler();

private Keys[] m_Keys;

public ButtonComboHandler m_Handler;

public ButtonCombo(ButtonComboHandler handler, params Keys[] keys)

{

this.m_Keys = new Keys[keys.Length];

for (int lcv = 0; lcv < keys.Length; lcv++)

{

this.m_Keys[lcv] = keys[lcv];

}

this.m_Handler = handler;

}

public bool HitTest(Keyboard keyboard)

{

foreach (Keys key in this.m_Keys)

{

if (!keyboard.IsKeyDown(key))

{

return false;

}

}

this.m_Handler();

return true;

}

}

}

 

Posted: Feb 02 2004, 11:26 PM by EdKaim | with 3 comment(s)
Filed under:
More Posts