CmPlatformImpl.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  1. #include "CmPlatform.h"
  2. #include "CmRenderWindow.h"
  3. #include "CmPixelUtil.h"
  4. #include "CmApplication.h"
  5. #include "CmWin32Defs.h"
  6. namespace CamelotFramework
  7. {
  8. boost::signal<void(RenderWindow*)> Platform::onMouseLeftWindow;
  9. boost::signal<void(const Int2&, OSPositionalInputButtonStates)> Platform::onCursorMoved;
  10. boost::signal<void(const Int2&, OSMouseButton button, OSPositionalInputButtonStates)> Platform::onCursorButtonPressed;
  11. boost::signal<void(const Int2&, OSMouseButton button, OSPositionalInputButtonStates)> Platform::onCursorButtonReleased;
  12. boost::signal<void(InputCommandType)> Platform::onInputCommand;
  13. boost::signal<void(float)> Platform::onMouseWheelScrolled;
  14. boost::signal<void(UINT32)> Platform::onCharInput;
  15. boost::signal<void(RenderWindow*)> Platform::onWindowFocusReceived;
  16. boost::signal<void(RenderWindow*)> Platform::onWindowFocusLost;
  17. boost::signal<void(RenderWindow*)> Platform::onWindowMovedOrResized;
  18. boost::signal<void()> Platform::onMouseCaptureChanged;
  19. Map<const RenderWindow*, WindowNonClientAreaData>::type Platform::mNonClientAreas;
  20. bool Platform::mIsTrackingMouse = false;
  21. Vector<RenderWindow*>::type Platform::mMouseLeftWindows;
  22. CM_STATIC_MUTEX_CLASS_INSTANCE(mSync, Platform);
  23. struct NativeCursorData::Pimpl
  24. {
  25. HCURSOR cursor;
  26. };
  27. NativeCursorData::NativeCursorData()
  28. {
  29. data = cm_new<Pimpl>();
  30. }
  31. NativeCursorData::~NativeCursorData()
  32. {
  33. cm_delete(data);
  34. }
  35. bool Platform::mIsCursorHidden = false;
  36. NativeCursorData Platform::mCursor;
  37. bool Platform::mUsingCustomCursor = false;
  38. void Platform::setCursorPosition(const Int2& screenPos)
  39. {
  40. SetCursorPos(screenPos.x, screenPos.y);
  41. }
  42. void Platform::captureMouse(const RenderWindow& window)
  43. {
  44. RenderWindowPtr primaryWindow = gApplication().getPrimaryWindow();
  45. HWND hwnd;
  46. primaryWindow->getCustomAttribute("WINDOW", &hwnd);
  47. PostMessage(hwnd, WM_CM_SETCAPTURE, WPARAM(hwnd), 0);
  48. }
  49. void Platform::releaseMouseCapture()
  50. {
  51. RenderWindowPtr primaryWindow = gApplication().getPrimaryWindow();
  52. HWND hwnd;
  53. primaryWindow->getCustomAttribute("WINDOW", &hwnd);
  54. PostMessage(hwnd, WM_CM_RELEASECAPTURE, WPARAM(hwnd), 0);
  55. }
  56. bool Platform::isPointOverWindow(const RenderWindow& window, const Int2& screenPos)
  57. {
  58. RenderWindowPtr primaryWindow = gApplication().getPrimaryWindow();
  59. POINT point;
  60. point.x = screenPos.x;
  61. point.y = screenPos.y;
  62. HWND hwndToCheck;
  63. window.getCustomAttribute("WINDOW", &hwndToCheck);
  64. HWND hwndUnderPos = WindowFromPoint(point);
  65. return hwndUnderPos == hwndToCheck;
  66. }
  67. void Platform::hideCursor()
  68. {
  69. mIsCursorHidden = true;
  70. // ShowCursor(FALSE) doesn't work. Presumably because we're in the wrong thread, and using
  71. // WM_SETCURSOR in message loop to hide the cursor is smarter solution anyway.
  72. RenderWindowPtr primaryWindow = gApplication().getPrimaryWindow();
  73. HWND hwnd;
  74. primaryWindow->getCustomAttribute("WINDOW", &hwnd);
  75. PostMessage(hwnd, WM_SETCURSOR, WPARAM(hwnd), (LPARAM)MAKELONG(HTCLIENT, WM_MOUSEMOVE));
  76. }
  77. void Platform::showCursor()
  78. {
  79. mIsCursorHidden = false;
  80. // ShowCursor(FALSE) doesn't work. Presumably because we're in the wrong thread, and using
  81. // WM_SETCURSOR in message loop to hide the cursor is smarter solution anyway.
  82. RenderWindowPtr primaryWindow = gApplication().getPrimaryWindow();
  83. HWND hwnd;
  84. primaryWindow->getCustomAttribute("WINDOW", &hwnd);
  85. PostMessage(hwnd, WM_SETCURSOR, WPARAM(hwnd), (LPARAM)MAKELONG(HTCLIENT, WM_MOUSEMOVE));
  86. }
  87. void Platform::clipCursorToWindow(const RenderWindow& window)
  88. {
  89. HWND hwnd;
  90. window.getCustomAttribute("WINDOW", &hwnd);
  91. // Clip cursor to the window
  92. RECT clipWindowRect;
  93. if(GetWindowRect(hwnd, &clipWindowRect))
  94. {
  95. ClipCursor(&clipWindowRect);
  96. }
  97. }
  98. void Platform::clipCursorToRect(const Rect& screenRect)
  99. {
  100. RECT clipWindowRect;
  101. clipWindowRect.left = screenRect.x;
  102. clipWindowRect.top = screenRect.y;
  103. clipWindowRect.right = screenRect.x + screenRect.width;
  104. clipWindowRect.bottom = screenRect.y + screenRect.height;
  105. ClipCursor(&clipWindowRect);
  106. }
  107. void Platform::clipCursorDisable()
  108. {
  109. ClipCursor(NULL);
  110. }
  111. void Platform::setCursor(CursorType type)
  112. {
  113. if(mUsingCustomCursor)
  114. {
  115. SetCursor(0);
  116. DestroyIcon(mCursor.data->cursor);
  117. mUsingCustomCursor = false;
  118. }
  119. switch(type)
  120. {
  121. case CursorType::Arrow:
  122. mCursor.data->cursor = LoadCursor(0, IDC_ARROW);
  123. break;
  124. case CursorType::Wait:
  125. mCursor.data->cursor = LoadCursor(0, IDC_WAIT);
  126. break;
  127. case CursorType::IBeam:
  128. mCursor.data->cursor = LoadCursor(0, IDC_IBEAM);
  129. break;
  130. case CursorType::Help:
  131. mCursor.data->cursor = LoadCursor(0, IDC_HELP);
  132. break;
  133. case CursorType::Hand:
  134. mCursor.data->cursor = LoadCursor(0, IDC_HAND);
  135. break;
  136. case CursorType::SizeAll:
  137. mCursor.data->cursor = LoadCursor(0, IDC_SIZEALL);
  138. break;
  139. case CursorType::SizeNESW:
  140. mCursor.data->cursor = LoadCursor(0, IDC_SIZENESW);
  141. break;
  142. case CursorType::SizeNS:
  143. mCursor.data->cursor = LoadCursor(0, IDC_SIZENS);
  144. break;
  145. case CursorType::SizeNWSE:
  146. mCursor.data->cursor = LoadCursor(0, IDC_SIZENWSE);
  147. break;
  148. case CursorType::SizeWE:
  149. mCursor.data->cursor = LoadCursor(0, IDC_SIZEWE);
  150. break;
  151. }
  152. // Make sure we notify the message loop to perform the actual cursor update
  153. RenderWindowPtr primaryWindow = gApplication().getPrimaryWindow();
  154. HWND hwnd;
  155. primaryWindow->getCustomAttribute("WINDOW", &hwnd);
  156. PostMessage(hwnd, WM_SETCURSOR, WPARAM(hwnd), (LPARAM)MAKELONG(HTCLIENT, WM_MOUSEMOVE));
  157. }
  158. // TODO - Add support for animated custom cursor
  159. void Platform::setCustomCursor(PixelData& pixelData, const Int2& hotSpot)
  160. {
  161. if(mUsingCustomCursor)
  162. {
  163. SetCursor(0);
  164. DestroyIcon(mCursor.data->cursor);
  165. }
  166. mUsingCustomCursor = true;
  167. BITMAPV5HEADER bi;
  168. ZeroMemory(&bi,sizeof(BITMAPV5HEADER));
  169. bi.bV5Size = sizeof(BITMAPV5HEADER);
  170. bi.bV5Width = pixelData.getWidth();
  171. bi.bV5Height = pixelData.getHeight();
  172. bi.bV5Planes = 1;
  173. bi.bV5BitCount = 32;
  174. bi.bV5Compression = BI_BITFIELDS;
  175. bi.bV5RedMask = 0x00FF0000;
  176. bi.bV5GreenMask = 0x0000FF00;
  177. bi.bV5BlueMask = 0x000000FF;
  178. bi.bV5AlphaMask = 0xFF000000;
  179. HDC hDC = GetDC(NULL);
  180. void* data = nullptr;
  181. HBITMAP hBitmap = CreateDIBSection(hDC, (BITMAPINFO *)&bi, DIB_RGB_COLORS,
  182. (void**)&data, NULL, (DWORD)0);
  183. HDC hBitmapDC = CreateCompatibleDC(hDC);
  184. ReleaseDC(NULL, hDC);
  185. // Create an empty mask bitmap.
  186. HBITMAP hMonoBitmap = CreateBitmap(pixelData.getWidth(), pixelData.getHeight(), 1, 1, NULL);
  187. //Select the bitmaps to DC
  188. HBITMAP hOldBitmap = (HBITMAP)SelectObject(hBitmapDC, hBitmap);
  189. //Scan each pixel of the source bitmap and create the masks
  190. Color pixel;
  191. DWORD *dst = (DWORD*)data;
  192. for(UINT32 y = 0; y < pixelData.getHeight(); ++y)
  193. {
  194. for(UINT32 x = 0; x < pixelData.getWidth(); ++x)
  195. {
  196. pixel = pixelData.getColorAt(x, pixelData.getHeight() - y - 1);
  197. *dst = pixel.getAsBGRA();
  198. dst++;
  199. }
  200. }
  201. SelectObject(hBitmapDC, hOldBitmap);
  202. DeleteDC(hBitmapDC);
  203. ICONINFO iconinfo = {0};
  204. iconinfo.fIcon = FALSE;
  205. iconinfo.xHotspot = (DWORD)hotSpot.x;
  206. iconinfo.yHotspot = (DWORD)hotSpot.y;
  207. iconinfo.hbmMask = hMonoBitmap;
  208. iconinfo.hbmColor = hBitmap;
  209. mCursor.data->cursor = CreateIconIndirect(&iconinfo);
  210. DeleteObject(hBitmap);
  211. DeleteObject(hMonoBitmap);
  212. // Make sure we notify the message loop to perform the actual cursor update
  213. RenderWindowPtr primaryWindow = gApplication().getPrimaryWindow();
  214. HWND hwnd;
  215. primaryWindow->getCustomAttribute("WINDOW", &hwnd);
  216. PostMessage(hwnd, WM_SETCURSOR, WPARAM(hwnd), (LPARAM)MAKELONG(HTCLIENT, WM_MOUSEMOVE));
  217. }
  218. void Platform::setCaptionNonClientAreas(const RenderWindow& window, const Vector<Rect>::type& nonClientAreas)
  219. {
  220. CM_LOCK_MUTEX(mSync);
  221. mNonClientAreas[&window].moveAreas = nonClientAreas;
  222. }
  223. void Platform::setResizeNonClientAreas(const RenderWindow& window, const Vector<NonClientResizeArea>::type& nonClientAreas)
  224. {
  225. CM_LOCK_MUTEX(mSync);
  226. mNonClientAreas[&window].resizeAreas = nonClientAreas;
  227. }
  228. void Platform::resetNonClientAreas(const RenderWindow& window)
  229. {
  230. CM_LOCK_MUTEX(mSync);
  231. auto iterFind = mNonClientAreas.find(&window);
  232. if(iterFind != end(mNonClientAreas))
  233. mNonClientAreas.erase(iterFind);
  234. }
  235. void Platform::copyToClipboard(const WString& string)
  236. {
  237. HANDLE hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, (string.size() + 1) * sizeof(WString::value_type));
  238. WString::value_type* buffer = (WString::value_type*)GlobalLock(hData);
  239. string.copy(buffer, string.size());
  240. buffer[string.size()] = '\0';
  241. GlobalUnlock(hData);
  242. if(OpenClipboard(NULL))
  243. {
  244. EmptyClipboard();
  245. SetClipboardData(CF_UNICODETEXT, hData);
  246. CloseClipboard();
  247. }
  248. else
  249. {
  250. GlobalFree(hData);
  251. }
  252. }
  253. WString Platform::copyFromClipboard()
  254. {
  255. if(OpenClipboard(NULL))
  256. {
  257. HANDLE hData = GetClipboardData(CF_UNICODETEXT);
  258. if(hData != NULL)
  259. {
  260. WString::value_type* buffer = (WString::value_type*)GlobalLock(hData);
  261. WString string(buffer);
  262. GlobalUnlock(hData);
  263. CloseClipboard();
  264. return string;
  265. }
  266. else
  267. {
  268. CloseClipboard();
  269. return L"";
  270. }
  271. }
  272. return L"";
  273. }
  274. void Platform::messagePump()
  275. {
  276. MSG msg;
  277. while(PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
  278. {
  279. TranslateMessage(&msg);
  280. DispatchMessage(&msg);
  281. }
  282. }
  283. void Platform::update()
  284. {
  285. Vector<RenderWindow*>::type windowsCopy;
  286. {
  287. CM_LOCK_MUTEX(mSync);
  288. windowsCopy = mMouseLeftWindows;
  289. mMouseLeftWindows.clear();
  290. }
  291. for(auto& window : windowsCopy)
  292. {
  293. if(!onMouseLeftWindow.empty())
  294. onMouseLeftWindow(window);
  295. }
  296. }
  297. void Platform::windowFocusReceived(RenderWindow* window)
  298. {
  299. if(!onWindowFocusReceived.empty())
  300. onWindowFocusReceived(window);
  301. }
  302. void Platform::windowFocusLost(RenderWindow* window)
  303. {
  304. if(!onWindowFocusLost.empty())
  305. onWindowFocusLost(window);
  306. }
  307. void Platform::windowMovedOrResized(RenderWindow* window)
  308. {
  309. if(!onWindowMovedOrResized.empty())
  310. onWindowMovedOrResized(window);
  311. }
  312. void Platform::win32ShowCursor()
  313. {
  314. SetCursor(mCursor.data->cursor);
  315. }
  316. void Platform::win32HideCursor()
  317. {
  318. SetCursor(nullptr);
  319. }
  320. }