using System; using System.Runtime.InteropServices; using System.Text; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Input; namespace EventInput { #if WINDOWS public class KeyboardLayout { const uint KLF_ACTIVATE = 1; //activate the layout const int KL_NAMELENGTH = 9; // length of the keyboard buffer const string LANG_EN_US = "00000409"; const string LANG_HE_IL = "0001101A"; [DllImport("user32.dll")] private static extern long LoadKeyboardLayout( string pwszKLID, // input locale identifier uint Flags // input locale identifier options ); [DllImport("user32.dll")] private static extern long GetKeyboardLayoutName( StringBuilder pwszKLID //[out] string that receives the name of the locale identifier ); public static string getName() { StringBuilder name = new StringBuilder(KL_NAMELENGTH); GetKeyboardLayoutName(name); return name.ToString(); } } #endif 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 delegate void CharEnteredHandler(object sender, CharacterEventArgs e); public delegate void KeyEventHandler(object sender, KeyEventArgs e); public static class EventInput { /// /// Event raised when a Character has been entered. /// public static event CharEnteredHandler CharEntered; /// /// Event raised when a key has been pressed down. May fire multiple times due to keyboard repeat. /// public static event KeyEventHandler KeyDown; /// /// Event raised when a key has been released. /// public static event KeyEventHandler KeyUp; static bool initialized; #if WINDOWS delegate IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam); static IntPtr prevWndProc; static WndProc hookProcDelegate; static IntPtr hIMC; //various Win32 constants that we need 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 = 0x0281; const int WM_INPUTLANGCHANGE = 0x51; const int WM_GETDLGCODE = 0x87; const int WM_IME_COMPOSITION = 0x10f; const int DLGC_WANTALLKEYS = 4; //Win32 functions that we're using [DllImport("Imm32.dll", CharSet = CharSet.Unicode)] static extern IntPtr ImmGetContext(IntPtr hWnd); [DllImport("Imm32.dll", CharSet = CharSet.Unicode)] static extern IntPtr ImmAssociateContext(IntPtr hWnd, IntPtr hIMC); [DllImport("user32.dll", CharSet = CharSet.Unicode)] static extern IntPtr CallWindowProc(IntPtr lpPrevWndFunc, IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam); [DllImport("user32.dll", CharSet = CharSet.Unicode)] static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong); #endif /// /// Initialize the TextInput with the given GameWindow. /// /// The XNA window to which text input should be linked. public static void Initialize(GameWindow window) { if (initialized) { return; } #if WINDOWS hookProcDelegate = HookProc; prevWndProc = (IntPtr)SetWindowLong(window.Handle, GWL_WNDPROC, (int)Marshal.GetFunctionPointerForDelegate(hookProcDelegate)); hIMC = ImmGetContext(window.Handle); #else window.TextInput += ReceiveInput; #endif initialized = true; } private static void ReceiveInput(object sender, TextInputEventArgs e) { OnCharEntered(e.Character); } public static void OnCharEntered(char character) { if (CharEntered != null) CharEntered(null, new CharacterEventArgs(character, 0)); } #if WINDOWS 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; } return returnCode; } #endif } }