You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity:程序间信息传递及后台监听键盘输入技术问询

Hey there! Let's tackle your launcher system's two key needs: background global keyboard listening and sending messages to the running app. I'll break this down with practical, Windows-specific solutions (since you're targeting .exe apps):

1. Background Global Keyboard Listening

Standard keyboard event handlers only work when your launcher has focus. To listen globally even when minimized or in the background, you'll need a low-level keyboard hook on Windows. This type of hook doesn’t require injecting code into other processes, making it perfect for a lightweight launcher.

Example Implementation (C#)

You’ll need to P/Invoke Windows API functions from user32.dll:

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

public class GlobalKeyboardListener
{
    private const int WH_KEYBOARD_LL = 13;
    private const int WM_KEYDOWN = 0x0100;

    private static LowLevelKeyboardProc _proc = HookCallback;
    private static IntPtr _hookID = IntPtr.Zero;

    public static void StartListening()
    {
        _hookID = SetHook(_proc);
        Application.Run(); // Keeps the message loop alive for the hook
    }

    public static void StopListening()
    {
        UnhookWindowsHookEx(_hookID);
    }

    private static IntPtr SetHook(LowLevelKeyboardProc proc)
    {
        using (var curProcess = System.Diagnostics.Process.GetCurrentProcess())
        using (var curModule = curProcess.MainModule)
        {
            return SetWindowsHookEx(WH_KEYBOARD_LL, proc,
                GetModuleHandle(curModule.ModuleName), 0);
        }
    }

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

    private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
    {
        if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
        {
            int vkCode = Marshal.ReadInt32(lParam);
            // Handle your key press here (e.g., trigger an action)
            Console.WriteLine($"Key pressed: {(Keys)vkCode}");
        }
        return CallNextHookEx(_hookID, nCode, wParam, lParam);
    }

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool UnhookWindowsHookEx(IntPtr hhk);

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

    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern IntPtr GetModuleHandle(string lpModuleName);
}
  • Critical note: The hook needs a running message loop (hence Application.Run()). If your launcher is a console app, run this in a separate thread or use a minimal Windows Forms/WPF skeleton to keep the loop active.
2. Sending Messages to the Running App

There are reliable ways to communicate with a running .exe process, depending on whether you control the target app’s code:

Option 1: Custom Windows Messages (For Your Own Target App)

If you built the target app, define a custom Windows message and handle it in its message loop. Use SendMessage from your launcher to send data:

[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

// Define a unique custom message (avoid conflicts with system messages)
private const uint WM_MY_LAUNCHER_MESSAGE = 0x0400 + 100;

// Send data to the target app's main window
public static void SendMessageToApp(IntPtr mainWindowHandle, string data)
{
    IntPtr dataPtr = Marshal.StringToHGlobalAuto(data);
    SendMessage(mainWindowHandle, WM_MY_LAUNCHER_MESSAGE, IntPtr.Zero, dataPtr);
    Marshal.FreeHGlobal(dataPtr);
}

In the target app, override WndProc to process the message:

protected override void WndProc(ref Message m)
{
    if (m.Msg == WM_MY_LAUNCHER_MESSAGE)
    {
        string receivedData = Marshal.PtrToStringAuto(m.LParam);
        // Handle the incoming data here
    }
    base.WndProc(ref m);
}

Option 2: Named Pipes (Flexible for Any App)

For bidirectional or complex communication, named pipes work seamlessly—even with third-party apps (if you can add a pipe listener to them). Here’s a quick launcher-side snippet:

using System.IO.Pipes;

public static void SendDataViaPipe(string data)
{
    using (var pipeClient = new NamedPipeClientStream(".", "MyLauncherPipe", PipeDirection.Out))
    {
        pipeClient.Connect(1000); // Connect to the target app's pipe server
        using (var writer = new StreamWriter(pipeClient))
        {
            writer.WriteLine(data);
            writer.Flush();
        }
    }
}

The target app would run a NamedPipeServerStream to listen for incoming data.

Putting It All Together
  1. When launching path/app.exe, store the process’s main window handle (use Process.MainWindowHandle once the window loads).
  2. Start the global keyboard listener in a background thread (or keep the message loop running).
  3. When a key press is detected, use your chosen inter-process communication method to send a message to the running app.

This setup lets your launcher stay in the background, listen for keyboard input globally, and communicate with the target app without needing focus.

内容的提问来源于stack exchange,提问作者Vanguard3000

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 11:48:45