2009-11-17 16 views
10

[EDIT 3] W pewnym sensie "rozwiązałem" go przy użyciu "dziwnej" wersji. Przynajmniej na najważniejsze klucze. Jest to wystarczające dla mojego przypadku, w którym chcę sprawdzić, czy ALT i ALT + A nie są takie same (tym samym upewniając się, że A nie jest wciśnięty). Nie idealne, ale już za dużo czasu na tak drobny problem. Dzięki za wszystkie odpowiedzi tak ... [EDIT 3]Wykryj, czy w C# zostanie naciśnięty dowolny klawisz (nie A, B, ale dowolny)

[EDIT 4] rozwiązać go znacznie czystsze dzięki 280Z28 [/ EDIT 4]

wiem jak sprawdzić klawiszy modyfikujących i jak przetestować pojedynczy klucz. Problem polega na tym, że chcę sprawdzić, czy naciśnięto jakiś klawisz. Poniższa metoda wydaje „dziwne” :-)

WPF aplikacja napisana w języku C#

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

wiem, że to jest enum, więc pomyślałem o pętli, ale to, co jest „największa liczba” używać. I czy to możliwe? Przy okazji, to jest bardzo szczególny przypadek, zwykle używałbym wydarzenia, ale w tym przypadku muszę to zrobić w ten sposób. Niestety, nie ma "listy" Keyboard.CurrentlyDownKeys. Przynajmniej nie widziałem tego.

Dzięki Chris

EDIT: Ok, ponieważ wydaje się być większa sprawa, tutaj powodem tego: I zdefiniowano "Keyset", który służy jako DictionaryKey dla funkcji niestandardowych. Jeśli ktokolwiek kliknie element, opakowanie przetwarza słownik i sprawdza, czy któryś z predefiniowanych "Zestawów klawiszy" jest aktywny.

To pozwala mi definiować proste wyzwalacze, np. Uruchom tę funkcję, jeśli naciśnięty zostanie ALT + A + B. Inną opcją jest np. Uruchom tę funkcję, jeśli naciśnięty zostanie ALT + STRG + A (podczas kliknięcia myszą elementu WPF).

Jedyny "problem" z bieżącą implementacją, jeśli zdefiniuję zestaw kluczy, który NIE zawiera żadnych kluczy REAL, np. Uruchom, gdy naciśnięty jest ALT, to jest również wyzwalany, gdy naciśnięty zostanie ALT + A. Och, pisząc to, zdaję sobie sprawę, że jest inny problem. ALT + A + B będzie również wyzwalać, jeśli naciśnięty zostanie ALT + A + B + C.

Być może moje podejście jest błędne i powinienem stworzyć "statyczny klucz do śledzenia" i porównać zestaw kluczy z jego wartościami (nabyte za pośrednictwem zdarzeń). Spróbuję.

EDIT 2 To nie działa, przynajmniej nie w prosty sposób. Potrzebuję FrameworkElement dołączyć do KeyDown, ale nie mam go w konstruktorze statycznym. I nie interesuje mnie KeyDownEvents jakiegoś elementu, ale "globalnie" ... Myślę, że zamierzam odłożyć ten problem, nie jest to aż tak ważne. Mimo to, jeśli ktoś wie lepiej od innego podejścia ...

Tak długo, dla każdego, kto dba, tu kod:

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

Jaka jest twoja aplikacja? Konsola? Windows Forms? WPF? Stronie internetowej? – jrista

+0

Zobacz nagłówek ... .NET C# –

+0

To nie pomaga. –

Odpowiedz

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

Dzięki za wysiłek, ale otrzymałem wyjątek "EntryPointNotFound". Może to być spowodowane ograniczeniami systemu Windows 7, innym jądrem, nie wiem. Ponadto, do niskiego poziomu (nawet jeśli byłby to jedyny sposób) ... –

+0

@Christian: zauważ, że początkowo miałem nieprawidłowy import określony - umieszczam jądro 32, ale powinno to być user32. –

+0

@Christian: dodałem także 'Skip (8)' do 'AnyKeyPressed', więc nie zwraca ono prawdziwości z powodu naciśnięcia przycisków myszy. –

0

Gdzie jest ten kod działa od? Czy jest to program obsługi zdarzeń? Wiele formularzy i elementów sterujących wywoła zdarzenie KeyPress, a także zdarzenie KeyDown. Możesz zajrzeć do tych wydarzeń i ustawić flagę na prawdziwą, gdy wystąpi jedna z nich. Musisz też posłuchać odpowiedniego zdarzenia, które powie ci, kiedy klucz zostanie wydany (KeyUp, także, myślę).

