Example #1
0
 bool IsUserInput() const {
   return IsKey() || (GetCharacterCount() > 0) || IsMouse();
 }
Example #2
0
 bool IsUserInput() const {
   return IsKey() || IsMouse();
 }
bool nxRawInputDevice::GetInformation(void)
{
    HKEY hKey = NULL;
    try
    {
        /// Retrieve the encoded device name
        UINT uSize = 0;
        // Retrieve the number of characters needed to store the device name (including the null)
        // Calling the unicode version, that way we get the number of characters properly.
        // All the characters used, in practice, are representable in ANSI.
        if (GetRawInputDeviceInfoW(hDevice,RIDI_DEVICENAME,NULL,&uSize) < 0)
            nxThrow("Couldn't retrieve length of device name string.");

        // Allocate the space
        strDeviceName.resize(uSize-1);
        // Retrieve the device name.  Example: "\\??\\ACPI#PNP0303#3&13c0b0c5&0#{884b96c3-56ef-11d1-bc8c-00a0c91405dd}"
        if (GetRawInputDeviceInfoA(hDevice,RIDI_DEVICENAME,const_cast<char*>(strDeviceName.c_str()),&uSize) < 0)
            nxThrow("Couldn't retrieve the encoded device name.");

        /// Multiply Occurring Error.  Placing here so we can include the device name.
        const std::string strFormatError = std::string("Device name is encoded in an unsupported format. \"") + strDeviceName + std::string("\"");
        // Validate the device name is nonempty.
        if (strDeviceName.empty())
                nxThrow(strFormatError);

        /// Split the device name into parts
        // Delimiter offsets
        std::string::size_type uCurrent, uNext;
        // First # position
        uNext = strDeviceName.find_first_of('#');
        // Position of the trailing slash of the beginning "\\??\\" part.
        uCurrent = strDeviceName.find_last_of('\\',uNext);

        /// Loop through the fields
        std::string strField;
        for (UINT uField = 0;uField < 4;++uField)
        {
            // Validate field offsets
            if (uCurrent == std::string::npos)
                nxThrow(strFormatError);
            // Pull out the field data
            if (uNext != std::string::npos)
                strField = strDeviceName.substr(uCurrent+1,uNext-uCurrent-1);
            else
                strField = strDeviceName.substr(uCurrent+1);

            // Ensure some value was retrieved
            if (strField.empty())
                nxThrow(strFormatError);

            /// Set the appropriate field
            switch (uField)
            {
                case 0:	strClassCode = strField; break;
                case 1:	strSubClassCode = strField; break;
                case 2:	strProtocolCode = strField; break;
                case 3:	strGUID = strField; break;
                default:
                    nxThrow("Unhandled token index, notify the developer of his silly mistake.");
            }
            // Advance to the next token.
            uCurrent = uNext;
            if (uCurrent != std::string::npos)
                uNext = strDeviceName.find_first_of('#',uCurrent+1);
            else
                uNext = std::string::npos;
        }

        /// Retrieve the device description and class from the registry
        DWORD dwKeyType;
        DWORD dwKeySize;
        std::string strRegKey = std::string("SYSTEM\\CurrentControlSet\\Enum\\")+strClassCode+"\\"+strSubClassCode+"\\"+strProtocolCode;
        if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,strRegKey.c_str(),0,KEY_QUERY_VALUE,&hKey) != ERROR_SUCCESS)
        {
            hKey = NULL;
            nxThrow(std::string("Couldn't open the device's registry key - ") + strRegKey);
        }
        // Retrieve data type and size (including null)
        if (RegQueryValueEx(hKey,"DeviceDesc",NULL,&dwKeyType,NULL,&dwKeySize) != ERROR_SUCCESS)
            nxThrow(std::string("Couldn't retrieve size of \"DeviceDesc\" value for registry key - ") + strRegKey);
        // Size the buffer accordingly
        strDeviceDesc.resize(dwKeySize-1);
        // Added the const_cast for clarity, though it isn't necessary.
        if (RegQueryValueEx(hKey,"DeviceDesc",NULL,&dwKeyType,(BYTE*)const_cast<char*>(strDeviceDesc.c_str()),&dwKeySize) != ERROR_SUCCESS)
            nxThrow(std::string("Couldn't retrieve value of \"DeviceDesc\" for registry key - ") + strRegKey);

        // Retrieve data type and size (including null)
        if (RegQueryValueEx(hKey,"Class",NULL,&dwKeyType,NULL,&dwKeySize) != ERROR_SUCCESS)
            nxThrow(std::string("Couldn't retrieve size of \"Class\" value for registry key - ") + strRegKey);
        // Size the buffer accordingly
        strDeviceClass.resize(dwKeySize-1);
        // Added the const_cast for clarity, though it isn't necessary.
        if (RegQueryValueEx(hKey,"Class",NULL,&dwKeyType,(BYTE*)const_cast<char*>(strDeviceClass.c_str()),&dwKeySize) != ERROR_SUCCESS)
            nxThrow(std::string("Couldn't retrieve value of \"Class\" for registry key - ") + strRegKey);

        /// Use registry information to verify our keyboards/mice are in fact keyboards and mice.
        // This will also turn the terminal services "system" devices to HID
        if (stricmp(strClassCode.c_str(),"root")==0)
            dwType = RIM_TYPEHID;
        else if (IsKeyboard())
        {
            if (stricmp(strDeviceClass.c_str(),"keyboard")!=0)
                dwType = RIM_TYPEHID;
        }
        else if (IsMouse())
        {
            if (stricmp(strDeviceClass.c_str(),"mouse")!=0)
                dwType = RIM_TYPEHID;
        }
        else //HID
        {
            if (stricmp(strDeviceClass.c_str(),"keyboard")==0)
                dwType = RIM_TYPEKEYBOARD;
            else if (stricmp(strDeviceClass.c_str(),"mouse")==0)
                dwType = RIM_TYPEMOUSE;
        }

        // Make sure this isn't vmware's keyboard driver (rather than a physical keyboard)
        if (IsKeyboard())
        {
            HKEY hKeyVM = NULL;
            // If this fails, then something is amiss (there should be a control key), but, it isn't really a bail-out situation
            if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,(strRegKey+"\\Control").c_str(),0,KEY_QUERY_VALUE,&hKeyVM) == ERROR_SUCCESS)
            {
                // Retrieve data type and size (including null)
                if (RegQueryValueEx(hKeyVM,"ActiveService",NULL,&dwKeyType,NULL,&dwKeySize) == ERROR_SUCCESS)
                {
                    std::string strActiveService;
                    // Size the buffer accordingly
                    strActiveService.resize(dwKeySize-1);
                    // Added the const_cast for clarity, though it isn't necessary.
                    if (RegQueryValueEx(hKeyVM,"ActiveService",NULL,&dwKeyType,(BYTE*)const_cast<char*>(strActiveService.c_str()),&dwKeySize) == ERROR_SUCCESS)
                    {
                        if (stricmp(strActiveService.c_str(),"vmkbd") == 0)
                        {
                            // It's the vmware keyboard, not a physical keyboard.
                            dwType = RIM_TYPEHID;
                        }
                    }
                }
                RegCloseKey(hKeyVM);
            }
        }

        // Clean up
        RegCloseKey(hKey);
        hKey=NULL;

        // Return false if it isn't a supported keyboard and mouse
        if (!IsMouse() && !IsKeyboard())
            return false;

    } catch (const std::exception&e)
    {
        nxLog << e.what() << std::endl;
        Clear();
        if (hKey)
            RegCloseKey(hKey);
        return false;
    }
    return true;
}