[英]Hooked keyboard duplicating input (c# / xna)
我在XNA項目中使用了Keyboard鈎子(使用XNA的任何人都知道內置鍵盤類對於“文本框”樣式鍵入的輸入是多么無用。
在引入表格之前,它可以很好地用於XNA項目。 如果我嘗試在項目中實現任何窗體,無論是自定義窗體,甚至只是OpenFileDialog,窗體文本框內的任何按鍵都會加倍,從而幾乎無法鍵入。
有誰知道我如何才能阻止郵件兩次到達表單? 也許是在我收到消息后就將其丟棄了? 也許有更好的解決方案? 也許這只是無法完成的事情。
任何幫助表示贊賞。
編輯:
下面是我正在使用的鍵盤掛鈎代碼,那些想尋找XNA鍵盤掛鈎的人可能會很熟悉,因為無論我在哪里尋找它,它似乎都會冒出來。
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms; // This class exposes WinForms-style key events.
namespace FatLib.Controls
{
class KeyboardHookInput : IDisposable
{
private string _buffer = "";
private bool _backSpace = false;
private bool _enterKey = false; // I added this to the original code
public string Buffer
{
get { return _buffer; }
}
public bool BackSpace
{
get
{
return _backSpace;
}
}
public bool EnterKey
{
get
{
return _enterKey;
}
}
public void Reset()
{
_buffer = "";
_backSpace = false;
_enterKey = false;
}
public enum HookId
{
// Types of hook that can be installed using the SetWindwsHookEx function.
WH_CALLWNDPROC = 4,
WH_CALLWNDPROCRET = 12,
WH_CBT = 5,
WH_DEBUG = 9,
WH_FOREGROUNDIDLE = 11,
WH_GETMESSAGE = 3,
WH_HARDWARE = 8,
WH_JOURNALPLAYBACK = 1,
WH_JOURNALRECORD = 0,
WH_KEYBOARD = 2,
WH_KEYBOARD_LL = 13,
WH_MAX = 11,
WH_MAXHOOK = WH_MAX,
WH_MIN = -1,
WH_MINHOOK = WH_MIN,
WH_MOUSE_LL = 14,
WH_MSGFILTER = -1,
WH_SHELL = 10,
WH_SYSMSGFILTER = 6,
};
public enum WindowMessage
{
// Window message types.
WM_KEYDOWN = 0x100,
WM_KEYUP = 0x101,
WM_CHAR = 0x102,
};
// A delegate used to create a hook callback.
public delegate int GetMsgProc(int nCode, int wParam, ref Message msg);
/// <summary>
/// Install an application-defined hook procedure into a hook chain.
/// </summary>
/// <param name="idHook">Specifies the type of hook procedure to be installed.</param>
/// <param name="lpfn">Pointer to the hook procedure.</param>
/// <param name="hmod">Handle to the DLL containing the hook procedure pointed to by the lpfn parameter.</param>
/// <param name="dwThreadId">Specifies the identifier of the thread with which the hook procedure is to be associated.</param>
/// <returns>If the function succeeds, the return value is the handle to the hook procedure. Otherwise returns 0.</returns>
[DllImport("user32.dll", EntryPoint = "SetWindowsHookExA")]
public static extern IntPtr SetWindowsHookEx(HookId idHook, GetMsgProc lpfn, IntPtr hmod, int dwThreadId);
/// <summary>
/// Removes a hook procedure installed in a hook chain by the SetWindowsHookEx function.
/// </summary>
/// <param name="hHook">Handle to the hook to be removed. This parameter is a hook handle obtained by a previous call to SetWindowsHookEx.</param>
/// <returns>If the function fails, the return value is zero. To get extended error information, call GetLastError.</returns>
[DllImport("user32.dll")]
public static extern int UnhookWindowsHookEx(IntPtr hHook);
/// <summary>
/// Passes the hook information to the next hook procedure in the current hook chain.
/// </summary>
/// <param name="hHook">Ignored.</param>
/// <param name="ncode">Specifies the hook code passed to the current hook procedure.</param>
/// <param name="wParam">Specifies the wParam value passed to the current hook procedure.</param>
/// <param name="lParam">Specifies the lParam value passed to the current hook procedure.</param>
/// <returns>This value is returned by the next hook procedure in the chain.</returns>
[DllImport("user32.dll")]
public static extern int CallNextHookEx(int hHook, int ncode, int wParam, ref Message lParam);
/// <summary>
/// Translates virtual-key messages into character messages.
/// </summary>
/// <param name="lpMsg">Pointer to an Message structure that contains message information retrieved from the calling thread's message queue.</param>
/// <returns>If the message is translated (that is, a character message is posted to the thread's message queue), the return value is true.</returns>
[DllImport("user32.dll")]
public static extern bool TranslateMessage(ref Message lpMsg);
/// <summary>
/// Retrieves the thread identifier of the calling thread.
/// </summary>
/// <returns>The thread identifier of the calling thread.</returns>
[DllImport("kernel32.dll")]
public static extern int GetCurrentThreadId();
// Handle for the created hook.
private readonly IntPtr HookHandle;
private readonly GetMsgProc ProcessMessagesCallback;
public KeyboardHookInput()
{
// Create the delegate callback:
this.ProcessMessagesCallback = new GetMsgProc(ProcessMessages);
// Create the keyboard hook:
this.HookHandle = SetWindowsHookEx(HookId.WH_KEYBOARD, this.ProcessMessagesCallback, IntPtr.Zero, GetCurrentThreadId());
}
public void Dispose()
{
// Remove the hook.
if (HookHandle != IntPtr.Zero) UnhookWindowsHookEx(HookHandle);
}
// comments found in this region are all from the original author: Darg.
private int ProcessMessages(int nCode, int wParam, ref Message msg)
{
// Check if we must process this message (and whether it has been retrieved via GetMessage):
if (nCode == 0 && wParam == 1)
{
// We need character input, so use TranslateMessage to generate WM_CHAR messages.
TranslateMessage(ref msg);
// If it's one of the keyboard-related messages, raise an event for it:
switch ((WindowMessage)msg.Msg)
{
case WindowMessage.WM_CHAR:
this.OnKeyPress(new KeyPressEventArgs((char)msg.WParam));
break;
case WindowMessage.WM_KEYDOWN:
this.OnKeyDown(new KeyEventArgs((Keys)msg.WParam));
break;
case WindowMessage.WM_KEYUP:
this.OnKeyUp(new KeyEventArgs((Keys)msg.WParam));
break;
}
}
// Call next hook in chain:
return CallNextHookEx(0, nCode, wParam, ref msg);
}
public event KeyEventHandler KeyUp;
protected virtual void OnKeyUp(KeyEventArgs e)
{
if (KeyUp != null) KeyUp(this, e);
}
public event KeyEventHandler KeyDown;
protected virtual void OnKeyDown(KeyEventArgs e)
{
if (KeyDown != null) KeyDown(this, e);
}
public event KeyPressEventHandler KeyPress;
protected virtual void OnKeyPress(KeyPressEventArgs e)
{
if (KeyPress != null) KeyPress(this, e);
if (e.KeyChar.GetHashCode().ToString() == "524296")
{
_backSpace = true;
}
else if (e.KeyChar == (char)Keys.Enter)
{
_enterKey = true;
}
else
{
_buffer += e.KeyChar;
}
}
}
}
由於XNA中必須有一個表單( GraphicsDevice
需要它),因此您將有2個選項,具體取決於您的庫用戶是創建表單(帶有XNA的winforms項目進行渲染),還是將表單創建為創建普通XNA游戲的結果。
在winforms情況下,您只可以處理關鍵事件,完成工作。
在標准XNA游戲情況下,您可以讓用戶傳遞圖形設備創建的窗口的句柄,然后在調用OnKey...
方法之前,檢查窗口是否具有焦點。
在兩種情況下,您都可以使用2nd選項,以使其更簡單。 庫的用戶將傳遞窗口的句柄以在KeyboardHookInput
構造函數中接收/緩沖按鍵。 然后,您將首先檢查窗口是否具有焦點(請參見此處: 如何確定窗口是否具有焦點?(Win32 API) )。
Windows Hook是獲取所有按鍵的一種非常討厭的方式,並且絕對是不得已的手段。
嘗試在您的應用程序中安裝消息過濾器 ,它可以監視發送到您的應用程序的所有鍵盤消息(WM_KEYPRESS,KEYUP,KEYDOWN等),而不會干擾其他應用程序。 如果需要,過濾器還可以使您停止到達應用程序中任何形式的任何消息。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.