15

[EDIT 3] I kind of "solved it" by at using the "strange" version. At least for the most important keys. It is suffient for my case, where I want to check that ALT and ALT+A are not the same (thereby making sure A is not pressed). Not perfect, but already to much time for such a tiny problem. Thanks for all the answers anyway... [EDIT 3]

[EDIT 4] Solved it much cleaner thanks to 280Z28 [/EDIT 4]

I know how to check for modifier keys and how to test for a single key. The problem is, I want to check if any key is pressed. The following approach seems "strange" :-)

WPF Application written in C#

if (Keyboard.IsKeyDown(Key.A)) return true;
if (Keyboard.IsKeyDown(Key.B)) return true;
if (Keyboard.IsKeyDown(Key.C)) return true;

I know it is an enum, so I thought about a loop, but what is the "biggest number" to use. And is this possible? btw, its a very special case, normally I would use an event, but in this case I have to do it this way. Unfortunatily, the there is no "list" Keyboard.CurrentlyDownKeys. At least I didnt see it.

Thanks, Chris

EDIT: Ok, because it seems to be a bigger deal, here the reason for this: I have defined a "KeySet" which serves as DictionaryKey for custom functions. If anybody clicks on an element, the wrapper iterates through the dictionary and checks if any of the predefined "Keysets" is active.

This allows me to define simple triggers, like e.g. Run this function if ALT+A+B is pressed. Another option is e.g. Run this function if ALT+STRG+A is pressed (during a mouse click on a WPF element).

The only "problem" with the current implementation, if I define a Keyset which does NOT contain any REAL keys, like run if ALT is pressed, it is also triggered if ALT+A is pressed. Oh, while writing this, I realize that there is another problem. ALT+A+B would currently also trigger if ALT+A+B+C is pressed.

Perhaps my approach is wrong, and I should create a "static key tracker" and compare the keyset to its values (aquired via events).. I will give this a try.

EDIT 2 This is not working, at least not in a simple way. I need an FrameworkElement to attach to KeyDown, but I do not have it in a static constructor. And I am not interested in KeyDownEvents of a certain element, but "globally"...I think I juts postpone this problem, its not that important. Still, if anybody knows a better of different approach...

So long, for anyone who cares, here some code:

public class KeyModifierSet
{
    internal readonly HashSet<Key> Keys = new HashSet<Key>();
    internal readonly HashSet<ModifierKeys> MKeys = new HashSet<ModifierKeys>();

    public override int GetHashCode()
    {
        int hash = Keys.Count + MKeys.Count;
        foreach (var t in Keys)
        {
            hash *= 17;
            hash = hash + t.GetHashCode();
        }
        foreach (var t in MKeys)
        {
            hash *= 19;
            hash = hash + t.GetHashCode();
        }
        return hash;
    }

    public override bool Equals(object obj)
    {
        return Equals(obj as KeyModifierSet);
    }

    public bool Equals(KeyModifierSet other)
    {
        // Check for null
        if (ReferenceEquals(other, null))
            return false;

        // Check for same reference
        if (ReferenceEquals(this, other))
            return true;

        // Check for same Id and same Values
        return Keys.SetEquals(other.Keys) && MKeys.SetEquals(other.MKeys);
    }

    public bool IsActive()
    {
        foreach (var k in Keys)
            if (Keyboard.IsKeyUp(k)) return false;
        
        if ((Keys.Count == 0) && !Keyboard.IsKeyDown(Key.None)) return false;


        foreach (var k in MKeys)
            if ((Keyboard.Modifiers & k) == 0) return false;

        if ((MKeys.Count == 0) && Keyboard.Modifiers > 0) return false;

        return true;
    }


    public KeyModifierSet(ModifierKeys mKey)
    {
        MKeys.Add(mKey);
    }

    public KeyModifierSet()
    {

    }

    public KeyModifierSet(Key key)
    {
        Keys.Add(key);
    }

    public KeyModifierSet(Key key, ModifierKeys mKey)
    {
        Keys.Add(key);
        MKeys.Add(mKey);
    }

    public KeyModifierSet Add(Key key)
    {
        Keys.Add(key);
        return this;
    }

    public KeyModifierSet Add(ModifierKeys key)
    {
        MKeys.Add(key);
        return this;
    }
}
Mark A. Donohoe
  • 28,442
  • 25
  • 137
  • 286
