2 Replies - 1039 Views - Last Post: 19 May 2011 - 06:16 AM Rate Topic: -----

#1 cokacola   User is offline

  • D.I.C Head
  • member icon

Reputation: 5
  • View blog
  • Posts: 65
  • Joined: 23-July 10

Key presses on non-active app

Posted 19 May 2011 - 06:04 AM

So, I've been adding a little to my Music app, and one of the features I'd like is buttons to pause / goto next and previous songs when playing games and such.
So what I need to do is find a way to read key presses when the program is not actually active.
I found this class on the internet somewhere(cannot remember where, or when), and when I use it it works, but once I actually press a bound key, the program crashes and says "This program has stopped working" or something like that:
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace Utilities {
	/// <summary>
	/// A class that manages a global low level keyboard hook
	/// </summary>
	class globalKeyboardHook {
		#region Constant, Structure and Delegate Definitions
		/// <summary>
		/// defines the callback type for the hook
		/// </summary>
		public delegate int keyboardHookProc(int code, int wParam, ref keyboardHookStruct lParam);

		public struct keyboardHookStruct {
			public int vkCode;
			public int scanCode;
			public int flags;
			public int time;
			public int dwExtraInfo;
		}

		const int WH_KEYBOARD_LL = 13;
		const int WM_KEYDOWN = 0x100;
		const int WM_KEYUP = 0x101;
		const int WM_SYSKEYDOWN = 0x104;
		const int WM_SYSKEYUP = 0x105;
		#endregion

		#region Instance Variables
		/// <summary>
		/// The collections of keys to watch for
		/// </summary>
		public List<Keys> HookedKeys = new List<Keys>();
		/// <summary>
		/// Handle to the hook, need this to unhook and call the next hook
		/// </summary>
		IntPtr hhook = IntPtr.Zero;
		#endregion

		#region Events
		/// <summary>
		/// Occurs when one of the hooked keys is pressed
		/// </summary>
		public event KeyEventHandler KeyDown;
		/// <summary>
		/// Occurs when one of the hooked keys is released
		/// </summary>
		public event KeyEventHandler KeyUp;
		#endregion

		#region Constructors and Destructors
		/// <summary>
		/// Initializes a new instance of the <see cref="globalKeyboardHook"/> class and installs the keyboard hook.
		/// </summary>
		public globalKeyboardHook() {
			hook();
		}

		/// <summary>
		/// Releases unmanaged resources and performs other cleanup operations before the
		/// <see cref="globalKeyboardHook"/> is reclaimed by garbage collection and uninstalls the keyboard hook.
		/// </summary>
		~globalKeyboardHook() {
			unhook();
		}
		#endregion

		#region Public Methods
		/// <summary>
		/// Installs the global hook
		/// </summary>
		public void hook() {
			IntPtr hInstance = LoadLibrary("User32");
			hhook = SetWindowsHookEx(WH_KEYBOARD_LL, hookProc, hInstance, 0);
		}

		/// <summary>
		/// Uninstalls the global hook
		/// </summary>
		public void unhook() {
			UnhookWindowsHookEx(hhook);
		}

		/// <summary>
		/// The callback for the keyboard hook
		/// </summary>
		/// <param name="code">The hook code, if it isn't >= 0, the function shouldn't do anyting</param>
		/// <param name="wParam">The event type</param>
		/// <param name="lParam">The keyhook event information</param>
		/// <returns></returns>
		public int hookProc(int code, int wParam, ref keyboardHookStruct lParam) {
			if (code >= 0) {
				Keys key = (Keys)lParam.vkCode;
				if (HookedKeys.Contains(key)) {
					KeyEventArgs kea = new KeyEventArgs(key);
					if ((wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN) && (KeyDown != null)) {
						KeyDown(this, kea) ;
					} else if ((wParam == WM_KEYUP || wParam == WM_SYSKEYUP) && (KeyUp != null)) {
						KeyUp(this, kea);
					}
					if (kea.Handled)
						return 1;
				}
			}
			return CallNextHookEx(hhook, code, wParam, ref lParam);
		}
		#endregion

		#region DLL imports
		/// <summary>
		/// Sets the windows hook, do the desired event, one of hInstance or threadId must be non-null
		/// </summary>
		/// <param name="idHook">The id of the event you want to hook</param>
		/// <param name="callback">The callback.</param>
		/// <param name="hInstance">The handle you want to attach the event to, can be null</param>
		/// <param name="threadId">The thread you want to attach the event to, can be null</param>
		/// <returns>a handle to the desired hook</returns>
		[DllImport("user32.dll")]
		static extern IntPtr SetWindowsHookEx(int idHook, keyboardHookProc callback, IntPtr hInstance, uint threadId);

		/// <summary>
		/// Unhooks the windows hook.
		/// </summary>
		/// <param name="hInstance">The hook handle that was returned from SetWindowsHookEx</param>
		/// <returns>True if successful, false otherwise</returns>
		[DllImport("user32.dll")]
		static extern bool UnhookWindowsHookEx(IntPtr hInstance);

		/// <summary>
		/// Calls the next hook.
		/// </summary>
		/// <param name="idHook">The hook id</param>
		/// <param name="nCode">The hook code</param>
		/// <param name="wParam">The wparam.</param>
		/// <param name="lParam">The lparam.</param>
		/// <returns></returns>
		[DllImport("user32.dll")]
		static extern int CallNextHookEx(IntPtr idHook, int nCode, int wParam, ref keyboardHookStruct lParam);

		/// <summary>
		/// Loads the library.
		/// </summary>
		/// <param name="lpFileName">Name of the library</param>
		/// <returns>A handle to the library</returns>
		[DllImport("kernel32.dll")]
		static extern IntPtr LoadLibrary(string lpFileName);
		#endregion
	}
}


