Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to log key events from non-standard keys under Windows 7

I have a two-fold problem and I'm familiar with neither branch of it.

Background: I've purchased a new laptop from MSI. As a feature I've never seen before, the CD-drive does not have a mechanical eject button mounted on the drive. Instead, a digital eject button is part of the "smart-bar" above the Function Keys. Unfortunately, the software underlying the smart-bar is atrocious. Even in passive mode it takes up screen real-estate and it takes up space on the task bar.* I have un-installed this software.

Project: I want to write a program that runs on startup and lies unobtrusively in the background. The only function of the program is to make that eject button eject the CD drive.

Step one: I want to find out what happens when I push that button. I suspect that I don't need to code anything but can use a utility - one of my colleagues mentioned an "event logger" but google provides nothing of use.

Step two: I want to write said program, which means I need to interact with either WIN32 or possibly the .net framework to perform the same function call windows uses when I right-click the CD-Drive under "My computer" and click "Eject."

Questions: First question: Do you know a utility that will tell me what happens when the button is pushed?

Second question: Do you know what function I need to call on that event to eject the drive?

Tertiary question: Am I overlooking some obvious other path?

I am open to any answers from "I had the same problem, here's the source code to the solution I wrote" to "I guess maybe this tutorial will help you?"

I would prefer to work in C/C++/C# but I am open to other suggestions. As the title states, I am working under Windows 7.

*For the curious, the software is the MSI S-Bar which is for some reason touted as a "feature" of this line of laptops.

like image 613
shieldfoss Avatar asked Aug 25 '11 14:08

shieldfoss


People also ask

How do I check keyboard inputs in Windows?

The Windows on-screen keyboard is a program included in Windows that shows an on-screen keyboard to test modifier keys and other special keys. For example, when pressing the Alt , Ctrl , or Shift key, the On-Screen Keyboard highlights the keys as pressed.

How do I turn off Sticky Keys Windows 7?

To turn off Sticky Keys, press the shift key five times or uncheck the Turn On Sticky Keys box in the Ease of Access control panel. If the default options are selected, pressing two keys simultaneously will also turn off Sticky Keys.

How do you type without shift key?

The Alt key can be used in place of the Shift key for capitalizing letters and typing special characters. Another way to type special characters is by using the numeric pad on your keyboard. To do this, hold down the Num Lock key and press the associated number on your numeric pad.


2 Answers

I encountered this same problem myself. I don't know whether or not you are familiar with autohotkeys, but used it to write a script to replace s-bar.

AutoHotKey (AHK) is a open source macro-creating and scripting language for Windows with a ton of functionality. You can run the scripts through the program itself or compile them into executables that can be run on any computer.

You can make the eject CD drive work with just a couple lines of code:

;CD eject button
SC142::
Drive, Eject
return

SC142 is the keycode. It might not be the same on every MSI laptop, but if you put the line "#InstallKeybdHook" at the top of your script. You can view all of the keyboard events AHK sees through a GUI.

I was able to map most of the buttons to various functions on my MSI laptop, although AHK wouldn't capture keyboard events from one of them.

For example:

;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
like image 104
kappamaki Avatar answered Nov 06 '22 05:11

kappamaki


Hotkeys

If they are part of the keyboard (just because they look like they are, doesn't mean they really are) they will have a scancode. SetWindowsHookEx can be used to find out the scancode, as well as react to it - the following code should help:

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: 0x{0: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();
    }
}

HID

A human interface device will be much harder to interact with. Hopefully The Code Project can help.

like image 38
Jonathan Dickinson Avatar answered Nov 06 '22 03:11

Jonathan Dickinson