1 #include "../ControllerInterface.h"
3 #ifdef CIFACE_USE_DIRECTINPUT_KBM
5 #include "DirectInputKeyboardMouse.h"
7 // TODO: maybe add a ClearInputState function to this device
9 // (lower would be more sensitive) user can lower sensitivity by setting range
10 // seems decent here ( at 8 ), I dont think anyone would need more sensitive than this
11 // and user can lower it much farther than they would want to with the range
12 #define MOUSE_AXIS_SENSITIVITY 8
14 // if input hasn't been received for this many ms, mouse input will be skipped
15 // otherwise it is just some crazy value
16 #define DROP_INPUT_TIME 250
26 const char* const name
;
29 #include "NamedKeys.h"
35 const char* const name
;
38 { VK_NUMLOCK
, "NUM LOCK" },
39 { VK_CAPITAL
, "CAPS LOCK" },
40 { VK_SCROLL
, "SCROLL LOCK" }
43 void InitKeyboardMouse( IDirectInput8
* const idi8
, std::vector
<ControllerInterface::Device
*>& devices
)
45 // mouse and keyboard are a combined device, to allow shift+click and stuff
46 // if thats dumb, i will make a VirtualDevice class that just uses ranges of inputs/outputs from other devices
47 // so there can be a separated Keyboard and mouse, as well as combined KeyboardMouse
49 // TODO: this has potential to not release devices if set datafmt or cooplevel fails
51 LPDIRECTINPUTDEVICE8 kb_device
;
52 LPDIRECTINPUTDEVICE8 mo_device
;
54 if ( DI_OK
== idi8
->CreateDevice( GUID_SysKeyboard
, &kb_device
, NULL
) )
55 if ( DI_OK
== kb_device
->SetDataFormat( &c_dfDIKeyboard
) )
56 if ( DI_OK
== kb_device
->SetCooperativeLevel( NULL
, DISCL_BACKGROUND
| DISCL_NONEXCLUSIVE
) )
57 if ( DI_OK
== kb_device
->Acquire() )
60 if ( DI_OK
== idi8
->CreateDevice( GUID_SysMouse
, &mo_device
, NULL
) )
61 if ( DI_OK
== mo_device
->SetDataFormat( &c_dfDIMouse2
) )
62 if ( DI_OK
== mo_device
->SetCooperativeLevel( NULL
, DISCL_BACKGROUND
| DISCL_NONEXCLUSIVE
) )
63 if ( DI_OK
== mo_device
->Acquire() )
65 devices
.push_back( new KeyboardMouse( kb_device
, mo_device
) );
79 kb_device
->Unacquire();
84 KeyboardMouse::~KeyboardMouse()
87 m_kb_device
->Unacquire();
88 m_kb_device
->Release();
90 m_mo_device
->Unacquire();
91 m_mo_device
->Release();
94 KeyboardMouse::KeyboardMouse( const LPDIRECTINPUTDEVICE8 kb_device
, const LPDIRECTINPUTDEVICE8 mo_device
)
95 : m_kb_device(kb_device
)
96 , m_mo_device(mo_device
)
98 m_last_update
= wxGetLocalTimeMillis();
100 ZeroMemory( &m_state_in
, sizeof(m_state_in
) );
101 ZeroMemory( m_state_out
, sizeof(m_state_out
) );
102 ZeroMemory( &m_current_state_out
, sizeof(m_current_state_out
) );
106 for ( unsigned int i
= 0; i
< sizeof(named_keys
)/sizeof(*named_keys
); ++i
)
107 inputs
.push_back( new Key( i
) );
109 for ( unsigned int i
= 0; i
< sizeof(named_lights
)/sizeof(*named_lights
); ++i
)
110 outputs
.push_back( new Light( i
) );
114 DIDEVCAPS mouse_caps
;
115 ZeroMemory( &mouse_caps
, sizeof(mouse_caps
) );
116 mouse_caps
.dwSize
= sizeof(mouse_caps
);
117 m_mo_device
->GetCapabilities(&mouse_caps
);
119 for ( unsigned int i
= 0; i
< mouse_caps
.dwButtons
; ++i
)
120 inputs
.push_back( new Button( i
) );
122 for ( unsigned int i
= 0; i
< mouse_caps
.dwAxes
; ++i
)
124 // each axis gets a negative and a positive input instance associated with it
125 inputs
.push_back( new Axis( i
, (2==i
) ? -1 : -MOUSE_AXIS_SENSITIVITY
) );
126 inputs
.push_back( new Axis( i
, -(2==i
) ? 1 : MOUSE_AXIS_SENSITIVITY
) );
131 bool KeyboardMouse::UpdateInput()
133 DIMOUSESTATE2 tmp_mouse
;
135 // if mouse position hasn't been updated in a short while, skip a dev state
136 wxLongLong cur_time
= wxGetLocalTimeMillis();
137 if ( cur_time
- m_last_update
> DROP_INPUT_TIME
)
140 ZeroMemory( &m_state_in
.mouse
, sizeof(m_state_in
.mouse
) );
141 // skip this input state
142 m_mo_device
->GetDeviceState( sizeof(tmp_mouse
), &tmp_mouse
);
145 m_last_update
= cur_time
;
147 if ( DI_OK
== m_kb_device
->GetDeviceState( sizeof(m_state_in
.keyboard
), &m_state_in
.keyboard
)
148 && DI_OK
== m_mo_device
->GetDeviceState( sizeof(tmp_mouse
), &tmp_mouse
) )
150 // need to smooth out the axes, otherwise it doesnt work for shit
151 for ( unsigned int i
= 0; i
< 3; ++i
)
152 ((&m_state_in
.mouse
.lX
)[i
] += (&tmp_mouse
.lX
)[i
]) /= 2;
154 // copy over the buttons
155 memcpy( m_state_in
.mouse
.rgbButtons
, tmp_mouse
.rgbButtons
, sizeof(m_state_in
.mouse
.rgbButtons
) );
162 bool KeyboardMouse::UpdateOutput()
164 class KInput
: public INPUT
167 KInput( const unsigned char key
, const bool up
= false )
169 memset( this, 0, sizeof(*this) );
170 type
= INPUT_KEYBOARD
;
172 if (up
) ki
.dwFlags
= KEYEVENTF_KEYUP
;
176 std::vector
< KInput
> kbinputs
;
177 for ( unsigned int i
= 0; i
< sizeof(m_state_out
)/sizeof(*m_state_out
); ++i
)
179 bool want_on
= false;
180 if ( m_state_out
[i
] )
181 want_on
= m_state_out
[i
] > wxGetLocalTimeMillis() % 255 ; // light should flash when output is 0.5
183 // lights are set to their original state when output is zero
184 if ( want_on
^ m_current_state_out
[i
] )
186 kbinputs
.push_back( KInput( named_lights
[i
].code
) ); // press
187 kbinputs
.push_back( KInput( named_lights
[i
].code
, true ) ); // release
189 m_current_state_out
[i
] ^= 1;
193 if ( kbinputs
.size() )
194 return ( kbinputs
.size() == SendInput( (UINT
)kbinputs
.size(), &kbinputs
[0], sizeof( kbinputs
[0] ) ) );
199 std::string
KeyboardMouse::GetName() const
201 return "Keyboard Mouse";
204 int KeyboardMouse::GetId() const
206 // should this be -1, idk
210 std::string
KeyboardMouse::GetSource() const
212 return "DirectInput";
215 ControlState
KeyboardMouse::GetInputState( const ControllerInterface::Device::Input
* const input
)
217 return ( ((Input
*)input
)->GetState( &m_state_in
) );
220 void KeyboardMouse::SetOutputState( const ControllerInterface::Device::Output
* const output
, const ControlState state
)
222 ((Output
*)output
)->SetState( state
, m_state_out
);
226 std::string
KeyboardMouse::Key::GetName() const
228 return named_keys
[m_index
].name
;
231 std::string
KeyboardMouse::Button::GetName() const
233 return std::string("Button ") + char('0'+m_index
);
236 std::string
KeyboardMouse::Axis::GetName() const
238 std::string
tmpstr("Mouse ");
239 tmpstr
+= "XYZ"[m_index
]; tmpstr
+= ( m_range
>0 ? '+' : '-' );
243 std::string
KeyboardMouse::Light::GetName() const
245 return named_lights
[ m_index
].name
;
249 ControlState
KeyboardMouse::Key::GetState( const State
* const state
)
251 return ( state
->keyboard
[named_keys
[m_index
].code
] > 0 );
254 ControlState
KeyboardMouse::Button::GetState( const State
* const state
)
256 return ( state
->mouse
.rgbButtons
[m_index
] > 0 );
259 ControlState
KeyboardMouse::Axis::GetState( const State
* const state
)
261 return std::max( 0.0f
, ControlState((&state
->mouse
.lX
)[m_index
]) / m_range
);
264 void KeyboardMouse::Light::SetState( const ControlState state
, unsigned char* const state_out
)
266 state_out
[ m_index
] = state
* 255;