s32 F_API INPKBUpdate() { if(!g_pDKeyboard) return RETCODE_SUCCESS; u32 i; ////////////////////// //reset buffer for(i=0; i < g_prevKNum; i++) { if(KEYRELEASED(g_buffState[i].ofs)) { g_buffState[i].state = INPUT_UP; g_keyState[g_buffState[i].ofs] = INPUT_UP; } } g_buffStateSize = 0; ////////////////////// HRESULT hr; g_prevKNum = SAMPLE_BUFFER_SIZE; //First, check to see if the keyboard is still working/functioning hr= g_pDKeyboard->GetDeviceData(sizeof(DIDEVICEOBJECTDATA),g_pKbBuff,(LPDWORD)&g_prevKNum,0); if(hr != DI_OK) { g_prevKNum = 0; //did we lose the keyboard? if(hr==DIERR_INPUTLOST || hr==DIERR_NOTACQUIRED) { //we gotta have it back! g_pDKeyboard->Acquire(); /*hr = g_pDKeyboard->Acquire(); if(FAILED(hr)) { DInputError(hr, "_INPKBUpdate"); return RETCODE_FAILURE; } */ return RETCODE_SUCCESS; } else return RETCODE_FAILURE; } //update the keyboard states for(i=0; i < g_prevKNum; i++) { g_buffState[i].ofs = g_pKbBuff[i].dwOfs; g_buffState[i].state = (g_pKbBuff[i].dwData & INPUT_DOWN) ? INPUT_DOWN : INPUT_RELEASED; g_keyState[g_buffState[i].ofs] = g_buffState[i].state; } g_buffStateSize=g_prevKNum; return RETCODE_SUCCESS; }
void PsychHIDOSKbQueueFlush(int deviceIndex) { LPDIRECTINPUTDEVICE8 kb; HRESULT rc; DWORD dwItems = INFINITE; if (deviceIndex < 0) { deviceIndex = PsychHIDGetDefaultKbQueueDevice(); // Ok, deviceIndex now contains our default keyboard to use - The first suitable keyboard. } if ((deviceIndex < 0) || (deviceIndex >= ndevices)) { // Out of range index: PsychErrorExitMsg(PsychError_user, "Invalid 'deviceIndex' specified. No such device!"); } // Does Keyboard queue for this deviceIndex already exist? if (NULL == psychHIDKbQueueFirstPress[deviceIndex]) { // No. Bad bad... printf("PsychHID-ERROR: Tried to flush non-existent keyboard queue for deviceIndex %i! Call KbQueueCreate first!\n", deviceIndex); PsychErrorExitMsg(PsychError_user, "Invalid 'deviceIndex' specified. No queue for that device yet!"); } kb = GetXDevice(deviceIndex); // Clear out current state for this queue: PsychLockMutex(&KbQueueMutex); // Flush device buffer: rc = kb->GetDeviceData(sizeof(DIDEVICEOBJECTDATA), NULL, &dwItems, 0); // Clear our buffer: memset(psychHIDKbQueueFirstPress[deviceIndex] , 0, (256 * sizeof(double))); memset(psychHIDKbQueueFirstRelease[deviceIndex] , 0, (256 * sizeof(double))); memset(psychHIDKbQueueLastPress[deviceIndex] , 0, (256 * sizeof(double))); memset(psychHIDKbQueueLastRelease[deviceIndex] , 0, (256 * sizeof(double))); PsychUnlockMutex(&KbQueueMutex); return; }
//----------------------------------------------------------------------------- // Name: ReadBufferedData() // Desc: Read the input device's state when in buffered mode and display it. //----------------------------------------------------------------------------- HRESULT ReadBufferedData( HWND hDlg ) { TCHAR strNewText[128] = TEXT(""); DIDEVICEOBJECTDATA didod[ SAMPLE_BUFFER_SIZE ]; // Receives buffered data DWORD dwElements; DWORD i; HRESULT hr; if( NULL == g_pMouse ) return S_OK; dwElements = SAMPLE_BUFFER_SIZE; hr = g_pMouse->GetDeviceData( sizeof(DIDEVICEOBJECTDATA), didod, &dwElements, 0 ); if( hr != DI_OK ) { // We got an error or we got DI_BUFFEROVERFLOW. // // Either way, it means that continuous contact with the // device has been lost, either due to an external // interruption, or because the buffer overflowed // and some events were lost. // // Consequently, if a button was pressed at the time // the buffer overflowed or the connection was broken, // the corresponding "up" message might have been lost. // // But since our simple sample doesn't actually have // any state associated with button up or down events, // there is no state to reset. (In a real game, ignoring // the buffer overflow would result in the game thinking // a key was held down when in fact it isn't; it's just // that the "up" event got lost because the buffer // overflowed.) // // If we want to be cleverer, we could do a // GetDeviceState() and compare the current state // against the state we think the device is in, // and process all the states that are currently // different from our private state. hr = g_pMouse->Acquire(); while( hr == DIERR_INPUTLOST ) hr = g_pMouse->Acquire(); // Update the dialog text if( hr == DIERR_OTHERAPPHASPRIO || hr == DIERR_NOTACQUIRED ) SetDlgItemText( hDlg, IDC_DATA, TEXT("Unacquired") ); // hr may be DIERR_OTHERAPPHASPRIO or other errors. This // may occur when the app is minimized or in the process of // switching, so just try again later return S_OK; } if( FAILED(hr) ) return hr; // Study each of the buffer elements and process them. // // Since we really don't do anything, our "processing" // consists merely of squirting the name into our // local buffer. for( i = 0; i < dwElements; i++ ) { // this will display then scan code of the key // plus a 'D' - meaning the key was pressed // or a 'U' - meaning the key was released switch( didod[ i ].dwOfs ) { case DIMOFS_BUTTON0: _tcscat( strNewText, TEXT("B0") ); break; case DIMOFS_BUTTON1: _tcscat( strNewText, TEXT("B1") ); break; case DIMOFS_BUTTON2: _tcscat( strNewText, TEXT("B2") ); break; case DIMOFS_BUTTON3: _tcscat( strNewText, TEXT("B3") ); break; case DIMOFS_X: _tcscat( strNewText, TEXT("X") ); break; case DIMOFS_Y: _tcscat( strNewText, TEXT("Y") ); break; case DIMOFS_Z: _tcscat( strNewText, TEXT("Z") ); break; default: _tcscat( strNewText, TEXT("") ); } switch( didod[ i ].dwOfs ) { case DIMOFS_BUTTON0: case DIMOFS_BUTTON1: case DIMOFS_BUTTON2: case DIMOFS_BUTTON3: if( didod[ i ].dwData & 0x80 ) _tcscat( strNewText, TEXT("U ") ); else _tcscat( strNewText, TEXT("D ") ); break; case DIMOFS_X: case DIMOFS_Y: case DIMOFS_Z: { TCHAR strCoordValue[20]; wsprintf( strCoordValue, TEXT("%d "), didod[ i ].dwData ); _tcscat( strNewText, strCoordValue ); break; } } } // Get the old text in the text box TCHAR strOldText[128]; GetDlgItemText( hDlg, IDC_DATA, strOldText, 127 ); // If nothing changed then don't repaint - avoid flicker if( 0 != lstrcmp( strOldText, strNewText ) ) SetDlgItemText( hDlg, IDC_DATA, strNewText ); return S_OK; }
// This is the event dequeue & process function which updates // Keyboard queue state. It can be called with 'blockingSinglepass' // set to TRUE to process exactly one event, if called from the // background keyboard queue processing thread. Alternatively it // can be called synchronously from KbQueueCheck with a setting of FALSE // to iterate over all available events and process them instantaneously: void KbQueueProcessEvents(psych_bool blockingSinglepass) { LPDIRECTINPUTDEVICE8 kb; DIDEVICEOBJECTDATA event; HRESULT rc; DWORD dwItems; double tnow; unsigned int i, keycode, keystate; PsychHIDEventRecord evt; WORD asciiValue[2]; UCHAR keyboardState[256]; while (1) { // Single pass or multi-pass? if (blockingSinglepass) { // Wait until at least one event available and dequeue it: // We use a timeout of 100 msecs. WaitForSingleObject(hEvent, 100); } else { // Check if event available, dequeue it, if so. Abort // processing if no new event available, aka queue empty: // TODO if (!XCheckTypedEvent(thread_dpy, GenericEvent, &KbQueue_xevent)) break; } // Take timestamp: PsychGetAdjustedPrecisionTimerSeconds(&tnow); // Need the lock from here on: PsychLockMutex(&KbQueueMutex); // Do a sweep over all keyboard devices whose queues are active: for (i = 0; i < (unsigned int) ndevices; i++) { // Skip this one if inactive: if (!psychHIDKbQueueActive[i]) continue; // Check this device: kb = GetXDevice(i); // Fetch one item from the buffer: // event.dwTimeStamp = Timestamp in msecs of timeGetTime() timebase. // event.dwSequence = Sequence number. // Fetch from this device, item-by-item, until nothing more to fetch: while (TRUE) { // Try one fetch from this device: dwItems = 1; rc = kb->GetDeviceData(sizeof(DIDEVICEOBJECTDATA), &event, &dwItems, 0); // If failed or nothing more to fetch, break out of fetch loop: if (!SUCCEEDED(rc) || (0 == dwItems)) break; // Clear ringbuffer event: memset(&evt, 0 , sizeof(evt)); // Init character code to "unmapped": It will stay like that for anything but real keyboards: evt.cookedEventCode = -1; // Map to key code and key state: keycode = event.dwOfs & 0xff; keystate = event.dwData & 0x80; // Remap keycode into target slot in our arrays, depending on input device: switch (info[i].dwDevType & 0xff) { case DI8DEVTYPE_KEYBOARD: // Try to map scancode to ascii character: memset(keyboardState, 0, sizeof(keyboardState)); if (GetAsyncKeyState(VK_SHIFT)) keyboardState[VK_SHIFT] = 0xff; if ((1 == ToAsciiEx(MapVirtualKeyEx(keycode, 1, GetKeyboardLayout(0)), keycode, keyboardState, (LPWORD) &(asciiValue[0]), 0, GetKeyboardLayout(0)))) { // Mapped to single char: Return it as cooked keycode: evt.cookedEventCode = (int) (asciiValue[0] & 0xff); } else { // Could not map key to valid ascii character: Mark as "not mapped" aka zero: evt.cookedEventCode = 0; } // Map scancode 'keycode' to virtual key code 'keycode': keycode = PsychHIDOSMapKey(keycode); break; case DI8DEVTYPE_MOUSE: case DI8DEVTYPE_SCREENPOINTER: // Button event? Otherwise skip it. if (keycode < 3 * sizeof(LONG)) continue; // Correct for buttons offset in data structure DIMOUSESTATE2: keycode -= 3 * sizeof(LONG); break; case DI8DEVTYPE_JOYSTICK: // Button event? Otherwise skip it. if (keycode < (8 * sizeof(LONG) + 4 * sizeof(DWORD))) continue; // Correct for buttons offset in data structure DIJOYSTATE2: keycode -= (8 * sizeof(LONG) + 4 * sizeof(DWORD)); // Also skip if beyond button array: if (keycode >= 128) continue; break; default: // Unkown device -- Skip it. continue; } // This keyboard queue interested in this keycode? if (psychHIDKbQueueScanKeys[i][keycode] != 0) { // Yes: The queue wants to receive info about this key event. // Press or release? if (keystate) { // Enqueue key press. Always in the "last press" array, because any // press at this time is the best candidate for the last press. // Only enqeue in "first press" if there wasn't any registered before, // ie., the slot is so far empty: if (psychHIDKbQueueFirstPress[i][keycode] == 0) psychHIDKbQueueFirstPress[i][keycode] = tnow; psychHIDKbQueueLastPress[i][keycode] = tnow; evt.status |= (1 << 0); } else { // Enqueue key release. See logic above: if (psychHIDKbQueueFirstRelease[i][keycode] == 0) psychHIDKbQueueFirstRelease[i][keycode] = tnow; psychHIDKbQueueLastRelease[i][keycode] = tnow; evt.status &= ~(1 << 0); // Clear cooked keycode - We don't record key releases this way: if (evt.cookedEventCode > 0) evt.cookedEventCode = 0; } // Update event buffer: evt.timestamp = tnow; evt.rawEventCode = keycode + 1; PsychHIDAddEventToEventBuffer(i, &evt); // Tell waiting userspace (under KbQueueMutex protection for better scheduling) something interesting has changed: PsychSignalCondition(&KbQueueCondition); } // Next fetch iteration for this device... } // Check next device... } // Done with shared data access: PsychUnlockMutex(&KbQueueMutex); // Done if we were only supposed to handle one sweep, which we did: if (blockingSinglepass) break; } return; }
//----------------------------------------------------------------------------- // Name: OnLeftButtonDown() // Desc: If we are drawing a curve, then read buffered data and draw // lines from point to point. By reading buffered data, we can // track the motion of the mouse accurately without coalescing. // // This function illustrates how a non-message-based program can // process buffered data directly from a device, processing // messages only occasionally (as required by Windows). // // This function also illustrates how an application can piece // together buffered data elements based on the sequence number. // A single mouse action (e.g., moving diagonally) is reported // as a series of events, all with the same sequence number. // Zero is never a valid DirectInput sequence number, so it is // safe to use it as a sentinel value. //----------------------------------------------------------------------------- VOID OnLeftButtonDown( HWND hWnd ) { HRESULT hr; LEFTBUTTONINFO lbInfo; BOOL bDone; DIDEVICEOBJECTDATA od; DWORD dwElements; MSG msg; // For performance, draw directly onto the window's DC instead of // invalidating and waiting for the WM_PAINT message. Of course, // we always draw onto our bitmap, too, since that's what really // counts. // hide cursor and initialize button info with cursor position StartPenDraw( hWnd, &lbInfo ); InvalidateCursorRect( hWnd ); UpdateWindow( hWnd ); // Keep reading data elements until we see a "mouse button up" event. bDone = FALSE; while( !bDone ) { dwElements = 1; hr = g_pMouse->GetDeviceData( sizeof(DIDEVICEOBJECTDATA), &od, &dwElements, 0 ); if( FAILED(hr) ) break; // If theres no data available, finish the element // we have been collecting, and then process our message // queue so the system doesn't think the app has hung. if( dwElements == 0 ) { // if there is a partial motion, flush it out OnLeftButtonDown_FlushMotion( &lbInfo ); while( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) { // If it's a quit message, we're outta here if( msg.message == WM_QUIT ) { // Re-post the quit message so the // outer loop will see it and exit. PostQuitMessage( (int)msg.wParam ); bDone = TRUE; break; } else { TranslateMessage( &msg ); DispatchMessage( &msg ); } } continue; } // If this is the start of a new event, flush out the old one if( od.dwSequence != lbInfo.dwSeqLastSeen ) { OnLeftButtonDown_FlushMotion( &lbInfo ); lbInfo.dwSeqLastSeen = od.dwSequence; } // Look at the element to see what happened switch( od.dwOfs ) { case DIMOFS_X: // Mouse horizontal motion UpdateCursorPosition( od.dwData, 0 ); lbInfo.bMoved = TRUE; break; case DIMOFS_Y: // Mouse vertical motion UpdateCursorPosition( 0, od.dwData ); lbInfo.bMoved = TRUE; break; case DIMOFS_BUTTON0: // Button 0 pressed or released case DIMOFS_BUTTON1: // Button 1 pressed or released if( ( g_bSwapMouseButtons && DIMOFS_BUTTON1 == od.dwOfs ) || ( !g_bSwapMouseButtons && DIMOFS_BUTTON0 == od.dwOfs ) ) { if( !(od.dwData & 0x80) ) { // Button released, so flush out dregs bDone = TRUE; OnLeftButtonDown_FlushMotion( &lbInfo ); } } break; } } ReleaseDC( hWnd, lbInfo.hdcWindow ); // Re-show the cursor now that scrawling is finished FinishPenDraw( hWnd ); InvalidateCursorRect( hWnd ); }
//----------------------------------------------------------------------------- // Name: OnMouseInput() // Desc: Handles responding to any mouse input that is generated from // the mouse event being triggered. //----------------------------------------------------------------------------- VOID OnMouseInput( HWND hWnd ) { BOOL bDone; DIDEVICEOBJECTDATA od; DWORD dwElements; HRESULT hr; // Invalidate the old cursor so it will be erased InvalidateCursorRect( hWnd ); // Attempt to read one data element. Continue as long as // device data is available. bDone = FALSE; while( !bDone ) { dwElements = 1; hr = g_pMouse->GetDeviceData( sizeof(DIDEVICEOBJECTDATA), &od, &dwElements, 0 ); if( hr == DIERR_INPUTLOST ) { SetAcquire(); break; } // Unable to read data or no data available if( FAILED(hr) || dwElements == 0 ) { break; } // Look at the element to see what happened switch( od.dwOfs ) { case DIMOFS_X: // Mouse horizontal motion UpdateCursorPosition( od.dwData, 0 ); break; case DIMOFS_Y: // Mouse vertical motion UpdateCursorPosition( 0, od.dwData ); break; case DIMOFS_BUTTON0: // Right button pressed or released case DIMOFS_BUTTON1: // Left button pressed or released // Is the right or a swapped left button down? if( ( g_bSwapMouseButtons && DIMOFS_BUTTON1 == od.dwOfs ) || ( !g_bSwapMouseButtons && DIMOFS_BUTTON0 == od.dwOfs ) ) { if( od.dwData & 0x80 ) { // left button pressed, so go into button-down mode bDone = TRUE; OnLeftButtonDown( hWnd ); } } // is the left or a swapped right button down? if( ( g_bSwapMouseButtons && DIMOFS_BUTTON0 == od.dwOfs ) || ( !g_bSwapMouseButtons && DIMOFS_BUTTON1 == od.dwOfs ) ) { if( !(od.dwData & 0x80) ) { // button released, so check context menu bDone = TRUE; OnRightButtonUp( hWnd ); } } break; } } // Invalidate the new cursor so it will be drawn InvalidateCursorRect( hWnd ); }
void input_Proc(const xhn::vector<input_buffer>& buffer) { if(g_pMouse != NULL) { DIDEVICEOBJECTDATA didod[DINPUT_BUFFERSIZE]; // Receives buffered data DWORD dwElements; HRESULT hr; hr = DIERR_INPUTLOST; memset(didod, 0, sizeof(didod)); dwElements = DINPUT_BUFFERSIZE; hr = g_pMouse->GetDeviceData(sizeof(DIDEVICEOBJECTDATA), didod, &dwElements, 0); if (hr != DI_OK) { hr = g_pMouse->Acquire(); if(FAILED(hr)) return; hr = g_pMouse->GetDeviceData(sizeof(DIDEVICEOBJECTDATA), didod, &dwElements, 0); } if(FAILED(hr)) { if (hr == (HRESULT)DIERR_INPUTLOST) printf("DIERR_INPUTLOST\n"); if (hr == (HRESULT)DIERR_INVALIDPARAM) printf("DIERR_INVALIDPARAM\n"); if (hr == (HRESULT)DIERR_NOTACQUIRED) printf("DIERR_NOTACQUIRED\n"); if (hr == (HRESULT)DIERR_NOTBUFFERED) printf("DIERR_NOTBUFFERED\n"); if (hr == (HRESULT)DIERR_NOTINITIALIZED) printf("DIERR_NOTINITIALIZED\n"); return; } else { for(DWORD i=0; i<dwElements; i++) { input_event event; memset(&event, 0, sizeof(event)); event.time_stamp = didod[i].dwTimeStamp; if (didod[i].dwOfs == (DWORD)DIMOFS_X) { int disp = didod[i].dwData; event.info.mouse_info.mouse_move_info.x = disp; event.type = MouseMoveEvent; } else if (didod[i].dwOfs == (DWORD)DIMOFS_Y) { int disp = didod[i].dwData; event.info.mouse_info.mouse_move_info.y = disp; event.type = MouseMoveEvent; } else if (didod[i].dwOfs == (DWORD)DIMOFS_BUTTON0) { if (didod[i].dwData & 0x80) event.type = MouseButtonDownEvent; else event.type = MouseButtonUpEvent; event.info.mouse_info.mouse_button_info = LeftButton; } else if (didod[i].dwOfs == (DWORD)DIMOFS_BUTTON1) { if (didod[i].dwData & 0x80) event.type = MouseButtonDownEvent; else event.type = MouseButtonUpEvent; event.info.mouse_info.mouse_button_info = RightButton; } else if (didod[i].dwOfs == (DWORD)DIMOFS_BUTTON2) { if (didod[i].dwData & 0x80) event.type = MouseButtonDownEvent; else event.type = MouseButtonUpEvent; event.info.mouse_info.mouse_button_info = MiddleButton; } else continue; for (euint i = 0; i < buffer.size(); i++) { RWBuffer input_buffer = buffer[i].input_buffer; InterRWBuffer inter_input_buffer = buffer[i].inter_input_buffer; inter_input_buffer.write(input_buffer, (const euint*)&event, sizeof(event)); } } POINT curPos; GetCursorPos(&curPos); ScreenToClient(g_hwnd, &curPos); input_event event; event.type = MouseAbsolutePositionEvent; event.info.mouse_info.mouse_abs_pos.x = curPos.x; event.info.mouse_info.mouse_abs_pos.y = curPos.y; ///inter_input_buffer.write(input_buffer, (const euint*)&event, sizeof(event)); for (euint i = 0; i < buffer.size(); i++) { RWBuffer input_buffer = buffer[i].input_buffer; InterRWBuffer inter_input_buffer = buffer[i].inter_input_buffer; inter_input_buffer.write(input_buffer, (const euint*)&event, sizeof(event)); } } } if(g_pKeyboard != NULL) { DIDEVICEOBJECTDATA didod[DINPUT_BUFFERSIZE]; // Receives buffered data DWORD dwElements; HRESULT hr; hr = DIERR_INPUTLOST; memset(didod, 0, sizeof(didod)); dwElements = DINPUT_BUFFERSIZE; hr = g_pKeyboard->GetDeviceData(sizeof(DIDEVICEOBJECTDATA), didod, &dwElements, 0); if (hr != DI_OK) { hr = g_pKeyboard->Acquire(); if(FAILED(hr)) return; hr = g_pKeyboard->GetDeviceData(sizeof(DIDEVICEOBJECTDATA), didod, &dwElements, 0); } if(FAILED(hr)) { if (hr == (HRESULT)DIERR_INPUTLOST) printf("DIERR_INPUTLOST\n"); if (hr == (HRESULT)DIERR_INVALIDPARAM) printf("DIERR_INVALIDPARAM\n"); if (hr == (HRESULT)DIERR_NOTACQUIRED) printf("DIERR_NOTACQUIRED\n"); if (hr == (HRESULT)DIERR_NOTBUFFERED) printf("DIERR_NOTBUFFERED\n"); if (hr == (HRESULT)DIERR_NOTINITIALIZED) printf("DIERR_NOTINITIALIZED\n"); return; } else { for(DWORD i=0; i<dwElements; i++) { input_event event; memset(&event, 0, sizeof(event)); event.time_stamp = didod[i].dwTimeStamp; if (didod[i].dwData & 0x80) event.type = KeyDownEvent; else event.type = KeyUpEvent; event.info.key_info = didod[i].dwOfs & 0xff; ///inter_input_buffer.write(input_buffer, (const euint*)&event, sizeof(event)); for (euint i = 0; i < buffer.size(); i++) { RWBuffer input_buffer = buffer[i].input_buffer; InterRWBuffer inter_input_buffer = buffer[i].inter_input_buffer; inter_input_buffer.write(input_buffer, (const euint*)&event, sizeof(event)); } } } } }
HRESULT _stdcall GetDeviceData(DWORD a,LPDIDEVICEOBJECTDATA b,LPDWORD c,DWORD d) { //This only gets called for keyboards, and can be ignored because we don't want to change buffered data return RealDevice->GetDeviceData(a,b,c,d); }
int main(int argc, wchar_t* argv[]) { try { HWND wnd; if (FAILED(wnd = CreateWindow(NULL, NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL))) throw "Can't create message window"; LPDIRECTINPUT8 di; if (FAILED(DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&di, NULL))) throw "Can't create directinput"; LPDIRECTINPUTDEVICE8 dev; if (FAILED(di->CreateDevice(GUID_SysKeyboard, &dev, NULL))) throw "Can't create device"; if (FAILED(dev->SetDataFormat(&c_dfDIKeyboard))) throw "Can't set keyboard format"; if (FAILED(dev->SetCooperativeLevel(wnd, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE))) throw "Can't set cooperative level."; HANDLE ev = CreateEvent(NULL, FALSE, FALSE, NULL); const size_t buffer_size = 50; { DIPROPDWORD dipdw; dipdw.diph.dwSize = sizeof(DIPROPDWORD); dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER); dipdw.diph.dwObj = 0; dipdw.diph.dwHow = DIPH_DEVICE; dipdw.dwData = buffer_size; if (FAILED(dev->SetProperty(DIPROP_BUFFERSIZE, &dipdw.diph))) throw "Couldn't set buffer size"; } if (FAILED(dev->SetEventNotification(ev))) throw "Couldn't set event"; if (FAILED(dev->Acquire())) throw "Failed to acquire"; DIDEVICEOBJECTDATA buffer[buffer_size]; while (WaitForSingleObject(ev, INFINITE) != WAIT_FAILED) { DWORD items = buffer_size; HRESULT hr; if (FAILED(hr = dev->GetDeviceData(sizeof(DIDEVICEOBJECTDATA), buffer, &items, 0))) throw "Couldn't get data"; for (size_t i = 0; i < items; ++i) if (buffer[i].dwData) std::cout << buffer[i].dwData << ", " << buffer[i].dwOfs << std::endl; } return 0; } catch (const char * c) { std::cout << "failure: " << c << std::endl; } catch (HRESULT hr) { std::cout << "failureno: " << hr << std::endl; } catch (...) { std::cout << "general failure" << std::endl; } return 7; }
//----------------------------------------------------------------------------- // Name: UpdateInput() // Desc: Update the user input. Called once per frame //----------------------------------------------------------------------------- void CMyApplication::UpdateInput() { if( NULL == m_pInputDeviceManager ) return; CMultiplayerInputDeviceManager::DeviceInfo* pDeviceInfos; DWORD dwNumDevices; // Get access to the list of semantically-mapped input devices m_pInputDeviceManager->GetDevices( &pDeviceInfos, &dwNumDevices ); // Loop through all devices and check game input for( DWORD i=0; i<dwNumDevices; i++ ) { // skip past any devices that aren't assigned, // since we don't care about them if( pDeviceInfos[i].pPlayerInfo == NULL ) continue; DIDEVICEOBJECTDATA rgdod[10]; DWORD dwItems = 10; HRESULT hr; LPDIRECTINPUTDEVICE8 pdidDevice = pDeviceInfos[i].pdidDevice; InputDeviceState* pInputDeviceState = (InputDeviceState*) pDeviceInfos[i].pParam; FLOAT fScale = 1.0f; if( pDeviceInfos[i].bRelativeAxis ) { // For relative axis data, the action mapper only informs us when // the delta data is non-zero, so we need to zero its state // out each frame pInputDeviceState->fAxisMoveUD = 0.0f; pInputDeviceState->fAxisRotateLR = 0.0f; // Scale the relative axis data to make it more equal to // absolute joystick data fScale = 5.0f; } hr = pdidDevice->Acquire(); hr = pdidDevice->Poll(); hr = pdidDevice->GetDeviceData( sizeof(DIDEVICEOBJECTDATA), rgdod, &dwItems, 0 ); if( FAILED(hr) ) continue; // Get the sematics codes for the game menu for( DWORD j=0; j<dwItems; j++ ) { BOOL bButtonState = (rgdod[j].dwData==0x80) ? TRUE : FALSE; FLOAT fButtonState = (rgdod[j].dwData==0x80) ? 1.0f : 0.0f; FLOAT fAxisState = (FLOAT)((int)rgdod[j].dwData)/100.0f * fScale; switch( rgdod[j].uAppData ) { // Handle relative axis data case INPUT_ROTATE_AXIS_LR: pInputDeviceState->fAxisRotateLR = fAxisState; break; case INPUT_MOVE_AXIS_UD: pInputDeviceState->fAxisMoveUD = -fAxisState; break; // Handle buttons separately so the button state data // doesn't overwrite the axis state data, and handle // each button separately so they don't overwrite each other case INPUT_TURNLEFT: pInputDeviceState->bButtonRotateLeft = bButtonState; break; case INPUT_TURNRIGHT: pInputDeviceState->bButtonRotateRight = bButtonState; break; case INPUT_FORWARDTHRUST: pInputDeviceState->bButtonForwardThrust = bButtonState; break; case INPUT_REVERSETHRUST: pInputDeviceState->bButtonReverseThrust = bButtonState; break; case INPUT_FIREWEAPONS: pInputDeviceState->bButtonFireWeapons = bButtonState; break; case INPUT_ENABLESHIELD: pInputDeviceState->bButtonEnableShield = bButtonState; break; // Handle one-shot buttons case INPUT_DISPLAYGAMEMENU: if( bButtonState ) m_UserInput[0].bDoConfigureInput = TRUE; break; case INPUT_QUITGAME: if( bButtonState ) m_UserInput[0].bDoQuitGame = TRUE; break; } } } for( DWORD iPlayer=0; iPlayer<m_dwNumPlayers; iPlayer++ ) { // Process user input and store result into pUserInput struct m_UserInput[iPlayer].fAxisRotateLR = 0.0f; m_UserInput[iPlayer].fAxisMoveUD = 0.0f; m_UserInput[iPlayer].bButtonFireWeapons = FALSE; m_UserInput[iPlayer].bButtonEnableShield = FALSE; // Concatinate the data from all the DirectInput devices for( i=0; i<dwNumDevices; i++ ) { // Only look at devices that are assigned to this player if( pDeviceInfos[i].pPlayerInfo == NULL || pDeviceInfos[i].pPlayerInfo->dwPlayerIndex != iPlayer ) continue; InputDeviceState* pInputDeviceState = (InputDeviceState*) pDeviceInfos[i].pParam; // Use the axis data that is furthest from zero if( fabs(pInputDeviceState->fAxisRotateLR) > fabs(m_UserInput[iPlayer].fAxisRotateLR) ) m_UserInput[iPlayer].fAxisRotateLR = pInputDeviceState->fAxisRotateLR; if( fabs(pInputDeviceState->fAxisMoveUD) > fabs(m_UserInput[iPlayer].fAxisMoveUD) ) m_UserInput[iPlayer].fAxisMoveUD = pInputDeviceState->fAxisMoveUD; // Process the button data if( pInputDeviceState->bButtonRotateLeft ) m_UserInput[iPlayer].fAxisRotateLR = -1.0f; else if( pInputDeviceState->bButtonRotateRight ) m_UserInput[iPlayer].fAxisRotateLR = 1.0f; if( pInputDeviceState->bButtonForwardThrust ) m_UserInput[iPlayer].fAxisMoveUD = 1.0f; else if( pInputDeviceState->bButtonReverseThrust ) m_UserInput[iPlayer].fAxisMoveUD = -1.0f; if( pInputDeviceState->bButtonFireWeapons ) m_UserInput[iPlayer].bButtonFireWeapons = TRUE; if( pInputDeviceState->bButtonEnableShield ) m_UserInput[iPlayer].bButtonEnableShield = TRUE; } } }