1 ////////////////////////////////////////////////////////////////////////////////////////
2 //
3 // Nestopia - NES/Famicom emulator written in C++
4 //
5 // Copyright (C) 2003-2008 Martin Freij
6 //
7 // This file is part of Nestopia.
8 //
9 // Nestopia is free software; you can redistribute it and/or modify
10 // it under the terms of the GNU General Public License as published by
11 // the Free Software Foundation; either version 2 of the License, or
12 // (at your option) any later version.
13 //
14 // Nestopia is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 // GNU General Public License for more details.
18 //
19 // You should have received a copy of the GNU General Public License
20 // along with Nestopia; if not, write to the Free Software
21 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22 //
23 ////////////////////////////////////////////////////////////////////////////////////////
24 
25 #ifndef NST_DIRECTX_DIRECTINPUT_H
26 #define NST_DIRECTX_DIRECTINPUT_H
27 
28 #pragma once
29 
30 #define DIRECTINPUT_VERSION 0x0800
31 
32 #include "NstDirectX.hpp"
33 #include "NstObjectPod.hpp"
34 #include "NstObjectHeap.hpp"
35 #include "NstCollectionVector.hpp"
36 #include <dinput.h>
37 
38 namespace Nestopia
39 {
40 	namespace DirectX
41 	{
42 		class DirectInput
43 		{
44 			class Keyboard;
45 			class Joystick;
46 
47 		public:
48 
49 			explicit DirectInput(HWND);
50 			~DirectInput();
51 
52 			enum
53 			{
54 				MAX_JOYSTICKS     = 32,
55 				NUM_KEYBOARD_KEYS = 256,
56 				AXIS_X            = 0x001,
57 				AXIS_Y            = 0x002,
58 				AXIS_Z            = 0x004,
59 				AXIS_RX           = 0x008,
60 				AXIS_RY           = 0x010,
61 				AXIS_RZ           = 0x020,
62 				AXIS_SLIDER_0     = 0x040,
63 				AXIS_SLIDER_1     = 0x080,
64 				AXIS_POV_0        = 0x100,
65 				AXIS_POV_1        = 0x200,
66 				AXIS_POV_2        = 0x400,
67 				AXIS_POV_3        = 0x800,
68 				AXIS_ALL          = 0xFFF,
69 				DEADZONE_MAX      = 100,
70 				DEFAULT_AXES      = AXIS_X|AXIS_Y|AXIS_Z|AXIS_RX|AXIS_RY|AXIS_RZ|AXIS_POV_0|AXIS_POV_1|AXIS_POV_2|AXIS_POV_3,
71 				DEFAULT_DEADZONE  = 50
72 			};
73 
74 			enum ScanMode
75 			{
76 				SCAN_MODE_ALL,
77 				SCAN_MODE_JOY
78 			};
79 
80 			enum ScanResult
81 			{
82 				SCAN_INVALID_KEY = -1,
83 				SCAN_NO_KEY,
84 				SCAN_GOOD_KEY
85 			};
86 
87 			class Key;
88 
89 			void Acquire();
90 			void Unacquire();
91 			void Calibrate();
92 			void Poll();
93 			void Build(const Key*,uint);
94 			bool MapKey(Key&,wcstring,const System::Guid* = NULL,uint=0) const;
95 			const HeapString GetKeyName(const Key&) const;
96 
97 			void BeginScanMode(HWND) const;
98 			ScanResult ScanKey(Key&,ScanMode=SCAN_MODE_ALL);
99 			void EndScanMode() const;
100 
101 			class Key
102 			{
103 				friend class DirectInput;
104 				friend class Keyboard;
105 				friend class Joystick;
106 
107 			public:
108 
109 				bool MapVirtualKey(uint,uint,uint,uint);
110 				bool MapVirtualKey(GenericString);
111 				bool GetVirtualKey(ACCEL&) const;
112 				bool IsVirtualKey() const;
113 				bool GetToggle(bool&) const;
114 
115 			private:
116 
117 				union
118 				{
119 					const BYTE* data;
120 					DWORD vKey;
121 				};
122 
123 				uint (*code)(const void* const);
124 
125 			public:
126 
Key()127 				Key()
128 				: data(NULL), code(KeyNone) {}
129 
operator ==(const Key & key) const130 				bool operator == (const Key& key) const
131 				{
132 					return data == key.data && code == key.code;
133 				}
134 
Unmap()135 				void Unmap()
136 				{
137 					data = NULL;
138 					code = KeyNone;
139 				}
140 
Assigned() const141 				bool Assigned() const
142 				{
143 					return data;
144 				}
145 
GetState() const146 				uint GetState() const
147 				{
148 					return code( data );
149 				}
150 
151 				template<typename Value>
GetState(Value & value,uint mask) const152 				void GetState(Value& value,uint mask) const
153 				{
154 					value |= code( data ) & mask;
155 				}
156 			};
157 
158 		private:
159 
160 			class Base
161 			{
162 				static IDirectInput8& Create();
163 
164 			public:
165 
166 				explicit Base(HWND);
167 				~Base();
168 
169 				IDirectInput8& com;
170 				HWND const hWnd;
171 			};
172 
173 			class Device
174 			{
175 			public:
176 
177 				void Enable(bool);
178 
179 			protected:
180 
181 				explicit Device(IDirectInputDevice8&);
182 				~Device();
183 
184 				bool Acquire(void*,uint);
185 				void Unacquire();
186 
187 				IDirectInputDevice8& com;
188 				bool enabled;
189 			};
190 
191 			class Keyboard : public Device
192 			{
193 			public:
194 
195 				explicit Keyboard(Base&);
196 
197 				enum
198 				{
199 					MAX_KEYS = NUM_KEYBOARD_KEYS
200 				};
201 
202 				void Acquire();
203 				void Unacquire();
204 
205 				NST_FORCE_INLINE void Poll();
206 
207 				bool Map(Key&,wcstring) const;
208 				bool Map(Key&,uint) const;
209 
210 				void BeginScanMode(HWND) const;
211 				bool Scan(uchar (&)[MAX_KEYS]) const;
212 				ScanResult Scan(Key&) const;
213 				void EndScanMode() const;
214 
215 				bool Assigned(const Key&) const;
216 				wcstring GetName(const Key&) const;
217 
218 			private:
219 
220 				enum
221 				{
222 					COOPERATIVE_FLAGS = DISCL_FOREGROUND|DISCL_NONEXCLUSIVE|DISCL_NOWINKEY,
223 					SCAN_COOPERATIVE_FLAGS = DISCL_BACKGROUND|DISCL_NONEXCLUSIVE
224 				};
225 
226 				static BOOL CALLBACK EnumObjects(LPCDIDEVICEOBJECTINSTANCE,LPVOID);
227 				static IDirectInputDevice8& Create(IDirectInput8&);
228 
229 				void SetCooperativeLevel(HWND,DWORD) const;
230 				void Clear();
231 
232 				NST_NO_INLINE void OnError(HRESULT);
233 
234 				typedef Object::Heap<BYTE,MAX_KEYS> Buffer;
235 
236 				Buffer buffer;
237 				HWND const hWnd;
238 
239 				static HeapString keyNames[MAX_KEYS];
240 
241 			public:
242 
GetBuffer() const243 				const uchar* GetBuffer() const
244 				{
245 					return buffer;
246 				}
247 			};
248 
249 			class Joystick : public Device
250 			{
251 			public:
252 
253 				Joystick(Base&,const DIDEVICEINSTANCE&);
254 
255 				enum
256 				{
257 					POV_CENTER    = 0xFFFF,
258 					POV_UPRIGHT   =  45 * DI_DEGREES,
259 					POV_DOWNRIGHT = 135 * DI_DEGREES,
260 					POV_DOWNLEFT  = 225 * DI_DEGREES,
261 					POV_UPLEFT    = 315 * DI_DEGREES
262 				};
263 
264 				enum Exception
265 				{
266 					ERR_API
267 				};
268 
269 				void Acquire();
270 				void Unacquire();
271 				void Calibrate();
272 
273 				NST_FORCE_INLINE void Poll();
274 
275 				bool Map(Key&,wcstring) const;
276 
277 				void BeginScanMode() const;
278 				bool Scan(Key&);
279 				void EndScanMode() const;
280 
281 				bool Assigned(const Key&) const;
282 				bool SetAxisDeadZone(uint);
283 				wcstring GetName(const Key&) const;
284 
285 			private:
286 
287 				static IDirectInputDevice8& Create(Base&,const GUID&);
288 
289 				void Clear();
290 
291 				NST_NO_INLINE void OnError(HRESULT);
292 
293 				class Caps
294 				{
295 					struct Context
296 					{
297 						Context(Caps&,IDirectInputDevice8&);
298 
299 						Caps& caps;
300 						IDirectInputDevice8& com;
301 						uint numButtons;
302 					};
303 
304 					enum
305 					{
306 						AXIS_MIN_RANGE = -1000,
307 						AXIS_MAX_RANGE = +1000
308 					};
309 
310 					static BOOL CALLBACK EnumObjectsProc(LPCDIDEVICEOBJECTINSTANCE,LPVOID);
311 
312 				public:
313 
314 					Caps(IDirectInputDevice8&,const DIDEVICEINSTANCE&);
315 
316 					enum
317 					{
318 						NUM_POVS    = 4,
319 						NUM_BUTTONS = 32
320 					};
321 
322 					uint axes;
323 					const System::Guid guid;
324 					const HeapString name;
325 				};
326 
327 				class Calibrator
328 				{
329 					long lX;
330 					long lY;
331 					long lZ;
332 					long lRx;
333 					long lRy;
334 					long lRz;
335 
336 				public:
337 
338 					Calibrator();
339 
340 					inline void Reset(DIJOYSTATE&,bool);
341 					inline void Fix(DIJOYSTATE&) const;
342 				};
343 
344 				const Caps caps;
345 				Object::Pod<DIJOYSTATE> state;
346 				Calibrator calibrator;
347 				bool calibrated;
348 				bool scanEnabled;
349 				uint deadZone;
350 				uint axes;
351 
352 				enum
353 				{
354 					TABLE_KEYS = 32
355 				};
356 
357 				struct Lookup;
358 				static const Lookup table[TABLE_KEYS];
359 
360 			public:
361 
GetGuid() const362 				const System::Guid& GetGuid() const
363 				{
364 					return caps.guid;
365 				}
366 
GetName() const367 				const HeapString& GetName() const
368 				{
369 					return caps.name;
370 				}
371 
GetAxisDeadZone() const372 				uint GetAxisDeadZone() const
373 				{
374 					return deadZone;
375 				}
376 
GetAvailableAxes() const377 				uint GetAvailableAxes() const
378 				{
379 					return caps.axes;
380 				}
381 
GetScannerAxes() const382 				uint GetScannerAxes() const
383 				{
384 					return axes;
385 				}
386 
ScanEnable(bool enable)387 				void ScanEnable(bool enable)
388 				{
389 					scanEnabled = enable;
390 				}
391 
ScanEnabled() const392 				bool ScanEnabled() const
393 				{
394 					return scanEnabled;
395 				}
396 
SetScannerAxes(uint flags)397 				void SetScannerAxes(uint flags)
398 				{
399 					NST_ASSERT( flags <= AXIS_ALL );
400 					axes = flags;
401 				}
402 
SetScannerAxes(uint flags,bool on)403 				void SetScannerAxes(uint flags,bool on)
404 				{
405 					NST_ASSERT( flags <= AXIS_ALL );
406 					axes = (on ? axes | flags : axes & ~flags);
407 				}
408 			};
409 
410 			typedef Collection::Vector<Joystick> Joysticks;
411 
412 			static BOOL CALLBACK EnumJoysticks(LPCDIDEVICEINSTANCE,LPVOID);
413 
414 			static uint KeyDown     (const void* const);
415 			static uint KeyNegDir   (const void* const);
416 			static uint KeyPosDir   (const void* const);
417 			static uint KeyPovUp    (const void* const);
418 			static uint KeyPovRight (const void* const);
419 			static uint KeyPovDown  (const void* const);
420 			static uint KeyPovLeft  (const void* const);
421 			static uint KeyNone     (const void* const);
422 
423 			Base base;
424 			Keyboard keyboard;
425 			Joysticks joysticks;
426 
427 		public:
428 
MapKeyboard(Key & key,uint code) const429 			bool MapKeyboard(Key& key,uint code) const
430 			{
431 				key.Unmap();
432 				return keyboard.Map( key, code );
433 			}
434 
NumJoysticks() const435 			uint NumJoysticks() const
436 			{
437 				return joysticks.Size();
438 			}
439 
JoystickScanEnabled(uint index) const440 			bool JoystickScanEnabled(uint index) const
441 			{
442 				NST_ASSERT( index < joysticks.Size() );
443 				return joysticks[index].ScanEnabled();
444 			}
445 
ScanEnableJoystick(uint index,bool enable)446 			void ScanEnableJoystick(uint index,bool enable)
447 			{
448 				NST_ASSERT( index < joysticks.Size() );
449 				joysticks[index].ScanEnable( enable );
450 			}
451 
GetJoystickGuid(uint index) const452 			const System::Guid& GetJoystickGuid(uint index) const
453 			{
454 				NST_ASSERT( index < joysticks.Size() );
455 				return joysticks[index].GetGuid();
456 			}
457 
GetJoystickName(uint index) const458 			const HeapString& GetJoystickName(uint index) const
459 			{
460 				NST_ASSERT( index < joysticks.Size() );
461 				return joysticks[index].GetName();
462 			}
463 
Calibrate(uint index)464 			void Calibrate(uint index)
465 			{
466 				NST_ASSERT( index < joysticks.Size() );
467 				joysticks[index].Calibrate();
468 			}
469 
SetAxisDeadZone(uint index,uint deadZone)470 			bool SetAxisDeadZone(uint index,uint deadZone)
471 			{
472 				NST_ASSERT( index < joysticks.Size() );
473 				return joysticks[index].SetAxisDeadZone( deadZone );
474 			}
475 
GetAxisDeadZone(uint index) const476 			uint GetAxisDeadZone(uint index) const
477 			{
478 				NST_ASSERT( index < joysticks.Size() );
479 				return joysticks[index].GetAxisDeadZone();
480 			}
481 
GetAvailableAxes(uint index) const482 			uint GetAvailableAxes(uint index) const
483 			{
484 				NST_ASSERT( index < joysticks.Size() );
485 				return joysticks[index].GetAvailableAxes();
486 			}
487 
SetScannerAxes(uint index,uint axes)488 			void SetScannerAxes(uint index,uint axes)
489 			{
490 				NST_ASSERT( index < joysticks.Size() );
491 				return joysticks[index].SetScannerAxes( axes );
492 			}
493 
SetScannerAxes(uint index,uint axes,bool state)494 			void SetScannerAxes(uint index,uint axes,bool state)
495 			{
496 				NST_ASSERT( index < joysticks.Size() );
497 				return joysticks[index].SetScannerAxes( axes, state );
498 			}
499 
GetScannerAxes(uint index) const500 			uint GetScannerAxes(uint index) const
501 			{
502 				NST_ASSERT( index < joysticks.Size() );
503 				return joysticks[index].GetScannerAxes();
504 			}
505 
GetKeyboardBuffer() const506 			const uchar* GetKeyboardBuffer() const
507 			{
508 				return keyboard.GetBuffer();
509 			}
510 
AnyPressed()511 			bool AnyPressed()
512 			{
513 				Key key;
514 				return ScanKey( key ) != SCAN_NO_KEY;
515 			}
516 		};
517 	}
518 }
519 
520 #endif
521