1

I am a beginner at C# and would like some advice on how to solve the following problem:

I want to make an event to enable some text boxes when random press the following key "ctrl + v + a" anywhere in form.

  private void test_KeyDown(object sender, KeyEventArgs e)
    {
        if ((int)e.KeyData == (int)Keys.Control + (int)Keys.V + (int)Keys.A)
        {
            textbox1.Enabled = true;
            textbox2.Enabled = true;

        }
    }

The following code is not working.

mrkefca
  • 55
  • 8
  • is it `WPF`/`WinForms`/`UWP` project? – ekvalizer Mar 01 '21 at 11:18
  • @ekvalizer It is WinForms project. – mrkefca Mar 01 '21 at 11:20
  • What do you mean by random press? If I only press v. Would be enough for Enabling? – Berkay Yaylacı Mar 01 '21 at 11:49
  • Whatever I do in a form and when I press a specific sequence of keys I want automatically enabling some textboxes. I will use that for calibrating some system and it need to be protected with specific sequence of keys. – mrkefca Mar 01 '21 at 12:07
  • @Berkay Like, you cannot put anything in a text box (it is disabled), until you unlock textbox by pressing specific sequence of keys (Ctlr+v+a or any other set sequence) – mrkefca Mar 01 '21 at 12:12

6 Answers6

3

Basically you want to track key events of forms.

First, you can inherit all your forms from base form (Form's KeyPreview property should be True), like;

public class BaseForm : Form
{
    private static List<Keys> keyPress = new List<Keys>(); // to store the key values
    public BaseForm()
    {
        this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.BaseForm_KeyDown); // register event for all forms which inherits from BaseForm
    }

    private void BaseForm_KeyDown(object sender, KeyEventArgs e)
    {
        if (e.KeyCode == Keys.ControlKey || e.KeyCode == Keys.C || e.KeyCode == Keys.V) // right now Control, C, V keys are included
        {

            if (keyPress.Any(x => x == e.KeyCode)) // If keypress list has the current key press so pattern is broken
            {
                keyPress.Clear(); //clear the list user should start again
            }
            else
            {
                keyPress.Add(e.KeyCode);
            }

            if (keyPress.Count > 2) 
            {
                this.Controls["textBox1"].Enabled = true; 
                keyPress.Clear(); // clear the keyPress list
            }
        }
    }
}

So by doing this, you don't need to register keydown event for all your forms.

Second, you can use global key hook. (More information click this) At the main thread enterance Low-LevelKeyboardHook will be attached to the process and every key event will be catched at HookCallback.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Linq;

namespace KeyHookTryApp
{
   static class Program
   {
       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 Form1 f;
       private static List<Keys> keyPress = new List<Keys>();
       /// <summary>
       /// The main entry point for the application.
       /// </summary>
       [STAThread]
       static void Main()
       {
           _hookID = SetHook(_proc);
           Application.EnableVisualStyles();
           Application.SetCompatibleTextRenderingDefault(false);
           f = new Form1();
           Application.Run(f);
           UnhookWindowsHookEx(_hookID);
       }
       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)
       {
           int vkCode = Marshal.ReadInt32(lParam);
           Keys key = (Keys)vkCode;

           if (nCode >= 0 && ((key == Keys.LControlKey || key == Keys.RControlKey) || key == Keys.C || key == Keys.V))
           {
               if (keyPress.Any(x => x == key))
               {
                   keyPress.Clear();
               }
               else
               {
                   keyPress.Add(key);
               } 

               if (keyPress.Count > 2)
               {
                   f.Controls["textBox1"].Enabled = true;
                   keyPress.Clear();
               }
           }
           else if(keyPress.Count > 0)
           {
               keyPress.Clear();
           }

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

If there are multiple forms. The form controls should be reachable from global, or the forms should have custom methods like EnableTextBoxes().

Berkay Yaylacı
  • 4,383
  • 2
  • 20
  • 37
1

Because KeyEventArgs e stores only one key I assume you have to store key V state.

private bool _keyVPressed;

private void Form1_KeyDown(object sender, KeyEventArgs e)
{
    _keyVPressed = _keyVPressed || KeyVPressed(e.KeyCode);
    if (e.Control && _keyVPressed && e.KeyCode == Keys.A)
    {
        textBox1.Enabled = true;
    }
}

private void Form1_KeyUp(object sender, KeyEventArgs e) => _keyVPressed = !KeyVPressed(e.KeyCode);

private bool KeyVPressed(Keys k) => k is Keys.V;

And to apply this behaviour anywhere in form you need to attach the events to every control at your form

this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.Form1_KeyDown);
this.KeyUp += new System.Windows.Forms.KeyEventHandler(this.Form1_KeyUp);
//...
//some designer code
//...
this.textBox1.KeyDown += new System.Windows.Forms.KeyEventHandler(this.Form1_KeyDown);
this.textBox1.KeyUp += new System.Windows.Forms.KeyEventHandler(this.Form1_KeyUp);
ekvalizer
  • 130
  • 1
  • 9
1

One way to do it would be to handle the KeyDown event and if the first key, say A is down and the Ctrl key, set a bool to true at the Form level to indicate that the sequence is starting. The next KeyDown event should be the second key in the sequence, say V, and the Ctrl key is down (still). If the bool you set at the start is still true, meaning the Ctrl key has not been released, then execute whatever you wanted to do. Use the KeyUp event to detect if the Ctrl key has been released and if it has, set the bool value to false because it's not in sequence.

The pseudocode would look like this:

  • private bool isSequence;
  • KeyDown event handler
    • if (Ctrl && e.KeyData == Keys.A) { isSequence = true; }
    • if (Ctrl && e.KeyData == Keys.V && isSequence) { DoWhateverThing(); }
  • KeyUp event handler
    • if (e.KeyData == Ctrl) { isSequence = false; }
Trey
  • 31
  • 3
0

you may miss '&&' if ((int)e.KeyData == (int)Keys.Control && (int)e.KeyData == (int)Keys.V && (int)e.KeyData == (int)Keys.A))

you can try this Javascript Code also:

document.addEventListener('keydown', logKey);

function logKey(e) {
  log.textContent += ` ${e.code}`;
}
MD. RAKIB HASAN
  • 3,670
  • 4
  • 22
  • 35
0

You can give e.Control==true && e.KeyCode==Keys.V && e.Keycode==Keys.A in if condition

0

So you want to do this Any Where In Form.
The best way for doing this is override the ProcessCmdKey method of the Form.
But it has some Limitations. You can use Control | Alt | Shift keys only with one more key.

like:
ctrl + V works
ctrl + A works
ctrl + alt + V works
ctrl + alt + shift + V works

ctrl + V + A does not work
ctrl + alt + V + A does not work

so you have to use another keys for example use ctrl + shift + V

    protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
    {
        switch (keyData)
        {
            case (Keys.Control | Keys.Shift | Keys.V):
                textbox1.Enabled = true;
                textbox2.Enabled = true;
                return true;

      // more keys if you want

            case (Keys.Control | Keys.H):
                MessageBox.Show("Hello World!");
                return true;
        }

        return base.ProcessCmdKey(ref msg, keyData);
    }
AmirJabari
  • 406
  • 3
  • 9