因为一些需求,Unity窗口不能成为焦点,但是需要能知道键盘输入,还好是Windows版本,比较简单。不过中间也发生了点crash问题。所以把最后对应的代码放出来,供遇到问题的人参考,对比。

using UnityEngine;
using System;
using System.Collections;
using System.Runtime.InteropServices;
using UnityEngine.UI;
using System.Globalization;

public class KBHooks : MonoBehaviour
{
    [DllImport("user32.dll")]
    static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc callback, IntPtr hInstance, uint threadId);

    [DllImport("user32.dll")]
    static extern bool UnhookWindowsHookEx(IntPtr hInstance);

    [DllImport("user32.dll")]
    static extern IntPtr CallNextHookEx(IntPtr idHook, int nCode, int wParam, IntPtr lParam);

    [DllImport("kernel32.dll")]
    static extern IntPtr LoadLibrary(string lpFileName);

    private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);

    const int WH_KEYBOARD_LL = 13;
    const int WM_KEYDOWN = 0x100;

    private LowLevelKeyboardProc _proc = hookProc;

    private static IntPtr hhook = IntPtr.Zero;

    public void SetHook()
    {
        IntPtr hInstance = LoadLibrary("User32");
        hhook = SetWindowsHookEx(WH_KEYBOARD_LL, _proc, hInstance, 0);
    }

    public void UnHook()
    {
        UnhookWindowsHookEx(hhook);
    }

    public static IntPtr hookProc(int code, IntPtr wParam, IntPtr lParam)
    {
        if (code >= 0 && wParam == (IntPtr)WM_KEYDOWN)
        {
            int vkCode = Marshal.ReadInt32(lParam);
            if (vkCode.ToString() == "32")
            {
                text.text += "Space bar press.\n";
            }
        }
 
        return CallNextHookEx(hhook, code, (int)wParam, lParam);
    }


    static Text text;

	// Use this for initialization
	void Start()
	{
		Debug.Log("install hook");

		text = GameObject.Find ("Canvas/Text").GetComponent<Text>();
        SetHook();
	}

	void OnDisable()
	{
		Debug.Log("Uninstall hook");
        UnHook();
	}

}

这段代码里,测试按键是键盘的A,Unity场景中放了一个Text组件用于输出。代码在Unity 2019.1上测试。

Codeplex中有inputsimulator库,可以模拟按键的输入:

https://archive.codeplex.com/?p=inputsimulator

下载后解压,WindowsInput目录下的cs文件,按原来的目录放置到目标工程中,编译后就能使用该库。

示例代码(用Unity模拟):

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using WindowsInput;
using WindowsInput.Native;

public class simulat : MonoBehaviour {

	// Use this for initialization
	InputSimulator sim;
	void Start () {
		sim = new InputSimulator();		
	}
	
	// Update is called once per frame
	void Update () {

		if (Input.GetKeyDown (KeyCode.A)) {
			sim.Keyboard.KeyDown(VirtualKeyCode.SPACE);
		}

		if (Input.GetKeyUp (KeyCode.A)) {
			sim.Keyboard.KeyUp(VirtualKeyCode.SPACE);
		}

		if (Input.GetKeyDown(KeyCode.Space)) {
			Debug.Log ("Space key down");
		}

		if (Input.GetKey(KeyCode.Space)) {
			Debug.Log ("Space key pressed");
		}

		if (Input.GetKeyUp(KeyCode.Space)) {
			Debug.Log ("Space key up");
		}		
	}
}

该代码在按下A键的时候,模拟是了空格键(Space)被按下的效果。

环境:QT 5

编译出的exe,一般都依赖很多的dll(第三方),qt的dll尤其多。所以官方带了个命令行工具:windeployqt

根据开发的目标是msvc还是mingw,我们可以在windows的菜单栏中寻找到对应的command的打开方式。比如我用msvc开发32bit,就使用msvc32这个qt 命令行。

在命令行模式下,使用cd命令进入exe(编译出的exe)的路径,假设exe叫做test.exe。

使用命令:

windeployqt test.exe

就能在该目录下自动拷贝qt的支撑文件(dll和其他)。

这一步做完,qt的支撑的文件就在同一个目录了。

在windows平台上,使用libvlc的库,发现libvlc_media_new_path()这个方法返回的0。

检查了给定的mp4的路径,完全是正确的。而且代码是从原来一个工程里靠过来的,原来的工程可以播放,所以觉得很奇怪。

折腾一番后,发现在windows上,路径需要给反斜杠的就会成功。

也就是,libvlc_media_new_path这个方法的第二个参数,const char* 指向的路径,在windows上,需要使用”\\”,而不是”/”。

没有深入研究,只是试验出的,所以不知道是不是库拿的太旧了。

附上一段做这个处理的c代码:

// const char* path; 
int pathLen = strlen(path);
char moviePath[MAX_PATH];
memset(moviePath, 0, MAX_PATH);
memcpy(moviePath, path, pathLen);
for (int i = 0; i < pathLen; ++i) {
	if (path[i] == '/') {
		moviePath[i] = '\\';
	}
}
md = libvlc_media_new_path(inst, moviePath);