2009-11-17 27 views
10

[EDIT 3] Tôi đã "giải quyết" bằng cách sử dụng phiên bản "lạ". Ít nhất là cho các phím quan trọng nhất. Nó là đủ cho trường hợp của tôi, nơi tôi muốn kiểm tra ALT và ALT + A không giống nhau (do đó đảm bảo A không được nhấn). Không hoàn hảo, nhưng đã có nhiều thời gian cho một vấn đề nhỏ như vậy. Cảm ơn tất cả các câu trả lời anyway ... [EDIT 3]Phát hiện nếu có phím nào được nhấn trong C# (không phải A, B, nhưng bất kỳ)

[EDIT 4] Giải quyết nó sạch hơn nhiều nhờ vào 280Z28 [/ EDIT 4]

tôi biết làm thế nào để kiểm tra các phím modifier và làm thế nào để kiểm tra một khóa duy nhất. Vấn đề là, tôi muốn kiểm tra xem có phím nào được nhấn hay không. Các phương pháp sau đây có vẻ "kỳ lạ" :-)

WPF Application viết bằng C#

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

Tôi biết nó là một enum, vì vậy tôi nghĩ về một vòng lặp, nhưng "số lớn nhất" là gì để sử dụng. Và điều này có thể? btw, một trường hợp rất đặc biệt của nó, thông thường tôi sẽ sử dụng một sự kiện, nhưng trong trường hợp này tôi phải làm theo cách này. Thật không may, không có "danh sách" Keyboard.CurrentlyDownKeys. Ít nhất tôi đã không nhìn thấy nó.

Cảm ơn, Chris

EDIT: Ok, vì nó có vẻ là một thỏa thuận lớn hơn, đây là lý do cho việc này: tôi đã xác định một "keyset" phục vụ như là DictionaryKey cho các chức năng tùy chỉnh. Nếu ai đó nhấp vào một phần tử, trình bao bọc sẽ lặp lại thông qua từ điển và kiểm tra xem có bất kỳ "Keysets" được xác định trước nào đang hoạt động hay không.

Điều này cho phép tôi xác định các trình kích hoạt đơn giản, ví dụ: ví dụ: Chạy chức năng này nếu nhấn ALT + A + B. Một tùy chọn khác là ví dụ: Chạy chức năng này nếu nhấn ALT + STRG + A (trong khi nhấp chuột vào phần tử WPF).

Chỉ "vấn đề" với việc triển khai hiện tại, nếu tôi xác định một Keyset không chứa bất kỳ phím REAL nào, như chạy nếu ALT được nhấn, nó cũng được kích hoạt nếu ALT + A được nhấn. Ồ, trong khi viết điều này, tôi nhận ra rằng có một vấn đề khác. ALT + A + B hiện cũng sẽ kích hoạt nếu ALT + A + B + C được nhấn.

Có lẽ cách tiếp cận của tôi là sai và tôi nên tạo "trình theo dõi khóa tĩnh" và so sánh keyset với giá trị của nó (được thu thập thông qua sự kiện) .. Tôi sẽ thử.

CHỈNH SỬA 2 Điều này không hoạt động, ít nhất là không theo cách đơn giản. Tôi cần một FrameworkElement để đính kèm vào KeyDown, nhưng tôi không có nó trong một constructor tĩnh. Và tôi không quan tâm đến KeyDownEvents của một yếu tố nhất định, nhưng "toàn cầu" ... Tôi nghĩ rằng tôi đã trì hoãn vấn đề này, nó không quan trọng. Tuy nhiên, nếu ai biết một tốt hơn về cách tiếp cận khác nhau ...

Chừng nào, cho bất cứ ai quan tâm, ở đây một số mã:

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

Đơn đăng ký của bạn là gì? Console? Windows Forms? WPF? Trang mạng? – jrista

+0

Xem tiêu đề ... .NET C# –

+0

Điều đó không hữu ích. –

Trả lời

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

Cảm ơn bạn đã nỗ lực nhưng tôi nhận được ngoại lệ "EntryPointNotFound". Có thể do hạn chế của Windows 7, hạt nhân khác nhau, không biết. Ngoài ra, để cấp thấp (ngay cả khi điều này sẽ là cách duy nhất) ... –

+0

@Christian: lưu ý rằng tôi ban đầu đã nhập sai quy định - Tôi đặt kernel32 nhưng nó được cho là user32. –

+0

@Christian: Ngoài ra, tôi đã thêm 'Skip (8)' vào 'AnyKeyPressed' để nó không trả về true do nhấn các nút chuột. –

0

đâu mã này chạy từ đâu? Là nó trong một xử lý sự kiện? Nhiều biểu mẫu và điều khiển sẽ kích hoạt sự kiện KeyPress cũng như sự kiện KeyDown. Bạn có thể muốn xem xét các sự kiện đó và đặt cờ của bạn thành true khi một trong số chúng xuất hiện. Bạn cũng phải lắng nghe sự kiện tương ứng cho bạn biết khi nào chìa khóa được phát hành (KeyUp, tôi cũng nghĩ vậy).