0

Jeśli używasz Windows.Forms, użyj zdarzenia KeyDown i odczytaj konkretny klucz, używając odpowiedniego KeyEventArgs. Możesz uzyskać dostęp do właściwości KeyCode w zmiennej KeyEventArgs.

Aby sprawdzić zakresach, powiedzmy między A i Z:

if (e.KeyCode>=Keys.A && e.KeyCode<=Keys.Z) 
{ 
    // do stuff...or not 
}
-1
normally I would use an event 

Należy nadal używać zdarzenie, najlepiej keyDown skoro nie masz nic, co naciśnięciu klawisza, jeśli programowanie w oknach. Jeśli nie, możesz użyć czegoś takiego jak Console.ReadLine();.

edit: Jeśli szukasz czegoś jak

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

musisz być żart ...

edit 2: Cóż, podejście z rejestratora jest interesująca, ale Myślę, że wymyślasz koło. Wszystkie języki programowania zapewniają pewien sposób obsługi naciśniętego klawisza, gdy jest to możliwe. W języku C# dla Windows odbywa się to przy użyciu zdarzeń. Poza tym myślę, że nie będziesz w stanie obsłużyć tego typu rzeczy samemu w .NET, ponieważ potrzebujesz dostępu do niektórych funkcji systemowych z poziomu Win32 API, a AFAIK nie możesz tego robić (przynajmniej łatwo. ..) w zarządzanym kodzie. Rozwiązaniem byłoby utworzenie HOOK i wysyłanie wiadomości do aplikacji, ale nie wiem jak to zrobić w języku C#. Tak było w Delphi, gdzie mam więcej doświadczenia.

+4

Nie żartuję :-) Ale oczywiście niewłaściwy ciąg myśli. Ale nie znajduję tego zbyt daleko. Mam na myśli, dlaczego nie, mogą być przypadki, jeśli chcę wiedzieć, czy naciśnięto DOWOLNY klawisz. Edytował wpis, spróbuje statycznego "rejestratora", którego można użyć do sprawdzenia ... –

+0

Możesz "wymyślić" ten typ stanu klucza, używając zdarzeń KeyUp i KeyDown w WinForm lub WPF - klawiszem w dół dodaj wciśnięty wartość klucza do listy, po naciśnięciu klawisza, usuń go - w dowolnym momencie możesz po prostu sprawdzić, czy lista zawiera wartości, których szukasz, a dowiesz się, czy klawisz zostanie naciśnięty, czy nie. – BrainSlugs83

0

pokazuje "specjalne" klucze. Inaczej myślę, że będziesz musiał ich monitorować. Zrzuty sumienia, jak chcesz zrobić to w całym systemie? Co próbujesz osiągnąć?

0

Można zwiększyć licznik dla każdego zdarzenia klucza i zmniejszyć go dla każdego zdarzenia kluczowania. Gdy licznik jest zerowy, żadne klawisze nie są wyłączone.

+0

niemożliwe, keyDown wydarzenia zjedzony przez niektórych elementów WPF, i może nawet nie być w mojej aplikacji po naciśnięciu A. Potem przytrzymaj go, kliknij na mojej aplikacji, i nie sprawdzić, czy jest wciśnięty ... –

+3

Ty oglądam dom. Osoba wchodzi. Osoba wychodzi. Osoba wchodzi. Osoba wychodzi. Osoba wychodzi. Co logicznie wyciągasz na temat tej sekwencji obserwacji? (1) w domu jest -1 osób, lub (2) byli ludzie w domu, zanim zacząłem oglądać? –

+1

@Eric: Powiedziałbym, że jeśli ktoś teraz wejdzie, dom będzie pusty. – Zano

3

Korzystając z frameworka XNA, możesz użyć polecenia thw follow w celu sprawdzenia, czy został naciśnięty dowolny klawisz.

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

Dlaczego każdy użytkownik chce użyć architektury XNA tylko do wykrywania naciśnięcia klawisza? XNA jest grubym klientem przeznaczonym do tworzenia gier wideo. – Rockstart

+2

Być może dlatego, że to, co próbuje zrobić OP, jest zwykle wykonywane tylko w grach wideo ... – BrainSlugs83

2

Dość stare pytanie, ale w przypadku gdy ktoś natknie tego i nie chce korzystać z zewnętrznych dll, można po prostu wyliczyć możliwe klucze i pętli nad nimi.

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

Można to nieco zoptymalizować poprzez wyliczenie poza funkcją i zachowanie listy na później.

Powiązane problemy