2012-08-16 34 views
2

对于Metro应用程序,存在Windows.Devices.Input.KeyboardCapabilities.KeyboardPresent。 Windows 8桌面程序是否有办法检测物理键盘是否存在?在Windows 8桌面程序中检测键盘存在

+0

复制的[Win32的确定何时键盘连接/断开(http://stackoverflow.com/questions/9930958/win32-确定何时键盘连接断开) – 2012-08-16 19:43:05

+0

@JamesMcNellis,这个问题是关于连接/断开键盘,而这一个是关于是否有一个可用的键盘。不完全相同,即使答案完全相关。 – 2012-08-16 19:55:17

+0

使用WMI,Win32_Keyboard类。 – 2012-08-16 20:51:06

回答

0

这是一个有点繁琐,我不知道是否我提议将在所有的情况下工作,但这是我最终使用的办法的办法:

  1. 使用SetupDiGetClassDevs找到所有的键盘设备。
  2. 使用SetupDiGetDeviceRegistryProperty阅读一些键盘设备属性忽略PS/2键盘
  3. 检查,因为赢8触摸设备触摸支持似乎总是有一个额外的HID键盘设备。

PS/2端口的问题之一是,即使没有插入任何东西,它们仍然是键盘设备。我只是通过假设没有人会使用PS/2来解决问题键盘和我过滤出来。我已经包括两个单独的检查来尝试并确定键盘是否为PS/2。我不知道任何一方的可靠程度,但对于我测试过的机器来说,这两者似乎都可以正常工作。

另一个问题(#3)是,当Windows 8计算机有触摸支持时,他们有一个额外的HID键盘设备,您需要忽略。 PS:我刚刚意识到的东西,我的代码使用“缓冲”类来进行属性查询。为了保留相关的代码,我把它放在了外面,但是你需要用一些适当的缓冲区/内存管理来替换它。

#include <algorithm> 
#include <cfgmgr32.h> 
#include <Setupapi.h> 
#include <boost/tokenizer.hpp> 
#include <boost/algorithm/string.hpp> 

struct KeyboardState 
{ 
    KeyboardState() : isPS2Keyboard(false) 
    { } 

    std::wstring deviceName; // The name of the keyboard device. 
    bool isPS2Keyboard;  // Whether the keyboard is a PS/2 keyboard. 
}; 

void GetKeyboardState(std::vector<KeyboardState>& result) 
{ 
    LPCWSTR PS2ServiceName = L"i8042prt"; 
    LPCWSTR PS2CompatibleId = L"*PNP0303"; 
    const GUID KEYBOARD_CLASS_GUID = { 0x4D36E96B, 0xE325, 0x11CE, { 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18 } }; 

    // Query for all the keyboard devices. 
    HDEVINFO hDevInfo = SetupDiGetClassDevs(&KEYBOARD_CLASS_GUID, NULL, NULL, DIGCF_PRESENT); 
    if (hDevInfo == INVALID_HANDLE_VALUE) 
    { 
     return; 
    } 

    // 
    // Enumerate all the keyboards and figure out if any are PS/2 keyboards. 
    // 
    bool hasKeyboard = false; 
    for (int i = 0;; ++i) 
    { 
     SP_DEVINFO_DATA deviceInfoData = { 0 }; 
     deviceInfoData.cbSize = sizeof (deviceInfoData); 
     if (!SetupDiEnumDeviceInfo(hDevInfo, i, &deviceInfoData)) 
     { 
      break; 
     } 

     KeyboardState currentKeyboard; 

     // Get the device ID 
     WCHAR szDeviceID[MAX_DEVICE_ID_LEN]; 
     CONFIGRET status = CM_Get_Device_ID(deviceInfoData.DevInst, szDeviceID, MAX_DEVICE_ID_LEN, 0); 
     if (status == CR_SUCCESS) 
     { 
      currentKeyboard.deviceName = szDeviceID; 
     } 

     // 
     // 1) First check the service name. If we find this device has the PS/2 service name then it is a PS/2 
     // keyboard. 
     // 
     DWORD size = 0; 
     if (!SetupDiGetDeviceRegistryProperty(hDevInfo, &deviceInfoData, SPDRP_SERVICE, NULL, NULL, NULL, &size)) 
     { 
      try 
      { 
       buffer buf(size); 
       if (SetupDiGetDeviceRegistryProperty(hDevInfo, &deviceInfoData, SPDRP_SERVICE, NULL, buf.get(), buf.size(), &size)) 
       { 
        LPCWSTR serviceName = (LPCWSTR)buf.get(); 
        if (boost::iequals(serviceName, PS2ServiceName)) 
        { 
         currentKeyboard.isPS2Keyboard = true; 
        } 
       } 
      } 
      catch (std::bad_alloc) 
      { 
      } 
     } 

     // 
     // 2) Fallback check for a PS/2 keyboard, if CompatibleIDs contains *PNP0303 then the keyboard is a PS/2 keyboard. 
     // 
     size = 0; 
     if (!currentKeyboard.isPS2Keyboard && !SetupDiGetDeviceRegistryProperty(hDevInfo, &deviceInfoData, SPDRP_COMPATIBLEIDS, NULL, NULL, NULL, &size)) 
     { 
      try 
      { 
       buffer buf(size); 
       if (SetupDiGetDeviceRegistryProperty(hDevInfo, &deviceInfoData, SPDRP_COMPATIBLEIDS, NULL, buf.get(), buf.size(), &size)) 
       { 
        std::wstring value = (LPCWSTR)buf.get(); 

        // Split the REG_MULTI_SZ values into separate strings. 
        boost::char_separator<wchar_t> sep(L"\0"); 
        typedef boost::tokenizer< boost::char_separator<wchar_t>, std::wstring::const_iterator, std::wstring > WStringTokenzier; 
        WStringTokenzier tokens(value, sep); 

        // Look for the "*PNP0303" ID that indicates a PS2 keyboard device. 
        for (WStringTokenzier::iterator itr = tokens.begin(); itr != tokens.end(); ++itr) 
        { 
         if (boost::iequals(itr->c_str(), PS2CompatibleId)) 
         { 
          currentKeyboard.isPS2Keyboard = true; 
          break; 
         } 
        } 
       } 
      } 
      catch (std::bad_alloc) 
      { 
      } 
     } 

     result.push_back(currentKeyboard); 
    } 
} 

bool IsNonPS2Keyboard(const KeyboardState& keyboard) 
{ 
    return !keyboard.isPS2Keyboard; 
} 

bool HasKeyboard() 
{ 
    std::vector<KeyboardState> keyboards; 
    GetKeyboardState(keyboards); 

    int countOfNonPs2Keyboards = std::count_if(keyboards.begin(), keyboards.end(), IsNonPS2Keyboard); 

    // Win 8 with touch support appear to always have an extra HID keyboard device which we 
    // want to ignore. 
    if ((NID_INTEGRATED_TOUCH & GetSystemMetrics(SM_DIGITIZER)) == NID_INTEGRATED_TOUCH) 
    { 
     return countOfNonPs2Keyboards > 1; 
    } 
    else 
    { 
     return countOfNonPs2Keyboards > 0; 
    } 
} 
-1

简单:看到HKEY_LOCAL_MACHINE \ SYSTEM \ ControlSet001 \服务\ kbdclass

相关问题