1
votes

I have searched for how to detect keyboard combinations in c#.

As of this I use the KeyDown Event of the Form with KeyPreview = true.

I need to check if the e.Modifiers is any Modifier and e.KeyCode is something else than a Modifier.

The best would be a really open statement like:

if(Keys.Modifiers.Contains(e.Modifiers) && !Keys.Modifiers.Contains(e.KeyCode)){}

Sadly this is not working.

This is not working too, it gets true with all of the modifier keys.

if ((e.Modifiers == Keys.Alt || e.Modifiers == Keys.Control || e.Modifiers == Keys.Shift)
    && (e.KeyCode != Keys.Alt && e.KeyCode != Keys.Control && e.KeyCode != Keys.Shift))

This is almost working, but as there is no Keys.AltKey it gets true when ALT is clicked.

if ((e.Modifiers == Keys.Alt || e.Modifiers == Keys.Control || e.Modifiers == Keys.Shift)
    && (e.KeyCode != Keys.Alt && e.KeyCode != Keys.ControlKey && e.KeyCode != Keys.ShiftKey))

How could I achive this? It should be possible that e.KeyCode could be anything than a Modifier.

The reason: I need to give the user the possibility of pressing any key-combination with at least ONE modifier and at least ONE other key.

After getting the statement correctly, how is the best way to save the combination in a variable and check it when entered again? I thought about something like saving every entered key (when one is a Modifier and the other not) in a List<Keys> and check it through a foreach which return false; when one key of the entered combination is not in the List.

Everything should be as dynamically as possible.

How could this be extended to check any combination? Like Ctrl + F + Shift + C or Ctrl + F + H

Thanks!

Michael

2

2 Answers

0
votes

Probably the cleanest way to accomplish this is to use a more low level API to obtain an array of every key that is currently pressed. This is going to make your logic a lot easier, but you'll have to do some fancy imports.

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetKeyboardState(byte [] lpKeyState);

var array = new byte[256];
GetKeyboardState(array);

Once you have the array, you can scan all the keys at the same time without any more O/S calls, which should create much less overhead.

For example, you can see how many keys are being pressed with something like

int countKeys = array.Count(a => a & 0x80);

If you just want to check if the left alt key is pressed, you can use

bool leftAlt = (array[(byte)Key.LeftAlt] & 0x80);
0
votes

I think you may to have to do as John Wu suggest or at least some low level way as you will have to remember the last key pressed. If you use “multiple” CHARACTER keys… NOT modifier keys then you will have to remember what the last key combination was. For example: Ctrl + F + Shift + C… you would have to remember the Ctrl + F + Shift part first before you can look for the “C” character.

Anytime you use multiple “Character” keys you have to remember the first key(s) in the sequence. I am not sure if using this many keys to accomplish something would be that user friendly. However one possible solution which came from @Vivelin at How to get a combination of keys in c# seems to do the trick. It looks messy and with only two different conditions.

Using your example let’s say we are looking for the combination Ctrl + F + Shift + C The code basically sets a Boolean value to true when the first part of the combination is met Ctrl + F + Shift then it exits. When the next key is pressed and the combination is Ctrl + Shift + C then you will know this combination Ctrl + F + Shift + C has been met. This is similar to other programs where you hold down a control key(s) then press one character then another character not necessarily at the same time. In the code below I used a disabled text box to output when the combination is fired. I hope this helps.

private bool keyCombo1 = false;
private bool keyCombo2 = false;

private void textBox1_KeyDown(object sender, KeyEventArgs e) {
  if (e.Control) {
    if (e.Shift) {
      if (e.KeyCode == Keys.F) {
        keyCombo1 = true;
      }
      else {
        if (e.KeyCode == Keys.C && keyCombo1) {
          textBox2.AppendText("Key Combo 1 hit" + Environment.NewLine);
        }
        else {
          keyCombo1 = false;
        }
      }
    }
    else {
      // control only no-shift
      if (e.KeyCode == Keys.F) {
        keyCombo2 = true;
      }
      else {
        if (e.KeyCode == Keys.H && keyCombo2) {
          textBox2.AppendText("Key Combo 2 hit" + Environment.NewLine);
        }
        else {
          keyCombo2 = false;
        }
      }
    }
  }
  else {
    // no control key pressed
  }
}