Linux无桌面环境下,如何用C#获取裸终端鼠标输入?
C# 实现控制台环境下的鼠标输入捕获
控制台本身没有原生支持鼠标事件,要实现你的简易桌面环境所需的鼠标坐标、按键及滚轮检测,必须调用Windows原生API。以下是完整的实现方案:
1. 核心API导入与工具类封装
首先封装Windows API调用,统一处理鼠标坐标转换、按键状态检测和控制台输入模式开启:
using System; using System.Runtime.InteropServices; public static class MouseInputHandler { // 鼠标按键常量 private const int VK_LBUTTON = 0x01; private const int VK_RBUTTON = 0x02; private const int WHEEL_STEP = 120; // Windows API声明 [DllImport("user32.dll")] private static extern bool GetCursorPos(out POINT lpPoint); [DllImport("user32.dll")] private static extern bool ScreenToClient(IntPtr hWnd, ref POINT lpPoint); [DllImport("kernel32.dll")] private static extern IntPtr GetConsoleWindow(); [DllImport("user32.dll")] private static extern short GetAsyncKeyState(int vKey); [DllImport("kernel32.dll")] private static extern bool SetConsoleMode(IntPtr hConsoleHandle, uint dwMode); [DllImport("kernel32.dll")] private static extern bool GetConsoleMode(IntPtr hConsoleHandle, out uint dwMode); [DllImport("kernel32.dll")] private static extern bool GetConsoleFontSize(IntPtr hConsoleOutput, int nFont, out COORD lpConsoleFontSize); [StructLayout(LayoutKind.Sequential)] public struct POINT { public int X; public int Y; } [StructLayout(LayoutKind.Sequential)] public struct COORD { public short X; public short Y; } // 启用控制台鼠标输入 public static void EnableConsoleMouseInput() { IntPtr consoleWnd = GetConsoleWindow(); if (!GetConsoleMode(consoleWnd, out uint mode)) return; // 开启鼠标输入模式 SetConsoleMode(consoleWnd, mode | 0x0010); // ENABLE_MOUSE_INPUT } // 获取控制台内的鼠标字符坐标(适配字体大小) public static POINT GetConsoleMouseCoords() { GetCursorPos(out POINT screenPos); IntPtr consoleWnd = GetConsoleWindow(); ScreenToClient(consoleWnd, ref screenPos); // 获取当前控制台字体的像素尺寸 GetConsoleFontSize(GetConsoleWindow(), 0, out COORD fontSize); // 转换为控制台字符坐标 return new POINT { X = screenPos.X / fontSize.X, Y = screenPos.Y / fontSize.Y }; } // 检测鼠标按键按下状态 public static bool IsLeftButtonDown() => (GetAsyncKeyState(VK_LBUTTON) & 0x8000) != 0; public static bool IsRightButtonDown() => (GetAsyncKeyState(VK_RBUTTON) & 0x8000) != 0; // 滚轮增量检测(简化版,精确检测需处理WM_MOUSEWHEEL消息) public static int GetWheelIncrement() { short wheelState = GetAsyncKeyState(0x08); // VK_XBUTTON1 对应滚轮按键,实际增量需结合消息循环 return wheelState != 0 ? WHEEL_STEP : 0; } }
2. 主循环中集成鼠标输入
在你的桌面环境主循环里,持续轮询鼠标状态:
class Program { static void Main(string[] args) { // 启用控制台鼠标支持 MouseInputHandler.EnableConsoleMouseInput(); while (true) { // 获取鼠标坐标 var mousePos = MouseInputHandler.GetConsoleMouseCoords(); Console.WriteLine($"Mouse: X={mousePos.X}, Y={mousePos.Y}"); // 检测点击事件 if (MouseInputHandler.IsLeftButtonDown()) { Console.WriteLine("Left Click Triggered"); // 在这里处理左键点击逻辑 } if (MouseInputHandler.IsRightButtonDown()) { Console.WriteLine("Right Click Triggered"); // 在这里处理右键点击逻辑 } // 滚轮处理 int wheelDelta = MouseInputHandler.GetWheelIncrement(); if (wheelDelta != 0) { Console.WriteLine($"Wheel Scrolled: {(wheelDelta > 0 ? "Up" : "Down")}"); // 在这里处理滚轮逻辑 } // 控制循环帧率,避免资源占用过高 System.Threading.Thread.Sleep(30); Console.Clear(); } } }
关键说明
- 坐标准确性:通过
GetConsoleFontSize获取字体像素尺寸,确保字符坐标转换的准确性,避免因系统字体设置导致的偏移。 - 精确滚轮检测:如果需要更精确的滚轮增量(比如每滚动一格的具体数值),需要替换为消息循环处理
WM_MOUSEWHEEL消息,轮询方式只能做基础检测。 - 输入模式:必须调用
EnableConsoleMouseInput开启控制台的鼠标输入模式,否则无法捕获任何鼠标事件。
内容的提问来源于stack exchange,提问作者Emil-Viktor Schwarze
相关产品推荐
相关产品推荐

