Here's Promit's event driven system updated with mouse handling. Note: This also fixed all my problems with the touch sensor and Wacom Pen on my tablet PC.
using System;
using System.Runtime.InteropServices;
namespace Microsoft.Xna.Framework.Input
{
public class CharacterEventArgs : EventArgs
{
private readonly char character;
private readonly int lParam;
public CharacterEventArgs(char character, int lParam)
{
this.character = character;
this.lParam = lParam;
}
public char Character
{
get { return character; }
}
public int Param
{
get { return lParam; }
}
public int RepeatCount
{
get { return lParam & 0xffff; }
}
public bool ExtendedKey
{
get { return (lParam & (1 << 24)) > 0; }
}
public bool AltPressed
{
get { return (lParam & (1 << 29)) > 0; }
}
public bool PreviousState
{
get { return (lParam & (1 << 30)) > 0; }
}
public bool TransitionState
{
get { return (lParam & (1 << 31)) > 0; }
}
}
public class KeyEventArgs : EventArgs
{
private Keys keyCode;
public KeyEventArgs(Keys keyCode)
{
this.keyCode = keyCode;
}
public Keys KeyCode
{
get { return keyCode; }
}
}
public class MouseEventArgs : EventArgs
{
private MouseButton button;
private int clicks;
private int x;
private int y;
private int delta;
public MouseButton Button { get { return button; } }
public int Clicks { get { return clicks; } }
public int X { get { return x; } }
public int Y { get { return y; } }
public Point Location { get { return new Point(x,y); } }
public int Delta { get { return delta; } }
public MouseEventArgs(MouseButton button, int clicks, int x, int y, int delta)
{
this.button = button;
this.clicks = clicks;
this.x = x;
this.y = y;
this.delta = delta;
}
}
public delegate void CharEnteredHandler(object sender, CharacterEventArgs e);
public delegate void KeyEventHandler(object sender, KeyEventArgs e);
public delegate void MouseEventHandler(object sender, MouseEventArgs e);
[Flags]
public enum MouseKeys
{
LButton = 0x01,
RButton = 0x02,
Shift = 0x04,
Control = 0x08,
MButton = 0x10,
XButton1 = 0x20,
XButton2 = 0x40
}
public enum MouseButton
{
None, Left, Right, Middle, X1, X2
}
public static class InputSystem
{
#region Events
public static event CharEnteredHandler CharEntered;
public static event KeyEventHandler KeyDown;
public static event KeyEventHandler KeyUp;
public static event MouseEventHandler MouseDown;
public static event MouseEventHandler MouseUp;
public static event MouseEventHandler MouseMove;
public static event MouseEventHandler MouseHover;
public static event MouseEventHandler MouseWheel;
public static event MouseEventHandler MouseDoubleClick;
#endregion
delegate IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
static bool initialized;
static IntPtr prevWndProc;
static WndProc hookProcDelegate;
static IntPtr hIMC;
#region Win32 Constants
const int GWL_WNDPROC = -4;
const int WM_KEYDOWN = 0x100;
const int WM_KEYUP = 0x101;
const int WM_CHAR = 0x102;
const int WM_IME_SETCONTEXT = 0x281;
const int WM_INPUTLANGCHANGE = 0x51;
const int WM_GETDLGCODE = 0x87;
const int WM_IME_COMPOSITION = 0x10F;
const int DLGC_WANTALLKEYS = 4;
const int WM_MOUSEMOVE = 0x200;
const int WM_LBUTTONDOWN = 0x201;
const int WM_LBUTTONUP = 0x202;
const int WM_LBUTTONDBLCLK = 0x203;
const int WM_RBUTTONDOWN = 0x204;
const int WM_RBUTTONUP = 0x205;
const int WM_RBUTTONDBLCLK = 0x206;
const int WM_MBUTTONDOWN = 0x207;
const int WM_MBUTTONUP = 0x208;
const int WM_MBUTTONDBLCLK = 0x209;
const int WM_MOUSEWHEEL = 0x20A;
const int WM_XBUTTONDOWN = 0x20B;
const int WM_XBUTTONUP = 0x20C;
const int WM_XBUTTONDBLCLK = 0x20D;
const int WM_MOUSEHOVER = 0x2A1;
#endregion
#region DLL Imports
[DllImport("Imm32.dll")]
static extern IntPtr ImmGetContext(IntPtr hWnd);
[DllImport("Imm32.dll")]
static extern IntPtr ImmAssociateContext(IntPtr hWnd, IntPtr hIMC);
[DllImport("user32.dll")]
static extern IntPtr CallWindowProc(IntPtr lpPrevWndFunc, IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
#endregion
public static Point MouseLocation
{
get
{
MouseState state = Mouse.GetState();
return new Point(state.X, state.Y);
}
}
public static bool ShiftDown
{
get
{
KeyboardState state = Keyboard.GetState();
return state.IsKeyDown(Keys.LeftShift) || state.IsKeyDown(Keys.RightShift);
}
}
public static bool CtrlDown
{
get
{
KeyboardState state = Keyboard.GetState();
return state.IsKeyDown(Keys.LeftControl) || state.IsKeyDown(Keys.RightControl);
}
}
public static bool AltDown
{
get
{
KeyboardState state = Keyboard.GetState();
return state.IsKeyDown(Keys.LeftAlt) || state.IsKeyDown(Keys.RightAlt);
}
}
public static void Initialize(GameWindow window)
{
if (initialized)
throw new InvalidOperationException("TextInput.Initialize can only be called once!");
hookProcDelegate = new WndProc(HookProc);
prevWndProc = (IntPtr)SetWindowLong(window.Handle, GWL_WNDPROC, (int)Marshal.GetFunctionPointerForDelegate(hookProcDelegate));
hIMC = ImmGetContext(window.Handle);
initialized = true;
}
static IntPtr HookProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam)
{
IntPtr returnCode = CallWindowProc(prevWndProc, hWnd, msg, wParam, lParam);
switch (msg)
{
case WM_GETDLGCODE:
returnCode = (IntPtr)(returnCode.ToInt32() | DLGC_WANTALLKEYS);
break;
case WM_KEYDOWN:
if (KeyDown != null)
KeyDown(null, new KeyEventArgs((Keys)wParam));
break;
case WM_KEYUP:
if (KeyUp != null)
KeyUp(null, new KeyEventArgs((Keys)wParam));
break;
case WM_CHAR:
if (CharEntered != null)
CharEntered(null, new CharacterEventArgs((char)wParam, lParam.ToInt32()));
break;
case WM_IME_SETCONTEXT:
if (wParam.ToInt32() == 1)
ImmAssociateContext(hWnd, hIMC);
break;
case WM_INPUTLANGCHANGE:
ImmAssociateContext(hWnd, hIMC);
returnCode = (IntPtr)1;
break;
case WM_MOUSEMOVE:
if (MouseMove != null)
{
short x, y;
MouseLocationFromLParam(lParam.ToInt32(), out x, out y);
MouseMove(null, new MouseEventArgs(MouseButton.None, 0, x, y, 0));
}
break;
case WM_MOUSEHOVER:
if (MouseHover != null)
{
short x, y;
MouseLocationFromLParam(lParam.ToInt32(), out x, out y);
MouseHover(null, new MouseEventArgs(MouseButton.None, 0, x, y, 0));
}
break;
case WM_MOUSEWHEEL:
if (MouseWheel != null)
{
short x, y;
MouseLocationFromLParam(lParam.ToInt32(), out x, out y);
MouseWheel(null, new MouseEventArgs(MouseButton.None, 0, x, y, (wParam.ToInt32() >> 16) / 120));
}
break;
case WM_LBUTTONDOWN: RaiseMouseDownEvent (MouseButton.Left, wParam.ToInt32(), lParam.ToInt32()); break;
case WM_LBUTTONUP: RaiseMouseUpEvent (MouseButton.Left, wParam.ToInt32(), lParam.ToInt32()); break;
case WM_LBUTTONDBLCLK: RaiseMouseDblClickEvent(MouseButton.Left, wParam.ToInt32(), lParam.ToInt32()); break;
case WM_RBUTTONDOWN: RaiseMouseDownEvent (MouseButton.Right, wParam.ToInt32(), lParam.ToInt32()); break;
case WM_RBUTTONUP: RaiseMouseUpEvent (MouseButton.Right, wParam.ToInt32(), lParam.ToInt32()); break;
case WM_RBUTTONDBLCLK: RaiseMouseDblClickEvent(MouseButton.Right, wParam.ToInt32(), lParam.ToInt32()); break;
case WM_MBUTTONDOWN: RaiseMouseDownEvent (MouseButton.Middle, wParam.ToInt32(), lParam.ToInt32()); break;
case WM_MBUTTONUP: RaiseMouseUpEvent (MouseButton.Middle, wParam.ToInt32(), lParam.ToInt32()); break;
case WM_MBUTTONDBLCLK: RaiseMouseDblClickEvent(MouseButton.Middle, wParam.ToInt32(), lParam.ToInt32()); break;
case WM_XBUTTONDOWN:
if ((wParam.ToInt32() & 0x10000) != 0)
{
RaiseMouseDownEvent(MouseButton.X1, wParam.ToInt32(), lParam.ToInt32());
}
else if ((wParam.ToInt32() & 0x20000) != 0)
{
RaiseMouseDownEvent(MouseButton.X2, wParam.ToInt32(), lParam.ToInt32());
}
break;
case WM_XBUTTONUP:
if ((wParam.ToInt32() & 0x10000) != 0)
{
RaiseMouseUpEvent(MouseButton.X1, wParam.ToInt32(), lParam.ToInt32());
}
else if ((wParam.ToInt32() & 0x20000) != 0)
{
RaiseMouseUpEvent(MouseButton.X2, wParam.ToInt32(), lParam.ToInt32());
}
break;
case WM_XBUTTONDBLCLK:
if ((wParam.ToInt32() & 0x10000) != 0)
{
RaiseMouseDblClickEvent(MouseButton.X1, wParam.ToInt32(), lParam.ToInt32());
}
else if ((wParam.ToInt32() & 0x20000) != 0)
{
RaiseMouseDblClickEvent(MouseButton.X2, wParam.ToInt32(), lParam.ToInt32());
}
break;
}
return returnCode;
}
#region Mouse Message Helpers
static void RaiseMouseDownEvent(MouseButton button, int wParam, int lParam)
{
if (MouseDown != null)
{
short x, y;
MouseLocationFromLParam(lParam, out x, out y);
MouseDown(null, new MouseEventArgs(button, 1, x, y, 0));
}
}
static void RaiseMouseUpEvent(MouseButton button, int wParam, int lParam)
{
if (MouseUp != null)
{
short x, y;
MouseLocationFromLParam(lParam, out x, out y);
MouseUp(null, new MouseEventArgs(button, 1, x, y, 0));
}
}
static void RaiseMouseDblClickEvent(MouseButton button, int wParam, int lParam)
{
if (MouseDoubleClick != null)
{
short x, y;
MouseLocationFromLParam(lParam, out x, out y);
MouseDoubleClick(null, new MouseEventArgs(button, 1, x, y, 0));
}
}
static void MouseLocationFromLParam(int lParam, out short x, out short y)
{
x = (short)(lParam & 0xFFFF);
y = (short)(lParam >> 16);
}
#endregion
}
}