So… before we go any further with CMouse, let’s look at the code to initialize DirectInput. Note that this code doesn’t belong in our CMouse::Init() routine; the DirectInput pointer is used by the entire game, not just the mouse, so the code that inits DirectInput should go in your main init function - the same time you init DirectDraw, DirectSound, etc. A DirectInput interface pointer is different than a DirectInput device pointer; you use DirectInput pointers to get DirectInputDevice pointers.
Here’s the code to initialize the master DirectInput interface pointer:
LPDIRECTINPUT di = NULL;
hr = DirectInputCreate(hinst, DIRECTINPUT_VERSION, &di, NULL);
if (FAILED(hr)) {
// error processing
}
That will put a valid DirectInput interface pointer into di. (Don’t forget to Release() it when your game ends!)
Now that we’ve got a DirectInput interface, let’s begin fleshing out our CMouse by implementing CMouse::Init().
bool CMouse::Init(LPDIRECTINPUT di) {
// Obtain an interface to the system mouse device.
hr = di-›CreateDevice(GUID_SysMouse, (LPDIRECTINPUTDEVICE*)&di_mouse, NULL);
if (FAILED(hr)) {/* handle errors! */}
// Set the data format to "mouse format".
hr = m_mousedev-›SetDataFormat(&c_dfDIMouse);
if (FAILED(hr)) {/* handle errors! */}
// Set the cooperativity level
hr = m_mousedev-›SetCooperativeLevel(hwnd, DISCL_NONEXCLUSIVE | DISCL_FOREGROUND);
if (FAILED(hr)) {/* handle errors! */}
}
That code does three important things. First, it gets a valid DirectInput mouse device interface, and puts it in di_mouse. Next, it sets the data format and the cooperative level for the device, basically letting windows know that we want to query the device as if it were a mouse, and that we don’t want to take exclusive ownership of it. (Exclusive ownership means that we’re the only app that can use the mouse - by specifying DISCL_NONEXCLUSIVE, we’ve told Windows that we’re going to be sharing the mouse with other applications.)
Now let’s flesh out CMouse::Refresh(), the function responsible for updating the CMouse’s internal button state and position variables. Here’s the code.
void CMouse::Refresh(void) {
C done = 0;
int q;
HRESULT hr;
POINT p;
DIMOUSESTATE dims;
if (!m_di) return;
// clear our struct - eventually, directinput will fill this in
memset(&dims, 0, sizeof(DIMOUSESTATE));
if (!m_mousedev) return; // we don’t have a pointer! Bail!
while (!done) {
hr = m_mousedev-›GetDeviceState(sizeof(DIMOUSESTATE), &dims);
if (FAILED(hr)) {
if (hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED) {
// device lost… reacquire
hr = m_mousedev-›Acquire();
if (FAILED(hr)) {
// houston, we have a problem… clear & bail
clear();
done=1;
}
} else {
// it’s some other error - clear and bail!
m_mousedev.clear();
done = 1;
}
} else // read mouse successfully!
{
done = 1;
}
} //while !done
m_position.z += dims.lZ;
if (m_vga-›isfullscreen()) {
// we're in fullscreen, so this is easy… just copy the coords
m_position.x += dims.lX;
m_position.y += dims.lY;
} else {
// we're in window mode, so this is not-so-easy…
// grab the relative mouse position
GetCursorPos(&p);
ScreenToClient((HWND)m_vga-›gethwnd(), &p);
if (p.x ‹ 0 || p.y ‹ 0) {
// the cursor is out of our window! "hide" it!
m_mousedev.setposition(KJM_AXES_X, m_vga-›getscreendims().getwidth());