简体   繁体   中英

Prevent Keyboard events during mouse Click (not released)

I'm actually working on a background processing (in a new created thread, not deamon) which allow several action binded on special keystrokes.

My special keystroke is : the left mouse click, and before release the click, press some key on the keyboard, then after the left mouse releases, some action are executed. This parts works only on few softwares.

For exemple, on Google Chrome in a html input, or notepad++, if I click then press some key, the lettre/digit pressed is display as usual, on release the action is performed (SMFL.Window.Keyboard is used to detech which key is pressed)

I want to prevent this default behavior, record the pressed keys during the "left click" and continue my processing with these keys recorded.

I got 2 ideas :

1 - Use BlockInput from pInvoke

[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern bool BlockInput([In, MarshalAs(UnmanagedType.Bool)] bool fBlockIt);

But this method always return false (zero). Is that because an input is currently performed ? (the left button of the mouse is pressed) It can be a very great solution but : I can't test it ; Does it will block every keyboard event ? (If I can't retrieve any information about the key pressed, it's useless for my app)

2 - Create invisible window with focus

Another way to prevent keyboard event on a specific window may be to open a invisible window, set the focus on it, close the window on mouse button release. I can't success to set the focus on this new opened window while my mouse button is pressed

Some code :

while (true) // background process listening
{
  if (Mouse.IsButtonPressed(Mouse.Button.Left)) // keyboard/mouse event with SFML
    {
         _focus = new focusManager(); // Start new thread to create new invisible window
         Thread thread = new Thread(new ThreadStart(_focus.preventFocus));
         thread.Start();
         _focus.forceFocus ();
    }
  else
    {
         _focus.giveFocus ();
    }

}

with

 class focusManager
    {
        [DllImport("user32.dll")]
        static extern IntPtr GetForegroundWindow();

        [DllImport("user32.dll")]
        static extern bool SetForegroundWindow(IntPtr hWnd);

        [DllImport("user32.dll")]
        private static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count);

        [DllImport("user32.dll")]
        static extern IntPtr SetFocus(IntPtr hWnd);

        [DllImport("kernel32.dll")]
        static extern IntPtr GetCurrentProcess();

        private IntPtr _focusedApp; // IntPtr id of "paused" app
        private IntPtr _currentId;  // IntPtr id of current app for invisible window focus
        private Form _f; // invisible window

        public void preventFocus ()
        {
            // save IntPtr of current focused window
            _focusedApp = GetForegroundWindow();

            // debug print
            StringBuilder name = new StringBuilder(256);
            GetWindowText(_focusedApp, name, 256);
            Console.WriteLine("Steal Focus from " + name);

            openInvisibleWindow();
        }

        private void openInvisibleWindow ()
        {
           // get process ID to be able to set the focus on the invisible window
            _currentId = GetCurrentProcess();

            // create invisible window form
            _f = new Form();
            _f.FormBorderStyle = FormBorderStyle.FixedToolWindow;
            _f.ShowInTaskbar = false;
            _f.StartPosition = FormStartPosition.Manual;
            _f.Location = new System.Drawing.Point(100, 100); // visible for testing
            _f.Size = new System.Drawing.Size(100, 100);
            _f.Focus();
            _f.TopMost = true;

            Application.Run(_f);

        }

        // set the focus on the new window
        public void forceFocus ()
        {
             SetForegroundWindow(_currentId);

             // debug print
             StringBuilder name = new StringBuilder(256);
             GetWindowText(_currentId, name, 256);
             Console.WriteLine("have Focus on " + name);
        }

        // set the focus on the "paused" app to launch keystroke action on it
        // close the invisible window
        public void giveFocus()
        {
            SetForegroundWindow(_focusedApp);
            Application.Exit();
        }
    }

Any idea why BlockInput always return False ? Any Idea why I can't set focus on this new window ? Last case : Any other idea to prevent the keyboard behavior on specific application (chrome, norepad++..., targets of my keystrokes actions)

Thanks a lot

Use a keyboard hook is the best working solution found. Instead of this article from code-project, I used a Kb Hook from GitHub , it's much easier to use and more compact.

In order to block the processing of the key on the current window, the callback has to return 1 instead of the value of the CallNextHookEx windows API function.

In the project found on Github, the callback is :

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

and the replace the last line :

return InterceptKeys.CallNextHookEx(hookId, nCode, wParam, lParam);

by

return (IntPtr) 1;

Be careful

The CallNextHookEx method (here defined in InterceptKeys class) call the next hook(s) for the key event. If you replace the call, the processing on the key event isn't processed anymore, it can be dangerous because target application may have its own keyboard Hook.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM