1 /*!
2 	@file
3 	@author		Albert Semenov
4 	@date		09/2009
5 */
6 
7 #include "Precompiled.h"
8 #include "InputManager.h"
9 #include "../InputConverter.h"
10 
11 #ifdef INPUT_KEY_NAME
12 #include <MyGUI.h>
13 #endif
14 
15 namespace input
16 {
17 
18 	// указатель на менеджер, куда транслируються сообщения
19 	InputManager* InputManager::msInputManager = 0;
20 
21 	// старая процедура, которую мы заменили
22 	LRESULT InputManager::msOldWindowProc = 0;
23 
24 	bool InputManager::msSkipMove = false;
25 
26 	// наша процедура для фильтрации сообщений
windowProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)27 	LRESULT CALLBACK InputManager::windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
28 	{
29 		// если колесо не определенно
30 		#ifndef WM_MOUSEWHEEL
31 			#define WM_MOUSEWHEEL 0x020A
32 			#define __WM_REALMOUSELAST WM_MOUSEWHEEL
33 		#else
34 			#define __WM_REALMOUSELAST WM_MOUSELAST
35 		#endif // WM_MOUSEWHEEL
36 
37 		// для взятия знаковых значений
38 		#define GET_HIWORD(param) ((short)HIWORD(param))
39 		#define GET_LOWORD(param) ((short)LOWORD(param))
40 
41 		// на нас кидают файлы
42 		if (WM_DROPFILES == uMsg)
43 		{
44 			HDROP hDrop = (HDROP)wParam;
45 			wchar_t buff[MAX_PATH] = { 0 };
46 			UINT fcount = DragQueryFileW(hDrop, 0xFFFFFFFF, nullptr, 0);
47 
48 			for (UINT index = 0; index < fcount; ++index)
49 			{
50 				DragQueryFileW(hDrop, index, buff, MAX_PATH);
51 				msInputManager->onFileDrop(buff);
52 			}
53 
54 			DragFinish(hDrop);
55 			return 0;
56 		}
57 		// нас пытаются закрыть
58 		else if (WM_CLOSE == uMsg)
59 		{
60 			if (!msInputManager->onWindowClose((size_t)hWnd))
61 				return 0;
62 		}
63 		else if ((uMsg >= WM_MOUSEFIRST) && (uMsg <= __WM_REALMOUSELAST))
64 		{
65 			static int old_x = 0;
66 			static int old_y = 0;
67 			static int old_z = 0;
68 			static bool left_button = false;
69 			static bool right_button = false;
70 
71 			switch (uMsg)
72 			{
73 			case WM_MOUSEMOVE:
74 			{
75 				int x = GET_LOWORD(lParam);
76 				int y = GET_HIWORD(lParam);
77 
78 				if (x < 0) x = 0;
79 				else if (x > msInputManager->mWidth) x = msInputManager->mWidth;
80 				if (y < 0) y = 0;
81 				else if (y > msInputManager->mHeight) y = msInputManager->mHeight;
82 
83 				old_x = x;
84 				old_y = y;
85 
86 				if (msSkipMove)
87 					msSkipMove = false;
88 				else
89 					msInputManager->mouseMove(old_x, old_y, old_z);
90 			}
91 
92 			break;
93 
94 			case WM_MOUSEWHEEL:
95 				old_z += GET_HIWORD(wParam);
96 				msInputManager->mouseMove(old_x, old_y, old_z);
97 				break;
98 
99 			case WM_LBUTTONDOWN:
100 				left_button = true;
101 				if (!right_button)
102 					::SetCapture(hWnd);
103 				msInputManager->mousePress(old_x, old_y, MyGUI::MouseButton::Left);
104 				break;
105 
106 			case WM_LBUTTONDBLCLK:
107 				left_button = true;
108 				if (!right_button)
109 					::SetCapture(hWnd);
110 				msInputManager->mousePress(old_x, old_y, MyGUI::MouseButton::Left);
111 				break;
112 
113 			case WM_RBUTTONDOWN:
114 				right_button = true;
115 				if (!left_button)
116 					::SetCapture(hWnd);
117 				msInputManager->mousePress(old_x, old_y, MyGUI::MouseButton::Right);
118 				break;
119 
120 			case WM_RBUTTONDBLCLK:
121 				right_button = true;
122 				if (!left_button)
123 					::SetCapture(hWnd);
124 				msInputManager->mousePress(old_x, old_y, MyGUI::MouseButton::Right);
125 				break;
126 
127 			case WM_MBUTTONDOWN:
128 				msInputManager->mousePress(old_x, old_y, MyGUI::MouseButton::Middle);
129 				break;
130 
131 			case WM_LBUTTONUP:
132 				msInputManager->mouseRelease(old_x, old_y, MyGUI::MouseButton::Left);
133 				left_button = false;
134 				if (!right_button)
135 					::SetCapture(0);
136 				break;
137 			case WM_RBUTTONUP:
138 				right_button = false;
139 				if (!left_button)
140 					::SetCapture(0);
141 				msInputManager->mouseRelease(old_x, old_y, MyGUI::MouseButton::Right);
142 				break;
143 			case WM_MBUTTONUP:
144 				msInputManager->mouseRelease(old_x, old_y, MyGUI::MouseButton::Middle);
145 				break;
146 			}
147 		}
148 		else if (WM_KEYDOWN == uMsg)
149 		{
150 			bool repeat = (lParam & (1 >> 30)) != 0;
151 			if (!repeat)
152 			{
153 				int scan_code = VirtualKeyToScanCode(wParam);
154 				int text = VirtualKeyToText(wParam);
155 				msInputManager->injectKeyPress(MyGUI::KeyCode::Enum(scan_code), (MyGUI::Char)text);
156 
157 #ifdef INPUT_KEY_NAME
158 				MyGUI::MYGUI_OUT("VirtKey : ", VirtualKeyToName(wParam), " to ScanCode : ", ScanCodeToName(scan_code));
159 #endif
160 			}
161 		}
162 		else if (WM_IME_CHAR == uMsg)
163 		{
164 			int text = 0;
165 #ifdef _UNICODE
166 			text = wParam;
167 #else
168 			char mbstr[3];
169 			BYTE hiByte = static_cast<BYTE>(wParam >> 8);
170 			BYTE loByte = wParam & 0x000000FF;
171 			if (hiByte == 0)
172 			{
173 				mbstr[0] = loByte;
174 				mbstr[1] = '\0';
175 			}
176 			else
177 			{
178 				mbstr[0] = hiByte;
179 				mbstr[1] = loByte;
180 				mbstr[2] = '\0';
181 			}
182 
183 			wchar_t wstr[2];
184 			/*int num = */MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, mbstr, -1, wstr, sizeof(wstr)/sizeof(wstr[0]));
185 			text = wstr[0];
186 #endif // _UNICODE
187 			msInputManager->injectKeyPress(MyGUI::KeyCode::None, (MyGUI::Char)text);
188 		}
189 		else if (WM_KEYUP == uMsg)
190 		{
191 			int scan_code = VirtualKeyToScanCode(wParam);
192 			MyGUI::KeyCode code = MyGUI::KeyCode::Enum(scan_code);
193 
194 			// принтскрин приходит только отжатие
195 			if (code == MyGUI::KeyCode::SysRq)
196 				msInputManager->injectKeyPress(code, (MyGUI::Char)0);
197 
198 			msInputManager->injectKeyRelease(code);
199 		}
200 
201 		// вызываем полюбому
202 		return CallWindowProc((WNDPROC)msOldWindowProc, hWnd, uMsg, wParam, lParam);
203 	}
204 
InputManager()205 	InputManager::InputManager() :
206 		mHwnd(0),
207 		mWidth(0),
208 		mHeight(0),
209 		mMouseX(0),
210 		mMouseY(0),
211 		mMouseZ(0),
212 		mMouseMove(false)
213 	{
214 		assert(!msInputManager);
215 		msInputManager = this;
216 	}
217 
~InputManager()218 	InputManager::~InputManager()
219 	{
220 		assert(msInputManager);
221 		msInputManager = 0;
222 	}
223 
createInput(size_t _handle)224 	void InputManager::createInput(size_t _handle)
225 	{
226 		mHwnd = (HWND)_handle;
227 
228 		// подсовываем нашу функцию калбеков
229 		if (!msOldWindowProc)
230 		{
231 			msOldWindowProc = GetWindowLongPtr(mHwnd, GWLP_WNDPROC);
232 			SetWindowLongPtr(mHwnd, GWLP_WNDPROC, (LONG_PTR)windowProc);
233 		}
234 
235 		// устанавливаем поддержку дропа файлов
236 		LONG_PTR style = GetWindowLongPtr(mHwnd, GWL_EXSTYLE);
237 		SetWindowLongPtr(mHwnd, GWL_EXSTYLE, style | WS_EX_ACCEPTFILES);
238 
239 		MyGUI::Gui::getInstance().eventFrameStart += MyGUI::newDelegate(this, &InputManager::frameEvent);
240 	}
241 
destroyInput()242 	void InputManager::destroyInput()
243 	{
244 		MyGUI::Gui::getInstance().eventFrameStart -= MyGUI::newDelegate(this, &InputManager::frameEvent);
245 
246 		// если мы подменили процедуру, то вернем на место
247 		if (msOldWindowProc)
248 		{
249 			SetWindowLongPtr((HWND)mHwnd, GWLP_WNDPROC, (LONG_PTR)msOldWindowProc);
250 			msOldWindowProc = 0;
251 		}
252 	}
253 
captureInput()254 	void InputManager::captureInput()
255 	{
256 	}
257 
setInputViewSize(int _width,int _height)258 	void InputManager::setInputViewSize(int _width, int _height)
259 	{
260 		mWidth = _width;
261 		mHeight = _height;
262 	}
263 
setMousePosition(int _x,int _y)264 	void InputManager::setMousePosition(int _x, int _y)
265 	{
266 		POINT point = { _x, _y };
267 		::ClientToScreen(mHwnd, &point);
268 
269 		msSkipMove = true;
270 		::SetCursorPos(point.x, point.y);
271 	}
272 
updateCursorPosition()273 	void InputManager::updateCursorPosition()
274 	{
275 	}
276 
frameEvent(float _time)277 	void InputManager::frameEvent(float _time)
278 	{
279 		computeMouseMove();
280 	}
281 
computeMouseMove()282 	void InputManager::computeMouseMove()
283 	{
284 		if (mMouseMove)
285 		{
286 			injectMouseMove(mMouseX, mMouseY, mMouseZ);
287 			mMouseMove = false;
288 		}
289 	}
290 
mouseMove(int _absx,int _absy,int _absz)291 	void InputManager::mouseMove(int _absx, int _absy, int _absz)
292 	{
293 		mMouseX = _absx;
294 		mMouseY = _absy;
295 		mMouseZ = _absz;
296 		mMouseMove = true;
297 	}
298 
mousePress(int _absx,int _absy,MyGUI::MouseButton _id)299 	void InputManager::mousePress(int _absx, int _absy, MyGUI::MouseButton _id)
300 	{
301 		computeMouseMove();
302 		injectMousePress(_absx, _absy, _id);
303 	}
304 
mouseRelease(int _absx,int _absy,MyGUI::MouseButton _id)305 	void InputManager::mouseRelease(int _absx, int _absy, MyGUI::MouseButton _id)
306 	{
307 		computeMouseMove();
308 		injectMouseRelease(_absx, _absy, _id);
309 	}
310 
311 } // namespace input
312