Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • Home
  • SEARCH
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 6185123
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 24, 20262026-05-24T01:39:27+00:00 2026-05-24T01:39:27+00:00

I am creating a program that monitors key presses for controlling iTunes globally. It

  • 0

I am creating a program that monitors key presses for controlling iTunes globally. It also has a few WinForms (for displaying track information and editing options).

The low-level keyboard hook works great for awhile. If I just start up the program, keyboard hook is set and iTunes opens. Then I open Notepad and can type tons of stuff really fast and every stroke is captured, with at most 30ms being spent in the hook function (and for the most part <10ms). The hook function simply adds the events onto a queue which is processed by another thread. It is running on its own high-priority thread using it’s own Application.Run().

However if I start doing things within iTunes (such as a couple of play/pause clicks which generate events in my program) or within the program (like opening the options window) then the hook function stops being called! This can happen even if the keyboard has never been used (e.g. startup, click play and pause a few times in iTunes, then press a key).

The cause of the hook not being called is not due to too much time being spent in the hook function.

When I call UnhookWindowsHookEx it always returns true, regardless if the hook function was still being called or not.

So, what could be the cause?

One idea (although I have no proof or solutions) is that the managed thread is no longer the correct native thread. I use numerous (managed) threads in my program and I have read that a single native thread can run many managed threads and that a managed thread can change which native thread is running it. Is it possible that the hook is still producing messages but sending them to the wrong thread? If this is the case, how can I work around it?


Edit: The hook and callbacks

A slightly stripped done version of my KeyMonitor. It is stripped down for clarity. I have removed some utilities (like most of the values of the Key enum and many functions of the Keys class like ToString() and FromString()) along with some error handling.

Most of the important stuff is in the KeyMonitor class. KeyMonitor.Start() starts a thread for the messages, KeyMonitor.HookThread() is that thread and creates the hook along with an Application.Run() for the message loop, KeyMonitor.KeyboardHookProc() is the callback function, and KeyMonitor.HookEventDispatchThread() is what dispatches events recorded by the callback.

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;

namespace KeyTest
{
    enum Key : int
    {
        Shift = 0x10, Ctrl, Alt,
        Left_Win = 0x5B, Right_Win,
        Left_Shift = 0xA0, Right_Shift, Left_Ctrl, Right_Ctrl, Left_Alt, Right_Alt,
    }

    class Keys
    {
        [DllImport("user32.dll")]
        private static extern int GetKeyboardState(byte[] pbKeyState);
        public const int Count = 256; // vkCode are from 1 to 254, but GetKeyboardState uses 0-255

        private readonly bool[] keys = new bool[Count];

        public Keys() { }

        private void DoModifier(Key x, Key l, Key r) { keys[(int)x] = keys[(int)l] || keys[(int)r]; }
        private void DoModifiers()
        {
            DoModifier(Key.Shift, Key.Left_Shift, Key.Right_Shift);
            DoModifier(Key.Ctrl, Key.Left_Ctrl, Key.Right_Ctrl);
            DoModifier(Key.Alt, Key.Left_Alt, Key.Right_Alt);
        }
        private void DoModifier(Key x, Key l, Key r, Key k) { if (k == l || k == r) keys[(int)x] = keys[(int)l] || keys[(int)r]; }
        private void DoModifiers(Key k)
        {
            DoModifier(Key.Shift, Key.Left_Shift, Key.Right_Shift, k);
            DoModifier(Key.Ctrl, Key.Left_Ctrl, Key.Right_Ctrl, k);
            DoModifier(Key.Alt, Key.Left_Alt, Key.Right_Alt, k);
        }

        public bool this[int i] { get { return this.keys[i]; } set { this.keys[i] = value; DoModifiers((Key)i); } }
        public bool this[Key k] { get { return this.keys[(int)k]; } set { this.keys[(int)k] = value; DoModifiers(k); } }

        public void LoadCurrentState()
        {
            byte[] keyState = new byte[Count];
            if (GetKeyboardState(keyState) != 0)
                for (int i = 0; i < Count; ++i)
                    keys[i] = (keyState[i] & 0x80) != 0;
            DoModifiers();
        }
    }

    static class KeyMonitor
    {
        #region Windows API
        private delegate int HookProc(int nCode, UIntPtr wParam, IntPtr lParam);

