DirectInput programming

xiaoxiao2021-03-06  43

Game programming is more than just the development of graphics programs, in fact, in many ways, this article is about how to use DirectInput to program the keyboard programming. In the DOS era, we are generally used to take over the keyboard interrupt to join your own processing code. But this set of survival is in a rich Windows society, we can only lead the API or DirectInput's relief. In the Windows API, a function with a getasyncKeyState () can return a current state of a specified key whether it is or loosen. This function can also return this specified key to the getaSyncKeyState () function after the last call. Although this function is very good, the programmer who is now led is less and less. The reason is nothing, just because DirectInput's relief is much thicker than this, and it seems to be more professional? In order to become a professional relief user as soon as possible, we will start from learning DirectInput's keyboard programming. When DirectInput is initialized, when DirectDraw, it is mentioned that Microsoft is designed by COM, so there is a DirectInput object to represent an input device, and a specific device is represented by the DirectInputDevice object. The actual establishment process is to create a DirectInput object first, then create a DirectInputDevice object through this object's CREATEVICE method. Examples are as follows:

#include #define DINPUT_BUFFERSIZE 16LPDIRECTINPUT lpDirectInput; // DirectInput objectLPDIRECTINPUTDEVICE lpKeyboard; // DirectInput deviceBOOL InitDInput (HWND hWnd) {HRESULT hr; // Create a DIRECTINPUT objects hr = DirectInputCreate (hInstanceCopy, DIRECTINPUT_VERSION, & lpDirectInput, NULL) If failed (hr) {// failed Return False;} // Create a DirectInputDevice interface hr = lpdirectinput-> createDevice (guid_syskeyboard, & lpkeyboard, null); if failed (hr) {// failed Return False;} // It is set to return the query status value hr = lpkeyboard-> setDataFormat (& c_dfdikeyboard); if failed (hr) {// failed Return False;} // Set collaboration mode hr = lpKeyboard-> setCoopeRATIVELEVEL (hwnd) , DISCL_NONEXCLUSIVE | DISCL_FOREGROUND); if failed (hr) {// failed Return False;} // Setting buffer size // If not set, the buffer size default value is 0, the program can only work according to immediate mode / / If you want to work with buffer mode, you must make the buffer size exceed 0 dipdword property; property.diph.dwsize = sizeof (DI) PROPDWORD); property.diph.dwHeaderSize = sizeof (DIPROPHEADER); property.diph.dwObj = 0; property.diph.dwHow = DIPH_DEVICE; property.dwData = DINPUT_BUFFERSIZE; hr = lpKeyboard-> SetProperty (DIPROP_BUFFERSIZE, & property.diph); If failed (hr) {// failed Return False;} hr = lpkeyboard-> acquire (); if failed (hr) {// failed Return False;} return true;}

In this code, we first define two pointers of LPDirectInput and LPKEYBOARD. The former is used to point to the DirectInput object, and the latter points to a DirectInputDevice interface. With DirectInputCreate (), we created a DirectInput object for LPDirectInput. Then we call CreateDevice to create a DirectInputDevice interface. The parameter Guid_syskeyboard indicates that the keyboard object is established. Next, setDataFormat Set the data format, setcooPERATIVEVELEvel setting collaboration mode, setProperty Set buffer mode. Because these function methods have a lot of parameters, I don't explain in detail, please check the help information of DirectX directly, it is very clear. After completing these work, we call the ACQUIRE method of the DirectInputDevice object to activate access to the device. It is specifically explained here, any DirectInput device, if it is not accessible if it is not acquire, it is unable to access. Also, when the system switches to another process, you must use the UNACQUIRE method to release access, and adjust the acquire when the system switches back to the process. Therefore, we usually processed as follows in the WindowProc: long FAR PASCAL WindowProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {switch (message) {case WM_ACTIVATEAPP: if (bActive) {if (lpKeyboard) lpKeyboard-> Acquire (); else {if (lpkeyboard) lpkeyboard-> unacquire ();} Break; ...}