Christian Ruppert
  • 3,749
  • 5
  • 47
  • 72
  • 2
    What is your application? Console? Windows Forms? WPF? Web site? – jrista Nov 17 '09 at 23:10
  • Corrected it in the Post, WPF application. Sorry, did not think of the big differences between winforms and WPF. And for this reason I want to avoid using events (seems overcomplicated with bubbling, eating of events, and so on.. - I know how its done, but still... Just want to know if any character key is pressed :-( – Christian Ruppert Nov 17 '09 at 23:40
  • Are there here the pros and cons of using WPF? Pro: Nice interface. Cons: very difficult to do some tasks, like handling key presses. – eKek0 Nov 17 '09 at 23:56
  • @eKek0: Did you really say it was *very difficult* to handle key presses in WPF? Not hardly. Show me any other UI technolgy that makes it significantly easier to handle key press events than WPF does. In WPF it is as simple as `KeyDown += (o, e) => { ... handler code ... }`. Can't get much simpler than that I think. – Ray Burns Nov 19 '09 at 10:20
  • See this question : [Capture KeyDown Event in WPF](http://stackoverflow.com/questions/347724/how-can-i-capture-keydown-event-on-a-wpf-page-or-usercontrol-object) – Salamander2007 Nov 17 '09 at 23:28
  • Yes, this makes my "static key tracker" approach not very feasible. At least it seems overcomplicated for such a "simple" thing like "tracking keysets on mouse clicks". See edit2 in post. – Christian Ruppert Nov 17 '09 at 23:36
  • 1
    All the different Edits throughout your question (in order of 3, 4, 1, 2) makes the reading of it a lot harder than it should be.. – Geerten Nov 09 '12 at 15:40

10 Answers10

15
[DllImport("user32.dll", EntryPoint = "GetKeyboardState", SetLastError = true)]
private static extern bool NativeGetKeyboardState([Out] byte[] keyStates);

private static bool GetKeyboardState(byte[] keyStates)
{
    if (keyStates == null)
        throw new ArgumentNullException("keyState");
    if (keyStates.Length != 256)
        throw new ArgumentException("The buffer must be 256 bytes long.", "keyState");
    return NativeGetKeyboardState(keyStates);
}

private static byte[] GetKeyboardState()
{
    byte[] keyStates = new byte[256];
    if (!GetKeyboardState(keyStates))
        throw new Win32Exception(Marshal.GetLastWin32Error());
    return keyStates;
}

private static bool AnyKeyPressed()
{
    byte[] keyState = GetKeyboardState();
    // skip the mouse buttons
    return keyState.Skip(8).Any(state => (state & 0x80) != 0);
}
Sam Harwell
  • 97,721
  • 20
  • 209
  • 280
  • Thanks for the effort, but I get a "EntryPointNotFound" exception. May be due to windows 7 restrictions, different kernel, dont know. Also, to low level (even if this would be the only way)... – Christian Ruppert Nov 18 '09 at 00:17
  • @Christian: note that I originally had the wrong import specified - I put kernel32 but it's supposed to be user32. – Sam Harwell Nov 18 '09 at 00:45
  • @Christian: also, I added a `Skip(8)` to `AnyKeyPressed` so it doesn't return true due to pressing mouse buttons. – Sam Harwell Nov 18 '09 at 00:46
  • Ok, nice, it works !! One more question, how could I "filter" the CTRL, ALT, Windows and SHIFT. Because they should not count as keys, I handle them using the ModifierKeys (design issue, would require a lot of changes otherwise). Is this possible? Thanks a lot in any case.. – Christian Ruppert Nov 18 '09 at 01:48
  • 1
    @Christian: You can check all the bytes except the ones you want to ignore. If you are ignoring the modifiers, are you also ignoring VK_NUMLOCK, etc. (this checks *down*, not toggled, but what do you do if the numlock key is actually *down*)? Virtual key code reference: http://msdn.microsoft.com/en-us/library/ms927178.aspx – Sam Harwell Nov 18 '09 at 01:51
  • Hi, I am a little stupid here. Tried to "ignore" special "places" by using this: var l = new List() {0, 1, 2, 3, 4, 5, 6, 7, 14,15,16,17}; var c = 0; return keyState.SkipWhile(x => l.Contains(c++)).Any(state => (state & 0x80) != 0); But it doesn't work, either I read the KeyReference wrong or I suck at list operations :-) If you still have patience, can you filter out the SHIFT in code. I will add the others then.. (Your mentioned problem is not really one, mainly letters are important, can live with some "loss" :-) – Christian Ruppert Nov 18 '09 at 02:11
  • `Enumerable.Range(0, keyState.Length).Except(l).Any(i => (keyState[i] & 0x80) != 0);` – Sam Harwell Nov 18 '09 at 02:57
5

Quite an old question but in case anyone comes across this and doesn't want to use external dll's, you could just enumerate the possible keys and loop over them.

bool IsAnyKeyPressed()
{
    var allPossibleKeys = Enum.GetValues(typeof(Key));
    bool results = false;
    foreach (var currentKey in allPossibleKeys)
    {
        Key key = (Key)currentKey;
        if (key != Key.None)
            if (Keyboard.IsKeyDown((Key)currentKey)) { results = true; break; }
    }
    return results;
}

You could optimize this a bit by doing the enum outside of the function and retaining the list for later.

Mark A. Donohoe
  • 28,442
  • 25
  • 137
  • 286
Andy
  • 6,366
  • 1
  • 32
  • 37
5

Using the XNA framework you can use thw follow for checking if any key has been pressed.

Keyboard.GetState().GetPressedKeys().Length > 0
Carlc75
  • 51
  • 1
  • 1
  • 1
    Why will any user want to use XNA framework just for detecting they key press? XNA is a thick client intended to be used for Video games development – Rockstart Oct 26 '12 at 06:23
  • 3
    Perhaps because what the OP's trying to do is typically only done in video games... – BrainSlugs83 Dec 23 '13 at 12:06
1

If you're using Windows.Forms, use the KeyDown event and read out the specific key using the appropriate KeyEventArgs. You can access the KeyCode property on the KeyEventArgs variable.

To check for ranges, say between A and Z:

if (e.KeyCode>=Keys.A && e.KeyCode<=Keys.Z)
{
  // do stuff...or not
}
Wim
  • 11,998
  • 1
  • 34
  • 57
0

Where is this code running from? Is it in an event handler? Many forms and controls will fire a KeyPress event as well as a KeyDown event. You may want to look into those events and set your flag to true when one of them occurs. You'd also have to listen for the corresponding event that tells you when the key is released (KeyUp, also, I think).

FrustratedWithFormsDesigner
  • 26,726
  • 31
  • 139
  • 202
0

http://sourceforge.net/projects/keystate/ shows "special" keys. Otherwise I think you're just going to have to monitor them. SOunds like you want to do this systemwide? What are you trying to accomplish?

No Refunds No Returns
  • 8,092
  • 4
  • 32
  • 43
0

You can increment a counter for each keydown event, and decrement it for each keyup event. When the counter is zero, no keys are down.

xpda
  • 15,585
  • 8
  • 51
  • 82
  • 1
    Not possible, KeyDown events get eaten by some WPF elements, and I may not even be in my app when pressing A. Then I hold it, click on my app, and it does not check that A is pressed... – Christian Ruppert Nov 17 '09 at 23:38
  • 3
    You're watching a house. A person goes in. A person goes out. A person goes in. A person goes out. A person goes out. What do you logically conclude about this sequence of observations? (1) there are -1 people in the house, or (2) there were people in the house before I started watching? – Eric Lippert Nov 18 '09 at 02:15
  • 1
    @Eric: I would say that if someone now goes in, the house will become empty. – Zano Feb 18 '10 at 14:14
0

To detect which key is pressed, you need to check every key state and which key is currently pressed or down.
Remember:Press & Down have difference.

    Public Sub Main()
        While True
            For i As Integer = 8 To 222
                Select Case i
                    Case 8, 13, 32, 48 To 57, 65 To 90, 186 To 192, 219 To 222
                        If GetAsyncKeyState(i) = -32767 And Not IsKeyDown(Keys.Control) Then
                            Console.Write(CodeToChar(i))
                        End If
            End Select
        Next
    End Sub
    
    Public Function IsKeyDown(Key As Keys) As Boolean
        Return (Control.ModifierKeys And Key) = Key
    End Function
    
    
    Function CodeToChar(i As Integer) As String
        Dim Character = Nothing
        IsShiftDown = IsKeyDown(Keys.Shift)
        If i > 64 And i < 91 Then c = If(Control.IsKeyLocked(Keys.CapsLock) Or IsShiftDown, Chr(i).ToString.ToUpper, Chr(i).ToString.ToLower) 
        If i = 8   Then Character = "[BACK]"
        If i = 13  Then Character = vbnewline
        If i = 32  Then Character = " "
        If i = 48  Then Character = If(IsShiftDown, ")", "0")
        If i = 49  Then Character = If(IsShiftDown, "!", "1")
        If i = 50  Then Character = If(IsShiftDown, "@", "2")
        If i = 51  Then Character = If(IsShiftDown, "#", "3")
        If i = 52  Then Character = If(IsShiftDown, "$", "4")
        If i = 53  Then Character = If(IsShiftDown, "%", "5")
        If i = 54  Then Character = If(IsShiftDown, "^", "6")
        If i = 55  Then Character = If(IsShiftDown, "&", "7")
        If i = 56  Then Character = If(IsShiftDown, "*", "8")
        If i = 57  Then Character = If(IsShiftDown, "(", "9")
        If i = 186 Then Character = If(IsShiftDown, ":", ";")
        If i = 187 Then Character = If(IsShiftDown, "+", "=")
        If i = 188 Then Character = If(IsShiftDown, "<", ",")
        If i = 189 Then Character = If(IsShiftDown, "_", "-")
        If i = 190 Then Character = If(IsShiftDown, ">", ".")
        If i = 191 Then Character = If(IsShiftDown, "?", "/")
        If i = 192 Then Character = If(IsShiftDown, "~", "`")
        If i = 219 Then Character = If(IsShiftDown, "{", "[")
        If i = 220 Then Character = If(IsShiftDown, "|", "\")
        If i = 221 Then Character = If(IsShiftDown, "}", "]")
        If i = 222 Then Character = If(IsShiftDown, """", "'")
        Return Character
    End Function

Convert here if you want to use c# version. Read keylogger codes to learn more about key-states.

Sorry IwontTell
  • 466
  • 10
  • 29
-1
normally I would use an event

You should still be using an event, preferably KeyDown since you don't mind what key is pressed, if you are programming on windows. If not, you could use something like Console.ReadLine();.

edit: If you are looking for something like

if (Keyboard.IsKeyDown(Key.AnyKey)) return true;

then you must be joking...

edit 2: Well, the approach of your logger is interesting, but I think that you are reinventing the wheel. All programming languages provides some way to handle wich key was pressed, when this can be known. In C# for Windows, this is done using events. Besides, I think you won't be able to handle this kind of things by yourself in .NET, since you need to access some system functions from the Win32 API, and AFAIK you aren't allowed to do this (at least easily...) in managed code. Some solution would be to create a HOOK and send messages from there to your application, but I don't know how to do this in C#. This was the way in Delphi, where I have more experience.

eKek0
  • 23,005
  • 25
  • 91
  • 119
  • 5
    Not joking :-) But obviously wrong train of thought. But I don't find it THAT far fetched. I mean why not, there might be cases if I want to know if ANY key is pressed. Edited the entry, will try the static "logger" which can be used for checking... – Christian Ruppert Nov 17 '09 at 23:28
  • You can "invent" this type of key state using the KeyUp and KeyDown events in either WinForms or WPF -- on key down add the pressed key's value to a List, on key up, remove it -- at anytime you can just check if the list contains the values you're looking for and you'll know if the key is being pressed or not. – BrainSlugs83 Dec 23 '13 at 12:05
-1

In the Key Enumeration there is an Enumeration value of Zero(0), which basically tests "No Key Pressed", which is opposite of "Any key pressed". So, something like this might work;

If !GetKeyState(0)==True then
    Do Something
End If

Or

If GetKeyState(0)==False then
    Do Something
End If
Paul Roub
  • 36,322
  • 27
  • 84
  • 93
  • Not sure this is correct. When you call `GetKeyState` with a zero, you get `System.ComponentModel.InvalidEnumArgumentException: 'The value of argument 'key' (0) is invalid for Enum type 'Key'. Parameter name: key'` – Mark A. Donohoe Nov 24 '20 at 05:52