如何模拟自定义键盘按键?扩展键盘特殊键码获取及模拟求助
Got it, I’ve run into this exact issue with extended keyboards before—those special mode-switch keys are total trouble because they fall outside the standard ConsoleKey enum. Let’s break down how to capture their key codes and simulate presses properly, using Windows system APIs since that’s where most extended keyboards target.
First: Capture the Raw Scan Code of the Special Key
ConsoleKey only covers standard keyboard keys, so we need to go lower-level with the Raw Input API. This lets us read raw data straight from the HID keyboard device, bypassing the system’s key mapping that filters out non-standard keys.
Step-by-Step Implementation (C# Example)
- Register your app to receive raw keyboard input:
You’ll need to hook into the system’s raw input pipeline first. If you’re using a console app, you’ll need a hidden Win32 window to catch these messages—console windows don’t handleWM_INPUTnatively:[DllImport("user32.dll")] private static extern bool RegisterRawInputDevices(RAWINPUTDEVICE[] pRawInputDevices, uint uiNumDevices, uint cbSize); // Set up the registration parameters var inputDevices = new RAWINPUTDEVICE[1]; inputDevices[0].usUsagePage = 0x01; // Generic desktop controls inputDevices[0].usUsage = 0x06; // Keyboard device inputDevices[0].dwFlags = RIDEV_INPUTSINK; inputDevices[0].hwndTarget = yourWindowHandle; // Replace with your window's handle RegisterRawInputDevices(inputDevices, (uint)inputDevices.Length, (uint)Marshal.SizeOf(typeof(RAWINPUTDEVICE))); - Handle the
WM_INPUTmessage to extract the scan code:
Once registered, your window will receiveWM_INPUTmessages whenever the keyboard sends input. Parse this message to get the raw scan code of your special key:
Don’t forget to define the required Win32 structs (likeprotected override void WndProc(ref Message m) { const int WM_INPUT = 0x00FF; const uint RID_INPUT = 0x10000003; const uint RIM_TYPEKEYBOARD = 1; const uint RI_KEY_BREAK = 0x0001; if (m.Msg == WM_INPUT) { uint dataSize = 0; GetRawInputData(m.LParam, RID_INPUT, IntPtr.Zero, ref dataSize, (uint)Marshal.SizeOf(typeof(RAWINPUTHEADER))); IntPtr buffer = Marshal.AllocHGlobal((int)dataSize); if (GetRawInputData(m.LParam, RID_INPUT, buffer, ref dataSize, (uint)Marshal.SizeOf(typeof(RAWINPUTHEADER))) == dataSize) { var rawInput = (RAWINPUT)Marshal.PtrToStructure(buffer, typeof(RAWINPUT)); if (rawInput.header.dwType == RIM_TYPEKEYBOARD) { uint scanCode = rawInput.data.keyboard.MakeCode; // Check if this is a key press (not release) if ((rawInput.data.keyboard.Flags & RI_KEY_BREAK) == 0) { Console.WriteLine($"Captured special key scan code: {scanCode}"); // Save this scan code for later simulation } } } Marshal.FreeHGlobal(buffer); } base.WndProc(ref m); }RAWINPUT,RAWINPUTDEVICE) via P/Invoke—you can find their standard definitions easily in .NET’s P/Invoke reference resources.
Second: Simulate Pressing the Special Key
Once you have the scan code, use the SendInput API to simulate the key press. This API sends low-level input events directly to the system, so it works with non-standard keys that ConsoleKey can’t handle.
C# Simulation Code
[DllImport("user32.dll", SetLastError = true)] private static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize); // Define the input structure private struct INPUT { public uint type; public KEYBDINPUT ki; } private struct KEYBDINPUT { public ushort wVk; public ushort wScan; public uint dwFlags; public uint time; public IntPtr dwExtraInfo; } const uint INPUT_KEYBOARD = 1; const uint KEYEVENTF_SCANCODE = 0x0008; const uint KEYEVENTF_KEYUP = 0x0002; // Simulate a full key press (down + up) public void SimulateSpecialKey(uint scanCode) { var input = new INPUT[1]; input[0].type = INPUT_KEYBOARD; input[0].ki.wScan = (ushort)scanCode; input[0].ki.dwFlags = KEYEVENTF_SCANCODE; // Press the key SendInput(1, input, Marshal.SizeOf(typeof(INPUT))); // Release the key input[0].ki.dwFlags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP; SendInput(1, input, Marshal.SizeOf(typeof(INPUT))); }
Quick Notes
- Console Apps: If you’re working in a console app, you’ll need to create a hidden Win32 window to handle
WM_INPUTmessages—console windows don’t support this natively. - HID-Only Keys: Some extended keyboards use custom HID reports instead of standard scan codes for special keys. If the above doesn’t capture the key, you’ll need to parse the raw HID report data from the
RAWINPUTstructure—this is more complex but still doable with Raw Input. - Scan Code Variability: Scan codes can vary between keyboard models, so always capture the code from your specific keyboard before simulating.
内容的提问来源于stack exchange,提问作者JDoe




