如何在 Windows 7 下从非标准键记录键事件
Posted
技术标签:
【中文标题】如何在 Windows 7 下从非标准键记录键事件【英文标题】:How to log key events from non-standard keys under Windows 7 【发布时间】:2011-11-03 17:54:39 【问题描述】:我有一个双重问题,我不熟悉它的任何一个分支。
背景: 我从 MSI 购买了一台新笔记本电脑。作为我以前从未见过的功能,CD 驱动器没有安装在驱动器上的机械弹出按钮。相反,数字弹出按钮是功能键上方“智能栏”的一部分。不幸的是,智能条的底层软件非常糟糕。即使在被动模式下,它也会占用屏幕空间并且它会占用任务栏上的空间。*我已经卸载了这个软件。
项目: 我想编写一个在启动时运行并在后台不显眼的程序。该程序的唯一功能是使弹出按钮弹出 CD 驱动器。
第一步:我想知道当我按下那个按钮时会发生什么。我怀疑我不需要编写任何代码,但可以使用实用程序——我的一位同事提到了“事件记录器”,但谷歌没有提供任何用处。
第二步:我想编写上述程序,这意味着我需要与 WIN32 或可能的 .net 框架进行交互,以执行当我右键单击“我的电脑”下的 CD-Drive 时 windows 使用的相同函数调用然后点击“弹出”。
问题: 第一个问题:您知道有一个实用程序可以告诉我按下按钮时会发生什么吗?
第二个问题:你知道我需要在那个事件上调用什么函数来弹出驱动器吗?
第三个问题:我是否忽略了一些明显的其他路径?
我愿意接受从“我遇到同样的问题,这是我编写的解决方案的源代码”到“我想也许本教程会对您有所帮助?”的任何答案
我更喜欢使用 C/C++/C# 工作,但我愿意接受其他建议。正如标题所述,我在 Windows 7 下工作。
*出于好奇,该软件是 MSI S-Bar,由于某种原因,它被吹捧为该系列笔记本电脑的“功能”。
【问题讨论】:
我有一些现有的代码可以弹出 CD。我会在星期一回到办公室时发布答案。 【参考方案1】:我自己也遇到过同样的问题。我不知道你是否熟悉autohotkeys,但是用它写了一个脚本来替换s-bar。
AutoHotKey (AHK) 是一种用于 Windows 的开源宏创建和脚本语言,具有大量功能。您可以通过程序本身运行这些脚本,也可以将它们编译成可以在任何计算机上运行的可执行文件。
只需几行代码即可使弹出 CD 驱动器工作:
;CD eject button
SC142::
Drive, Eject
return
SC142 是键码。在每台 MSI 笔记本电脑上可能都不一样,但是如果您将“#InstallKeybdHook”行放在脚本的顶部。您可以通过 GUI 查看 AHK 看到的所有键盘事件。
我能够将大部分按钮映射到我的 MSI 笔记本电脑上的各种功能,尽管 AHK 不会从其中一个捕获键盘事件。
例如:
;Star key (AHK only receives KeyUp event)
SC139 UP::
Run, Control
return
;CinemaPro Key
SC13B::
Run, "C:\Program Files\Media Player Classic\mpc-hc64.exe"
return
【讨论】:
【参考方案2】:热键
如果它们是键盘的一部分(只是因为它们看起来像,并不意味着它们真的是),它们将有一个扫描码。 SetWindowsHookEx 可用于找出扫描码并对其做出反应 - 以下代码应该会有所帮助:
class Program
static void Main(string[] args)
var myClass = new MyClass();
myClass.Install();
Application.Run(new Form()); // You need a form, not sure why.
myClass.Uninstall();
public class MyClass : CriticalFinalizerObject
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(HookType idHook, HookProc 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);
[DllImport("winmm.dll")]
static extern Int32 mciSendString(String command, StringBuilder buffer, Int32 bufferSize, IntPtr hwndCallback);
private delegate IntPtr HookProc(int nCode, IntPtr wParam, IntPtr lParam);
private enum HookType : int
WH_KEYBOARD = 2,
WH_KEYBOARD_LL = 13
private enum WindowsMessage : int
WM_KEYUP = 0x101
private HookProc _myCallbackDelegate;
private IntPtr _hook;
public MyClass()
_myCallbackDelegate = MyCallbackFunction;
public void Install()
Uninstall();
using (Process process = Process.GetCurrentProcess())
using (ProcessModule module = process.MainModule)
_hook = SetWindowsHookEx(HookType.WH_KEYBOARD_LL, _myCallbackDelegate, GetModuleHandle(module.ModuleName), 0);
public void Uninstall()
var ptr = Interlocked.Exchange(ref _hook, IntPtr.Zero);
if (ptr != IntPtr.Zero)
UnhookWindowsHookEx(ptr);
private IntPtr MyCallbackFunction(int code, IntPtr wParam, IntPtr lParam)
if (code >= 0 && wParam == (IntPtr)WindowsMessage.WM_KEYUP)
var sk = Marshal.ReadInt32(lParam);
// This can be used to find the scancode.
// Press the key and watch the console to find out the scancode.
Console.WriteLine("ScanCode: 0x0:x4", sk);
if (sk == 0x0041) // 0x0041 is A
// We can't hold up the hook for too long; start the
// tray open on another thread.
new Action(OpenTray).BeginInvoke(null, null);
return CallNextHookEx(IntPtr.Zero, code, wParam, lParam);
private void OpenTray()
mciSendString("set CDAudio door open", null, 0, IntPtr.Zero);
~MyClass()
Uninstall();
隐藏
人机界面设备将更难与之交互。希望The Code Project 能帮上忙。
【讨论】:
【参考方案3】:弹出 CD 驱动器。不需要管理员权限。
#include <windows.h>
#include <vfw.h>
#include <stdio.h>
#pragma comment(lib, "Vfw32.lib")
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
char msg[512];
HANDLE h;
DWORD bytesreturned;
h = CreateFile("\\\\.\\cdrom0", MAXIMUM_ALLOWED, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if (h == INVALID_HANDLE_VALUE)
sprintf(msg, "CreateFile: %u\n", GetLastError());
MessageBox(NULL, msg, "ejectcd", MB_OK);
return 1;
if (!DeviceIoControl(h, IOCTL_STORAGE_EJECT_MEDIA, NULL, 0, NULL, 0, &bytesreturned, NULL))
sprintf(msg, "DeviceIoControl: %u\n", GetLastError());
MessageBox(NULL, msg, "ejectcd", MB_OK);
return 1;
return 0;
【讨论】:
【参考方案4】:在这里查看:
c:
CDR
c#:
OpenCD
【讨论】:
【参考方案5】:您必须使用 mciSendString
API 。看看这里SO link for this,如果你打算以编程方式进行。
【讨论】:
【参考方案6】:您可以编写一个简单的程序,在您按下弹出键时简单地轮询键盘。使用GetKeyboardState() 并检查按下的内容。或者您可以处理WM_KEYDOWN 消息并在您按下弹出键时检查键码。
您是否尝试过查看控制面板?转到控制面板>监视器>按键设置 - 从那里您将能够重新分配键盘上的按键。
【讨论】:
以上是关于如何在 Windows 7 下从非标准键记录键事件的主要内容,如果未能解决你的问题,请参考以下文章
如何在不使用 for 循环的情况下从 appsettings 文件中读取对象数组中特定键的值
如何在 Linux 中获取箭头键并在键盘上输入键以表现得像 Windows 7