First thing's first. To use DirectInput we need to add a new include file and two library files to our project. If you don't add these to your project you'll get compiler and linker errors. I've included the new header file in Game.h just below where I have included d3dx8.h. You can add the library files by going to Project > Settings… then on the Link tab, type the new library file names into the Object/Library Modules input box. The new files are listed below:
· dinput.h
· dinput8.lib
· dxguid.lib
The controls for this tutorial will be as follows:
· Up arrow: Scale Earth up
· Down arrow: Scale Earth down
· Left arrow: Rotate Earth more to the left
· Right arrow: Rotate Earth more to the right
· Move mouse: Change Earth x and y position
· Left mouse button: Stop Earth rotation
· Right mouse button: Start Earth rotation at default speed and direction
The first thing we need to do is to initialise DirectInput. To do this, I have a new function called InitialiseDirectInput that is called from the main CGame::Initialise function. The code snippet below will create a DirectInput object that we will use to create further objects for user input.
//Create the DirectInput object
if (FAILED(DirectInput8Create(hInst, DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&m_pDirectInput, NULL))) {
LogError("<li>Unable to create DirectInput interface.");
return false;
} else {
LogInfo("<li>DirectInput interface created OK");
}
The first parameter to DirectInput8Create is the HINSTANCE of our application which has been passed through from our WinMain function. The second parameter is the DirectInput version, this will always be DIRECTINPUT_VERSION. The third parameter is the desired interface, this will always be IID_IDirectInput8. The fourth parameter is the important one, this is a pointer the DirectInput interface which we will use later. The fifth parameter, for our examples is always NULL.
m_pDirectInput is a member variable of CGame and is of type LPDIRECTINPUT8.
Once we have created DirectInput interface pointer, we are ready to setup the keyboard. Shown below is the code required to setup the keyboard, take a look at it and I'll explain it below.
//KEYBOARD =======================================================================
//Create the keyboard device object
if (FAILED(m_pDirectInput->CreateDevice(GUID_SysKeyboard, &m_pKeyboard, NULL))) {
CleanUpDirectInput();
LogError("<li>Unable to create DirectInput keyboard device interface.");
return false;
} else {
LogInfo("<li>DirectInput keyboard device interface created OK.");
}
//Set the data format for the keyboard
if (FAILED(m_pKeyboard->SetDataFormat(&c_dfDIKeyboard))) {
CleanUpDirectInput();
LogError("<li>Unable to set the keyboard data format.");
return false;
} else {
LogInfo("<li>Set the keyboard data format OK.");
}
//Set the cooperative level for the keyboard
if (FAILED(m_pKeyboard->SetCooperativeLevel(hWnd, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE))) {
CleanUpDirectInput();
LogError("<li>Unable to set the keyboard cooperative level.");
return false;
} else {
LogInfo("<li>Set the keyboard cooperative level OK.");
}
//Acquire the keyboard
if (m_pKeyboard) {
m_pKeyboard->Acquire();
}
First of all, we need to create a keyboard device. We do this by calling the CreateDevice method of DirectInput. The first parameter is the GUID (Globally Unique Identifier) of the device to create, in our case the system keyboard device, so we simply pass in the GUID_SysKeyboard predefined GUID. The next parameter will receive a pointer to the keyboard device, we have defined this variable as a member of CGame. The last parameter is always NULL, take a look in the SDK for further details.
The next thing to do is set the data format for the keyboard device. To do this we simply pass in the predefined keyboard format c_dfDIKeyboard.
Then, we need to set how our input device (the keyboard) will cooperate with our application and Windows. We will need to specify the cooperation level by selecting "foreground" or "background" and "exclusive" or "nonexclusive". To do this, we need to pass in the relevant flags (DISCL_FOREGROUND, DISCL_BACKGROUND, DISCL_EXCLUSIVE and DISCL_NONEXCLUSIVE) to the SetCooperativeLevel method.
· DISCL_FOREGROUND: Input device is available when the application is in the foreground (has focus).
· DISCL_BACKGROUND: Input device is available at all times, foreground and background.
· DISCL_EXCLUSIVE: No other instance of the device can obtain exclusive access to the device while it is acquired.
· DISCL_NONEXCLUSIVE: Access to the device does not interfere with other applications that are accessing the same device.
The final thing to do is to acquire the keyboard, this means that we can now get access to the device's data. We do this by calling the Acquire method of the device.
As with the keyboard, we need to set up the mouse before we can get access to it. Below is the code required, take a look and you'll notice that it is very similar to the keyboard set up code above.
//MOUSE =======================================================================
//Create the mouse device object
if (FAILED(m_pDirectInput->CreateDevice(GUID_SysMouse, &m_pMouse, NULL))) {
CleanUpDirectInput();
LogError("<li>Unable to create DirectInput mouse device interface.");
return false;
} else {
LogInfo("<li>DirectInput mouse device interface created OK.");
}
//Set the data format for the mouse
if (FAILED(m_pMouse->SetDataFormat(&c_dfDIMouse))) {
CleanUpDirectInput();
LogError("<li>Unable to set the mouse data format.");
return false;
} else {
LogInfo("<li>Set the mouse data format OK.");
}
//Set the cooperative level for the mouse
if (FAILED(m_pMouse->SetCooperativeLevel(hWnd, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE))) {
CleanUpDirectInput();
LogError("<li>Unable to set the mouse cooperative level.");
return false;
} else {
LogInfo("<li>Set the mouse cooperative level OK.");
}
//Acquire the mouse
if (m_pMouse) {
m_pMouse->Acquire();
}
So, for the mouse we have the same basic steps as for the keyboard. One of the differences is that we pass in the predefined GUID for the system mouse (GUID_SysMouse) into the CreateDevice method instead of the one for the keyboard which will return a pointer to the mouse. Another difference is that we need to use a different data format, c_dfDIMouse instead of c_dfDIKeyboard. We then set the cooperation level as before and finally acquire the mouse. We are now ready to get data from the keyboard and mouse.