]> git.lizzy.rs Git - irrlicht.git/blob - source/Irrlicht/CIrrDeviceWin32.h
4af8d02773ec1e470c6d2470ea0fd2193c71fe01
[irrlicht.git] / source / Irrlicht / CIrrDeviceWin32.h
1 // Copyright (C) 2002-2012 Nikolaus Gebhardt\r
2 // This file is part of the "Irrlicht Engine".\r
3 // For conditions of distribution and use, see copyright notice in irrlicht.h\r
4 \r
5 #ifndef __C_IRR_DEVICE_WIN32_H_INCLUDED__\r
6 #define __C_IRR_DEVICE_WIN32_H_INCLUDED__\r
7 \r
8 #include "IrrCompileConfig.h"\r
9 #ifdef _IRR_COMPILE_WITH_WINDOWS_DEVICE_\r
10 \r
11 #include "CIrrDeviceStub.h"\r
12 #include "IrrlichtDevice.h"\r
13 \r
14 #define WIN32_LEAN_AND_MEAN\r
15 #include <windows.h>\r
16 #include <mmsystem.h> // For JOYCAPS\r
17 #include <windowsx.h>\r
18 #if !defined(GET_X_LPARAM)\r
19 #define GET_X_LPARAM(lp) ((int)(short)LOWORD(lp))\r
20 #define GET_Y_LPARAM(lp) ((int)(short)HIWORD(lp))\r
21 #endif\r
22 \r
23 namespace irr\r
24 {\r
25         struct SJoystickWin32Control;\r
26 \r
27         class CIrrDeviceWin32 : public CIrrDeviceStub\r
28         {\r
29         friend struct SJoystickWin32Control;\r
30         public:\r
31 \r
32                 //! constructor\r
33                 CIrrDeviceWin32(const SIrrlichtCreationParameters& params);\r
34 \r
35                 //! destructor\r
36                 virtual ~CIrrDeviceWin32();\r
37 \r
38                 //! runs the device. Returns false if device wants to be deleted\r
39                 bool run() override;\r
40 \r
41                 //! Cause the device to temporarily pause execution and let other processes to run\r
42                 // This should bring down processor usage without major performance loss for Irrlicht\r
43                 void yield() override;\r
44 \r
45                 //! Pause execution and let other processes to run for a specified amount of time.\r
46                 void sleep(u32 timeMs, bool pauseTimer) override;\r
47 \r
48                 //! sets the caption of the window\r
49                 void setWindowCaption(const wchar_t* text) override;\r
50 \r
51                 //! returns if window is active. if not, nothing need to be drawn\r
52                 bool isWindowActive() const override;\r
53 \r
54                 //! returns if window has focus\r
55                 bool isWindowFocused() const override;\r
56 \r
57                 //! returns if window is minimized\r
58                 bool isWindowMinimized() const override;\r
59 \r
60                 //! returns last state from maximizeWindow() and restoreWindow()\r
61                 bool isWindowMaximized() const override;\r
62 \r
63                 //! notifies the device that it should close itself\r
64                 void closeDevice() override;\r
65 \r
66                 //! Notifies the device, that it has been resized\r
67                 /** Must be publis as it is called from free function (event handler) */\r
68                 void OnResized();\r
69 \r
70                 //! Sets if the window should be resizable in windowed mode.\r
71                 void setResizable(bool resize=false) override;\r
72 \r
73                 //! Resize the render window.\r
74                 void setWindowSize(const irr::core::dimension2d<u32>& size) override;\r
75 \r
76                 //! Minimizes the window.\r
77                 void minimizeWindow() override;\r
78 \r
79                 //! Maximizes the window.\r
80                 void maximizeWindow() override;\r
81 \r
82                 //! Restores the window size.\r
83                 void restoreWindow() override;\r
84 \r
85                 //! Get the position of the window on screen\r
86                 core::position2di getWindowPosition() override;\r
87 \r
88                 //! Activate any joysticks, and generate events for them.\r
89                 bool activateJoysticks(core::array<SJoystickInfo> & joystickInfo) override;\r
90 \r
91                 //! Remove all messages pending in the system message loop\r
92                 void clearSystemMessages() override;\r
93 \r
94                 //! Get the device type\r
95                 E_DEVICE_TYPE getType() const override\r
96                 {\r
97                         return EIDT_WIN32;\r
98                 }\r
99 \r
100                 //! Compares to the last call of this function to return double and triple clicks.\r
101                 //! \return Returns only 1,2 or 3. A 4th click will start with 1 again.\r
102                 u32 checkSuccessiveClicks(s32 mouseX, s32 mouseY, EMOUSE_INPUT_EVENT inputEvent ) override\r
103                 {\r
104                         // we just have to make it public\r
105                         return CIrrDeviceStub::checkSuccessiveClicks(mouseX, mouseY, inputEvent );\r
106                 }\r
107 \r
108                 //! Switch to fullscreen\r
109                 bool switchToFullScreen();\r
110 \r
111                 // convert an Irrlicht texture to a windows cursor\r
112                 HCURSOR TextureToCursor(HWND hwnd, irr::video::ITexture * tex, const core::rect<s32>& sourceRect, const core::position2d<s32> &hotspot);\r
113 \r
114                 //! Implementation of the win32 cursor control\r
115                 class CCursorControl : public gui::ICursorControl\r
116                 {\r
117                 public:\r
118 \r
119                         CCursorControl(CIrrDeviceWin32* device, const core::dimension2d<u32>& wsize, HWND hwnd, bool fullscreen);\r
120                         ~CCursorControl();\r
121 \r
122                         //! Changes the visible state of the mouse cursor.\r
123                         void setVisible(bool visible) override\r
124                         {\r
125                                 CURSORINFO info;\r
126                                 info.cbSize = sizeof(CURSORINFO);\r
127                                 BOOL gotCursorInfo = GetCursorInfo(&info);\r
128                                 while ( gotCursorInfo )\r
129                                 {\r
130 #ifdef CURSOR_SUPPRESSED\r
131                                         // Since Windows 8 the cursor can be suppressed by a touch interface\r
132                                         if (visible && info.flags == CURSOR_SUPPRESSED)\r
133                                         {\r
134                                                 break;\r
135                                         }\r
136 #endif\r
137                                         if ( (visible && info.flags == CURSOR_SHOWING) || // visible\r
138                                                 (!visible && info.flags == 0 ) ) // hidden\r
139                                         {\r
140                                                 break;\r
141                                         }\r
142                                         // this only increases an internal\r
143                                         // display counter in windows, so it\r
144                                         // might have to be called some more\r
145                                         const int showResult = ShowCursor(visible);\r
146                                         // if result has correct sign we can\r
147                                         // stop here as well\r
148                                         if (( !visible && showResult < 0 ) ||\r
149                                                 (visible && showResult >= 0))\r
150                                                 break;\r
151                                         // yes, it really must be set each time\r
152                                         info.cbSize = sizeof(CURSORINFO);\r
153                                         gotCursorInfo = GetCursorInfo(&info);\r
154 \r
155 #ifdef CURSOR_SUPPRESSED\r
156                                         // Not sure if a cursor which we tried to hide still can be suppressed.\r
157                                         // I have no touch-display for testing this and MSDN doesn't describe it.\r
158                                         // But adding this check shouldn't hurt and might prevent an endless loop.\r
159                                         if (!visible && info.flags == CURSOR_SUPPRESSED)\r
160                                         {\r
161                                                 break;\r
162                                         }\r
163 #endif\r
164                                 }\r
165                                 IsVisible = visible;\r
166                         }\r
167 \r
168                         //! Returns if the cursor is currently visible.\r
169                         bool isVisible() const override\r
170                         {\r
171                                 return IsVisible;\r
172                         }\r
173 \r
174                         //! Sets the new position of the cursor.\r
175                         void setPosition(const core::position2d<f32> &pos) override\r
176                         {\r
177                                 setPosition(pos.X, pos.Y);\r
178                         }\r
179 \r
180                         //! Sets the new position of the cursor.\r
181                         void setPosition(f32 x, f32 y) override\r
182                         {\r
183                                 if (!UseReferenceRect)\r
184                                         setPosition(core::round32(x*WindowSize.Width), core::round32(y*WindowSize.Height));\r
185                                 else\r
186                                         setPosition(core::round32(x*ReferenceRect.getWidth()), core::round32(y*ReferenceRect.getHeight()));\r
187                         }\r
188 \r
189                         //! Sets the new position of the cursor.\r
190                         void setPosition(const core::position2d<s32> &pos) override\r
191                         {\r
192                                 setPosition(pos.X, pos.Y);\r
193                         }\r
194 \r
195                         //! Sets the new position of the cursor.\r
196                         void setPosition(s32 x, s32 y) override\r
197                         {\r
198                                 if (UseReferenceRect)\r
199                                 {\r
200                                         SetCursorPos(ReferenceRect.UpperLeftCorner.X + x,\r
201                                                                 ReferenceRect.UpperLeftCorner.Y + y);\r
202                                 }\r
203                                 else\r
204                                 {\r
205                                         RECT rect;\r
206                                         if (GetWindowRect(HWnd, &rect))\r
207                                                 SetCursorPos(x + rect.left + BorderX, y + rect.top + BorderY);\r
208                                 }\r
209 \r
210                                 CursorPos.X = x;\r
211                                 CursorPos.Y = y;\r
212                         }\r
213 \r
214                         //! Returns the current position of the mouse cursor.\r
215                         const core::position2d<s32>& getPosition(bool updateCursor) override\r
216                         {\r
217                                 if ( updateCursor )\r
218                                         updateInternalCursorPosition();\r
219                                 return CursorPos;\r
220                         }\r
221 \r
222                         //! Returns the current position of the mouse cursor.\r
223                         core::position2d<f32> getRelativePosition(bool updateCursor) override\r
224                         {\r
225                                 if ( updateCursor )\r
226                                         updateInternalCursorPosition();\r
227 \r
228                                 if (!UseReferenceRect)\r
229                                 {\r
230                                         return core::position2d<f32>(CursorPos.X * InvWindowSize.Width,\r
231                                                 CursorPos.Y * InvWindowSize.Height);\r
232                                 }\r
233 \r
234                                 return core::position2d<f32>(CursorPos.X / (f32)ReferenceRect.getWidth(),\r
235                                                 CursorPos.Y / (f32)ReferenceRect.getHeight());\r
236                         }\r
237 \r
238                         //! Sets an absolute reference rect for calculating the cursor position.\r
239                         void setReferenceRect(core::rect<s32>* rect=0) override\r
240                         {\r
241                                 if (rect)\r
242                                 {\r
243                                         ReferenceRect = *rect;\r
244                                         UseReferenceRect = true;\r
245 \r
246                                         // prevent division through zero and uneven sizes\r
247 \r
248                                         if (!ReferenceRect.getHeight() || ReferenceRect.getHeight()%2)\r
249                                                 ReferenceRect.LowerRightCorner.Y += 1;\r
250 \r
251                                         if (!ReferenceRect.getWidth() || ReferenceRect.getWidth()%2)\r
252                                                 ReferenceRect.LowerRightCorner.X += 1;\r
253                                 }\r
254                                 else\r
255                                         UseReferenceRect = false;\r
256                         }\r
257 \r
258                         /** Used to notify the cursor that the window was resized. */\r
259                         void OnResize(const core::dimension2d<u32>& size)\r
260                         {\r
261                                 WindowSize = size;\r
262                                 if (size.Width!=0)\r
263                                         InvWindowSize.Width = 1.0f / size.Width;\r
264                                 else\r
265                                         InvWindowSize.Width = 0.f;\r
266 \r
267                                 if (size.Height!=0)\r
268                                         InvWindowSize.Height = 1.0f / size.Height;\r
269                                 else\r
270                                         InvWindowSize.Height = 0.f;\r
271                         }\r
272 \r
273                         /** Used to notify the cursor that the window resizable settings changed. */\r
274                         void updateBorderSize(bool fullscreen, bool resizable)\r
275                         {\r
276                                 if (!fullscreen)\r
277                                 {\r
278                                         s32 paddingBorder = 0;\r
279                                         #ifdef SM_CXPADDEDBORDER\r
280                                                 paddingBorder = GetSystemMetrics(SM_CXPADDEDBORDER);\r
281                                         #endif\r
282 \r
283                                         if (resizable)\r
284                                         {\r
285                                                 BorderX = GetSystemMetrics(SM_CXSIZEFRAME) + paddingBorder;\r
286                                                 BorderY = GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYSIZEFRAME) + paddingBorder;\r
287                                         }\r
288                                         else\r
289                                         {\r
290                                                 BorderX = GetSystemMetrics(SM_CXDLGFRAME) + paddingBorder;\r
291                                                 BorderY = GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYDLGFRAME) + paddingBorder;\r
292                                         }\r
293                                 }\r
294                                 else\r
295                                 {\r
296                                         BorderX = BorderY = 0;\r
297                                 }\r
298                         }\r
299 \r
300 \r
301                         //! Sets the active cursor icon\r
302                         void setActiveIcon(gui::ECURSOR_ICON iconId) override;\r
303 \r
304                         //! Gets the currently active icon\r
305                         gui::ECURSOR_ICON getActiveIcon() const override\r
306                         {\r
307                                 return ActiveIcon;\r
308                         }\r
309 \r
310                         //! Add a custom sprite as cursor icon.\r
311                         gui::ECURSOR_ICON addIcon(const gui::SCursorSprite& icon) override;\r
312 \r
313                         //! replace the given cursor icon.\r
314                         void changeIcon(gui::ECURSOR_ICON iconId, const gui::SCursorSprite& icon) override;\r
315 \r
316                         //! Return a system-specific size which is supported for cursors. Larger icons will fail, smaller icons might work.\r
317                         core::dimension2di getSupportedIconSize() const override;\r
318 \r
319                         void update();\r
320 \r
321                 private:\r
322 \r
323                         //! Updates the internal cursor position\r
324                         void updateInternalCursorPosition()\r
325                         {\r
326                                 POINT p;\r
327                                 if (!GetCursorPos(&p))\r
328                                 {\r
329                                         DWORD xy = GetMessagePos();\r
330                                         p.x = GET_X_LPARAM(xy);\r
331                                         p.y = GET_Y_LPARAM(xy);\r
332                                 }\r
333 \r
334                                 if (UseReferenceRect)\r
335                                 {\r
336                                         CursorPos.X = p.x - ReferenceRect.UpperLeftCorner.X;\r
337                                         CursorPos.Y = p.y - ReferenceRect.UpperLeftCorner.Y;\r
338                                 }\r
339                                 else\r
340                                 {\r
341                                         RECT rect;\r
342                                         if (GetWindowRect(HWnd, &rect))\r
343                                         {\r
344                                                 CursorPos.X = p.x-rect.left-BorderX;\r
345                                                 CursorPos.Y = p.y-rect.top-BorderY;\r
346                                         }\r
347                                         else\r
348                                         {\r
349                                                 // window seems not to be existent, so set cursor to\r
350                                                 // a negative value\r
351                                                 CursorPos.X = -1;\r
352                                                 CursorPos.Y = -1;\r
353                                         }\r
354                                 }\r
355                         }\r
356 \r
357                         CIrrDeviceWin32* Device;\r
358                         core::position2d<s32> CursorPos;\r
359                         core::dimension2d<u32> WindowSize;\r
360                         core::dimension2d<f32> InvWindowSize;\r
361                         HWND HWnd;\r
362 \r
363                         s32 BorderX, BorderY;\r
364                         core::rect<s32> ReferenceRect;\r
365                         bool UseReferenceRect;\r
366                         bool IsVisible;\r
367 \r
368 \r
369                         struct CursorFrameW32\r
370                         {\r
371                                 CursorFrameW32() : IconHW(0) {}\r
372                                 CursorFrameW32(HCURSOR icon) : IconHW(icon) {}\r
373 \r
374                                 HCURSOR IconHW; // hardware cursor\r
375                         };\r
376 \r
377                         struct CursorW32\r
378                         {\r
379                                 CursorW32() {}\r
380                                 explicit CursorW32(HCURSOR iconHw, u32 frameTime=0) : FrameTime(frameTime)\r
381                                 {\r
382                                         Frames.push_back( CursorFrameW32(iconHw) );\r
383                                 }\r
384                                 core::array<CursorFrameW32> Frames;\r
385                                 u32 FrameTime;\r
386                         };\r
387 \r
388                         core::array<CursorW32> Cursors;\r
389                         gui::ECURSOR_ICON ActiveIcon;\r
390                         u32 ActiveIconStartTime;\r
391 \r
392                         void initCursors();\r
393                 };\r
394 \r
395                 //! returns the win32 cursor control\r
396                 CCursorControl* getWin32CursorControl();\r
397 \r
398         private:\r
399 \r
400                 //! create the driver\r
401                 void createDriver();\r
402 \r
403                 //! Process system events\r
404                 void handleSystemMessages();\r
405 \r
406                 void getWindowsVersion(core::stringc& version);\r
407 \r
408                 void resizeIfNecessary();\r
409 \r
410                 DWORD getWindowStyle(bool fullscreen, bool resizable) const;\r
411 \r
412                 HWND HWnd;\r
413 \r
414                 bool Resized;\r
415                 bool ExternalWindow;\r
416                 CCursorControl* Win32CursorControl;\r
417 \r
418                 SJoystickWin32Control* JoyControl;\r
419 \r
420                 bool WindowMaximized;\r
421         };\r
422 \r
423 } // end namespace irr\r
424 \r
425 #endif // _IRR_COMPILE_WITH_WINDOWS_DEVICE_\r
426 #endif // __C_IRR_DEVICE_WIN32_H_INCLUDED__\r