        [DllImport("user32.dll", SetLastError = true)]
        private static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hMod, int dwThreadId);
        [DllImport("user32.dll", SetLastError = true)]
        private static extern int UnhookWindowsHookEx(int idHook);
        [DllImport("user32.dll")]
        private static extern int CallNextHookEx(int idHook, int nCode, UIntPtr wParam, IntPtr lParam);

        private const int WH_KEYBOARD_LL = 13;
        private readonly static UIntPtr WM_KEYDOWN = new UIntPtr(0x100), WM_SYSKEYDOWN = new UIntPtr(0x104);
        #endregion

        public static event KeyEventHandler OverridingKeyChange;
        public static event KeyEventHandler KeyChange;

        private struct KeyEventData { public int vk; public bool down; }

        private static int hook = 0;
        private static Thread dispatchThread = null, hookThread = null;
        private static Keys keys = new Keys();
        private static Queue<KeyEventData> queue = new Queue<KeyEventData>();

        private static void Enqueue(int vk, bool down)
        {
            lock (queue)
            {
                queue.Enqueue(new KeyEventData() { vk = vk, down = down });
                Monitor.Pulse(queue);
            }
        }
        public static Keys Keys { get { return keys; } }

        public static void Start()
        {
            if (hook == 0)
            {
                dispatchThread = new Thread(HookEventDispatchThread);
                hookThread = new Thread(HookThread);
                hookThread.Priority = ThreadPriority.Highest;
                dispatchThread.Start();
                hookThread.Start();
            }
        }

        public static void Stop()
        {
            if (hook != 0)
            {
                // Minimal cleanup...
                UnhookWindowsHookEx(hook);
                Application.Exit();
                dispatchThread.Interrupt();
            }
        }

        private static void HookThread()
        {
            hook = SetWindowsHookEx(WH_KEYBOARD_LL, new HookProc(KeyboardHookProc), IntPtr.Zero, 0);
            if (hook == 0) { /* Handle error */ }
            keys.LoadCurrentState();
            Application.Run();
        }

        private static int KeyboardHookProc(int nCode, UIntPtr wParam, IntPtr lParam)
        {
            if (nCode >= 0)
                Enqueue(Marshal.ReadInt32(lParam), wParam == WM_SYSKEYDOWN || wParam == WM_KEYDOWN);
            return CallNextHookEx(hook, nCode, wParam, lParam);
        }

        private static void HookEventDispatchThread()
        {
            for (; ; )
            {
                KeyEventData data;
                lock (queue)
                {
                    if (queue.Count == 0)
                        try
                        {
                            Monitor.Wait(queue);
                        }
                        catch (ThreadInterruptedException) { return; }
                    data = queue.Dequeue();
                }
                if (data.vk == -1)
                {
                    // Done!
                    keys = new Keys();
                    queue.Clear();
                    return;
                }
                else if (keys[data.vk] == data.down)
                    continue;

                keys[data.vk] = data.down;
                KeyEventArgs e = new KeyEventArgs((System.Windows.Forms.Keys)data.vk);
                if (OverridingKeyChange != null) OverridingKeyChange(null, e);
                if (!e.Handled && KeyChange != null) KeyChange(null, e);
            }
        }
    }

}
  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-24T01:39:29+00:00Added an answer on May 24, 2026 at 1:39 am

    You need to save the delegate to a variable that will survive for the duration of your application. Otherwise, delegate is garbage-collected (strange the app did not crash!).

    static HookProc hookProc;
    ...
    
    hookProc = new HookProc(KeyboardHookProc);
    hook = SetWindowsHookEx(WH_KEYBOARD_LL, hookProc, IntPtr.Zero, 0);
    
    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I'm creating a program that authenticates from a before it runs. I also want
I'm creating a program that needs to store key-value pairs. The program needs to
I am creating a program that will be installed using the .net installer project.
I am creating a program that needs to store the user's data in encrypted
I am creating a program that displays a popup at certain times (just like
I have been tasked with creating a program that will generate an amortization schedule.
Let's say I'm creating a program in C that needs to use a tempfile.
I'm creating an initialising function for the class 'Room', and found that the program
I am creating a program which has an installer-like interface. Is it better to
I am creating a program that will fill in a given grammar. Right now

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.