Обнаружить, если в С# нажата какая-либо клавиша (не A, B, а любая)

[РЕДАКТИРОВАТЬ 3] Я как бы "решил это" при использовании "странной" версии. По крайней мере, для самых важных ключей. Это достаточно для моего случая, когда я хочу проверить, что ALT и ALT + A не совпадают (тем самым убедитесь, что A не нажата). Не идеальный, но уже много времени для такой крошечной проблемы. Спасибо всем за ответы! [РЕДАКТИРОВАТЬ 3]

[РЕДАКТИРОВАТЬ 4] Решила его намного чище благодаря 280Z28 [/EDIT 4]

Я знаю, как проверять ключи-модификаторы и как тестировать один ключ. Проблема в том, что я хочу проверить, нажата ли какая-либо клавиша. Следующий подход кажется "странным": -)

Приложение WPF, написанное на С#

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

Я знаю, что это перечисление, поэтому я подумал о цикле, но что такое "самое большое число". И возможно ли это? Кстати, это очень частный случай, обычно я бы использовал событие, но в этом случае я должен сделать это таким образом. К несчастью, нет "списка" Keyboard.CurrentlyDownKeys. По крайней мере, я этого не видел.

Спасибо, Крис

РЕДАКТИРОВАТЬ: Хорошо, потому что это похоже на большую сделку, вот причина для этого: Я определил "KeySet", который служит в качестве словаря для пользовательских функций. Если кто-либо нажимает на элемент, обертка выполняет итерацию через словарь и проверяет, активен ли какой-либо из предопределенных "Ключей".

Это позволяет мне определять простые триггеры, например, Запустите эту функцию, если нажать ALT + A + B. Другим вариантом является, например, Запустите эту функцию, если ALT + STRG + A нажата (во время щелчка мыши на элементе WPF).

Единственная "проблема" с текущей реализацией, если я определяю Keyset, который НЕ содержит никаких REAL-ключей, например run, если ALT нажат, он также запускается при нажатии ALT + A. О, когда я пишу это, я понимаю, что есть еще одна проблема. ALT + A + B также будет запускаться, если нажать ALT + A + B + C.

Возможно, мой подход ошибочен, и я должен создать "статический ключевой трекер" и сравнить набор ключей с его значениями (приобретенными через события). Я попробую попробовать.

РЕДАКТИРОВАТЬ 2 Это не работает, по крайней мере, не простым способом. Мне нужен элемент FrameworkElement для присоединения к KeyDown, но у меня его нет в статическом конструкторе. И меня не интересует KeyDownEvents определенного элемента, но "глобально"... Я думаю, что я откладываю отложить эту проблему, ее не так важно. Тем не менее, если кто-то знает лучше другого подхода...

До тех пор, для тех, кто интересуется, вот какой код:

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

Ответ 1

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

Ответ 2

Используя инфраструктуру XNA, вы можете использовать следующую информацию для проверки того, нажата ли клавиша.

Keyboard.GetState().GetPressedKeys().Length > 0

Ответ 3

Довольно старый вопрос, но в случае, если кто-то сталкивается с этим и не хочет использовать внешние dll, вы можете просто перечислить возможные клавиши и перебрать их.

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

Вы можете немного оптимизировать это, выполнив перечисление вне функции и сохранив список позже.

Ответ 4

Где этот код работает? Это в обработчике событий? Многие формы и элементы управления будут запускать событие KeyPress, а также событие KeyDown. Возможно, вы захотите изучить эти события и установить флаг в true, когда происходит одно из них. Вам также нужно будет прослушать соответствующее событие, которое сообщит вам, когда будет выпущен ключ (KeyUp, также, я думаю).

Ответ 5

Если вы используете Windows.Forms, используйте событие KeyDown и зачитайте конкретный ключ, используя соответствующий KeyEventArgs. Вы можете получить доступ к свойству KeyCode в переменной KeyEventArgs.

Чтобы проверить диапазоны, скажем между A и Z:

if (e.KeyCode>=Keys.A && e.KeyCode<=Keys.Z)
{
  // do stuff...or not
}

Ответ 6

http://sourceforge.net/projects/keystate/ показывает "специальные" ключи. В противном случае, я думаю, вам просто нужно будет следить за ними. SOunds, как вы хотите сделать это в масштабах всей системы? Что вы пытаетесь выполнить?

Ответ 7

Вы можете увеличить счетчик для каждого события keydown и уменьшить его для каждого события keyup. Когда счетчик равен нулю, никакие клавиши не будут.

Ответ 8

normally I would use an event

Вы все равно должны использовать событие, желательно KeyDown, так как вы не возражаете против нажатия клавиши, если вы программируете на окнах. Если нет, вы можете использовать что-то вроде Console.ReadLine();.

изменить: Если вы ищете что-то вроде

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

тогда вы должны шутить...

edit 2: Ну, подход вашего регистратора интересен, но я думаю, что вы изобретаете колесо. Все языки программирования обеспечивают некоторый способ обработки нажатия клавиши, когда это можно узнать. В С# для Windows это делается с помощью событий. Кроме того, я думаю, вы не сможете справиться с такими вещами самостоятельно в .NET, так как вам нужно получить доступ к некоторым системным функциям из Win32 API и AFAIK, вам не разрешено это делать (по крайней мере легко...) в управляемом коде. Некоторое решение было бы создать HOOK и отправить сообщения оттуда в ваше приложение, но я не знаю, как это сделать на С#. Так было в Delphi, где у меня больше опыта.