我希望增加在XNA游戏中输入西里尔字母的可能性。 我不能使用默认的Input.KeyboardState,因为Input.Keys枚举只包含英文字母。所以,我使用了keyboard-hook来处理Windows输入。但它返回键码,可以用于英文字母(因为ASCII码与键码相匹配),但不适用于西里尔语。对于“a-я”可以使用848偏移量,但对于更具体的字母,如“і”或“ї”,则有不同的值。
有没有有效的方法将密钥代码转换为ASCII格式的西里尔字母?或者也许有没有令人讨厌的键盘钩子的解决方案?
顺便说一下,这里的键盘钩类列表:#region EventArgs
public class CharacterEventArgs : EventArgs
{
private readonly char character;
private readonly int lParam;
private readonly int keyLayout;
public CharacterEventArgs(char character, int lParam, int keyLayout)
{
this.character = character;
this.lParam = lParam;
this.keyLayout = keyLayout;
}
#region Properties
public int KeyLayout
{
get { return keyLayout; }
}
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; }
}
#endregion
}
public class KeyEventArgs : EventArgs
{
private Keys keyCode;
public KeyEventArgs(Keys keyCode)
{
this.keyCode = keyCode;
}
public Keys KeyCode
{
get { return keyCode; }
}
}
#endregion
#region delegats
public delegate void CharEnteredHandler(object sender, CharacterEventArgs e);
public delegate void KeyEventHandler(object sender, KeyEventArgs e);
#endregion
public static class EventInput
{
#region events
/// <summary>
/// Event raised when a character has been entered.
/// </summary>
public static event CharEnteredHandler CharEntered;
/// <summary>
/// Event raised when a key has been pressed down. May fire multiple times due to keyboard repeat.
/// </summary>
public static event KeyEventHandler KeyDown;
/// <summary>
/// Event raised when a key has been released.
/// </summary>
public static event KeyEventHandler KeyUp;
#endregion
delegate IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
static bool initialized;
static IntPtr prevWndProc;
static WndProc hookProcDelegate;
static IntPtr hIMC;
static GameWindow gameWindow;
#region 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 = 0x0281;
const int WM_INPUTLANGCHANGE = 0x51;
const int WM_GETDLGCODE = 0x87;
const int WM_IME_COMPOSITION = 0x10f;
const int DLGC_WANTALLKEYS = 4;
#endregion
#region Win32-functions
//to handle input
[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);
//to get keyboard layout
[DllImport("user32.dll", SetLastError = true)]
static extern int GetWindowThreadProcessId(
[In] IntPtr hWnd,
[Out, Optional] IntPtr lpdwProcessId
);
[DllImport("user32.dll", SetLastError = true)]
static extern ushort GetKeyboardLayout(
[In] int idThread
);
#endregion
static ushort GetKeyboardLayout()
{
return GetKeyboardLayout(GetWindowThreadProcessId(gameWindow.Handle, IntPtr.Zero));
}
#region Initialize
/// <summary>
/// Initialize the TextInput with the given GameWindow.
/// </summary>
/// <param name="window">The XNA window to which text input should be linked.</param>
public static void Initialize(GameWindow window)
{
if (initialized)
throw new InvalidOperationException("TextInput.Initialize can only be called once!");
gameWindow = window;
hookProcDelegate = new WndProc(HookProc);
prevWndProc = (IntPtr)SetWindowLong(window.Handle, GWL_WNDPROC,
(int)Marshal.GetFunctionPointerForDelegate(hookProcDelegate));
hIMC = ImmGetContext(window.Handle);
initialized = true;
}
#endregion
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(), GetKeyboardLayout()));
}
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;
}
}
答案 0 :(得分:2)
您是否考虑过使用Windows窗体进行字符输入?我不会说俄语,但我只能假设KeyPress事件必须在俄语语言环境中正确处理Cyrillic,这比自己抽取Windows消息简单得多。
using System.Windows.Forms;
...
var form = (Form)Form.FromHandle(window.Handle);
form.KeyPress += form_KeyPress;
...
private void form_KeyPress(Object sender, KeyPressEventArgs e)
{
Console.WriteLine(e.KeyChar);
e.Handled = true;
}