STDMETHODIMP CSoftKeyboard::HitKeyOnce(KBD_KEYS KeyCode) /*++ Routine Description: Implement the HitKeyOnce method for the interface ISoftKeyboard. This simulate a key being hit. Synchronization: None Arguments: KeyCode - keycode of "pressed" key. Return Value: E_FAIL Could not queue request for processing. E_INVALIDARG Returned if supplied keycode is out of supported range of keys. S_OK Success. --*/ { HRESULT hr = S_OK; // Check for faulty input IfFalseHrGo(KeyCode > KEY_NONE && KeyCode <= KEY_PAUSE, E_INVALIDARG); IfFailHrGo(PostMessage2Task(m_KeyPressedMsg, KeyCode, 0)); IfFailHrGo(PostMessage2Task(m_KeyReleasedMsg, KeyCode, 0)); Exit: return hr; } // CSoftKeyboard::HitKeyOnce
HRESULT CLoopbackDevice::SetupConnectionPoint(IUnknown* punkObject, REFIID iidConnectionPoint) { HRESULT hr = S_OK; IConnectionPointContainer* piConnectionPointContainer = NULL; IUnknown* punkSink = NULL; //If there is already connection point enabled, disable it if(NULL != m_piConnectionPoint) { IfFailHrGo(ReleaseConnectionPoint()); } IfFailHrGo(punkObject->QueryInterface(IID_IConnectionPointContainer, reinterpret_cast<void **>(&piConnectionPointContainer))); IfFailHrGo(piConnectionPointContainer->FindConnectionPoint(iidConnectionPoint, &m_piConnectionPoint)); // Get the IUknown of this interface as this is the event sink punkSink = (this)->GetUnknown(); if(NULL == punkSink) { IfFailHrGo(E_UNEXPECTED); } IfFailHrGo(m_piConnectionPoint->Advise(punkSink, &m_dwConnectionCookie)); Exit: return hr; }
STDMETHODIMP CLoopbackDevice::OnWriteTransfer(BYTE DataToggle, BYTE* pbDataBuffer, ULONG cbDataBuffer, BYTE * pbStatus) { HRESULT hr = S_OK; BYTE bINStatus = USB_ACK; UNREFERENCED_PARAMETER(DataToggle); // Check that the IN endpoint is valid if (NULL == m_piINEndpoint) { IfFailHrGo(E_UNEXPECTED); } // Send the data to the IN Endpoint IfFailHrGo(m_piINEndpoint->QueueINData(pbDataBuffer, cbDataBuffer, bINStatus, SOFTUSB_FOREVER)); // ACK the status as the data was successfully sent to the IN endpoint *pbStatus = USB_ACK; Exit: if (FAILED(hr)) *pbStatus = USB_STALL; return hr; }
HRESULT CSoftHIDInputKbdMapper::SetupEventSink ( IUnknown *punkObject, IUnknown *punkSink, REFIID iidConnectionPoint, IConnectionPoint *&rpiConnectionPoint, DWORD &rdwCookie ) /*++ Routine Description: If punkObject is non-NULL installs event sink on specific connection point and returns IConnectionPoint and cookie. Arguments: punkObject - IUnknown on object punkSink - IUnknown of event sink to install iidConnectionPoint - IID of desired connection point rpiConnectionPoint - connection point returned here rdwCookie - connection point cookie returned here Synchronization: None Return value: S_OK - success other - from called routines --*/ { HRESULT hr = S_OK; IConnectionPointContainer *piConnectionPointContainer = NULL; rpiConnectionPoint = NULL; rdwCookie = 0; IfFalseHrGo(NULL != punkObject, S_OK); IfFailHrGo(punkObject->QueryInterface(IID_IConnectionPointContainer, reinterpret_cast<void **>(&piConnectionPointContainer))); IfFailHrGo(piConnectionPointContainer->FindConnectionPoint(iidConnectionPoint, &rpiConnectionPoint)); IfFailHrGo(rpiConnectionPoint->Advise(punkSink, &rdwCookie)); Exit: if (FAILED(hr)) { RELEASE(rpiConnectionPoint); rdwCookie = 0; } RELEASE(piConnectionPointContainer); return hr; }
HRESULT CSoftHIDInputKbdMapper::ProcessKbdOutput(SAFEARRAY* psa) /*++ Routine Description: Processes keyboard output report. Synchronization: None Arguments: psa - pointer to safearray containing Output Report data Return Value: S_OK Success E_UNEXPECTED Unxpected size of Output Report data buffer E_FAIL Could not report indicator status to keyboard object. --*/ { BYTE HUGEP* pArrayData = NULL; LONG lLBound = 0; LONG lUBound = 0; HRESULT hr = S_OK; KEYBOARD_INDICATOR_PARAMETERS Indicator; ZeroMemory(&Indicator, sizeof(Indicator)); IfFalseHrGo(NULL != m_piSoftKeyboard, E_FAIL); // Get SAFEARRAY size IfFailHrGo(SafeArrayGetLBound(psa, 1, &lLBound)); IfFailHrGo(SafeArrayGetUBound(psa, 1, &lUBound)); // Check the size of Output Report data IfFalseHrGo(1 == (lUBound - lLBound + 1), E_UNEXPECTED); IfFailHrGo(::SafeArrayAccessData(psa, (void HUGEP**)&pArrayData)); // Only 5 least significant bits are valid in output report byte. // TODO: this would be controlled by OutputReportMask property later. Indicator.usLedFlags = pArrayData[0] & 0xE0; IfFailHrGo(::SafeArrayUnaccessData(psa)); IfFailHrGo(m_piSoftKeyboard->put_Indicators(&Indicator)); Exit: // the safe array was allocated by the call to // m_piSoftProtXlator->ReadOutputPort in CSoftHID::Run. // Now we are done with it so we should free it here. if (NULL != psa) { (void)::SafeArrayDestroy(psa); } return hr; } // CSoftHIDInputKbdMapper::ProcessKbdOutput
HRESULT CSoftHIDInputKbdMapper::SendInputReport ( PVOID pbReportData, ULONG cbReportData ) /*++ Routine Description: Prepares safearray and sends it as Input Report to lower layer. Synchronization: None Arguments: pbReportData - pointer to data buffer with Input Report cbReportData - size of the data buffer Return Value: S_OK Success E_OUTOFMEMORY Could not allocate enough memory for safearray From called function --*/ { SAFEARRAY* psa = NULL; BYTE HUGEP* pArrayData = NULL; HRESULT hr = S_OK; // Create safearray psa = SafeArrayCreateVector(VT_UI1, 0, cbReportData); IfFalseHrGo(NULL != psa, E_OUTOFMEMORY); IfFailHrGo(::SafeArrayAccessData(psa, (void HUGEP**)&pArrayData)); CopyMemory(pArrayData, pbReportData, cbReportData); IfFailHrGo(::SafeArrayUnaccessData(psa)); // Send Input Report IfFailHrGo(m_piSoftProtXlator->WriteInputReport(psa)); Exit: if (NULL != psa) { // Delete safearray ::SafeArrayDestroy(psa); psa = NULL; } return hr; } // CSoftHIDInputKbdMapper::SendInputReport
HRESULT CLoopbackDevice::ConfigureConfig(ISoftUSBConfiguration* piConfig) { HRESULT hr = S_OK; // config number passed to SetConfig IfFailHrGo(piConfig->put_ConfigurationValue(1)); // Index of string descriptor IfFailHrGo(piConfig->put_Configuration((BYTE)m_iConfigString)); // Self powered IfFailHrGo(piConfig->put_Attributes(0x40)); // Max power in 2mA units: 50 = 100mA IfFailHrGo(piConfig->put_MaxPower(50)); Exit: return hr; }
HRESULT CLoopbackDevice::FinalConstruct() { // Perform tasks which may fail when the class CLoopbackDevice // is finally constructed. This involves creating the USB device // object and initializing the device so that it is recognized // as a valid USB device by the controller HRESULT hr = S_OK; hr = CreateUSBDevice(); IfFailHrGo(hr); hr = ConfigureDevice(); IfFailHrGo(hr); Exit: return hr; }
STDMETHODIMP CSoftHIDInputKbdMapper::KeyTouched(void) /*++ Routine Description: Implements the KeyTouched event from ISoftInputKbdDeviceEvents interface. Called by SoftKeyboard object when it gets new input in its buffer. Schedules processing of contents of keyboard buffer. Synchronization: None Arguments: None Return Value: E_FAIL Could not send message to task S_OK Success --*/ { HRESULT hr = S_OK; IfFailHrGo(PostMessage2Task(m_KeyTouchedMsg, 0, 0)); Exit: return hr; } // CSoftHIDInputKbdMapper::KeyTouched
STDMETHODIMP CSoftKeyboard::get_Translator( SoftKbdTranslator **ppTranslator) /*++ Routine Description: Implement the get Translator propery for the interface ISoftKeyboard. Synchronization: None Arguments: ppTranslator - caller allocated space to hold the property value. Return Value: E_POINTER Invalid pointer for output parameter From called function --*/ { HRESULT hr = S_OK; // Check if we have valid pointer to returned parameter IfFalseHrGo(NULL != ppTranslator, E_POINTER); *ppTranslator = NULL; ADDREF(m_piSoftKbdTranslator); *ppTranslator = reinterpret_cast<SoftKbdTranslator *>(m_piSoftKbdTranslator); IfFailHrGo(hr); Exit: return hr; } // CSoftKeyboard::get_Translator
HRESULT CSoftKeyboard::FinalConstruct() /*++ Routine Description: Overwrites the default FinalConstruct. Creates the default properties, gets pointer to COM task memory allocator. Synchronization: None Arguments: None Return Value: From called function --*/ { HRESULT hr = S_OK; ISoftKbdTranslator* piDefaultASCIIXlator = NULL; // Acquire COM memory management interface IfFailHrGo(CoGetMalloc(1, &m_pMalloc)); // Register notification messages IfFailHrGo(RegisterMessage(MSG_KEYPRESSED, &m_KeyPressedMsg)); IfFailHrGo(RegisterMessage(MSG_KEYRELEASED, &m_KeyReleasedMsg)); // Construct default translator object //pcDefaultASCIIXlator = new CDefaultASCIIXlator(); hr = CDefaultASCIIXlator::CreateInstance(&piDefaultASCIIXlator); IfFailHrGo(hr); m_piSoftKbdTranslator = piDefaultASCIIXlator; // Set default values to properties m_KbdAttributes.usKeyboardMode = KEYBOARD_SCAN_CODE_SET2; m_KbdTypematicParam.ulRate = KEYBOARD_TYPEMATIC_RATE_DEFAULT; m_KbdTypematicParam.ulDelay = KEYBOARD_TYPEMATIC_DELAY_DEFAULT; // Start internal thread IfFailHrGo(Start(60000)); Exit: return hr; } // CSoftKeyboard::FinalConstruct
STDMETHODIMP CLoopbackDevice::StopAsyncEventProcessing() { HRESULT hr = S_OK; // Remove the event sink on the OUT endpoint IfFailHrGo(ReleaseConnectionPoint()); Exit: return hr; }
STDMETHODIMP CSoftHIDInputKbdMapper::AttachProtocolXlator(SoftHIDProtocolXlator* pSoftProtXlator) /*++ Routine Description: Implements the AttachProtocolXlator method for the interface ISoftHIDInputKdbMapper. Allows a SoftHIDUSBDevice object to attach to the HID device object. Synchronization: None Arguments: m_piProtocolXlator - protocol translator to be attached Return Value: S_OK --*/ { HRESULT hr = S_OK; // Disconnect from the old object IfFailHrGo(Disconnect()); // Set reference to ISoftHIDProtocolXlator interface RELEASE(m_piSoftProtXlator); if (NULL != pSoftProtXlator) { IfFailHrGo(reinterpret_cast<IUnknown *>(pSoftProtXlator)->QueryInterface(__uuidof(ISoftHIDProtocolXlator), reinterpret_cast<void **>(&m_piSoftProtXlator))); // Write Report Descriptor IfFailHrGo(m_piSoftProtXlator->WriteReportDescriptor(m_psaReportDescriptor)); // Connect to the new object IfFailHrGo(Connect(m_piSoftProtXlator)); // Set device type as keyboard IfFailHrGo(m_piSoftProtXlator->put_DeviceType(DEVICE_TYPE_KEYBOARD)); } Exit: return hr; } // CSoftHIDInputKbdMapper::AttachProtocolXlator
STDMETHODIMP CLoopbackDevice::get_DSFDevice(DSFDevice** ppDSFDevice) { HRESULT hr = S_OK; DSFDevice* pDSFDevice = NULL; //Validate the the UDB device exists else this is an //internal error if (NULL == m_piSoftUSBDevice) { IfFailHrGo(E_UNEXPECTED); } if (NULL == ppDSFDevice) { IfFailHrGo(E_POINTER); } IfFailHrGo(m_piSoftUSBDevice->get_DSFDevice(&pDSFDevice)); IfFailHrGo(reinterpret_cast<IDSFDevice *>(pDSFDevice)->QueryInterface(__uuidof(IDispatch), reinterpret_cast<void **>(ppDSFDevice))); Exit: if (NULL != pDSFDevice) reinterpret_cast<IDSFDevice *>(pDSFDevice)->Release(); return hr; }
STDMETHODIMP CLoopbackDevice::StartEventProcessing() { /* Demonstrates how to setup event sinks so that the event mechanism can be used to control data flow to and from the USB controller. In this example an event sink is installed on the OUT USB endpoint, when the controller has data to send to the device the OnWriteTransfer event will fire, this will occur on an arbitrary thread. The device then simply copies this data and passes it the IN queue of the IN Endpoint. */ HRESULT hr = S_OK; BOOL fKeepLooping = TRUE; VARIANT_BOOL fvarContinue = VARIANT_TRUE; // Set up event sink on the OUT endpoint IfFailHrGo(SetupConnectionPoint(m_piOUTEndpoint, __uuidof(ISoftUSBEndpointEvents))); // Loop waiting for Events to be fired while (TRUE == fKeepLooping) { // Context switch to allow other threads to process ::Sleep(1); // Fire Event to check if the caller want to continue processing IfFailHrGo(Fire_ContinueEventProcessing(&fvarContinue)); // Check to see if the return value is VARIANT_FALSE if (VARIANT_FALSE == fvarContinue) fKeepLooping = FALSE; } // Remove the event sink from the OUT endpoint IfFailHrGo(ReleaseConnectionPoint()); Exit: return hr; }
HRESULT CSoftHIDInputKbdMapper::FinalConstruct() /*++ Routine Description: Overwrites the default FinalConstruct. Creates the default properties, gets pointer to COM task memory allocator. Synchronization: None Arguments: None Return Value: E_OUTOFMEMORY Could not create safearray for Report Descriptor data From called function --*/ { BYTE HUGEP* pArrayData = NULL; HRESULT hr = S_OK; IfFailHrGo(CoGetMalloc(1, &m_pMalloc)); // Register notification messages IfFailHrGo(RegisterMessage(MSG_KEYTOUCHED, &m_KeyTouchedMsg)); IfFailHrGo(RegisterMessage(MSG_OUTREPORTREADY, &m_OutReportReadyMsg)); // Create safearray with Report Descriptor data m_psaReportDescriptor = SafeArrayCreateVector(VT_UI1, 0, sizeof(m_ReportDescriptor)); IfFalseHrGo(NULL != m_psaReportDescriptor, E_OUTOFMEMORY); IfFailHrGo(::SafeArrayAccessData(m_psaReportDescriptor, (void HUGEP**)&pArrayData)); // Copy Report Descriptor data into safearray CopyMemory(pArrayData, &m_ReportDescriptor, sizeof(m_ReportDescriptor)); IfFailHrGo(::SafeArrayUnaccessData(m_psaReportDescriptor)); // Start internal thread IfFailHrGo(CMessageTask::Start(DEFAULT_SYNC_DELAY)); // Call OnConstruct method of CSoftHIDDevice class IfFailHrGo(CSoftHID::OnConstruct(this, m_OutReportReadyMsg)); Exit: return hr; } // CSoftHIDInputKbdMapper::FinalConstruct
STDMETHODIMP CLoopbackDevice::StartAsyncEventProcessing() { /* Demonstrates how to setup event sinks so that the event mechanism can be used to control data flow to and from the USB controller. In this example an event sink is installed on the OUT USB endpoint, when the controller has data to send to the device the OnWriteTransfer event will fire, this will occur on an arbitrary thread. The device then simply copies this data and passes it the IN queue of the IN Endpoint. Control returns to the caller and event processing continues in an arbitrary thread. To terminate event processing call StopAsyncEventProcessing. */ HRESULT hr = S_OK; // Set up event sink on the OUT endpoint IfFailHrGo(SetupConnectionPoint(m_piOUTEndpoint, __uuidof(ISoftUSBEndpointEvents))); Exit: return hr; }
HRESULT CLoopbackDevice::ConfigureOUTEndpoint() { HRESULT hr = S_OK; if (NULL == m_piOUTEndpoint) { IfFailHrGo(E_UNEXPECTED); } // Endpoint #2 OUT IfFailHrGo(m_piOUTEndpoint->put_EndpointAddress(0x02)); // Bulk data endpoint IfFailHrGo(m_piOUTEndpoint->put_Attributes(0x02)); IfFailHrGo(m_piOUTEndpoint->put_MaxPacketSize(1024)); IfFailHrGo(m_piOUTEndpoint->put_Interval(0)); IfFailHrGo(m_piOUTEndpoint->put_Halted(FALSE)); //back pointer to the device IfFailHrGo(m_piOUTEndpoint->put_USBDevice(reinterpret_cast<SoftUSBDevice*>(m_piSoftUSBDevice))); Exit: return hr; }
HRESULT CLoopbackDevice::ConfigureInterface(ISoftUSBInterface* piInterface) { HRESULT hr = S_OK; IfFailHrGo(piInterface->put_InterfaceNumber(0)); IfFailHrGo(piInterface->put_AlternateSetting(0)); // Vendor specific class code IfFailHrGo(piInterface->put_InterfaceClass(0xFF)); // Vendor specific sub class code IfFailHrGo(piInterface->put_InterfaceSubClass(0xFF)); // Vendor specific protcol IfFailHrGo(piInterface->put_InterfaceProtocol(0xFF)); //Index for string describing the interface IfFailHrGo(piInterface->put_Interface((BYTE)m_iInterfaceString)); Exit: return hr; }
STDMETHODIMP CLoopbackDevice::AreKeystrokesWaiting( VARIANT_BOOL* pfvarKeyWaiting) { /* Implements IDeviceEmulator::AreKeystrokesWaiting. It calls the low level IO function _kbhit to see if the keyboard has been struck. If the Keyboard has been hit the function return VARIANT_TRUE otherwise it returns VARIANT_FALSE */ HRESULT hr = S_OK; int iKeyHit = 0; if (NULL == pfvarKeyWaiting) { IfFailHrGo(E_POINTER); } *pfvarKeyWaiting = VARIANT_FALSE; iKeyHit = _kbhit(); if (0 != iKeyHit) *pfvarKeyWaiting = VARIANT_TRUE; Exit: return hr; }
STDMETHODIMP CSoftKeyboard::put_Translator( SoftKbdTranslator *pTranslator) /*++ Routine Description: Implement the put Translator propery for the interface ISoftKeyboard. Synchronization: None Arguments: pTranslator - new value of the property. Return Value: From called function --*/ { HRESULT hr = S_OK; ISoftKbdTranslator *piNewInterface = NULL; ISoftKbdTranslator *piOldInterface = m_piSoftKbdTranslator; if (NULL != pTranslator) { IfFailHrGo(reinterpret_cast<IUnknown *>(pTranslator)->QueryInterface(__uuidof(ISoftKbdTranslator), reinterpret_cast<void **>(&piNewInterface))); } (void)InterlockedExchangePointer((void**)m_piSoftKbdTranslator, piNewInterface); RELEASE(piOldInterface); Exit: return hr; } // CSoftKeyboard::put_Translator
HRESULT CLoopbackDevice::ConfigureDevice() { HRESULT hr = S_OK; ISoftUSBConfiguration* piConfig = NULL; ISoftUSBInterface* piInterface = NULL; ISoftUSBConfigList* piConfigList = NULL; ISoftUSBInterfaceList* piInterfaceList = NULL; ISoftUSBEndpointList* piEndpointList= NULL; VARIANT varIndex; VariantInit(&varIndex); // All members of the collection will be added at the default locations // so set up the index appropriately varIndex.vt = VT_ERROR; varIndex.scode = DISP_E_PARAMNOTFOUND; // Create the IN Endpoint hr = CoCreateInstance(CLSID_SoftUSBEndpoint, NULL, CLSCTX_INPROC_SERVER, __uuidof(ISoftUSBEndpoint), reinterpret_cast<void**>(&m_piINEndpoint)); IfFailHrGo(hr); // Setup the IN Endpoint IfFailHrGo(ConfigureINEndpoint()); // Create the OUT Endpoint hr = CoCreateInstance(CLSID_SoftUSBEndpoint, NULL, CLSCTX_INPROC_SERVER, __uuidof(ISoftUSBEndpoint), reinterpret_cast<void**>(&m_piOUTEndpoint)); IfFailHrGo(hr); // Setup the OUT Endpoint IfFailHrGo(ConfigureOUTEndpoint()); // Create the device interface hr = CoCreateInstance(CLSID_SoftUSBInterface, NULL, CLSCTX_INPROC_SERVER, __uuidof(ISoftUSBInterface), reinterpret_cast<void**>(&piInterface)); IfFailHrGo(hr); // Setup the device interface IfFailHrGo(ConfigureInterface(piInterface)); // Add the Endpoints to the endpoint list IfFailHrGo(piInterface->get_Endpoints(&piEndpointList)); IfFailHrGo(piEndpointList->Add(reinterpret_cast<SoftUSBEndpoint*>(m_piINEndpoint), varIndex)); IfFailHrGo(piEndpointList->Add(reinterpret_cast<SoftUSBEndpoint*>(m_piOUTEndpoint), varIndex)); // Create the configuration hr = CoCreateInstance(CLSID_SoftUSBConfiguration, NULL, CLSCTX_INPROC_SERVER, __uuidof(ISoftUSBConfiguration), reinterpret_cast<void**>(&piConfig)); IfFailHrGo(hr); // Set the configuration data up IfFailHrGo(ConfigureConfig(piConfig)); // Add the interface to the interface collection IfFailHrGo(piConfig->get_Interfaces(&piInterfaceList)); IfFailHrGo(piInterfaceList->Add(reinterpret_cast<SoftUSBInterface*>(piInterface), varIndex)); // Add the configuration to the configuration collection IfFailHrGo(m_piSoftUSBDevice->get_Configurations(&piConfigList)); IfFailHrGo(piConfigList->Add(reinterpret_cast<SoftUSBConfiguration*>(piConfig), varIndex)); Exit: RELEASE(piConfig); RELEASE(piInterface); RELEASE(piConfigList); RELEASE(piInterfaceList); RELEASE(piEndpointList); return hr; }
HRESULT CSoftHIDInputKbdMapper::ProcessKbdInput() /*++ Routine Description: Reads and handles data from input keyboard buffer. Synchronization: None Arguments: None Return Value: S_OK Success E_FAIL Could not read data from keyboard buffer --*/ { USHORT usUnits = 0; KEYBOARD_INPUT_DATA* pKbdData = NULL; HRESULT hr = S_OK; // Read data from keyboard buffer IfFalseHrGo(NULL != m_piSoftKeyboard, E_FAIL); IfFailHrGo(m_piSoftKeyboard->Read(&usUnits, &pKbdData)); IfFalseHrGo(NULL != pKbdData, E_FAIL); // Check whether Protocol Translator interface pointer is set // If not, do not fail the function, but dispose the data IfFalseHrGo(NULL != m_piSoftProtXlator, S_OK); // Process keyboard data for(USHORT i = 0; i < usUnits; i++) { // Generate Input Report if (GenInputReport((USHORT)pKbdData[i].ulMakeCode, pKbdData[i].usFlags)) { // Send Input Report IfFailHrGo(SendInputReport(&m_InputReport, sizeof(m_InputReport))); } // Report phantom state else { HID_INPUTREPORT PhantomReport; // Initialize Phantom report. Modifier byte is still reported. FillMemory(&PhantomReport, sizeof(PhantomReport), 1); PhantomReport.bReserved = 0; PhantomReport.bModifier = m_InputReport.bModifier; // Send Phantom Report IfFailHrGo(SendInputReport(&PhantomReport, sizeof(PhantomReport))); } } Exit: // Release COM buffer if (NULL != pKbdData) { m_pMalloc->Free(pKbdData); } return hr; } // CSoftHIDInputKbdMapper::ProcessKbdInput
STDMETHODIMP CSoftKeyboard::PressAndReleaseKeys( BSTR bstrKeyStrokes) /*++ Routine Description: Implement the PressAndRelease method for the interface ISoftKeyboard. This simulate a key stroke for a UNICODE character Synchronization: None Arguments: bstrKeyStrokes - Keystrokes to be simulated Return Value: E_FAIL Could not generate a sequence of keycodes to simulate a keystroke. E_INVALIDARG Invalid keystroke length. S_OK Success. --*/ { HRESULT hr = S_OK; UINT nUnits = 0; KBD_KEYCODE* pKeyCodes = NULL; UINT nSize = SysStringLen(bstrKeyStrokes); // Check if string is not NULL IfFalseHrGo(nSize != 0, E_INVALIDARG); // Check is Translator property is set IfFalseHrGo(NULL != m_piSoftKbdTranslator, E_UNEXPECTED); hr = m_piSoftKbdTranslator->TranslateString2Keycodes(nSize, bstrKeyStrokes, &nUnits, &pKeyCodes); IfFailHrGo(hr); // Go through returned sequence and queue it for processing for(UINT i = 0; i < nUnits; i++) { // Call PressKey method if (KEY_MAKE == pKeyCodes[i].ucFlag) { IfFailHrGo(PressKey(pKeyCodes[i].KeyCode)); } // Call ReleaseKey method else if (KEY_BREAK == pKeyCodes[i].ucFlag) { IfFailHrGo(ReleaseKey(pKeyCodes[i].KeyCode)); } // Call HitKeyOnce method else if ((KEY_BREAK | KEY_MAKE) == pKeyCodes[i].ucFlag) { IfFailHrGo(HitKeyOnce(pKeyCodes[i].KeyCode)); } // Should never hit this code, but check anyway else { IfFailHrGo(E_FAIL); } } Exit: m_pMalloc->Free(pKeyCodes); return hr; } // CSoftKeyboard::PressAndReleaseKeys
HRESULT CLoopbackDevice::CreateStrings() { HRESULT hr = S_OK; ISoftUSBStringList* piStringList = NULL; ISoftUSBString* piStringManufacturer = NULL; ISoftUSBString* piStringProductDesc = NULL; ISoftUSBString* piStringSerialNo = NULL; ISoftUSBString* piStringConfig = NULL; ISoftUSBString* piStringEndpoint = NULL; BSTR bstrManufacturer = ::SysAllocString(L"Google, Inc"); BSTR bstrProductDesc = ::SysAllocString(L"USB Emulating Device"); BSTR bstrSerialNo = ::SysAllocString(L"123456789ABCDEF"); BSTR bstrConfig = ::SysAllocString(L"Configuration with a single interface"); BSTR bstrEndpoint = ::SysAllocString(L"Interface with bulk IN endpoint and bulk OUT endpoint"); VARIANT varIndex; VariantInit(&varIndex); // Check that all BSTR allocations succeeded IfFalseHrGo(0 != ::SysStringLen(bstrManufacturer), E_OUTOFMEMORY); IfFalseHrGo(0 != ::SysStringLen(bstrProductDesc), E_OUTOFMEMORY); IfFalseHrGo(0 != ::SysStringLen(bstrSerialNo), E_OUTOFMEMORY); IfFalseHrGo(0 != ::SysStringLen(bstrConfig), E_OUTOFMEMORY); IfFalseHrGo(0 != ::SysStringLen(bstrEndpoint), E_OUTOFMEMORY); //Set up the varaint used as the index varIndex.vt = VT_I4; varIndex.lVal = STRING_IDX_MANUFACTURER; //Create and initialize the string descriptors. Also create a string //descriptor index for each. This index is used both to set the string's //descriptors position in the m_piSoftUSBDevice.Strings and is the index value //the GetDescriptors request from the host. Note that we don't use //string descriptor index zero because that is a reserved value for a //device's language ID descriptor. //Get the string list from the device hr = m_piSoftUSBDevice->get_Strings(&piStringList); IfFailHrGo(hr); hr = CoCreateInstance(CLSID_SoftUSBString, NULL, CLSCTX_INPROC_SERVER, __uuidof(ISoftUSBString), reinterpret_cast<void**>(&piStringManufacturer)); IfFailHrGo(hr); IfFailHrGo(piStringManufacturer->put_Value(bstrManufacturer)); IfFailHrGo(piStringList->Add(reinterpret_cast<SoftUSBString*>(piStringManufacturer), varIndex)); hr = CoCreateInstance(CLSID_SoftUSBString, NULL, CLSCTX_INPROC_SERVER, __uuidof(ISoftUSBString), reinterpret_cast<void**>(&piStringProductDesc)); IfFailHrGo(hr); IfFailHrGo(piStringProductDesc->put_Value(bstrProductDesc)); varIndex.lVal = STRING_IDX_PRODUCT_DESC; IfFailHrGo(piStringList->Add(reinterpret_cast<SoftUSBString*>(piStringProductDesc), varIndex)); hr = CoCreateInstance(CLSID_SoftUSBString, NULL, CLSCTX_INPROC_SERVER, __uuidof(ISoftUSBString), reinterpret_cast<void**>(&piStringSerialNo)); IfFailHrGo(hr); IfFailHrGo(piStringSerialNo->put_Value(bstrSerialNo)); varIndex.lVal = STRING_IDX_SERIAL_NO; IfFailHrGo(piStringList->Add(reinterpret_cast<SoftUSBString*>(piStringSerialNo), varIndex)); hr = CoCreateInstance(CLSID_SoftUSBString, NULL, CLSCTX_INPROC_SERVER, __uuidof(ISoftUSBString), reinterpret_cast<void**>(&piStringConfig)); IfFailHrGo(hr); IfFailHrGo(piStringConfig->put_Value(bstrConfig)); varIndex.lVal = STRING_IDX_CONFIG; m_iConfigString = varIndex.lVal; IfFailHrGo(piStringList->Add(reinterpret_cast<SoftUSBString*>(piStringConfig), varIndex)); hr = CoCreateInstance(CLSID_SoftUSBString, NULL, CLSCTX_INPROC_SERVER, __uuidof(ISoftUSBString), reinterpret_cast<void**>(&piStringEndpoint)); IfFailHrGo(hr); IfFailHrGo(piStringEndpoint->put_Value(bstrEndpoint)); varIndex.lVal = STRING_IDX_INTERFACE; m_iInterfaceString = varIndex.lVal; IfFailHrGo(piStringList->Add(reinterpret_cast<SoftUSBString*>(piStringEndpoint), varIndex)); Exit: RELEASE(piStringList); RELEASE(piStringManufacturer); RELEASE(piStringProductDesc); RELEASE(piStringSerialNo); RELEASE(piStringConfig); RELEASE(piStringEndpoint); ::SysFreeString(bstrManufacturer); ::SysFreeString(bstrProductDesc); ::SysFreeString(bstrSerialNo); ::SysFreeString(bstrConfig); ::SysFreeString(bstrEndpoint); return hr; }
STDMETHODIMP CSoftHIDInputKbdMapper::AttachKbd(SoftKeyboard *pSoftKbd) /*++ Routine Description: Implements the AttachKbd method for the interface ISoftHIDInputKdbMapper. Allows a keyboard input device to attach to the HID device object. Synchronization: None Arguments: pSoftKbd - device to be attached Return Value: S_OK --*/ { HRESULT hr = S_OK; KEYBOARD_ATTRIBUTES* pKbdAttrib = NULL; KEYBOARD_TYPEMATIC_PARAMETERS* pTypematic = NULL; // Disconnect event sink from the old source TearDownEventSink(m_piConnectionPointKbd, m_dwKbdSinkCookie); // Set reference to ISoftKeyboard interface RELEASE(m_piSoftKeyboard); if (NULL != pSoftKbd) { IfFailHrGo(reinterpret_cast<IUnknown *>(pSoftKbd)->QueryInterface(__uuidof(ISoftInputKbdDevice), reinterpret_cast<void **>(&m_piSoftKeyboard))); // Set HID settings IfFailHrGo(m_piSoftKeyboard->get_Attributes(&pKbdAttrib)); pKbdAttrib->usKeyboardMode = KEYBOARD_HID_USAGE; IfFailHrGo(m_piSoftKeyboard->put_Attributes(pKbdAttrib)); // Disable autorepeat function IfFailHrGo(m_piSoftKeyboard->get_Typematic(&pTypematic)); pTypematic->ulDelay = KEYBOARD_TYPEMATIC_DELAY_INFINITE; IfFailHrGo(m_piSoftKeyboard->put_Typematic(pTypematic)); // Install event sink IfFailHrGo(SetupEventSink( m_piSoftKeyboard, GetUnknown(), __uuidof(ISoftInputKbdDeviceEvents), m_piConnectionPointKbd, m_dwKbdSinkCookie)); } Exit: if (NULL != pKbdAttrib) { m_pMalloc->Free(pKbdAttrib); } if (NULL != pTypematic) { m_pMalloc->Free(pTypematic); } return hr; } // CSoftHIDInputKbdMapper::AttachKbd
HRESULT CLoopbackDevice::CreateUSBDevice() { // Creates the USB device and initializes the device member variables // and creates and initializes the device qualifier. The device qualifier // is required for USB2.0 devices. HRESULT hr = S_OK; ISoftUSBDeviceQualifier* piDeviceQual = NULL; USHORT prod_id = DEVICE_EMULATOR_PROD_ID; hr = ::CoCreateInstance(CLSID_SoftUSBDevice, NULL, CLSCTX_INPROC_SERVER, __uuidof(ISoftUSBDevice), reinterpret_cast<void**>(&m_piSoftUSBDevice)); IfFailHrGo(hr); // Create the device qualifer hr = ::CoCreateInstance(CLSID_SoftUSBDeviceQualifier, NULL, CLSCTX_INPROC_SERVER, __uuidof(ISoftUSBDeviceQualifier), reinterpret_cast<void**>(&piDeviceQual)); IfFailHrGo(hr); // Setup the device qualifier // binary coded decimal USB version 2.0 IfFailHrGo(piDeviceQual->put_USB(0x0200)); // FF=Vendor specfic device class IfFailHrGo(piDeviceQual->put_DeviceClass(0xff)); // FF = Vendor specific device sub-class IfFailHrGo(piDeviceQual->put_DeviceSubClass(0xff)); // FF = Vendor specific device protocol IfFailHrGo(piDeviceQual->put_DeviceProtocol(0xff)); // Max packet size endpoint 0 IfFailHrGo(piDeviceQual->put_MaxPacketSize0(64)); // Number of configurations IfFailHrGo(piDeviceQual->put_NumConfigurations(1)); // Setup the device // binary coded decimal USB version 2.0 IfFailHrGo(m_piSoftUSBDevice->put_USB(0x0200)); // FF=Vendor specfic device class IfFailHrGo(m_piSoftUSBDevice->put_DeviceClass(0xff)); // FF = Vendor specific device sub-class IfFailHrGo(m_piSoftUSBDevice->put_DeviceSubClass(0xff)); // FF = Vendor specific device protocol IfFailHrGo(m_piSoftUSBDevice->put_DeviceProtocol(0xff)); // Max packet size endpoint 0 IfFailHrGo(m_piSoftUSBDevice->put_MaxPacketSize0(64)); // Vendor ID - Google IfFailHrGo(m_piSoftUSBDevice->put_Vendor(DEVICE_VENDOR_ID)); // product id - Device Emulator IfFailHrGo(m_piSoftUSBDevice->put_Product(static_cast<SHORT>(prod_id))); // Binary decimal coded version 1.0 IfFailHrGo(m_piSoftUSBDevice->put_Device(0x0100)); // Device does not suppport remote wake up IfFailHrGo(m_piSoftUSBDevice->put_RemoteWakeup(VARIANT_FALSE)); // Index of the manufacturer string IfFailHrGo(m_piSoftUSBDevice->put_Manufacturer(STRING_IDX_MANUFACTURER)); // Index of the product descripton string IfFailHrGo(m_piSoftUSBDevice->put_ProductDesc(STRING_IDX_PRODUCT_DESC)); // Index of the serial number string IfFailHrGo(m_piSoftUSBDevice->put_SerialNumber(STRING_IDX_SERIAL_NO)); // Indicate that the device is self-powered IfFailHrGo(m_piSoftUSBDevice->put_SelfPowered(VARIANT_TRUE)); // Indicate that the device has power IfFailHrGo(m_piSoftUSBDevice->put_Powered(VARIANT_TRUE)); // Create the strings associated with the device IfFailHrGo(CreateStrings()); // Add the device qualifier IfFailHrGo(m_piSoftUSBDevice->put_DeviceQualifier(piDeviceQual)); Exit: RELEASE(piDeviceQual); return hr; }
STDMETHODIMP CLoopbackDevice::DoPolledLoopback(long lTimeInterval) { /* Demonstrates how to use the drain OUT queue and queue IN data methods to communicate with the host controller. The code checks to see if there is any data in the OUT, if no data is present an event is fired to indicate if the function should exit. If the function should not exit then the function sleeps for the time interval before re-checking the queue. If there is data then the function reads the data and passes the data to the IN queue. This simply provides a loopback mechanism to the host controller. */ HRESULT hr = S_OK; BOOL fKeepLooping = TRUE; // Number of items currently in the queue ULONG ulNoOfQueuedItems = 0; // Only going to read one transfer at a time ULONG ulTransfers = 1; SOFTUSB_OUT_TRANSFER* pOUTTransfer = NULL; // Copied the message status BYTE bStatus = 0; // Copied the message data BYTE* pDataBuffer = NULL; // Holds the size of the data buffer ULONG cbDataBuffer = 0; VARIANT_BOOL fvarContinue = VARIANT_TRUE; if (NULL == m_piINEndpoint || NULL == m_piOUTEndpoint) { IfFailHrGo(E_UNEXPECTED); } while (fKeepLooping) { // Reset the number of queued items ulNoOfQueuedItems = 0; // Check to see if there is any data in the out queue IfFailHrGo(m_piOUTEndpoint->DrainOUTQueue(0, &ulNoOfQueuedItems, NULL)); if (0 == ulNoOfQueuedItems) { // There is no data in the list so we need to check // If we should continue to loop // Fire Event to check if more processing is required IfFailHrGo(Fire_ContinueToPoll(&fvarContinue)); // Check to see if the return value is VARIANT_FALSE if (VARIANT_FALSE == fvarContinue) fKeepLooping = FALSE; if (fKeepLooping) ::Sleep(lTimeInterval); } else { // There is data to read, loop until we have moved all // the data from the OUT queue to the IN queue moving // one data item at a time do { // Get the OUT data IfFailHrGo(m_piOUTEndpoint->DrainOUTQueue(ulTransfers, &ulNoOfQueuedItems, &pOUTTransfer)); // Setup the IN data bStatus= pOUTTransfer->bStatus; cbDataBuffer = pOUTTransfer->cbData; pDataBuffer =&pOUTTransfer->Data[0]; // Send the data to the out queue IfFailHrGo(m_piINEndpoint->QueueINData(pDataBuffer, cbDataBuffer, bStatus, SOFTUSB_FOREVER)); // Free the memory used by pOUTTransfer m_piOUTEndpoint->FreeOUTQueue(pOUTTransfer); pOUTTransfer = NULL; // Force a context switch ::Sleep(1); } while (0 != ulNoOfQueuedItems); } } Exit: // If one of the calls failed pOUTTransfer will be NON-NULL // And needs to be freed if (NULL != pOUTTransfer) { // Free the memory used by pOUTTransfer m_piOUTEndpoint->FreeOUTQueue(pOUTTransfer); pOUTTransfer = NULL; } return hr; }