Lock keyboard and mouse in C#, but keeping the execution of a method

Asked

Viewed 1,168 times

3

I need to block the use of keyboard and mouse in form while it will perform a certain function of the system, on which I am placing the call of the blocking method in the event of Load of the form, in which it is actually blocking the keyboard and mouse, but does not execute the method that is right after your call. Follow a test code I’m doing to test this procedure:

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

namespace GSD
{
    public partial class FormTeste : Form
    {
        public FormTeste()
        {
            InitializeComponent();
        }

        private void FormTeste_Load(object sender, EventArgs e)
        {
            SetHookMouse();
            SetHookTeclado();

            Teste();
        }


        private void Teste()
        {
            //Implementação do método            
        }


        //------------------------------------------------------------------------------------------------------------------------------------
        //
        //Raliza o Bloqueio do Mouse
        //
        //-------------------------------------------------------------------

        // Importa as funções que serão usadas
        [DllImport("user32.dll")]
        private static extern IntPtr SetWindowsHookExMouse(int idHook,
            LowLevelMouseProc lpfn, IntPtr hMod, uint dwThreadId);

        [DllImport("user32.dll")]
        static extern bool UnhookWindowsHookExMouse(IntPtr hInstance);

        [DllImport("user32.dll")]
        static extern IntPtr CallNextHookExMouse(IntPtr idHook, int code, int wParam, IntPtr lParam);

        [DllImport("kernel32.dll")]
        static extern IntPtr LoadLibraryMouse(string lpFileName);

        private delegate IntPtr LowLevelMouseProc(int code, IntPtr wParam, IntPtr lParam);

        private enum MouseMessages
        {
            WM_LBUTTONDOWN = 0x0201,
            WM_LBUTTONUP = 0x0202,
            WM_MOUSEMOVE = 0x0200,
            WM_MOUSEWHEEL = 0x020A,
            WM_RBUTTONDOWN = 0x0204,
            WM_RBUTTONUP = 0x0205
        }

        const int WH_MOUSE_LL = 14; // Tipo de hook que será usado

        private LowLevelMouseProc hookMouse = hookProcMouse;
        private static IntPtr hhookMouse = IntPtr.Zero;

        public void SetHookMouse()
        {
            IntPtr hInstance = LoadLibraryMouse("User32");
            hhookMouse = SetWindowsHookExMouse(WH_MOUSE_LL, hookMouse, hInstance, 0); // Instala o hook para a interceptação dos eventos do mouse
        }

        public static void UnHookMouse()
        {
            UnhookWindowsHookExMouse(hhookMouse); // Remove o hook instalado
        }

        public static IntPtr hookProcMouse(int code, IntPtr wParam, IntPtr lParam)
        {
            // Se a mensagem recebida for > 0 e o clique do mouse for do botão esquerdo ou direito
            if (code >= 0 && MouseMessages.WM_LBUTTONDOWN == (MouseMessages)wParam || MouseMessages.WM_RBUTTONDOWN == (MouseMessages)wParam)
            {
                return (IntPtr)1; // Inibe o clique
            }
            else
                return CallNextHookExMouse(hhookMouse, code, (int)wParam, lParam); // Passa para o próximo evento
        }

        //------------------------------------------------------------------------------------------------------------------------------------
        //
        //Raliza o Bloqueio do Teclado
        //
        //-------------------------------------------------------------------

        // Importa as funções que serão usadas
        [DllImport("user32.dll")]
        static extern IntPtr SetWindowsHookExTeclado(int idHook, LowLevelKeyboardProc callback, IntPtr hInstance, uint threadId);

        [DllImport("user32.dll")]
        static extern bool UnhookWindowsHookExTeclado(IntPtr hInstance);

        [DllImport("user32.dll")]
        static extern IntPtr CallNextHookExTeclado(IntPtr idHook, int code, int wParam, IntPtr lParam);

        [DllImport("kernel32.dll")]
        static extern IntPtr LoadLibraryTeclado(string lpFileName);

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

        const int WH_KEYBOARD_LL = 13; // Tipo de hook que será usado
        const int WM_KEYDOWN = 0x100;  // Messagem usada para quando uma tecla for pressionada

        private LowLevelKeyboardProc hookTeclado = hookProcTeclado;
        private static IntPtr hhookTeclado = IntPtr.Zero;

        public void SetHookTeclado()
        {
            IntPtr hInstance = LoadLibraryTeclado("User32");
            hhookTeclado = SetWindowsHookExTeclado(WH_KEYBOARD_LL, hookTeclado, hInstance, 0); // Instala o hook para o teclado
        }

        public static void UnHookTeclado()
        {
            UnhookWindowsHookExTeclado(hhookTeclado);
        }

        public static IntPtr hookProcTeclado(int code, IntPtr wParam, IntPtr lParam)
        {
            if (code >= 0 && wParam == (IntPtr)WM_KEYDOWN)
            { // Quando uma tecla for pressionada
                return (IntPtr)1; // Inibe o funcionamento
            }
            else
                return CallNextHookExTeclado(hhookTeclado, code, (int)wParam, lParam); // Passa para o próximo evento
        }

