unity3d屏蔽Windows10输入法

在win10上,如果安装了某些输入法(比如QQ输入法),会造成unity的键盘事件被输入法捕获而不能触发的情况。只有将输入法切换到英文状态下才能响应键盘事件。

解决办法有,

1:用户主动切换输入法,甚至卸载输入法

2:程序在非输入状态下,屏蔽输入法

由于方法1在全屏状态下,用户完全不知道是否在输入法劫持中,常常导致以为是程序的bug,所以这里采用方法2

在unity中,官方并没有提供一个很好的解决方案(Input.imeCompositionMode无效)。所以只能借助win api。

其中最为重要的API是设置输入法状态:

[DllImport("imm32.dll")]
private static extern bool ImmSetOpenStatus(IntPtr himc, bool b);

其中himc为当前正在输入的窗口的输入法句柄,b为true表示开启,false表示关闭

himc可以通过另外一个api函数获取

[DllImport("imm32.dll")]
private static extern IntPtr ImmGetContext(IntPtr hwnd);

其中,hwnd为程序窗口的句柄

该值的获取方式可以参考:http://blog.csdn.net/linkrules/article/details/50420797

整个代码如下:

复制代码
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;

public class Win32Help
{
    private delegate bool Wndenumproc(IntPtr hwnd, uint lParam);

    [DllImport("user32.dll", SetLastError = true)]
    private static extern bool EnumWindows(Wndenumproc lpEnumFunc, uint lParam);

    [DllImport("user32.dll", SetLastError = true)]
    private static extern IntPtr GetParent(IntPtr hWnd);
    [DllImport("user32.dll")]
    private static extern uint GetWindowThreadProcessId(IntPtr hWnd, ref uint lpdwProcessId);

    [DllImport("kernel32.dll")]
    private static extern void SetLastError(uint dwErrCode);


    /// <summary>
    /// 获取当前进程的窗口句柄
    /// </summary>
    /// <returns></returns>
    public static IntPtr GetProcessWnd()
    {
        var ptrWnd = IntPtr.Zero;
        var pid = (uint)Process.GetCurrentProcess().Id;  // 当前进程 ID  

        var bResult = EnumWindows(delegate (IntPtr hwnd, uint lParam)
        {
            uint id = 0;

            if (GetParent(hwnd) != IntPtr.Zero)
                return true;
            GetWindowThreadProcessId(hwnd, ref id);
            if (id != lParam)
                return true;
            ptrWnd = hwnd;   // 把句柄缓存起来  
            SetLastError(0);    // 设置无错误  
            return false;   // 返回 false 以终止枚举窗口  
        }, pid);

        return (!bResult && Marshal.GetLastWin32Error() == 0) ? ptrWnd : IntPtr.Zero;
    }

    [DllImport("imm32.dll")]
    private static extern IntPtr ImmGetContext(IntPtr hwnd);
    [DllImport("imm32.dll")]
    private static extern bool ImmGetOpenStatus(IntPtr himc);
    [DllImport("imm32.dll")]
    private static extern bool ImmSetOpenStatus(IntPtr himc, bool b);

    /// <summary>
    /// 设置输入法状态
    /// </summary>
    /// <param name="tf"></param>
    public static void SetImeEnable(bool tf)
    {
        var handle = GetProcessWnd();
        var hIme = ImmGetContext(handle);
        ImmSetOpenStatus(hIme, tf);
    }

    /// <summary>
    /// 获取输入法状态
    /// </summary>
    /// <returns></returns>
    public bool GetImeStatus()
    {
        var handle = GetProcessWnd();
        var hIme = ImmGetContext(handle);
        return ImmGetOpenStatus(hIme);
    }
}
复制代码

 

然后在程序中可以使用Win32Help.SetImeEnable(false)的方法来屏蔽输入法,比如:

复制代码
using UnityEngine;
public class InputTest : MonoBehaviour
{
    // Use this for initialization
    protected void Start()
    {
        Win32Help.SetImeEnable(false);
    }


    // Update is called once per frame
    protected void Update()
    {
        if (Input.GetKey(KeyCode.A))
        {
            Debug.Log("AAAAAAAAAAAs");
        }
    }
}
复制代码

注意:只对Windows系统有效,Win10测试可用,其他系统未经测试

posted @   CodeGize  阅读(5885)  评论(0编辑  收藏  举报
编辑推荐:
· 从问题排查到源码分析:ActiveMQ消费端频繁日志刷屏的秘密
· 一次Java后端服务间歇性响应慢的问题排查记录
· dotnet 源代码生成器分析器入门
· ASP.NET Core 模型验证消息的本地化新姿势
· 对象命名为何需要避免'-er'和'-or'后缀
阅读排行:
· 编程神器Trae:当我用上后,才知道自己的创造力被低估了多少
· 开发的设计和重构,为开发效率服务
· 从零开始开发一个 MCP Server!
· Ai满嘴顺口溜,想考研?浪费我几个小时
· 从问题排查到源码分析:ActiveMQ消费端频繁日志刷屏的秘密
CodeGize的个人博客
点击右上角即可分享
微信分享提示