#include "ASW.h" #include "ASW_Input_W32.H" const ASW::Input::KeyType InputW32::m_enmMsInputKeys[('z' - 'a') + 1] = { ASW::Input::KEY_A, ASW::Input::KEY_B, ASW::Input::KEY_C, ASW::Input::KEY_D, ASW::Input::KEY_E, ASW::Input::KEY_F, ASW::Input::KEY_G, ASW::Input::KEY_H, ASW::Input::KEY_I, ASW::Input::KEY_J, ASW::Input::KEY_K, ASW::Input::KEY_L, ASW::Input::KEY_M, ASW::Input::KEY_N, ASW::Input::KEY_O, ASW::Input::KEY_P, ASW::Input::KEY_Q, ASW::Input::KEY_R, ASW::Input::KEY_S, ASW::Input::KEY_T, ASW::Input::KEY_U, ASW::Input::KEY_V, ASW::Input::KEY_W, ASW::Input::KEY_X, ASW::Input::KEY_Y, ASW::Input::KEY_Z, }; /* During initialization, both the WndProc() routine and the 'user data' of the window are saved, and overwritten with our own values. Our own 'user data' is simply a pointer to 'this', which we retrieve again in our WndProc() and use to access member variables (see the WndProc() method below). Our mechanism of saving the current 'user data' and WndProc() and calling it for messages we don't handle is overkill and can probably be commented out or conditionally ignored. Oh well, I'll think about it later */ InputW32:: InputW32(WindowW32 & p_clsWindow) : m_blnRecievedQuit(false), m_blnMouse(false), m_stuMouseDelta(0), m_ftnWndProc(NULL), m_lngOldValue(0), m_ptrWindow(NULL) { m_ptrWindow = &p_clsWindow; HWND hndWindow = p_clsWindow.GetWindow(); m_ftnWndProc = (WNDPROC)(GetWindowLongPtr(hndWindow, GWLP_WNDPROC)); m_lngOldValue = GetWindowLongPtr(hndWindow, GWLP_USERDATA); SetWindowLongPtr(hndWindow, GWLP_USERDATA, (long)(this)); SetWindowLongPtr(hndWindow, GWLP_WNDPROC, (long)(WndProc)); } /* Old WndProc() and 'user data' are restored */ InputW32:: ~InputW32() { if ( m_ptrWindow != NULL ) { SetWindowLongPtr(m_ptrWindow->GetWindow(), GWLP_USERDATA, m_lngOldValue); SetWindowLongPtr(m_ptrWindow->GetWindow(), GWLP_WNDPROC, (long)(m_ftnWndProc)); } } /* Aquiring is simply grabbing the focus, after which we should start recieving messages via WndProc() */ bool InputW32:: Acquire() { return m_ptrWindow->Focus(); } /* Standard WndProc() routine as required by Windows programs. State changes (i.e. mouse and keyboard changes) are inserted into the m_clsKeys variable and the Sync() method removes them. It follows that it is important for Sync() to be called (via the Get() method of Input), or else state changes will continue to pile up here */ LRESULT CALLBACK InputW32:: WndProc(HWND p_hndWindow, UINT p_uintMsg, WPARAM p_wParam, LPARAM p_lParam) { // // A pointer to 'this' is stored in the 'user data' of the window (see the constructor) // InputW32 * ptrInput = (InputW32 *)(GetWindowLongPtr(p_hndWindow, GWLP_USERDATA)); if ( ptrInput == NULL ) return DefWindowProc(p_hndWindow, p_uintMsg, p_wParam, p_lParam); // // Check the message type // ASW::Input::KeyChange stuKey; stuKey.m_enmKey = ASW::Input::KEY_UNKNOWN; switch ( p_uintMsg ) { case WM_LBUTTONDOWN: stuKey.m_enmKey = ASW::Input::KEY_MB0; stuKey.m_blnDown = true; break; case WM_LBUTTONUP: stuKey.m_enmKey = ASW::Input::KEY_MB0; stuKey.m_blnDown = false; break; case WM_RBUTTONDOWN: stuKey.m_enmKey = ASW::Input::KEY_MB1; stuKey.m_blnDown = true; break; case WM_RBUTTONUP: stuKey.m_enmKey = ASW::Input::KEY_MB1; stuKey.m_blnDown = false; break; case WM_MOUSEMOVE: if ( ptrInput->m_blnMouse ) { ptrInput->m_stuMouseDelta[0] += ptrInput->m_stuMousePos[0] - (int)(p_lParam & 0xffff); ptrInput->m_stuMouseDelta[1] += ptrInput->m_stuMousePos[1] - (int)((p_lParam >> 16) & 0xffff); ptrInput->m_stuMousePos[0] = (int)(p_lParam & 0xffff); ptrInput->m_stuMousePos[1] = (int)((p_lParam >> 16) & 0xffff); } else { ptrInput->m_stuMousePos[0] = (int)(p_lParam & 0xffff); ptrInput->m_stuMousePos[1] = (int)((p_lParam >> 16) & 0xffff); ptrInput->m_blnMouse = true; } break; case WM_KEYDOWN: case WM_KEYUP: stuKey.m_blnDown = ( p_uintMsg == WM_KEYDOWN ); if ( p_wParam < 'A' || p_wParam > 'Z' ) { switch ( p_wParam ) { case VK_TAB: stuKey.m_enmKey = ASW::Input::KEY_TAB; break; case VK_UP: stuKey.m_enmKey = ASW::Input::KEY_UP; break; case VK_DOWN: stuKey.m_enmKey = ASW::Input::KEY_DOWN; break; case VK_LEFT: stuKey.m_enmKey = ASW::Input::KEY_LEFT; break; case VK_RIGHT: stuKey.m_enmKey = ASW::Input::KEY_RIGHT; break; } } else stuKey.m_enmKey = InputW32::m_enmMsInputKeys[p_wParam - 'A']; break; default: break; } // // Only add the key to the state change array if it is one we care // about (it is not UNKNOWN) and at least one action uses it // if ( stuKey.m_enmKey != ASW::Input::KEY_UNKNOWN && ptrInput->m_ptrActionIndices[stuKey.m_enmKey] ) { // // Since Windows will keep sending messages for keys that are // held down, only add the key if there is actually a state change // if ( stuKey.m_blnDown == false || ptrInput->m_blnKeys[stuKey.m_enmKey] == false ) ptrInput->m_clsKeys.push_back(stuKey); return 0; } else { // // Call the old WndProc routine for this window (this is probably // not necessary and can be commented out if you don't care to // support the old WndProc (see the constructor)) // SetWindowLongPtr(p_hndWindow, GWLP_WNDPROC, (long)(ptrInput->m_ftnWndProc)); SetWindowLongPtr(p_hndWindow, GWLP_USERDATA, ptrInput->m_lngOldValue); LRESULT stuTemp = CallWindowProc(ptrInput->m_ftnWndProc, p_hndWindow, p_uintMsg, p_wParam, p_lParam); ptrInput->m_ftnWndProc = (WNDPROC)(GetWindowLongPtr(p_hndWindow, GWLP_WNDPROC)); ptrInput->m_lngOldValue = GetWindowLongPtr(p_hndWindow, GWLP_USERDATA); SetWindowLongPtr(p_hndWindow, GWLP_WNDPROC, (long)(InputW32::WndProc)); SetWindowLongPtr(p_hndWindow, GWLP_USERDATA, (long)(ptrInput)); return stuTemp; } } /* Here the action array is copied into the parameter array, after which the action array is emptied. Refer to WndProc() to see how the action array is filled. It is important to call this method every so often (via the Get() method of Input), or else the action array will keep filling up with state changes. */ bool InputW32:: Sync(ASW::Input::KeyChange * p_ptrChanges, unsigned int & p_uintAmount, ASW::Point3i & p_stuMouseMovement) { // // Copy the member action array to the parameter action array, then // empty the member action array. // // WE SHOULD HAVE SOME SORT OF MUTEX AROUND THIS, AS WndProc() CAN BE // ADDING TO THIS ARRAY AT THE SAME TIME WE ARE EMPTYING IT. ALSO, WE // CAN'T HAVE MORE THAN 255 THIS WAY // p_uintAmount = m_clsKeys.size(); memcpy(p_ptrChanges, &(m_clsKeys[0]), p_uintAmount * sizeof(ASW::Input::KeyChange)); m_clsKeys.clear(); p_stuMouseMovement[0] = m_stuMouseDelta[0]; p_stuMouseMovement[1] = m_stuMouseDelta[1]; m_stuMouseDelta = 0; return m_ptrWindow->Focus(); }