MonoGame (Windows/Ubuntu) 中的跨平台文本框输入

Posted

技术标签:

【中文标题】MonoGame (Windows/Ubuntu) 中的跨平台文本框输入【英文标题】:Cross-platform textbox input in MonoGame (Windows/Ubuntu) 【发布时间】:2016-02-04 20:17:24 【问题描述】:

我正在开发一款使用 MonoGame 的桌面平台游戏。以前,它只针对 Windows 并使用纯 XNA。我正在探索使用 MonoGame 使其支持其他平台的选项,我当前的备用测试平台是 Ubuntu 15.04。

游戏的一项功能是支持与标准 Windows UI 文本框控件类似的文本框。为了实现这一点,我使用了来自this *** answer 的代码。

我的问题是:如何从链接的答案中编写可移植版本的功能,使其可以在其他桌面平台(在本例中为 Ubuntu)上运行?我正在寻找能够从 Windows 和 Ubuntu 上的游戏窗口捕获按键事件的东西。

其他信息:

链接的答案会覆盖游戏窗口的WndProc,并通过触发事件(CharEnteredKeyDownKeyUp)将输入传递到当前文本框。我已将答案的代码重构到可以将所有 Windows 功能封装在单个“事件”类中的程度:

internal class Win32KeyboardEvents : IKeyboardEvents

    public event CharEnteredHandler CharEntered;
    public event KeyEventHandler KeyDown;
    public event KeyEventHandler KeyUp;

    private readonly IntPtr _prevWndProc;
    private readonly NativeMethods.WndProc _hookProcDelegate;

    public Win32KeyboardEvents(GameWindow window)
    
        _hookProcDelegate = HookProc;
        _prevWndProc = (IntPtr)NativeMethods.SetWindowLong(window.Handle, NativeMethods.GWL_WNDPROC,
            (int)Marshal.GetFunctionPointerForDelegate(_hookProcDelegate));
    

    private IntPtr HookProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam)
    
        IntPtr returnCode = NativeMethods.CallWindowProc(_prevWndProc, hWnd, msg, wParam, lParam);

        switch (msg)
        
            case NativeMethods.WM_GETDLGCODE:
                returnCode = (IntPtr)(returnCode.ToInt32() | NativeMethods.DLGC_WANTALLKEYS);
                break;

            case NativeMethods.WM_KEYDOWN:
                if (KeyDown != null) //fire events that are subscribed to by textbox object based on which windows message is received
                    KeyDown(null, new XNAKeyEventArgs((Keys)wParam));
                break;

            case NativeMethods.WM_KEYUP:
                if (KeyUp != null)
                    KeyUp(null, new XNAKeyEventArgs((Keys)wParam));
                break;

            case NativeMethods.WM_CHAR:
                if (CharEntered != null)
                    CharEntered(null, new Win32CharEnteredEventArgs((char)wParam, lParam.ToInt32()));
                break;
        

        return returnCode;
    

我第一次尝试在 Ubuntu 上运行的东西是创建一个 GameComponent 派生对象,它在组件的 Update() 中侦听键盘输入并适当地触发事件,但这很快就变得太复杂了。

我已经使用 GTK# 进行了调查,但有很多依赖项我不想安装,除非 GTK# 是最好的方法。这是我的 GTK# 尝试,由于缺少依赖项,目前尚未测试:

