Direct Input MADNESS!

This is a discussion on Direct Input MADNESS! within the Game Programming forums, part of the General Programming Boards category; I'm very confused with this particular error, and was hoping that someone here would be kind enough to tell me ...

Direct Input MADNESS!

This is a different question, but is just as puzzling to me. In my last post (Found Here) I provided code snippets so you could see what I was doing.

In the Directinput GetDeviceState method, I found that it copies the states into your array in a very odd manner. For example, the state of key "F2" is stored in my variable, state[30] with a value of 128. However, "F3" is ALSO stored in state[30], but with a value of 32768.

I noticed that these two values are repeated. When I do

Code:

(state[key] & 128)

, I will get one key, whereas

Code:

(state[key] & 32768)

will give me a different key.

This just seems very odd to me, and makes me think that I am using Directinput incorrectly. But if anyone can justify this seemingly odd form of obtaining key states, please do so here.

I would advise you place the key mapping into an array that lines up with the DIK constants you are mapping to. You can use a map or a hash. You might hash the message "fire" to some DIK_ constant. If you do this in an array or a map you can change the mapping of the keys in your game at any time.

I'm sort of doing that, but writing it in a function...my point is that the keys that are already defined aren't working for me for some unknown reason.

For example, DIK_ESCAPE (which is defined as 0x01), is read as key Num1 on my computer, for some ungodly reason.

I had to redefine all of the keys on my keyboard, one by one...very tedious and annoying. The signatures are ALL different though...which confuses me very very much. Windows and DirectInput BOTH define DIK_ESCAPE as 0x01...but my program reads state[1] as number 1...I just don't understand it.

I actually originally had it that way, and it didn't work...the keys listed above are surprisingly the working ones! For some reason, DIK_whatever just won't work. It compiles just fine, the only problem is that the key doesn't correspond to the name!

For example, if I replace Keys::Escape in my code with DIK_ESCAPE, it will be broken...it will read the input as key NUM1, rather than DIK_ESCAPE....so for me, it is the Direct Input defined keys that are giving me issues...

For key down you and the result with 0x80. Anything else is undefined and would be outside the scope of how DirectInput is to be used.

Immediate Keyboard Data
To retrieve the current state of the keyboard, call the IDirectInputDevice8::GetDeviceState method with a pointer to an array of 256 bytes that will hold the returned data.

The IDirectInputDevice8::GetDeviceState method behaves in the same way as the Microsoft Win32 GetKeyboardState function. It returns a snapshot of the current state of the keyboard. Each key is represented by a byte in the array of 256 bytes whose address was passed as the lpvData parameter. If the high bit of the byte is set, the key is down. The array is most conveniently indexed with the Microsoft DirectInput Keyboard Device. (See also Interpreting Keyboard Data.)

The following code example calls a function in response to the ESC key being down. Assume that lpdiKeyboard is an acquired DirectInput device.

...and KeyDown() AND's the keystate array with 0x80 to get the result then there is no way that DIK_ESCAPE can map to some other key. I cannot see your keyboard code so I'm not sure it is working correctly. You must call GetDeviceState() in order to get the current mouse and keyboard state. This must be done before every frame.

Incidentally if you only acquire the device once it can actually fail. You should acquire continually until it succeeds or it's possible that the device will not be re-acquired and your app will not accept keyboard input. Normally it will succeed the first time but if it's a windowed app and you set the focus to another app window and come back...it could take a slight bit of time to re-acquire and your code does not account for this. It assumes the acquire succeeded when it may have failed. In my experience it appears that the keyboard is the primary device most affected by this.

All DirectX functions return an HRESULT which can be checked via the FAILED() and SUCEEDED() macros. Normally I will choose either FAILED() or SUCEEDED() but I will not mix them in the code. If you choose one then use it all the time or your error conditions can become confusing.

I didn't know about continual acquires, but fortunately, I am doing that. However, the GetDeviceState() function is copying information in a very odd way.

I have my BYTE keystate[256] array, and have used GetDeviceState() on every update (which happens everytime time the program goes through the game loop). The problem is that certain keys are being stored in the same array location.

For example:

Code:

if(keystate[30] & 128) //128 is 0x80

will give me the state of F2. However, the following will give me the state of F3:

Code:

if(keystate[30] & 32768)

So...as you can see, both keys are stored in the same array location. I have used multiple keyboards, and have been given the same result. The code posted in my first post should compile...so feel free to toy with it and see what happens when you use it.

Yes, but I was under the impression that information about each key would be copied to a separate array location or byte. What would be the purpose of copying multiple keys to the same location...and how would I have been able to change the GetDeviceState() function in order to make it do that?!

Also...now that I think about it, how is it even possible to have a value of 32768 in a byte?!
** Correction, I forgot that I wasn't using an actual byte. (BYTE is typedef'ed from an unsigned short)

Yes, but I was under the impression that information about each key would be copied to a separate array location or byte. What would be the purpose of copying multiple keys to the same location...and how would I have been able to change the GetDeviceState() function in order to make it do that?!

Also...now that I think about it, how is it even possible to have a value of 32768 in a byte?!
** Correction, I forgot that I wasn't using an actual byte. (BYTE is typedef'ed from an unsigned short)

So if you change everything to use proper bytes (if your BYTE typedef is broken as such, then maybe using unsigned char) does that fix all those issues in your previous thread?

The moral of the story is that if you want to get things running properly, you should stick with the API defines and macros/functions to access everything. Even if you were to successfully process the data-structures "by-hand" (an interesting excercise, actually, if you've got some spare time on your hands, to be sure) it wouldn't be sufficient for production-quality code, since the underlying layout can change from system to system. In other words, aside from the purely academic excercise in curiosity, the approach is basically worthless.

Unless you're retrieving joystick data, you shouldn't use DirectInput. Even MS actively discourages its use for anything other than Joysticks.

Originally Posted by http://msdn.microsoft.com/en-us/library/bb219802(VS.85).aspx

The use of DirectInput for keyboard and mouse input is not recommended, Windows messages should be used instead.

One of the DX MVP's sums up the reasons against it (it's under the to-do lists). Also, from Bubba's quote, it doesn't look like GetDeviceState does anything that GetKeyboardState doesn't, so the extra setup and maintainance required for the pleasure doesn't seem worth it.

Unless you're retrieving joystick data, you shouldn't use DirectInput. Even MS actively discourages its use for anything other than Joysticks.

One of the DX MVP's sums up the reasons against it (it's under the to-do lists). Also, from Bubba's quote, it doesn't look like GetDeviceState does anything that GetKeyboardState doesn't, so the extra setup and maintainance required for the pleasure doesn't seem worth it.

Well, at least none of their other API's are broken - oh, wait...nevermind.

And you are ANDing this with 32768? Why? Where did you get that number? How did you think it was going to work when you just invented a number to use as a mask?

They are not being stored in the same place. How do you suppose you are using a BYTE array yet ANDing that with a short? What bits are you trying to mask off? The mask has more bits than the source so I'm lost as to why you think you can AND it with any arbitrary value and get back meaningful information or assume it is meaningful.