So, is that code just useless, or is there something I can change to make it work?
BTW, since is uses DDLImport and such, I'll mention that I use Windows 7.

Since I assume its relevant, I used the class like this:
In my form load:
globalKeyboardHook gkh = new globalKeyboardHook();
gkh.HookedKeys.Add(Keys.MediaPlayPause);
gkh.KeyDown += new KeyEventHandler(gkh_KeyDown);
gkh.KeyUp += new KeyEventHandler(gkh_KeyUp);


gkh_KeyDown:
void gkh_KeyDown(object sender, KeyEventArgs e)
    {
       if(e.KeyCode == Keys.MediaPlayPause) {
	playPause();
       }
    }


gkh_KeyUp:
void gkh_KeyUp(object sender, KeyEventArgs e) {
	
}

Can someone help me?
Is there an alternative to this apparently broken class?
BTW, the PlayPause() function works fine, as that is the same function used by hand clicked buttons and such.
Also, I have tried other keys besides MediaPlayPause.

Thanks :)

Is This A Good Question/Topic? 0
  • +

Replies To: Key presses on non-active app

#2 tlhIn`toq   User is offline

  • Xamarin Cert. Dev.
  • member icon

Reputation: 6535
  • View blog
  • Posts: 14,450
  • Joined: 02-June 10

Re: Key presses on non-active app

Posted 19 May 2011 - 06:12 AM

GlobalKeyboardHook works well. I've used it.
The crash is happening within your program most likely.
You'll need to debug your app.
Start with a breakpoint at the method called from the keypress and go from there.


Debugging tutorial
Debugging tips
Great debugging tips
It still doesn't work, article
Was This Post Helpful? 0
  • +
  • -

#3 cokacola   User is offline

  • D.I.C Head
  • member icon

Reputation: 5
  • View blog
  • Posts: 65
  • Joined: 23-July 10

Re: Key presses on non-active app

Posted 19 May 2011 - 06:16 AM

Oh, your right!
I just made a new project and tried it out, it worked fine.
Not sure whats in my program that could mess it up :/

EDIT:
Right, I'm confused.
When I debug it, if I press ANY key the program crashes, and when I run it normally, pressing any key at all(even the correct key) just does nothing...

EDIT2:
I fixed it :D
I just put the code into a new class, and called that class from the main form.
No idea how that fixed it, but it did.
It could be that I called the class from the Form1_Load rather than just Form1.
Which ever one worked, it worked :)

This post has been edited by cokacola: 19 May 2011 - 06:45 AM

Was This Post Helpful? 0
  • +
  • -

Page 1 of 1