0

I'm searching a way to disable alt and ctrl key input while I'm pressing it. I'm actually developping a Macro Configurer and when I press my macro (for example Alt+Ctrl+NumPad0) and I want that the keys H+E+L+L+O are sent, it won't work because I'm pressing Alt. The computer probably tries to execute unknown shortcuts for Alt+Ctrl+H, Alt+Ctrl+E ... So I want that when I press my macro and the program detects I pressed it, it disable temporary alt while the output keys are sent, and enable again Alt when it's finished. I use a LowLevelKeyboardProc to detect when i press a key, but I can't prevent the Alt pressing because i'm actually pressing it to execute my macro.

//The code from my form

private void Listener_OnKeyUp(object sender, KeyUpArgs e)
{
    KeyAction.RemoveKeyDown(e.KeyUp);
}


private void Listener_OnKeyPressed(object sender, KeyPressedArgs e)
{
    try
    {
        KeyAction.PutKeyDown(e.KeyPressed);
        foreach (MacroEntree macro in macros)
        {
            if (macro.Activated)
                if (macro.Action != null)
                    if (macro.isMacroDown())
                    {
                        listener.OnKeyPressed -= new EventHandler<KeyPressedArgs>(Listener_OnKeyPressed);
                        new Thread(delegate ()
                        {
                            while (IsAltCtrlDown()) ;
                            macro.ExecuteAction();
                            Thread.Sleep(100);
                            listener.OnKeyPressed += new EventHandler<KeyPressedArgs>(Listener_OnKeyPressed);

                        }).Start();
                    }
        }
    }
    catch (Exception ex)
    {

        MessageBox.Show("Erreur : " + ex.Message);
    }
}
private bool IsAltCtrlDown()
{
    if (KeyAction.isKeyDown(Key.LeftAlt) || KeyAction.isKeyDown(Key.RightAlt))
        return true;
    if (KeyAction.isKeyDown(Key.LeftCtrl) || KeyAction.isKeyDown(Key.RightCtrl))
        return true;
    return false;
}


//the code from my class that checks if the macro is down
public class KeyAction
{
   static List<Key> keyDown = new List<Key>();

    public static bool isKeyDown(Key k)
    {
        return keyDown.Contains(k);
    }
    public static void PutKeyDown(Key k)
    {
        if (!keyDown.Contains(k))
            keyDown.Add(k);
    }
    public static void RemoveKeyDown(Key k)
    {
        keyDown.Remove(k);
    }

}

Fosheus Badabu
  • 351
  • 1
  • 3
  • 10

2 Answers2

3

You could set a low-level keyboard hook to swallow keyboard input messages in windows.

Every native Windows program bases on a so called message loop that is basicly this.

MSG msg;
while(GetMessage(&msg, NULL, 0, 0))
{ 
    TranslateMessage(&msg); 
    DispatchMessage(&msg); 
}

With an low-level keyboard hook you can handle messages in this loop on the desktop process and with that prevent keys from being pressed.

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

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(
    int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);

private const int WH_KEYBOARD_LL = 13;
private static IntPtr SetHook(LowLevelKeyboardProc proc)
{
    return SetWindowsHookEx(
        WH_KEYBOARD_LL, 
        proc, 
        0, // hook on all input (https://stackoverflow.com/questions/7715480/is-zero-ever-a-valid-handle)
        0); // for all threads
}

You can use the code like the following. When you do not call CallNextHookEx the key event will not have any impact.

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
    IntPtr wParam, IntPtr lParam);

private const int WM_KEYDOWN = 0x0100;

private static IntPtr HookCallback(
    int nCode, IntPtr wParam, IntPtr lParam)
{
    // check if it is a key down message
    if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
    {
        int vkCode = Marshal.ReadInt32(lParam);
        // check if the pressed key is the `Alt` key
        if((Keys)vkCode == Keys.Alt)
        {
            // return 1 for handled if its the alt key
            return (IntPtr) 1; 
        }
    } 

    // let the message bubble if its not a keydown message or it wasn't the alt key which was pressed               
    return CallNextHookEx(_hookID, nCode, wParam, lParam);
}

// with this line you can set the `HookCallback` into the message loop
IntPtr hookID = SetHook(HookCallback);

And don't forget to unset the hook.

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);

UnhookWindowsHookEx(hookID);
Community
  • 1
  • 1
NtFreX
  • 10,379
  • 2
  • 43
  • 63
  • Thank your for your response. I've already tried this but I can't prevent the Alt key to be pressed if I'm actually pressing it to execute my macro. I would need to disable Alt key while I'm pressing it and until the executed action is finished. – Fosheus Badabu Dec 12 '16 at 09:10
  • 1
    @FosheusBadabu How is the code supposed to determine if any key is being pressed as a part of the macro or not? What if the user presses the Alt key, but waits a minute and a half to complete the macro? – krillgar Dec 12 '16 at 14:14
  • Sorry for late response.The macro will be executed a minute and a half later, and tht's not what i want. I've an event in the Hookcallback that my form catches. I've also a class that check if the macro is down. When a key is catch in the event, I check if other keys are down with my class (It's a list that I fill and clean when ever a key is being down or up), and while the macro is down I wait until alt and ctrl are released. – Fosheus Badabu Dec 12 '16 at 22:08
  • @FosheusBadabu this is a problem related to your other code. show code samples about what you have done. But think about it first if its related to this question or a compleatly new one – NtFreX Dec 12 '16 at 22:12
  • I actually know how to disable certain key but i just want to disable the alt key for some µseconds to execute my macro and reenable it after. The problem is that i can't disable alt key in the HookCallback because I'm already pressing it. – Fosheus Badabu Dec 12 '16 at 22:30
0

Thanks to @Manfred Radlwimmer I solved the problem. I send a Alt and Ctrl key up before executing my action and it works fine.

    private void Listener_OnKeyPressed(object sender, KeyPressedArgs e)
    {
        try
        {
            KeyAction.PutKeyDown(e.KeyPressed);
            foreach (MacroEntree macro in macros)
            {
                if (macro.Activated)
                    if (macro.Action != null)
                        if (macro.isMacroDown())
                        {
                            listener.OnKeyPressed -= new EventHandler<KeyPressedArgs>(Listener_OnKeyPressed);
                            new Thread(delegate ()
                            {
                                KeyboardOperations.SendKeyUp(KeyboardOperations.KeyCode.LALT);
                                KeyboardOperations.SendKeyUp(KeyboardOperations.KeyCode.LCONTROL);

                                macro.ExecuteAction();
                                Thread.Sleep(100);
                                listener.OnKeyPressed += new EventHandler<KeyPressedArgs>(Listener_OnKeyPressed);

                            }).Start();
                        }
            }
        }
        catch (Exception ex)
        {

            MessageBox.Show("Erreur : " + ex.Message);
        }
    }
Fosheus Badabu
  • 351
  • 1
  • 3
  • 10