0
votes

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);
    }

}

2
Can't you sent a KeyUp for Ctrl + Alt? Maybe that way the system might think you already released the keys (with keybd_event).Manfred Radlwimmer
I will try this,I didn't think about it.Fosheus Badabu
Edit : I just tried it and it's working, it was too easy to think about it.... Thank you !!Fosheus Badabu
Glad to hear that. You could post the actual solution as an answer to this question so people with the same problem can use it too.Manfred Radlwimmer

2 Answers

3
votes

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://stackguides.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);
0
votes

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);
        }
    }