Oh, yes, the previous routine also refers to the immediate mode and buffer mode. In DirectInput, these two working modes are different. If you use an immediate mode, you can only return the device status when the query is returned. The buffer mode will record all device status changes. For personal preferences, the author preferences, because this generally does not lose any button information. Correspondingly, if the query frequency is too low when using the former, it is difficult to ensure the integrity of the data. DIRECTINPUT's Data Query Immediate Mode is relatively simple, please see the following example: Byte Diks [256]; // DirectInput Keyboard State Buffer Keyboard Status Data Buffer HRESULT UPDATEINPUTSTATE (Void) {if (LpKeyboard! = Null) // If the LPKEYBOARD object interface exists {HRESULT HR; HR = DIERR_INPUTLOST; / / For loop detection, prepare // if INPUT IS LOST THEN ACQUIRE AND Keep Trying While (hr == dierr_inputlost) {// Read input device status value to state data Buffer hr = lpkeyboard-> getDeviceState; if (hr == dierr_inputlost) {// DirectInput report input stream is interrupted // must be recredited first, then try again HR = LpKeyBoard- > Acquire (); failed (hr)) Return HR;}} f (failed (hr)) Return HR;} Return S_OK;

In the above example, the key is to use the getDeviceState method to read the input device status value and the processing of the abnormal condition. By using the getDeviceState method, we put the status value of the input device in a 256-byte array. If the highest bit of an array element in the array is 1, the key indicating the corresponding encoded is being pressed at this time. For example, if DIKS [1] & 0x80> 0, then the ESC button is pressed. Data query where learn mode immediately after, we started following the buffering mode: HRESULT UpdateInputState (void) {DWORD i; if (! LpKeyboard = NULL) {DIDEVICEOBJECTDATA didod [DINPUT_BUFFERSIZE]; // Receives buffered data DWORD dwElements; HRESULT hr; hr = DIERR_INPUTLOST; while (hr = DI_OK!) {dwElements = DINPUT_BUFFERSIZE; hr = lpKeyboard-> GetDeviceData (sizeof (DIDEVICEOBJECTDATA), didod, & dwElements, 0); if (! hr = DI_OK) {// the occurrence of a Error // This error may be Di_BufferoverFlow buffer overflow error // but no matter which error, it means that the connection with the input device is lost // This error caused by the most serious consequences of this error is if you press one When the key is not released, an error occurs when it is wrong, and the message will be released later will be lost.

In this way, your program // may think that this button has not been released, there is some unexpected case // Now this code does not process the error / / a way to solve this problem is that this When an error is incorrect, you will call once // getDeviceState (), then compare the result of the result of the result to the status of the program, thereby correcting the possible error HR = lpKeyboard-> acquire (); if (Failed (HR) Return HR;}}}}}} // getDeviceData () After calling it, // DWELEments will indicate that the call has received several buffer records. / / We use a loop to handle each record for (INT i = 0; i UNACQUIRE (); lpkeyboard-> release (); lpkeyboard = null;} lpdirectinput-> release;}; lpdirectInput

This code is simple, it is to call the Release method to release the resource for each object of DirectInput. This process is substantially the same as other parts of DirectX.

DirectInput mouse programming

Previously, I briefly introduced how to use DirectInput to program the keyboard programming, this return will be described on how to use DirectInput to another very important input device ---- mouse programming problem. The process of programming with keyboard is very similar. With the last foundation, you can see that both are in the form of it is exactly different. DirectInput's initialization is the same as the process of programming the keyboard, we will start with the initialization of DirectInput: #include

#define dinput_buffersize 16lpdirectinput lpdirectinput; // DirectInput Object

LPDirectInputDevice lpmouse; // DirectInput Device

BOOL INITDINPUT (HWND HWND)

{

HRESULT HR;

// Create a DirectInput object

HR = DirectInputCreate (HinstanceCopy, DirectInput_Version, & lpDirectInput, null);

IF failed (HR)

{

// failed

Return False;

}

// Create a DirectInputDevice interface

HR = lpdirectinput-> CreateDevice (guid_sysmouse, & lpmouse, null);

IF failed (HR)

{

// failed

Return False;

}

/ / Set the return data format of the query mouse state

HR = lpmouse-> setDataFormat (& c_dfdimouse);

IF failed (HR)

{

// failed

Return False;

}

/ / Set collaboration mode

HR = lpmouse-> setCooperativeElevel (hwnd, discl_exclusive | discl_Foreground);

IF failed (HR)

{

// failed

Return False;

}

// Set the buffer size

// If not set, the buffer size default is 0, and the program can only work according to immediately.

// If you want to work with buffer mode, you must make the buffer more than 0

DipropdWord property DIPROPDWORD Property

Property.diph.dwsize = sizeof (dipropdword);

Property.diph.dwheadersize = sizeof (dipropheader);

Property.diph.dwobj = 0;

Property.diph.dwhow = DIPH_DEVICE;

Property.dwdata = DINPUT_BUFFERSIZE;

HR = lpmouse-> setproperty (Diprop_Buffersize, & Property.DIPH);

IF failed (HR)

{

// failed

Return False;

}

HR = lpmouse-> acquire ();

IF failed (HR)

{

// failed

Return False;

}

Return True;

}

In addition to a few modifications, this code is basically exactly the same as the code programmed in the previously described keyboard. Note that CreateDevice is called to create a DirectInputDevice interface, and the parameters we use are Guid_SYSMOUSE instead of guid_syskeyboard, which we specifically established a mouse object. Correspondingly, when using setDataFormat to set the return data, we use the parameters to be & c_dfdimouse instead of & c_dfdikeyboard. It is also important to note that the keyboard mentioned earlier is to work in a collaborative method, and the mouse can work according to the non-alone mode, or work in exclusive way. DirectInput's data query When you use the DirectInput mouse data query, I usually use buffer mode instead of immediate mode. The reason is simple, because the frequency of mouse movements is high, it is difficult to ensure that no data is lost according to immediate mode. As for the routine in the DirectX SDK, use immediate mode to read data because they use a multimedia timer to ensure that the mouse data is accepted at frequencies per second. After understanding this, let's take a look at the corresponding code.

Since the routine in the DirectX SDK has an immediate mode code, I just peeks, just give the code in a buffer mode: HRESULT UpdateInputState (void) {DWORD I; if (lpmouse! = Null) {DideviceObjectData Didod ; // Receives Buffered Data Data DWORD DWELEMENTS; HRESULT HR; While (True) {DWELEments = 1; // Read a data from the buffer from the buffer HR = lpmouse-> getDevicedata (Sizeof (DideviceObjectData), & Didod, & DWELEments, 0) If failed (hr) {// has an error if (hr == dierr_inputlost) {hr = lpmouse-> acquire (); // attempt to retrieve the device if failed (hr) {return s_false; // failed} }}} Else if (Elements == 1) {switch (didod.dwofs) {case DIMOFS_X: // X-axis offset // Didod.dwdata It is the specific offset relative value, the unit is pixel Break; Case Dimofs_y: // Y-axis offset // DidOd.dwdata is a specific offset relative value, unit is pixel Break; Case Dimofs_Button0: // 0 key ( Left key) Status // Didod.dwdata is a specific status value // low byte up to 1 indicator indicating that the highest bit of low byte is 0 indicates unpaid BREAK; Case Dimofs_Button1: // 1 (Right-click) status // 同 上 BREAK; CASE DIMOFS_BUTTON2: // 2 key (middle key)

转载请注明原文地址:https://www.9cbs.com/read-55895.html

New Post(0)