GCPadNew: Added option to disable input when Dolphin window isn't active. Some other...
[dolphin.git] / Source / Plugins / Plugin_GCPadNew / Src / ControllerInterface / DirectInput / DirectInputKeyboardMouse.cpp
blob6f79af95e386dca7c2088de2ecd405971831a1f1
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
18 namespace ciface
20 namespace DirectInput
23 struct
25 const BYTE code;
26 const char* const name;
27 } named_keys[] =
29 #include "NamedKeys.h"
32 struct
34 const BYTE code;
35 const char* const name;
36 } named_lights[] =
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 ) );
66 return;
68 else
69 goto release_mouse;
71 goto unacquire_kb;
73 else
74 goto release_kb;
76 release_mouse:
77 mo_device->Release();
78 unacquire_kb:
79 kb_device->Unacquire();
80 release_kb:
81 kb_device->Release();
84 KeyboardMouse::~KeyboardMouse()
86 // kb
87 m_kb_device->Unacquire();
88 m_kb_device->Release();
89 // mouse
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) );
104 // KEYBOARD
105 // add keys
106 for ( unsigned int i = 0; i < sizeof(named_keys)/sizeof(*named_keys); ++i )
107 inputs.push_back( new Key( i ) );
108 // add lights
109 for ( unsigned int i = 0; i < sizeof(named_lights)/sizeof(*named_lights); ++i )
110 outputs.push_back( new Light( i ) );
112 // MOUSE
113 // get caps
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);
118 // mouse buttons
119 for ( unsigned int i = 0; i < mouse_caps.dwButtons; ++i )
120 inputs.push_back( new Button( i ) );
121 // mouse axes
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 )
139 // set axes to zero
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) );
156 return true;
158 else
159 return false;
162 bool KeyboardMouse::UpdateOutput()
164 class KInput : public INPUT
166 public:
167 KInput( const unsigned char key, const bool up = false )
169 memset( this, 0, sizeof(*this) );
170 type = INPUT_KEYBOARD;
171 ki.wVk = key;
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] ) ) );
195 else
196 return true;
199 std::string KeyboardMouse::GetName() const
201 return "Keyboard Mouse";
204 int KeyboardMouse::GetId() const
206 // should this be -1, idk
207 return 0;
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 );
225 // names
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 ? '+' : '-' );
240 return tmpstr;
243 std::string KeyboardMouse::Light::GetName() const
245 return named_lights[ m_index ].name;
248 // get/set state
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;
272 #endif