Определить, нажата ли какая-либо клавиша в C # (не A, B, а любая) - PullRequest
10 голосов
/ 18 ноября 2009

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

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

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

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

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

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

Спасибо, Chris

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

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

Единственная «проблема» с текущей реализацией, если я определяю набор ключей, который НЕ содержит никаких РЕАЛЬНЫХ клавиш, например, запускается, если нажата клавиша 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;
    }
}

Ответы [ 8 ]

11 голосов
/ 18 ноября 2009
[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);
}
3 голосов
/ 23 июля 2013

Довольно старый вопрос, но в случае, если кто-то сталкивается с этим и не хочет использовать внешние библиотеки 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;
    }

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

3 голосов
/ 12 февраля 2012

Используя платформу XNA, вы можете использовать thw follow для проверки, нажата ли какая-либо клавиша.

Keyboard.GetState().GetPressedKeys().Length > 0
0 голосов
/ 18 ноября 2009

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

0 голосов
/ 18 ноября 2009

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

0 голосов
/ 18 ноября 2009
normally I would use an event

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

edit: Если вы ищете что-то вроде

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

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

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

0 голосов
/ 18 ноября 2009

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

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

if (e.KeyCode>=Keys.A && e.KeyCode<=Keys.Z)
{
  // do stuff...or not
}
0 голосов
/ 18 ноября 2009

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

...