0

Nếu bạn đang sử dụng Windows.Forms, hãy sử dụng sự kiện KeyDown và đọc khóa cụ thể bằng cách sử dụng KeyEventArgs thích hợp. Bạn có thể truy cập thuộc tính KeyCode trên biến số KeyEventArgs.

Để kiểm tra cho các phạm vi, nói giữa A và Z:

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

Bạn vẫn nên sử dụng một sự kiện, tốt nhất KeyDown kể từ khi bạn không nhớ những gì quan trọng được nhấn, nếu bạn đang lập trình trên cửa sổ. Nếu không, bạn có thể sử dụng một cái gì đó như Console.ReadLine();.

chỉnh sửa: Nếu bạn đang tìm kiếm cái gì đó như

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

sau đó bạn phải đùa ...

chỉnh sửa 2: Vâng, cách tiếp cận của logger của bạn là thú vị, nhưng Tôi nghĩ rằng bạn đang tái phát minh ra bánh xe. Tất cả các ngôn ngữ lập trình cung cấp một số cách để xử lý các phím được nhấn, khi điều này có thể được biết đến. Trong C# cho Windows, điều này được thực hiện bằng cách sử dụng các sự kiện. Bên cạnh đó, tôi nghĩ bạn sẽ không thể tự mình xử lý những thứ này bằng .NET, vì bạn cần truy cập một số chức năng hệ thống từ API Win32 và AFAIK bạn không được phép thực hiện việc này (ít nhất là dễ dàng. ..) trong mã được quản lý. Một số giải pháp sẽ là tạo ra một HOOK và gửi tin nhắn từ đó đến ứng dụng của bạn, nhưng tôi không biết làm thế nào để làm điều này trong C#. Đây là cách ở Delphi, nơi tôi có nhiều kinh nghiệm hơn.

+4

Không nói đùa :-) Nhưng rõ ràng là đào tạo sai ý nghĩ. Nhưng tôi không tìm thấy nó xa vời. Tôi có nghĩa là tại sao không, có thể có trường hợp nếu tôi muốn biết nếu bất kỳ phím nào được nhấn. Đã chỉnh sửa mục nhập, sẽ thử "nhật ký" tĩnh có thể được sử dụng để kiểm tra ... –

+0

Bạn có thể "phát minh" loại trạng thái khóa này bằng các sự kiện KeyUp và KeyDown trong cả WinForms hoặc WPF - khi phím tắt thêm nhấn giá trị của khóa vào Danh sách, khi bật khóa, xóa nó - bất cứ lúc nào bạn chỉ có thể kiểm tra xem danh sách có chứa các giá trị bạn đang tìm kiếm hay không và bạn có biết liệu khóa đó có đang được nhấn hay không. – BrainSlugs83

0

http://sourceforge.net/projects/keystate/ hiển thị các phím "đặc biệt". Nếu không, tôi nghĩ bạn sẽ phải theo dõi chúng. SOunds như bạn muốn làm điều này trên toàn hệ thống? Bạn đang cố gắng để thực hiện?

0

Bạn có thể tăng bộ đếm cho mỗi sự kiện nhấn phím và giảm số lần truy cập cho mỗi sự kiện khóa. Khi bộ đếm bằng không, không có phím nào bị hỏng.

+0

Không thể, các sự kiện KeyDown bị một số phần tử WPF ăn, và thậm chí tôi không thể sử dụng ứng dụng của tôi khi nhấn A. Sau đó, tôi giữ nó, bấm vào ứng dụng của tôi, và nó không kiểm tra xem A đã được nhấn ... –

+3

Bạn đang xem một ngôi nhà. Một người đi vào. Một người đi ra ngoài. Một người đi vào. Một người đi ra ngoài. Một người đi ra ngoài. Bạn kết luận một cách logic về chuỗi quan sát này? (1) có 1 người trong nhà, hoặc (2) có người trong nhà trước khi tôi bắt đầu xem không? –

+1

@Eric: Tôi sẽ nói rằng nếu ai đó đi vào, ngôi nhà sẽ trở nên trống rỗng. – Zano

3

Sử dụng khung XNA mà bạn có thể sử dụng để theo dõi xem có phím nào được nhấn hay không.

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

Tại sao mọi người dùng lại muốn sử dụng khung công tác XNA chỉ để phát hiện họ nhấn phím? XNA là một khách hàng dày được dự định sẽ được sử dụng để phát triển trò chơi video – Rockstart

+2

Có lẽ vì những gì OP cố gắng làm thường chỉ được thực hiện trong các trò chơi video ... – BrainSlugs83

2

Khá câu hỏi cũ nhưng trong trường hợp bất kỳ ai gặp phải điều này và không muốn sử dụng dll bên ngoài, bạn chỉ có thể liệt kê các khóa có thể và lặp lại chúng.

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

Bạn có thể tối ưu hóa điều này một chút bằng cách thực hiện enum bên ngoài chức năng và giữ lại danh sách sau này.

Các vấn đề liên quan