        private void FormTeste_FormClosing(object sender, FormClosingEventArgs e)
        {
            UnHookMouse();

            UnHookTeclado();
        }
    }
}

I have tried to use this code as an alternative but it does not lock really be blocking the event generated by the mouse, then with a time the application starts to appear the message that the system has stopped responding. Remembering that all these codes are based on the examples that are available in: Block keyboard and mouse or prevent user from leaving window in C#

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

  private void FormTeste_Load(object sender, EventArgs e)
            {
                BlockInput(true);

                Teste();
            }
  • What is the minimum version of the OS that will run? You need to lock your keyboard and mouse and keep the screen or what you really want is to block the workstation while running a routine?

  • @Intruder would only lock the keyboard and mouse only in the form being called and keeping the execution of its functions, so soon after the completion of this functions this form will be closed and since it is called as ShowDialog the rest of the application will also be active. On the operating system used will be from windows XP.

  • So actually what you need is to avoid input of data via keyboard/mouse in the application (form), right? Have you ever tried to block the form input controls instead of locking the keyboard/mouse? It would make the code much simpler.

  • @Intruder is juxtaposing the lock only in the form, in which I have also defined the form Enabled = false; only that the problem being that when this form is called usually it will take about 3 to 5 minutes without the user can do anything in it, ai if during that time it keeps clicking or doing anything else the application starts to appear to msg that the application is not responding.

  • Implement a background worker run its process. Instead of blocking the form, check the status of the background worker. This will keep your application responsive, while you can send a message that the process is still running - or even display a runtime percentage.

  • @Ibotinelly actually that was the first thing I started to do, but I have some problems like being in the post: http://answall.com/questions/108392/progressbar-e-backgroundworker-em-c ai ai as alternative I came to lock the mouse and keyboard that is not working, Now I don’t know how else to do it. Because what I need is that during a certain time, time that I have no way of knowing for sure how much it will be necessary for the reading of sql file and execution of the same for the population of the database and during that period the user can not do anything in the application.

  • See if my answer helps.

Show 2 more comments

1 answer

2


Separate the execution thread of the screen (from the form) from the execution thread of your method. The application hangs and looks as if it is not responding because by default the form thread is used to run the events (methods) of your form. So he either upgrades or executes, you know,?

To solve, you can simply put your method into another thread and lock the form controls until the thread is finished. There are many ways to do this, but each one has some implications.

Use a delegate for a method that runs when finishing the thread. As you may know, a delegate is a "pointer" to a method and can be called on event-oriented executions. Usually, when you click on a button and declare a method, when you look at the properties, you check that method is "assigned" to the 'on_click' button event. In fact, you have a delegate pointing to your method and that delegate is called when someone clicks.

public class Form1 : Form
{
    int _count;

    void ButtonClick(object sender, EventArgs e)
    {
        ThreadWorker worker = new ThreadWorker(HandleThreadDone);

        Thread thread1 = new Thread(worker.Run);
        thread1.Start();

        _count = 1;
    }

    void HandleThreadDone()
    {
        // As before - just a simple example
        if (_count == 1)
        {
            ThreadWorker worker = new ThreadWorker();

            Thread thread2 = new Thread(worker.Run);
            thread2.Start(HandleThreadDone);

            _count++;
        }
    }

    class ThreadWorker
    {
        // Switch to your favourite Action<T> or Func<T>
        public void Run(object state)
        {
            // Do a task

            Action completeAction = (Action)state;
            completeAction.Invoke();
        }
    }
}

Use an event. You can trigger an event at the end of a tread job (remember the explanation above). See the example:

public class Form1 : Form
{
    int _count;

    void ButtonClick(object sender, EventArgs e)
    {
        ThreadWorker worker = new ThreadWorker();
        worker.ThreadDone += HandleThreadDone;

        Thread thread1 = new Thread(worker.Run);
        thread1.Start();

        _count = 1;
    }

    void HandleThreadDone(object sender, EventArgs e)
    {
        // You should get the idea this is just an example
        if (_count == 1)
        {
            ThreadWorker worker = new ThreadWorker();
            worker.ThreadDone += HandleThreadDone;

            Thread thread2 = new Thread(worker.Run);
            thread2.Start();

            _count++;
        }
    }

    class ThreadWorker
    {
        public event EventHandler ThreadDone;

        public void Run()
        {
            // Do a task

            if (ThreadDone != null)
                ThreadDone(this, EventArgs.Empty);
        }
    }
}

The differences are subtle, but you should be able to understand the concept. In your particular case, you will need 2 more ways, one to block the form controls and the other to enable the controls. In the initial state, you fire your task and block the controls and when finishing the thread, run the method to unlock.

The screen will be updated (locked), but will no longer display the message of not responding.

  • to be honest I did not understand much no, if possible you could explain a little more as is the logic of functioning of the class Threadworker and the method Rum. Thanks in advance!

Browser other questions tagged

You are not signed in. Login or sign up in order to post.