/***************************************************************************** * * diqacq.c * * "Data" (acquire) property sheet page. * *****************************************************************************/ #include "diquick.h" /***************************************************************************** * * Acq_AddDeviceData * *****************************************************************************/ void INTERNAL Acq_AddDeviceData(PDEVDLGINFO pddi, LPTSTR ptsz) { if (pddi->celtData >= pddi->celtDataMax) { ListBox_DeleteString(pddi->hwndData, 0); } else { pddi->celtData++; } ListBox_AddString(pddi->hwndData, ptsz); } /***************************************************************************** * * Acq_OnDataAvailable * *****************************************************************************/ void INTERNAL Acq_OnDataAvailable(HWND hdlg) { PDEVDLGINFO pddi = GetDialogPtr(hdlg); HRESULT hres; TCHAR tszBuf[1024]; DWORD dw; DIDEVICEOBJECTDATA rgdod[10]; ResetEvent(pddi->hevt); hres = pddi->pvtbl->UpdateStatus(pddi, tszBuf); if (SUCCEEDED(hres)) { TCHAR tszPrev[256]; GetWindowText(pddi->hwndState, tszPrev, cA(tszPrev)); /* Don't set text if same as before; avoids flicker */ if (lstrcmp(tszBuf, tszPrev)) { SetWindowText(pddi->hwndState, tszBuf); UpdateWindow(pddi->hwndState); } } else { if (hres == DIERR_INPUTLOST) { SetWindowText(pddi->hwndState, TEXT("Input lost")); } else if (hres == DIERR_NOTACQUIRED) { SetWindowText(pddi->hwndState, TEXT("Not acquired")); } else { wsprintf(tszBuf, TEXT("Error %08x"), hres); SetWindowText(pddi->hwndState, tszBuf); } } dw = cA(rgdod); hres = IDirectInputDevice_GetDeviceData(pddi->pdid, cbX(rgdod[0]), rgdod, &dw, 0); if (SUCCEEDED(hres)) { DWORD idod; for (idod = 0; idod < dw; idod++) { DIDEVICEOBJECTINSTANCE doi; if (SUCCEEDED(GetObjectInfo(pddi, &doi, rgdod[idod].dwOfs, DIPH_BYOFFSET))) { } else { lstrcpy(doi.tszName, TEXT("?")); } wsprintf(tszBuf, TEXT("%04x %04x %5d %02x [%s]"), rgdod[idod].dwSequence & 0xFFFF, rgdod[idod].dwTimeStamp & 0xFFFF, rgdod[idod].dwData, rgdod[idod].dwOfs, doi.tszName); Acq_AddDeviceData(pddi, tszBuf); } if (hres == S_FALSE) { Acq_AddDeviceData(pddi, TEXT("")); } } } #define TEST_SENDDEVICEDATA #ifdef TEST_SENDDEVICEDATA #include DWORD INTERNAL Acq_GetUsageId(IDirectInputDevice2 *pdid2, DWORD dwUsage) { HRESULT hres; DIDEVICEOBJECTINSTANCE inst; inst.dwSize = cbX(inst); hres = IDirectInputDevice_GetObjectInfo(pdid2, &inst, dwUsage, DIPH_BYUSAGE); if (SUCCEEDED(hres)) { return inst.dwType; } else { return 0; } } #endif /***************************************************************************** * * Acq_CheckDataAvailable * * Timer callback procedure * *****************************************************************************/ void CALLBACK Acq_CheckDataAvailable(HWND hdlg, UINT wm, UINT_PTR id, DWORD tm) { PDEVDLGINFO pddi = GetDialogPtr(hdlg); /* * If we can QI for IDirectInputDevice2::Poll, then call it. */ IDirectInputDevice2 *pdid2; HRESULT hres; hres = IDirectInputDevice_QueryInterface(pddi->pdid, &IID_IDirectInputDevice2, (PV)&pdid2); if (SUCCEEDED(hres)) { IDirectInputDevice2_Poll(pdid2); #ifdef TEST_SENDDEVICEDATA { // static int rgiBlah[] = { 1, 3, 2, 6, 4, 6, 2, 3 }; static int rgiBlah[] = { 1, 2, 4, 2 }; static int iBlah; DWORD cdod = 3; static DIDEVICEOBJECTDATA rgdod[3]; HRESULT hres; iBlah = (iBlah + 1) % cA(rgiBlah); // ZeroMemory(rgdod, sizeof(rgdod)); if (rgdod[2].dwOfs == 0) { rgdod[0].dwOfs = Acq_GetUsageId(pdid2, DIMAKEUSAGEDWORD(HID_USAGE_PAGE_LED, HID_USAGE_LED_NUM_LOCK)); rgdod[1].dwOfs = Acq_GetUsageId(pdid2, DIMAKEUSAGEDWORD(HID_USAGE_PAGE_LED, HID_USAGE_LED_CAPS_LOCK)); rgdod[2].dwOfs = Acq_GetUsageId(pdid2, DIMAKEUSAGEDWORD(HID_USAGE_PAGE_LED, HID_USAGE_LED_SCROLL_LOCK)); } // rgdod[0].dwOfs = 0x80006e84; // rgdod[1].dwOfs = 0x80006f84; // rgdod[2].dwOfs = 0x80007084; rgdod[0].dwData = (rgiBlah[iBlah] & 1) != 0; rgdod[1].dwData = (rgiBlah[iBlah] & 2) != 0; rgdod[2].dwData = (rgiBlah[iBlah] & 4) != 0; hres = IDirectInputDevice2_SendDeviceData(pdid2, sizeof(DIDEVICEOBJECTDATA), rgdod, &cdod, 0); } #endif IDirectInputDevice_Release(pdid2); } Acq_OnDataAvailable(hdlg); } /***************************************************************************** * * Acq_Listbox_Subclass * * Subclass procedure for the list box control, so that we eat * every single key. Except that we allow syskeys to go through * so that keyboard accelerators work. * *****************************************************************************/ LRESULT CALLBACK Acq_Listbox_Subclass(HWND hwnd, UINT wm, WPARAM wp, LPARAM lp) { PDEVDLGINFO pddi = GetDialogPtr(GetParent(hwnd)); if (pddi->fAcquired) { switch (wm) { case WM_GETDLGCODE: return DLGC_WANTALLKEYS; case WM_KEYDOWN: return 0; } } return CallWindowProc(pddi->wpListbox, hwnd, wm, wp, lp); } /***************************************************************************** * * Acq_OnInitDialog * * Init random goo. * *****************************************************************************/ BOOL INTERNAL Acq_OnInitDialog(HWND hdlg, LPARAM lp) { PDEVDLGINFO pddi = (PV)(((LPPROPSHEETPAGE)lp)->lParam); RECT rc; SetDialogPtr(hdlg, pddi); pddi->hevt = CreateEvent(0, 1, 0, 0); pddi->hwndState = GetDlgItem(hdlg, IDC_ACQ_STATE); pddi->hwndData = GetDlgItem(hdlg, IDC_ACQ_DATA); pddi->celtData = 0; GetClientRect(pddi->hwndData, &rc); pddi->celtDataMax = (rc.bottom - rc.top) / ListBox_GetItemHeight(pddi->hwndData, 0); pddi->wpListbox = SubclassWindow(pddi->hwndData, Acq_Listbox_Subclass); SetFocus(pddi->hwndData); return 0; } /***************************************************************************** * * Acq_OnSetActive * * Don't put up message boxes, because we aren't visible yet. * *****************************************************************************/ BOOL INTERNAL Acq_OnSetActive(HWND hdlg) { PDEVDLGINFO pddi = GetDialogPtr(hdlg); HRESULT hres; UINT ids = 0; hres = IDirectInputDevice_SetEventNotification(pddi->pdid, pddi->fPoll ? 0 : pddi->hevt); if (SUCCEEDED(hres)) { hres = IDirectInputDevice_Acquire(pddi->pdid); if (SUCCEEDED(hres)) { pddi->fAcquired = 1; SetFocus(pddi->hwndData); if (pddi->fPoll) { SetTimer(hdlg, IDT_DATA, msData, Acq_CheckDataAvailable); } } else { ids = IDS_ERR_ACQUIRE; } } else { ids = IDS_ERR_SETEVENTNOT; } if (ids) { TCHAR tsz[256]; LoadString(g_hinst, ids, tsz, cA(tsz)); SetDlgItemText(hdlg, IDC_ACQ_STATE, tsz); } else { Acq_OnDataAvailable(hdlg); } return 0; } /***************************************************************************** * * Acq_OnKillActive * *****************************************************************************/ BOOL INTERNAL Acq_OnKillActive(HWND hdlg) { PDEVDLGINFO pddi = GetDialogPtr(hdlg); if (pddi) { if (pddi->fAcquired) { pddi->fAcquired = 0; IDirectInputDevice_Unacquire(pddi->pdid); } if (pddi->fPoll) { KillTimer(hdlg, IDT_DATA); } else { IDirectInputDevice_SetEventNotification(pddi->pdid, 0); } } return 0; } /***************************************************************************** * * Acq_OnDestroy * * Clean up. * *****************************************************************************/ BOOL INTERNAL Acq_OnDestroy(HWND hdlg) { PDEVDLGINFO pddi = GetDialogPtr(hdlg); Acq_OnKillActive(hdlg); if (pddi && pddi->hevt) { CloseHandle(pddi->hevt); } return 1; } /***************************************************************************** * * Acq_OnSelfEnterIdle * * This dialog box is idle. Do a custom message loop if needed. * *****************************************************************************/ BOOL INTERNAL Acq_OnSelfEnterIdle(HWND hdlg) { PDEVDLGINFO pddi = GetDialogPtr(hdlg); if (pddi->fAcquired && !pddi->fPoll) { for (;;) { DWORD dwRc; MSG msg; dwRc = MsgWaitForMultipleObjects(1, &pddi->hevt, 0, INFINITE, QS_ALLINPUT); switch (dwRc) { case WAIT_OBJECT_0: /* Data available */ Acq_OnDataAvailable(hdlg); break; /* Sometimes we get woken spuriously */ case WAIT_OBJECT_0 + 1: if (PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE)) { goto stop; } break; default: /* Return and let the dialog box loop handle the message */ goto stop; } } stop:; } return 1; } /***************************************************************************** * * Acq_OnNotify * *****************************************************************************/ BOOL INLINE Acq_OnNotify(HWND hdlg, NMHDR *pnm) { switch (pnm->code) { case PSN_SETACTIVE: return Acq_OnSetActive(hdlg); case PSN_KILLACTIVE: return Acq_OnKillActive(hdlg); } return 0; } /***************************************************************************** * * Acq_OnUnacquire * *****************************************************************************/ BOOL INTERNAL Acq_OnUnacquire(PDEVDLGINFO pddi, HWND hdlg) { HRESULT hres; hres = IDirectInputDevice_Unacquire(pddi->pdid); return 1; } /***************************************************************************** * * Acq_OnCommand * *****************************************************************************/ BOOL INTERNAL Acq_OnCommand(HWND hdlg, int id, UINT cmd) { PDEVDLGINFO pddi = GetDialogPtr(hdlg); if (cmd == BN_CLICKED) { switch (id) { case IDC_ACQ_UNACQ: return Acq_OnUnacquire(pddi, hdlg); break; } } return 0; } /***************************************************************************** * * Acq_DlgProc * *****************************************************************************/ INT_PTR CALLBACK Acq_DlgProc(HWND hdlg, UINT wm, WPARAM wp, LPARAM lp) { switch (wm) { case WM_INITDIALOG: return Acq_OnInitDialog(hdlg, lp); case WM_DESTROY: return Acq_OnDestroy(hdlg); case WM_SELFENTERIDLE: return Acq_OnSelfEnterIdle(hdlg); case WM_NOTIFY: return Acq_OnNotify(hdlg, (NMHDR *)lp); case WM_COMMAND: return Acq_OnCommand(hdlg, (int)GET_WM_COMMAND_ID(wp, lp), (UINT)GET_WM_COMMAND_CMD(wp, lp)); } return 0; }