当前位置:  开发笔记 > 编程语言 > 正文

XNA - 键盘文本输入

如何解决《XNA-键盘文本输入》经验,为你挑选了1个好方法。

好的,基本上我希望能够检索键盘文本.就像将文本输入文本字段或其他内容一样.我只是为Windows编写游戏.我忽略了使用Guide.BeginShowKeyboardInput,因为它打破了自包含游戏的感觉,而且指南总是显示XBOX按钮的事实对我来说也不合适.是的,这是最简单的方法,但我不喜欢它.

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

所以我的最后一个想法是创建一个Thread级别的低级键盘钩子.到目前为止,这是最成功的.我收到WM_KEYDOWN消息,(还没试过WM_CHAR)将虚拟键码与Win32函数MapVirtualKey一起转换为char.我收到了我的文字!(我现在只是用Debug.Write打印)

但是有几个问题.好像我有大写锁定,并且没有响应的移位键.(当然不是,它只是每个键只有一个虚拟键代码,所以只翻译它有一个输出)并且它增加了开销,因为它将自己附加到Windows Hook列表并且没有我那么快d喜欢它,但缓慢可能更多是由于Debug.Write.

有没有其他人接近这个并解决它,而不必求助于屏幕键盘?还是有人有进一步的想法让我尝试?

提前致谢.

吉米问的问题

也许我不理解这个问题,但为什么你不能使用XNA Keyboard和KeyboardState类?

我的评论:

这是因为虽然您可以读取键状态,但您无法访问键入的文本以及用户键入的方式.

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


似乎我的窗口挂钩是要走的路,只是我没有得到WM_CHAR的原因是因为XNA消息泵不做翻译消息.

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

所以我按照自己的意愿工作.

非常感谢Jimmy提供了一个非常丰富的线索链接.



1> Sekhat..:

用于在XNA中添加Windows挂钩

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;
            }

            /// 
            ///  Defines the windows proc delegate to pass into the windows hook
            ///                   
            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
    }
}

推荐阅读
coco2冰冰
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有