c# - XNA - 键盘文本输入

标签 c# .net xna

好的,基本上我希望能够检索键盘文本。就像在文本字段中输入文本之类的。我只是在为 Windows 编写游戏。 我忽略了使用 Guide.BeginShowKeyboardInput,因为它打破了独立游戏的感觉,而且 Guide 总是显示 XBOX 按钮这一事实对我来说也不合适。是的,这是最简单的方法,但我不喜欢它。

接下来我尝试使用 System.Windows.Forms.NativeWindow。我创建了一个继承自它的类,并将游戏窗口句柄传递给它,实现了 WndProc 函数以捕获 WM_CHAR(或 WM_KEYDOWN),尽管 WndProc 被调用以获取其他消息,WM_CHAR 和 WM_KEYDOWN 从未这样做过。所以我不得不放弃这个想法,此外,我还引用了整个 Windows 窗体,这意味着不必要的内存占用膨胀。

所以我最后的想法是创建一个线程级别的低级别键盘 Hook 。这是迄今为止最成功的。我收到 WM_KEYDOWN 消息,(尚未尝试 WM_CHAR)将具有 Win32 函数 MapVirtualKey 的虚拟键码转换为字符。我收到了我的短信! (我现在只是用 Debug.Write 打印)

不过有几个问题。就好像我打开了大写锁定键和一个无响应的 shift 键。 (当然不是,只是每个键只有一个虚拟键码,所以翻译它只有一个输出)并且它增加了开销,因为它附加到 Windows Hook 列表并且没有我那么快'我希望如此,但速度缓慢可能更多是由于 Debug.Write。

有没有其他人在无需借助屏幕键盘的情况下接近并解决了这个问题?或者有人有进一步的想法让我尝试吗?

提前致谢。

吉米问的问题

Maybe I'm not understanding the question, but why can't you use the XNA Keyboard and KeyboardState classes?

我的评论:

It's because though you can read keystates, you can't get access to typed text as and how it is typed by the user.

所以让我进一步澄清。我想实现能够读取用户输入的文本,就好像他们在窗口中输入文本框一样。 keyboard 和 KeyboardState 类获取所有键的状态,但我必须将每个键和组合映射到它的字符表示。当用户使用的键盘语言与我不同,尤其是符号(我的双引号是 shift + 2,而美式键盘在返回键附近有他们的双引号)时,这会失败。


看来我的窗口钩子(Hook)是可行的方法,我没有得到 WM_CHAR 的原因是 XNA 消息泵不翻译消息。

每当我收到 WM_KEYDOWN 消息时添加 TranslateMessage 意味着我收到了 WM_CHAR 消息,然后我使用它在我的 KeyboardBuffer 类订阅的 MessageHook 类中触发一个字符类型事件,然后将其缓冲到文本缓冲区 :D(或 StringBuilder,但结果相同)

所以我让一切都按我想要的方式工作。

非常感谢 Jimmy 提供了指向非常有用的线程的链接。

最佳答案

在 XNA 中添加一个 windows 钩子(Hook)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Reflection;

/* Author: Sekhat
 * 
 * License: Public Domain.
 * 
 * Usage:
 *
 * Inherit from this class, and override the WndProc function in your derived class, 
 * in which you handle your windows messages.
 * 
 * To start recieving the message, create an instance of your derived class, passing in the
 * window handle of the window you want to listen for messages for.
 * 
 * in XNA: this would be the Game.Window.Handle property
 * in Winforms Form.Handle property
 */

namespace WindowsHookExample
{
    public abstract class WindowsHook : IDisposable
    {
        IntPtr hHook;
        IntPtr hWnd;
        // Stored here to stop it from getting garbage collected
        Win32.WndProcDelegate wndProcDelegate;

        public WindowsHook(IntPtr hWnd)
        {
            this.hWnd = hWnd;

            wndProcDelegate = WndProcHook;

            CreateHook();
        }

        ~WindowsHook()
        {
            Dispose(false);
        }

        private void CreateHook()
        {

            uint threadId = Win32.GetWindowThreadProcessId(hWnd, IntPtr.Zero);

            hHook = Win32.SetWindowsHookEx(Win32.HookType.WH_CALLWNDPROC, wndProcDelegate, IntPtr.Zero, threadId);

        }

        private int WndProcHook(int nCode, IntPtr wParam, ref Win32.Message lParam)
        {
            if (nCode >= 0)
            {
                Win32.TranslateMessage(ref lParam); // You may want to remove this line, if you find your not quite getting the right messages through. This is here so that WM_CHAR is correctly called when a key is pressed.
                WndProc(ref lParam);
            }

            return Win32.CallNextHookEx(hHook, nCode, wParam, ref lParam);
        }

        protected abstract void WndProc(ref Win32.Message message);

        #region Interop Stuff
        // I say thankya to P/Invoke.net.
        // Contains all the Win32 functions I need to deal with
        protected static class Win32
        {
            public enum HookType : int
            {
                WH_JOURNALRECORD = 0,
                WH_JOURNALPLAYBACK = 1,
                WH_KEYBOARD = 2,
                WH_GETMESSAGE = 3,
                WH_CALLWNDPROC = 4,
                WH_CBT = 5,
                WH_SYSMSGFILTER = 6,
                WH_MOUSE = 7,
                WH_HARDWARE = 8,
                WH_DEBUG = 9,
                WH_SHELL = 10,
                WH_FOREGROUNDIDLE = 11,
                WH_CALLWNDPROCRET = 12,
                WH_KEYBOARD_LL = 13,
                WH_MOUSE_LL = 14
            }

            public struct Message
            {
                public IntPtr lparam;
                public IntPtr wparam;
                public uint msg;
                public IntPtr hWnd;
            }

            /// <summary>
            ///  Defines the windows proc delegate to pass into the windows hook
            /// </summary>                  
            public delegate int WndProcDelegate(int nCode, IntPtr wParam, ref Message m);

            [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
            public static extern IntPtr SetWindowsHookEx(HookType hook, WndProcDelegate callback,
                IntPtr hMod, uint dwThreadId);

            [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
            public static extern bool UnhookWindowsHookEx(IntPtr hhk);

            [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
            public static extern int CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, ref Message m);

            [DllImport("coredll.dll", SetLastError = true)]
            public static extern IntPtr GetModuleHandle(string module);

            [DllImport("user32.dll", EntryPoint = "TranslateMessage")]
            public extern static bool TranslateMessage(ref Message m);

            [DllImport("user32.dll")]
            public extern static uint GetWindowThreadProcessId(IntPtr window, IntPtr module);
        }
        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            Dispose(true);
        }

        private void Dispose(bool disposing)
        {
            if (disposing)
            {
                // Free managed resources here
            }
            // Free unmanaged resources here
            if (hHook != IntPtr.Zero)
            {
                Win32.UnhookWindowsHookEx(hHook);
            }
        }

        #endregion
    }
}

关于c# - XNA - 键盘文本输入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/375316/

相关文章:

c# - 如何获取不属于我的应用程序的事件窗口?

c# - SpriteBatch.DrawString 中原点和位置参数的区别

c# - 在每个大小为 150 MB 的多个文本文件中搜索字符串 C#

c# - 使用 azure-sdk-for-net 将大型 blob 上传到 azure 超时

c# - 正在保存上传的文件 - 进程无法访问

c# - 同一个 ResourceDictionary 的多个实例

c# - c#中重定向stdout的问题

c# - .net MVC Controller 如何解析参数

c# - 编译 XNA 项目时无法执行请求的操作错误

c# - C# 中的二进制序列化 - 附加到文件