internal class CrossPlatformKeyboardEvents : DrawingArea, IKeyboardEvents

    public event CharEnteredHandler CharEntered = delegate  ;
    public event KeyEventHandler KeyDown = delegate  ;
    public event KeyEventHandler KeyUp = delegate  ;

    public CrossPlatformKeyboardEvents()
    
        Application.Init();
        Application.Run();

        AddEvents((int)EventMask.KeyPressMask);
        AddEvents((int)EventMask.KeyReleaseMask);
    

    [ConnectBefore]
    protected override bool OnKeyPressEvent(EventKey evnt)
    
        if (IsPastEvent(evnt))
        
            CharEntered(null, new CharEnteredEventArgs(KeyboardDispatcher.CHAR_PASTE_CODE));
            return base.OnKeyPressEvent(evnt);
        

        switch (evnt.Key)
        
            case Key.Return:
                CharEntered(null, new CharEnteredEventArgs(KeyboardDispatcher.CHAR_RETURNKEY_CODE));
                break;
            case Key.BackSpace:
                CharEntered(null, new CharEnteredEventArgs(KeyboardDispatcher.CHAR_BACKSPACE_CODE));
                break;
            case Key.Tab:
                CharEntered(null, new CharEnteredEventArgs(KeyboardDispatcher.CHAR_TAB_CODE));
                break;
        

        var keyCode = GetXNAKey(evnt.Key);
        if (keyCode != Keys.None)
            KeyDown(null, new XNAKeyEventArgs(keyCode));

        return base.OnKeyPressEvent(evnt);
    

    [ConnectBefore]
    protected override bool OnKeyReleaseEvent(EventKey evnt)
    
        var keyCode = GetXNAKey(evnt.Key);
        if (keyCode != Keys.None)
            KeyUp(null, new XNAKeyEventArgs(keyCode));
        return base.OnKeyReleaseEvent(evnt);
    

    private bool IsPastEvent(EventKey evnt)
    
        return (evnt.State & ModifierType.ControlMask) > 0 && (evnt.Key == Key.V || evnt.Key == Key.v);
    

    private Keys GetXNAKey(Key key)
    
        if ((key >= Key.Key_0 && key <= Key.Key_9) ||
            (key >= Key.A && key <= Key.Z))
        
            return (Keys) key;
        
        if (key >= Key.a && key <= Key.z)
        
            return (Keys) (key - 32);
        

        return Keys.None;
        //switch (key)
        //

        //
    

【问题讨论】:

您无法重新创建该代码,它使用显式的 Windows API 调用。取而代之的是,如果您要为 monogame 重写代码,请尝试仅使用 OpenTK,然后您可以使用 Gwen .net 之类的界面 @Gusman 也许我不清楚,我知道我无法准确地重新创建该代码。我想一个更好的词选择是我试图以与平台无关的方式模拟 Windows 功能,并且不知道如何在 Linux 平台上做到这一点。我会研究 OpenTK 和 Gwen.net,我对这两个都不熟悉。 【参考方案1】:

我通过在 MonoGame 中使用 TextInput event on GameWindow 解决了这个问题。

这是一个扩展,它是 MonoGame 的一部分,但不是 Xna 的一部分。目前,我有 2 个项目 - 一个用于标准 Xna,一个用于 Monogame。 Monogame 项目具有指向我 Xna 项目中所有文件的链接,因此它们共享相同的代码。

由于我的项目的设置方式,我还必须添加一个编译器标志 (MONO),以排除此代码为标准 XNA 编译。

完整课程(替换问题中发布的 CrossPlatformKeyboardEvents):

internal sealed class MonoGameKeyboardEvents : IKeyboardEvents

    public event CharEnteredHandler CharEntered;

    private readonly GameWindow _window;

    public MonoGameKeyboardEvents(GameWindow window)
    
        _window = window;
#if !MONO
        if (CharEntered != null) //hide warning for "member is not used"
            CharEntered(null, null);
#else
        _window.TextInput += GameWindow_TextInput;
#endif
    

#if MONO
    private void GameWindow_TextInput(object sender, TextInputEventArgs e)
    
        if (CharEntered != null)
        
            CharEntered(null, new CharEnteredEventArgs(e.Character));
        
    

    ~MonoGameKeyboardEvents()
    
        Dispose(false);
    
#endif

    public void Dispose()
    
#if !MONO
    
#else
        Dispose(true);
    

    private void Dispose(bool disposing)
    
        if (!disposing) return;

        _window.TextInput -= GameWindow_TextInput;
    
#endif

【讨论】:

以上是关于MonoGame (Windows/Ubuntu) 中的跨平台文本框输入的主要内容,如果未能解决你的问题,请参考以下文章

Monogame如何调整图像大小

Monogame - 音乐和音效不能同时播放

Monogame,为啥即使有功能,块也不会移动?

Monogame 进口 Blender .FBX 不受灯光影响

我的球和我的矩形不会正确碰撞(Monogame)

无法将非默认字体导入monogame