2013-04-12 32 views
7

Theo MSDN wparam nên giữ mã khóa. Vấn đề là, khi nhấn phím shift, mã là 16 (VK_SHIFT), nhưng tôi cần phải phân biệt giữa VK_LSHIFT và VK_RSHIFT.Làm thế nào để bạn nói với LSHIFT ngoài RSHIFT trong các sự kiện WM_KEYDOWN?

Đối VK_CONTROL, có vẻ là một cách giải quyết:

if(wParam == VK_CONTROL) { 
    if (lParam&EXTENDED_KEYMASK) 
     wParam = VK_RCONTROL; 
    else 
     wParam = VK_LCONTROL; 
} 

Tuy nhiên, tương tự sẽ không làm việc cho VK_SHIFT:

if(wparam == VK_SHIFT) { 
    if (lParam&EXTENDED_KEYMASK) 
     wParam = VK_RSHIFT; 
    else 
     wParam = VK_LSHIFT; 
} 

Trong ví dụ sau, nó sẽ chỉ luôn giả định LSHIFT .

+0

Đã lâu rồi, nhưng theo như tôi nhớ, các hệ thống cũ không phân biệt được giữa các lần bấm phím shift trái hoặc phải. – DragonZero

+2

Chỉ 'GetKeyState()' và 'GetAsyncKeyState()' sẽ phân biệt giữa các phím bấm trái và phải (từ WinUser.h). –

Trả lời

11

Để phân biệt giữa các phiên bản bên trái và bên phải của phím Shift, Ctrl hoặc Alt, bạn phải sử dụng chức năng MapVirtualKey() hoặc bit 'khóa mở rộng' trong lParam được truyền bằng thông điệp của khóa ảo. Các chức năng sau đây sẽ thực hiện dịch đó cho bạn - chỉ cần vượt qua trong mã phím ảo và lParam từ tin nhắn, và bạn sẽ lấy lại trái/phải mã phím ảo cụ thể cho phù hợp:

WPARAM MapLeftRightKeys(WPARAM vk, LPARAM lParam) 
{ 
    WPARAM new_vk = vk; 
    UINT scancode = (lParam & 0x00ff0000) >> 16; 
    int extended = (lParam & 0x01000000) != 0; 

    switch (vk) { 
    case VK_SHIFT: 
     new_vk = MapVirtualKey(scancode, MAPVK_VSC_TO_VK_EX); 
     break; 
    case VK_CONTROL: 
     new_vk = extended ? VK_RCONTROL : VK_LCONTROL; 
     break; 
    case VK_MENU: 
     new_vk = extended ? VK_RMENU : VK_LMENU; 
     break; 
    default: 
     // not a key we map from generic to left/right specialized 
     // just return it. 
     new_vk = vk; 
     break;  
    } 

    return new_vk; 
} 

Nếu mã phím ảo được truyền vào không phải là bản đồ được chuyển sang phiên bản bên trái/phải, mã khóa ban đầu được truyền lại không thay đổi. Vì vậy, bạn chỉ có thể chạy thông số WM_KEYDOWN/WM_KEYUP/WM_SYSKEYDOWN/WM_SYSKEYUP thông qua hàm bất cứ khi nào bạn cần phân biệt giữa các biến thể bên trái và bên phải.

Bằng cách sử dụng MapVirtualKey() bạn không cần phải biết truyền thuyết về các thay đổi bên trái và dịch chuyển phải là 0x2a và 0x36 - API sẽ quản lý chi tiết đó. Và nếu chúng từng xảy ra khác nhau (không phải điều đó sẽ thực sự xảy ra), Windows sẽ chịu trách nhiệm đối phó với nó, không phải bạn.

Vì vậy, trong WM_KEYDOWN/WM_KEYUP/WM_SYSKEYDOWN/WM_SYSKEYUP bạn xử lý bạn chỉ cần thêm một dòng mã mà trông giống như:

wparam = MapLeftRightKeys(wparam, lparam); 

và phần còn lại của mã của bạn có thể hoạt động trên trái/phải cụ thể Mã VK như thể thông báo hệ thống chỉ cung cấp cho bạn ngay từ đầu.

+0

Cảm ơn bạn, loại sir! Tôi đã thử nghiệm này, và nó xuất hiện để làm việc ra tốt. Nó cũng sạch hơn và an toàn hơn nhiều so với những gợi ý khác, nên tôi chấp nhận cái này. :) – cib

6

Gọi GetKeyState qua VK_LSHIFT hoặc VK_RSHIFT.

+0

Ý tưởng hay, tôi rõ ràng sẽ thích cái gì đó giống như "hack" trong ví dụ của tôi, nhưng nếu không có gì như thế, điều này chắc chắn sẽ hoạt động. – cib

+0

Đây là một cách rất sạch sẽ để làm điều đó. Sử dụng API trạng thái khóa đồng bộ. –

+0

Nó sạch sẽ miễn là chúng ta có thể giả định rằng các trạng thái quan trọng luôn được cập nhật trước khi tin nhắn WM_KEYDOWN được gửi đi. Tôi đã không chắc chắn về điều đó trước đây, nhưng bạn có vẻ đúng, từ những gì tôi có thể đọc thêm trong tài liệu GetKeyState. – cib

1

"Theo MSDN":

  • VK_LSHIFT
  • VK_RSHIFT
  • VK_LCONTROL
  • VK_RCONTROL
  • VK_LMENU
  • VK_RMENU

Các hằng số phân biệt trái và phải này chỉ có sẵn cho ứng dụng thông qua các hàm GetKeyboardState, SetKeyboardState, GetAsyncKeyState, GetKeyState và MapVirtualKey.

6

Có lịch sử cổ xưa đằng sau câu hỏi của bạn. Bàn phím IBM PC ban đầu không có các phím Alt và Ctrl phù hợp. Chúng được thêm vào sau trên bố trí bàn phím mở rộng, bộ điều khiển bàn phím gửi chúng với tiền tố 0xe0 tới mã quét để phân biệt chúng là các khóa mở rộng. Nhưng bố trí bàn phím ban đầu luôn có hai phím shift để chúng có mã quét không mở rộng của riêng chúng. Đó là lý do tại sao mã của bạn không hoạt động.

Câu trả lời của David là một cách hay để giải quyết vấn đề của bạn. Nhưng bạn thực sự có thể nhận được nó ra khỏi tin nhắn, những mã quét được đúc bằng đá bởi Windows logo requirements. Có sẵn trong lParam, phím shift trái có mã quét 42, phím shift phải là 54. Không có #define trong các tiêu đề cửa sổ cho chúng không may, điều đó làm cho nó xấu xí.

+0

Cảm ơn bài học lịch sử. :) – cib

+0

Làm thế nào để bạn có được scancode? 'unsigned char scancode = (unsigned char) (lParam >> 16);' dường như không hoạt động, hoặc cho các số khác nhau ít nhất. Xin lỗi, tôi đã không làm việc với WinAPI nhiều. – cib

+0

Mã quét được lưu trữ theo bit 16-23, do đó, nó là (lParam & 0xff0000) >> 16. –

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