The Media Center Sandbox

Resources and discussion for developing experiences in the Windows Media Center platform.
Welcome to The Media Center Sandbox Sign in | Join | Help
in Search

A C# form test prog to see what the remote control is doing

Last post 11-04-2008, 10:05 PM by davidtjudd. 22 replies.
Page 1 of 2 (23 items)   1 2 Next >
Sort Posts: Previous Next
  •  04-09-2007, 9:15 AM 2392

    A C# form test prog to see what the remote control is doing

    Edit: Please go towards the end of the thread if you're looking for a working bit of code for use in a background app. The first few posts are basically describing my experiments and search for a solution and aren't necessary (and aren't what you want probably) :) Gordon


    I have no idea if this will be useful to anyone, but using a test C# forms program I can "listen" to the basic windows messages that are generated with a remote control (possibly other messages.)

    It just produces a beep (or rather a stream of beeps/clicks) in response to remote control keys.

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Text;
    using System.Windows.Forms;

    using System.Runtime.InteropServices;
    using Microsoft.Win32;

    namespace Test
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }

            [StructLayout(LayoutKind.Sequential)]
            internal struct RAWINPUTDEVICE
            {
                [MarshalAs(UnmanagedType.U2)]
                public ushort usUsagePage;
                [MarshalAs(UnmanagedType.U2)]
                public ushort usUsage;
                [MarshalAs(UnmanagedType.U4)]
                public int dwFlags;
                public IntPtr hwndTarget;
            }

            RAWINPUTDEVICE[] rid = new RAWINPUTDEVICE[1];

            [DllImport("User32.dll")]
            extern static bool RegisterRawInputDevices(RAWINPUTDEVICE[] pRawInputDevice, uint uiNumDevices, uint cbSize);

            [DllImport("Kernel32.dll")]  //for beep
            public static extern bool Beep(UInt32 frequency, UInt32 duration);
           
            private void Form1_Load(object sender, EventArgs e)
            {
                //Register a raw input device - the remote control
                rid[0].usUsagePage  = 0xFFBC;
                rid[0].usUsage      = 0x88;
                rid[0].dwFlags      = 0;
                //rid[0].hwndTarget   = hwnd;
                RegisterRawInputDevices(rid, (uint)rid.Length, (uint)Marshal.SizeOf(rid[0]));
            }

            //override the WndProc so that we can look at the device messages, incl remote control
            protected override void WndProc(ref Message message)
            {
                Beep(200, 10);

                base.WndProc(ref message);
            }

        }
    }


    I used the following references to help me get this far

    http://www.codeproject.com/cs/system/rawinput.asp
    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/userinput/rawinput/aboutrawinput.asp
    http://msdn2.microsoft.com/en-us/library/aa468212.aspx

    The stephen Toub article also contains much info http://blogs.msdn.com/toub/archive/2005/04/19/409845.aspx
    and updated for vmc http://blogs.msdn.com/toub/archive/2007/01/03/position-changer-add-in-updated-for-windows-vista.aspx

    I shall update as my experiments help me understand this stuff! :)


    edit: of course a beep isn't of much use so, except on mce to test that something is happening
    so replace it with                
    Console.WriteLine(message.WParam.ToString()); and open an output window to see what is going on.

    You might try

                if (message.Msg == WM_KEYDOWN)
                {
                    Console.WriteLine(message.WParam.ToString());
                }

    where WM_KEYDOWN is defined as
    private const int WM_KEYDOWN = 0x0100;

    This reveal codes for quite a few keys although unfortunately for me the teletext buttons, though providing a message, do not seem to have any definition attached to them - anyone know anything?





    Gordon: Has reached the end!
  •  04-09-2007, 12:41 PM 2401 in reply to 2392

    Re: A C# form test prog to see what the remote control is doing

    Why do I bother?

    I was trying to transfer the basic  routines above to my background app, but I can't reference the WndProc. No matter what namespaces i use or checking that they are referenced, I can't seem to find one that works. i thought it was in System.Windows.Forms???

    However, in doing more research, I have discovered that this method aint going to work anyway.

    sugar!!!

    Looks like I really am going to have to hack the keyboard hooks...


    Gordon: Has reached the end!
  •  04-09-2007, 1:01 PM 2406 in reply to 2392

    Re: A C# form test prog to see what the remote control is doing

    Boy you really like the difficult stuff don't you!!!

    The issue with doing anything like this is that you're going to have to write your own handlers for keyboard input, as the KeyHandler and ShortcutHandler elements are much more restrictive than the raw input API.  

    Some of the keys on the remote pass back an APP_COMMAND message rather than a WM_INPUT message, so you'll need to process them differently.  There's an MSDN article on the remote control and what messages you get for each key - search for "Remote Control" or similar on MSDN and you should find it.

    Cheers,
    Andrew

  •  04-09-2007, 2:48 PM 2411 in reply to 2406

    Re: A C# form test prog to see what the remote control is doing

    Yeah, that's where I found the code for the remote Control, but I think it's out of date for Vista. One of the posters here in a thread on the remote control pointed out in  Toub's update vista app that this method wouldn't work - because of security I think, the ui just blocks it all (if I understood it?)

    As I said I can't egt the reference to wndproc to be recognised, otherwise since all I wanted to do was recognise one key (i.e. the hash key) then it would have been sweet. But nothing is ever that simple.

    Anyway, after investigating keyboard hooks and trying to find some simple code and failing, I've managed to hack Stephen's code to extract the stuff needed to display the basic keys.

    Here it is: Please note folks that this is Stephen's code and really you should acknowledge that in any apps (is permission needed in commercial apps?)

    using System;
    using System.Timers;
    using System.Collections;
    using System.Collections.Generic;
    using System.Threading;
    using Microsoft.MediaCenter;
    using Microsoft.MediaCenter.Hosting;
    using Microsoft.MediaCenter.UI;
    using System.Runtime.InteropServices;
    using System.Windows.Forms;
    using System.Diagnostics;
    using System.ComponentModel;
    using System.IO;
    using System.Runtime.ConstrainedExecution;
    using System.Security;
    using System.Security.Permissions;
    using Microsoft.Win32.SafeHandles;

    namespace VMCMusicList
    {
        public class VMCMusicList : IAddInModule, IAddInEntryPoint
        {

            private AddInHost _host;
            private ManualResetEvent vmcWaitForExit;
           
            private Process _ehshellProcess;

            // Initialize (IAddInModule)
            public void Initialize(Dictionary<string, object> appInfo, Dictionary<string, object> entryPointInfo)
            {
            }

            // Uninitialize (IAddInModule)
            public void Uninitialize()
            {
            }

            // Launch (IAddInModule)
            public void Launch(AddInHost host)
            {
                try
                {
                    _host = host;                                           //so that host is available globally in the code

                    using (vmcWaitForExit = new ManualResetEvent(false))    //Keep app alive till vmc exit
                    {
                        using (_ehshellProcess = GetEhShellProcess())       // Get the ehshell process
                        using (new KeyboardHook(_ehshellProcess.Id, hook_KeyDown))
                        {

                            vmcWaitForExit.WaitOne();                       //this should just sit here until vmc is closed
                        }
                    }
                   
                    _host = null;                                           //host is invalid once Launch returns... make sure we don't use it after this
                }
                catch (Exception exc)
                {
                    host.MediaCenterEnvironment.Dialog("Unable to launch. " + exc.ToString(),
                        "VMCMusicList", Microsoft.MediaCenter.DialogButtons.Ok, 0, true);
                    throw;
                }
            }

    //*******This is the "key" bit - ahem ***********      
            private void hook_KeyDown(object sender, KeyEventArgs e)        //handle the key
            {
                //Let's see what we have
                _host.MediaCenterEnvironment.Dialog(e.KeyCode.ToString(), "", Microsoft.MediaCenter.DialogButtons.Ok, 0, true);
            }

            /// <summary>Gets a reference to the Process instance for the running ehshell.exe</summary>
            private Process GetEhShellProcess()
            {
                // Get the current terminal services session ID
                int currentSessionId;
                using (Process currentProcess = Process.GetCurrentProcess()) currentSessionId = currentProcess.SessionId;

                // Get all ehome processes on the machine, and find the one in the current session
                Process[] procs = Process.GetProcessesByName("ehshell");
                Process ehshell = null;
                for (int i = 0; i < procs.Length; i++)
                {
                    if (ehshell == null && procs[i].SessionId == currentSessionId) ehshell = procs[i];
                    else procs[i].Dispose();
                }
                return ehshell;
            }

            /// <summary>StephenToub's Simple implementation of a keyboard hook for key down events on the GUI thread of an application.</summary>
            public sealed class KeyboardHook : IDisposable
            {
                /// <summary>Low-level keyboard hook id.</summary>
                private const int WH_KEYBOARD_LL = 13;
                /// <summary>Posted to the window with the keyboard focus when a nonsystem key is pressed.</summary>
                private const int WM_KEYDOWN = 0x0100;
                /// <summary>OS handle for the registered keyboard hook.</summary>
                private SafeWindowsHookHandle _hookHandle = null;
                /// <summary>Hook callback when a WH_KEYBOARD event occurs.</summary>
                private LowLevelKeyboardProc _hookProc;
                /// <summary>Delegate called when a key is pressed down.</summary>
                private KeyEventHandler _keyDown;
                /// <summary>Target process ID.</summary>
                private int _pid;

                /// <summary>Initializes the keyboard hook.</summary>
                /// <param name="keyDown">The delegate to be called when a key down event occurs.</param>
                public KeyboardHook(int targetProcessID, KeyEventHandler keyDown)
                {
                    if (keyDown == null) throw new ArgumentNullException("keyDown");

                    // Store the user's KeyDown delegate
                    _keyDown = keyDown;
                    _pid = targetProcessID;

                    // Create the callback and make sure it doesn't get GC'd,
                    // since it'll be called from unmanaged code
                    _hookProc = new LowLevelKeyboardProc(HookCallback);

                    // Set the hook for just the GUI thread
                    using (Process curProcess = Process.GetCurrentProcess())
                    using (ProcessModule curModule = curProcess.MainModule)
                    {
                        _hookHandle = SafeWindowsHookHandle.SetWindowsHookEx(
                            WH_KEYBOARD_LL, _hookProc, GetModuleHandle(curModule.ModuleName), 0);
                    }
                    if (_hookHandle.IsInvalid)
                    {
                        Exception exc = new Win32Exception();
                        Dispose();
                        throw exc;
                    }
                }

                /// <summary>Dispose the KeyboardHook.</summary>
                public void Dispose()
                {
                    if (_hookHandle != null)
                    {
                        _hookHandle.Dispose();
                        _hookHandle = null;
                    }
                }

                /// <summary>Event raised when an exception is encountered from a callback.</summary>
                public ErrorEventHandler Error = delegate { };

                /// <summary>HookCallback data.</summary>
                private struct KBDLLHOOKSTRUCT
                {
                    #pragma warning disable 0649
                    public uint vkCode;
                    public uint scanCode;
                    public uint flags;
                    public uint time;
                    public IntPtr dwExtraInfo;
                    #pragma warning restore 0649
                }

                /// <summary>Callback from the installed hook.</summary>
                ///</returns>
                private IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
                {
                    bool handled = false;
                    try
                    {
                        // Only respond to key down events when the shift key isn't pressed
                        if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
                        {
                            uint pid;
                            GetWindowThreadProcessId(GetForegroundWindow(), out pid);
                            if (pid == _pid)
                            {
                                KBDLLHOOKSTRUCT hookParam = (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));
                                Keys key = (Keys)hookParam.vkCode;
                                if (key == Keys.Packet) key = (Keys)hookParam.scanCode;

                                KeyEventArgs e = new KeyEventArgs(key | ModifierKeys);
                                _keyDown(this, e);
                                handled = e.Handled | e.SuppressKeyPress;
                            }
                        }

                        // If the event has not been handled/eaten by the user, relegate to the next hook in line.
                        return handled ?
                            new IntPtr(1) :
                            SafeWindowsHookHandle.CallNextHookEx(_hookHandle, nCode, wParam, lParam);
                    }
                    catch (Exception exc) { Error(this, new ErrorEventArgs(exc)); }
                    return new IntPtr(1);
                }

                /// <summary>Gets the modifier keys currently in use.</summary>
                private static Keys ModifierKeys
                {
                    get
                    {
                        Keys modifiers = Keys.None;
                        if (GetKeyState(VK_SHIFT) < 0) modifiers |= Keys.Shift;
                        if (GetKeyState(VK_CONTROL) < 0) modifiers |= Keys.Control;
                        if (GetKeyState(VK_ALT) < 0) modifiers |= Keys.Alt;
                        return modifiers;
                    }
                }

                /// <summary>
                /// The GetWindowThreadProcessId function retrieves the identifier of the thread that created the specified window
                /// and, optionally, the identifier of the process that created the window.
                /// </summary>
                /// <param name="hWnd">Handle to the window.</param>
                /// <param name="lpdwProcessId">Pointer to a variable that receives the process identifier.</param>
                /// <returns>The return value is the identifier of the thread that created the window.</returns>
                [DllImport("user32.dll", SetLastError = true)]
                private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);

                /// <summary>Returns a handle to the foreground window (the window with which the user is currently working).</summary>
                /// <returns>A handle to the foreground window.</returns>
                [DllImport("user32.dll", SetLastError = true)]
                private static extern IntPtr GetForegroundWindow();

                /// <summary>Virtual key value for shift.</summary>
                private const uint VK_SHIFT = 0x10;
                private const uint VK_CONTROL = 0x11;
                private const uint VK_ALT = 0x12;

                /// <summary>The GetKeyState function retrieves the status of the specified virtual key.</summary>
                /// <param name="nVirtKey">Specifies a virtual key.</param>
                /// <returns>The return value specifies the status of the specified virtual key.</returns>
                [DllImport("user32.dll", SetLastError = true)]
                private static extern short GetKeyState(uint nVirtKey);

                /// <summary>Retrieves a module handle for the specified module. The module must have been loaded by the calling process</summary>
                /// <param name="lpModuleName">The name of the loaded module (either a .dll or .exe file).</param>
                /// <returns>
                /// If the function succeeds, the return value is a handle to the specified module.
                /// If the function fails, the return value is NULL.
                /// </returns>
                [DllImport("kernel32.dll", SetLastError = true)]
                private static extern IntPtr GetModuleHandle(string lpModuleName);
            }

            /// <summary>LowLevelKeyboardProc for callbacks from the OS.</summary>
            internal delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);

            /// <summary>A SafeHandle for windows hook handles.</summary>
            [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
            internal sealed class SafeWindowsHookHandle : SafeHandleZeroOrMinusOneIsInvalid
            {
                /// <summary>Initializes the SafeWindowsHookHandle.</summary>
                private SafeWindowsHookHandle() : base(true) { }

                /// <summary>Releases the handle.</summary>
                /// <returns>true on success; false, otherwise.</returns>
                protected override bool ReleaseHandle()
                {
                    return UnhookWindowsHookEx(handle);
                }

                /// <summary>The UnhookWindowsHookEx function removes a hook procedure installed in a hook chain by the SetWindowsHookEx function.</summary>
                /// <param name="hhk">Handle to the hook procedure</param>
                /// <returns>true on success; otherwise, false.</returns>
                [SuppressUnmanagedCodeSecurity]
                [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
                [DllImport("user32.dll", SetLastError = true)]
                [return: MarshalAs(UnmanagedType.Bool)]
                private static extern bool UnhookWindowsHookEx(IntPtr hhk);

                /// <summary>The SetWindowsHookEx function installs an application-defined hook procedure into a hook chain.</summary>
                /// <param name="idHook">Specifies the type of hook procedure to be installed.</param>
                /// <param name="lpfn">Pointer to the hook procedure.</param>
                /// <param name="hMod">Handle to the DLL containing the hook procedure pointed to by the lpfn parameter.</param>
                /// <param name="dwThreadId">Specifies the identifier of the thread with which the hook procedure is to be associated.</param>
                /// <returns>If the function succeeds, the return value is the handle to the hook procedure; otherwise, 0.</returns>
                [DllImport("user32.dll", SetLastError = true)]
                public static extern SafeWindowsHookHandle SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);

                /// <summary>The CallNextHookEx function passes the hook information to the next hook procedure in the current hook chain.</summary>
                /// <param name="hhk">Handle to the current hook.</param>
                /// <param name="nCode">Specifies the hook code passed to the current hook procedure.</param>
                /// <param name="wParam">Specifies the wParam value passed to the current hook procedure.</param>
                /// <param name="lParam">Specifies the lParam value passed to the current hook procedure.</param>
                /// <returns>This value is returned by the next hook procedure in the chain.</returns>
                [DllImport("user32.dll", SetLastError = true)]
                public static extern IntPtr CallNextHookEx(SafeWindowsHookHandle hhk, int nCode, IntPtr wParam, IntPtr lParam);
            }

        }
    }



    Gordon: Has reached the end!
  •  04-09-2007, 2:55 PM 2412 in reply to 2411

    Re: A C# form test prog to see what the remote control is doing

    If anyone cares to reduce this to the bare minimum as there's lot's of stuff here that i'm not sure is totally necessary for the prupose of understanding - I don't :(


    Gordon: Has reached the end!
  •  04-09-2007, 4:42 PM 2416 in reply to 2411

    Re: A C# form test prog to see what the remote control is doing

    The problem with the code above is that yet again it is completely beyond me, so I have no idea how I can adapt it, simplify it, alter it to allow me to look at other controls.

    Can anyone explain it? apart from Stephen Toub

    I decided to have another look at my first wndproc override idea that seems a lot simpler. Then I spotted this thread  http://discuss.mediacentersandbox.com/forums/post/1656.aspx  where AndyC says that because MS changed things, it is not possible to basically link into the main window, so you can't use wndproc.

    So, apart from these keyboard hooks, is there any other simple way of seeing what messages are going on?

    If not, then could someone show how a basic and simple global keyboard/remote/mouse hook works, please.

    Is anything simple in this media center world????



    Gordon: Has reached the end!
  •  04-09-2007, 11:15 PM 2438 in reply to 2416

    Re: A C# form test prog to see what the remote control is doing

    Gordon,

    What exactly is it that you're trying to do?

    The reason I ask is that you are taking the most imaginably complex way about getting a key press out of Media Center, as you are trying to do something that the platform isn't designed to do - that's why it's difficult.

    If you are trying to intercept the # key while (for example) watching TV, then yes it is possible in Vista.  There is an update to Stephens article that works with a global, low-level keyboard hook which intercepts ALL keypresses regardless of whether they are destined for Media Center or Wordpad, Outlook, etc.    A simple example (or at least as simple as this topic gets) is here: http://blogs.msdn.com/toub/archive/2006/05/03/589423.aspx

    The method that works with MCE2005 Update Rollup 2 also works in Vista - the UR2 version of Stephens add-in is here: http://blogs.msdn.com/toub/archive/2005/10/14/481082.aspx

    If you just want to get a keypress from within an interactive add-in (i.e. one that is in "More Programs" and shows a UI before requiring a keypress), have a look at KeyHandler and ShortcutHandler in the MCE SDK.

    Cheers,
    Andrew

     

  •  04-10-2007, 2:53 AM 2443 in reply to 2438

    Re: A C# form test prog to see what the remote control is doing

    Thanks Andy.

    All I'm trying to achieve is to do something like

    launch Addin(..)
    {
    //whilst waiting for vmc to end

    SetUpAnEventForWhenARemoteKeyIsPresed( EventForRemoteKeyPressed)  //is this what delegates do?

    //sit here unit vmc exits
    }

    EventForRemoteKeyPressed (or mouse or any device)
    {
    //Check what key pressed
    DoMyProcessing()
    }

    domyprocessing()
    {
    }

    This is how windows forms work? event driven architecture. I assumed that it would be how vmc would work?

    I saw the article on low level kbd hooks and thought that's it, but being thick, I couldn't see how to utilise it. I assume that something is returning the keystrokes to the console that's opened by Application.Run, but I just don't know how to utilise it. As you may have seen there is no explanation of how it works (okay, well Stephen's |time travel explains things granted). As I said I  realise I don't have a very good understanding of .Net really. :( - I've got loads of books though :)

    I didn't realise I was being complex in what I was trying to do. it seemed to me naively that intercepting the messages that the remote sends to media center (which is a net app?) and hijacking it by overriding wndproc seemed eminently sensible and simple. I accept that there are performance issues to this, and that there are more sophisticetd ways - keyboard hooks, but if the sdk would just add an event for the remote button pressed, we could do what we want.

    In fact Stephen warns about using keyboard hooks as they may not work in future, so once again we are left with no safe mechanism for doing something that should be trivial.

    I asuume that media center itself is a collection of apps, they must read the remote, so how do they do it, and why can't they simply open up the interface?

    Anyway if you know how I can utilise the Toub low level hooks I'd be very grateful.

    [Thanks my friend for all your interest and involvement. It is deeply appreciated by me and I'm sure by many others - Thankyou. I owe you a few pints that's for sure.]


    Edit: I'm reading the second article now (I must have missed the explanations? of what changed or didn't understand it at the time) and the kb article it refers to, so hopefully I may understand better soon.






    Gordon: Has reached the end!
  •  04-10-2007, 4:05 AM 2444 in reply to 2443

    Re: A C# form test prog to see what the remote control is doing

    Is your addin a background addin or a foreground addin?

     

  •  04-10-2007, 4:39 AM 2446 in reply to 2444

    Re: A C# form test prog to see what the remote control is doing

    It's a background app.

    I think I've found what I was looking for.

    There is a Console.Writeline in the HookCallback method which returns the keys to the console. Application.console just starts up the console, I think.

    If I change this to call my processing procedure and just make sure I grab the proper process, I think I should be in with a shout.





    Gordon: Has reached the end!
  •  04-10-2007, 5:51 AM 2450 in reply to 2446

    Re: A C# form test prog to see what the remote control is doing

    So after a bit of tweaking of S. Toub's low level keyboard hook, mentioned in AndyC's reply which in particular involved setting my user method to be static, and also vmcHost to be also static I got this:

    using System;
    using System.Collections.Generic;
    using System.Threading;
    using Microsoft.MediaCenter;
    using Microsoft.MediaCenter.Hosting;
    using Microsoft.MediaCenter.UI;
    using System.Runtime.InteropServices;
    using System.Diagnostics;

    namespace VMCMusicList
    {
        public class VMCMusicList : IAddInModule, IAddInEntryPoint
        {
            private static AddInHost vmcHost;
            private ManualResetEvent vmcWaitForExit;

            // Initialize (IAddInModule)
            public void Initialize(Dictionary<string, object> appInfo, Dictionary<string, object> entryPointInfo)
            {
            }

            // Uninitialize (IAddInModule)
            public void Uninitialize()
            {
            }

            // Launch (IAddInModule)
            public void Launch(AddInHost host)
            {
                try
                {
                    vmcHost = host;                                         //so that host is available globally in the code

                    using (vmcWaitForExit = new ManualResetEvent(false))    //Keep app alive till vmc exit
                    {
                        _hookID = SetHook(_proc);

                        vmcWaitForExit.WaitOne();                           //this should just sit here until vmc is closed
                        UnhookWindowsHookEx(_hookID);
                    }

                    vmcHost = null;                                           //host is invalid once Launch returns... make sure we don't use it after this
                }
                catch (Exception exc)
                {
                    host.MediaCenterEnvironment.Dialog("Unable to launch. " + exc.ToString(),
                        "VMCMusicList", Microsoft.MediaCenter.DialogButtons.Ok, 0, true);
                    throw;
                }
            }


            private static void HandleRemoteControlKeys(int vkCode)   //this is where I intend to handle my app, I'm not sure I understand the static keyword though. I assume it's because I will only ever have the one instance. Anyway Toub's routines can't access it if its not static.
            {
                vmcHost.MediaCenterEnvironment.Dialog(vkCode.ToString(), "", Microsoft.MediaCenter.DialogButtons.Ok, 0, true);
            }

            //S Toub's Low level Keyboard Hook http://blogs.msdn.com/toub/archive/2006/05/03/589423.aspx
            private const int WH_KEYBOARD_LL = 13;
            private const int WM_KEYDOWN = 0x0100;
            private static LowLevelKeyboardProc _proc = HookCallback;
            private static IntPtr _hookID = IntPtr.Zero;

            private static IntPtr SetHook(LowLevelKeyboardProc proc)
            {
                using (Process curProcess = Process.GetCurrentProcess())
                using (ProcessModule curModule = curProcess.MainModule)
                {
                    return SetWindowsHookEx(WH_KEYBOARD_LL, proc,
                        GetModuleHandle(curModule.ModuleName), 0);
                }
            }

            private delegate IntPtr LowLevelKeyboardProc(
                int nCode, IntPtr wParam, IntPtr lParam);

            private static IntPtr HookCallback(
                int nCode, IntPtr wParam, IntPtr lParam)
            {
                if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
                {
                    int vkCode = Marshal.ReadInt32(lParam);

                    HandleRemoteControlKeys(vkCode);
                }
                return CallNextHookEx(_hookID, nCode, wParam, lParam);
            }

            [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            private static extern IntPtr SetWindowsHookEx(int idHook,
                LowLevelKeyboardProc 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);

        }
    }

    It justs shows the keycodes in a dialogbox. Again you have to wait about ten seconds before its active!

    Okay there are a couple of things that I'm wondering about.

    1) I've placed the  UnhookWindowsHookEx(_hookID); after the  vmcWaitForExit.WaitOne(); routine. I assume this is okay?

    2) In Toub's main article and the code for vista (also in one of the above posts, he has a much more sophisticated GetEhShellprocess routine. Should this be incorporated into the app and if so how? Is it just a matter of replacing the  using (Process curProcess = Process.GetCurrentProcess()) in the SetHook routine with    using (Process curProcess = Process.GetEhShellprocess())
    If required, what is it's point?







    Gordon: Has reached the end!
  •  04-10-2007, 6:41 AM 2452 in reply to 2450

    Re: A C# form test prog to see what the remote control is doing

    1) You could put the Unhook... in a finally clause so that it definitely gets called, exception or not.

    2) Yes that should be okay - the more complicated one is to ensure you get the right EhShell when running on a system with more than one copy running (e.g. when using extenders)

    Cheers,
    Andrew

  •  04-10-2007, 8:21 AM 2454 in reply to 2452

    Re: A C# form test prog to see what the remote control is doing

    Excellent.

    Whe hey, onto the next battle,

    blood is dripping from his vorpal blade, but no manxome foe does he fear. Beware jabberwock!!!

    -apologies to the Rev Charles Dodgson (deceased)



    Gordon: Has reached the end!
  •  10-30-2008, 9:23 AM 8546 in reply to 2454

    Re: A C# form test prog to see what the remote control is doing

    Hey People.

    I will bring back this Thread up to the top :).

    I  have test your Background app. Works fine.
    Now I have adapt the Code to a separate Class (see appendix)

    In my app I want to use it like this

    VMCRemoteControl rc = new VMCRemoteControl();

    and in the HandleRemoteControlKeys(int vkCode) Method I want to handle with a switch block the Keys.

    VMCRemoteControl.cs

    Debbugging shows me, that the rc-Object is built, but he never breaks at the HandleRemoteControlKeys or HookCallBack Method.

    Why not?

    Is it generally possible to hook Keys like numeric 0 inside of my Addin-Code with this LowLevelKeyBoardHook?

    Saw and test Projects like VMCControl and others. But they only can send Input. I want to receive from RemoteControl inside Media Center :)

    For a form it is easy.


    best regards, tronic
  •  10-30-2008, 9:31 AM 8547 in reply to 8546

    Re: A C# form test prog to see what the remote control is doing

    tronic,

    What is it that you are trying to do?  The same applies here as to Gordon - this is a very complex way of getting a keypress from Media Center that you shouldn't use unless you really have to.

    Cheers,
    Andrew

Page 1 of 2 (23 items)   1 2 Next >
View as RSS news feed in XML
Powered by Community Server, by Telligent Systems