BsPlatformImpl.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558
  1. //__________________________ Banshee Project - A modern game development toolkit _________________________________//
  2. //_____________________________________ www.banshee-project.com __________________________________________________//
  3. //________________________ Copyright (c) 2014 Marko Pintera. All rights reserved. ________________________________//
  4. #include "BsPlatform.h"
  5. #include "BsRenderWindow.h"
  6. #include "BsPixelUtil.h"
  7. #include "BsCoreApplication.h"
  8. #include "BsDebug.h"
  9. #include "Win32/BsWin32Defs.h"
  10. #include "Win32/BsWin32DropTarget.h"
  11. #include <iphlpapi.h>
  12. namespace BansheeEngine
  13. {
  14. Event<void(RenderWindow*)> Platform::onMouseLeftWindow;
  15. Event<void(const Vector2I&, OSPointerButtonStates)> Platform::onCursorMoved;
  16. Event<void(const Vector2I&, OSMouseButton button, OSPointerButtonStates)> Platform::onCursorButtonPressed;
  17. Event<void(const Vector2I&, OSMouseButton button, OSPointerButtonStates)> Platform::onCursorButtonReleased;
  18. Event<void(const Vector2I&, OSPointerButtonStates)> Platform::onCursorDoubleClick;
  19. Event<void(InputCommandType)> Platform::onInputCommand;
  20. Event<void(float)> Platform::onMouseWheelScrolled;
  21. Event<void(UINT32)> Platform::onCharInput;
  22. Event<void(RenderWindow*)> Platform::onWindowFocusReceived;
  23. Event<void(RenderWindow*)> Platform::onWindowFocusLost;
  24. Event<void(RenderWindow*)> Platform::onWindowMovedOrResized;
  25. Event<void()> Platform::onMouseCaptureChanged;
  26. Map<const RenderWindow*, WindowNonClientAreaData> Platform::mNonClientAreas;
  27. bool Platform::mIsTrackingMouse = false;
  28. Vector<RenderWindow*> Platform::mMouseLeftWindows;
  29. Stack<RenderWindow*> Platform::mModalWindowStack;
  30. NativeDropTargetData Platform::mDropTargets;
  31. bool Platform::mRequiresStartUp = false;
  32. bool Platform::mRequiresShutDown = false;
  33. BS_STATIC_MUTEX_CLASS_INSTANCE(mSync, Platform);
  34. struct NativeCursorData::Pimpl
  35. {
  36. HCURSOR cursor;
  37. };
  38. NativeCursorData::NativeCursorData()
  39. {
  40. data = bs_new<Pimpl>();
  41. }
  42. NativeCursorData::~NativeCursorData()
  43. {
  44. bs_delete(data);
  45. }
  46. struct NativeDropTargetData::Pimpl
  47. {
  48. Map<const RenderWindow*, Win32DropTarget*> dropTargetsPerWindow;
  49. Vector<Win32DropTarget*> dropTargetsToInitialize;
  50. Vector<Win32DropTarget*> dropTargetsToDestroy;
  51. };
  52. NativeDropTargetData::NativeDropTargetData()
  53. {
  54. data = bs_new<Pimpl>();
  55. }
  56. NativeDropTargetData::~NativeDropTargetData()
  57. {
  58. bs_delete(data);
  59. }
  60. bool Platform::mIsCursorHidden = false;
  61. NativeCursorData Platform::mCursor;
  62. bool Platform::mUsingCustomCursor = false;
  63. Vector2I Platform::getCursorPosition()
  64. {
  65. Vector2I screenPos;
  66. POINT cursorPos;
  67. GetCursorPos(&cursorPos);
  68. screenPos.x = cursorPos.x;
  69. screenPos.y = cursorPos.y;
  70. return screenPos;
  71. }
  72. void Platform::setCursorPosition(const Vector2I& screenPos)
  73. {
  74. SetCursorPos(screenPos.x, screenPos.y);
  75. }
  76. void Platform::captureMouse(const RenderWindow& window)
  77. {
  78. RenderWindowPtr primaryWindow = gCoreApplication().getPrimaryWindow();
  79. HWND hwnd;
  80. primaryWindow->getCustomAttribute("WINDOW", &hwnd);
  81. PostMessage(hwnd, WM_BS_SETCAPTURE, WPARAM(hwnd), 0);
  82. }
  83. void Platform::releaseMouseCapture()
  84. {
  85. RenderWindowPtr primaryWindow = gCoreApplication().getPrimaryWindow();
  86. HWND hwnd;
  87. primaryWindow->getCustomAttribute("WINDOW", &hwnd);
  88. PostMessage(hwnd, WM_BS_RELEASECAPTURE, WPARAM(hwnd), 0);
  89. }
  90. bool Platform::isPointOverWindow(const RenderWindow& window, const Vector2I& screenPos)
  91. {
  92. RenderWindowPtr primaryWindow = gCoreApplication().getPrimaryWindow();
  93. POINT point;
  94. point.x = screenPos.x;
  95. point.y = screenPos.y;
  96. HWND hwndToCheck;
  97. window.getCustomAttribute("WINDOW", &hwndToCheck);
  98. HWND hwndUnderPos = WindowFromPoint(point);
  99. return hwndUnderPos == hwndToCheck;
  100. }
  101. void Platform::hideCursor()
  102. {
  103. mIsCursorHidden = true;
  104. // ShowCursor(FALSE) doesn't work. Presumably because we're in the wrong thread, and using
  105. // WM_SETCURSOR in message loop to hide the cursor is smarter solution anyway.
  106. RenderWindowPtr primaryWindow = gCoreApplication().getPrimaryWindow();
  107. HWND hwnd;
  108. primaryWindow->getCustomAttribute("WINDOW", &hwnd);
  109. PostMessage(hwnd, WM_SETCURSOR, WPARAM(hwnd), (LPARAM)MAKELONG(HTCLIENT, WM_MOUSEMOVE));
  110. }
  111. void Platform::showCursor()
  112. {
  113. mIsCursorHidden = false;
  114. // ShowCursor(FALSE) doesn't work. Presumably because we're in the wrong thread, and using
  115. // WM_SETCURSOR in message loop to hide the cursor is smarter solution anyway.
  116. RenderWindowPtr primaryWindow = gCoreApplication().getPrimaryWindow();
  117. HWND hwnd;
  118. primaryWindow->getCustomAttribute("WINDOW", &hwnd);
  119. PostMessage(hwnd, WM_SETCURSOR, WPARAM(hwnd), (LPARAM)MAKELONG(HTCLIENT, WM_MOUSEMOVE));
  120. }
  121. void Platform::clipCursorToWindow(const RenderWindow& window)
  122. {
  123. HWND hwnd;
  124. window.getCustomAttribute("WINDOW", &hwnd);
  125. // Clip cursor to the window
  126. RECT clipWindowRect;
  127. if(GetWindowRect(hwnd, &clipWindowRect))
  128. {
  129. ClipCursor(&clipWindowRect);
  130. }
  131. }
  132. void Platform::clipCursorToRect(const RectI& screenRect)
  133. {
  134. RECT clipWindowRect;
  135. clipWindowRect.left = screenRect.x;
  136. clipWindowRect.top = screenRect.y;
  137. clipWindowRect.right = screenRect.x + screenRect.width;
  138. clipWindowRect.bottom = screenRect.y + screenRect.height;
  139. ClipCursor(&clipWindowRect);
  140. }
  141. void Platform::clipCursorDisable()
  142. {
  143. ClipCursor(NULL);
  144. }
  145. // TODO - Add support for animated custom cursor
  146. void Platform::setCursor(PixelData& pixelData, const Vector2I& hotSpot)
  147. {
  148. if(mUsingCustomCursor)
  149. {
  150. SetCursor(0);
  151. DestroyIcon(mCursor.data->cursor);
  152. }
  153. mUsingCustomCursor = true;
  154. BITMAPV5HEADER bi;
  155. ZeroMemory(&bi,sizeof(BITMAPV5HEADER));
  156. bi.bV5Size = sizeof(BITMAPV5HEADER);
  157. bi.bV5Width = pixelData.getWidth();
  158. bi.bV5Height = pixelData.getHeight();
  159. bi.bV5Planes = 1;
  160. bi.bV5BitCount = 32;
  161. bi.bV5Compression = BI_BITFIELDS;
  162. bi.bV5RedMask = 0x00FF0000;
  163. bi.bV5GreenMask = 0x0000FF00;
  164. bi.bV5BlueMask = 0x000000FF;
  165. bi.bV5AlphaMask = 0xFF000000;
  166. HDC hDC = GetDC(NULL);
  167. void* data = nullptr;
  168. HBITMAP hBitmap = CreateDIBSection(hDC, (BITMAPINFO *)&bi, DIB_RGB_COLORS,
  169. (void**)&data, NULL, (DWORD)0);
  170. HDC hBitmapDC = CreateCompatibleDC(hDC);
  171. ReleaseDC(NULL, hDC);
  172. // Create an empty mask bitmap.
  173. HBITMAP hMonoBitmap = CreateBitmap(pixelData.getWidth(), pixelData.getHeight(), 1, 1, NULL);
  174. //Select the bitmaps to DC
  175. HBITMAP hOldBitmap = (HBITMAP)SelectObject(hBitmapDC, hBitmap);
  176. //Scan each pixel of the source bitmap and create the masks
  177. Color pixel;
  178. DWORD *dst = (DWORD*)data;
  179. for(UINT32 y = 0; y < pixelData.getHeight(); ++y)
  180. {
  181. for(UINT32 x = 0; x < pixelData.getWidth(); ++x)
  182. {
  183. pixel = pixelData.getColorAt(x, pixelData.getHeight() - y - 1);
  184. *dst = pixel.getAsBGRA();
  185. dst++;
  186. }
  187. }
  188. SelectObject(hBitmapDC, hOldBitmap);
  189. DeleteDC(hBitmapDC);
  190. ICONINFO iconinfo = {0};
  191. iconinfo.fIcon = FALSE;
  192. iconinfo.xHotspot = (DWORD)hotSpot.x;
  193. iconinfo.yHotspot = (DWORD)hotSpot.y;
  194. iconinfo.hbmMask = hMonoBitmap;
  195. iconinfo.hbmColor = hBitmap;
  196. mCursor.data->cursor = CreateIconIndirect(&iconinfo);
  197. DeleteObject(hBitmap);
  198. DeleteObject(hMonoBitmap);
  199. // Make sure we notify the message loop to perform the actual cursor update
  200. RenderWindowPtr primaryWindow = gCoreApplication().getPrimaryWindow();
  201. HWND hwnd;
  202. primaryWindow->getCustomAttribute("WINDOW", &hwnd);
  203. PostMessage(hwnd, WM_SETCURSOR, WPARAM(hwnd), (LPARAM)MAKELONG(HTCLIENT, WM_MOUSEMOVE));
  204. }
  205. void Platform::setCaptionNonClientAreas(const RenderWindow& window, const Vector<RectI>& nonClientAreas)
  206. {
  207. BS_LOCK_MUTEX(mSync);
  208. mNonClientAreas[&window].moveAreas = nonClientAreas;
  209. }
  210. void Platform::setResizeNonClientAreas(const RenderWindow& window, const Vector<NonClientResizeArea>& nonClientAreas)
  211. {
  212. BS_LOCK_MUTEX(mSync);
  213. mNonClientAreas[&window].resizeAreas = nonClientAreas;
  214. }
  215. void Platform::resetNonClientAreas(const RenderWindow& window)
  216. {
  217. BS_LOCK_MUTEX(mSync);
  218. auto iterFind = mNonClientAreas.find(&window);
  219. if(iterFind != end(mNonClientAreas))
  220. mNonClientAreas.erase(iterFind);
  221. }
  222. void Platform::copyToClipboard(const WString& string)
  223. {
  224. HANDLE hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, (string.size() + 1) * sizeof(WString::value_type));
  225. WString::value_type* buffer = (WString::value_type*)GlobalLock(hData);
  226. string.copy(buffer, string.size());
  227. buffer[string.size()] = '\0';
  228. GlobalUnlock(hData);
  229. if(OpenClipboard(NULL))
  230. {
  231. EmptyClipboard();
  232. SetClipboardData(CF_UNICODETEXT, hData);
  233. CloseClipboard();
  234. }
  235. else
  236. {
  237. GlobalFree(hData);
  238. }
  239. }
  240. WString Platform::copyFromClipboard()
  241. {
  242. if(OpenClipboard(NULL))
  243. {
  244. HANDLE hData = GetClipboardData(CF_UNICODETEXT);
  245. if(hData != NULL)
  246. {
  247. WString::value_type* buffer = (WString::value_type*)GlobalLock(hData);
  248. WString string(buffer);
  249. GlobalUnlock(hData);
  250. CloseClipboard();
  251. return string;
  252. }
  253. else
  254. {
  255. CloseClipboard();
  256. return L"";
  257. }
  258. }
  259. return L"";
  260. }
  261. bool Platform::getMACAddress(MACAddress& address)
  262. {
  263. std::memset(&address, 0, sizeof(address));
  264. PIP_ADAPTER_INFO adapterInfo = bs_alloc<IP_ADAPTER_INFO>();
  265. ULONG len = sizeof(IP_ADAPTER_INFO);
  266. DWORD rc = GetAdaptersInfo(adapterInfo, &len);
  267. if (rc == ERROR_BUFFER_OVERFLOW)
  268. {
  269. bs_free(adapterInfo);
  270. adapterInfo = reinterpret_cast<IP_ADAPTER_INFO*>(bs_alloc(len));
  271. }
  272. else if (rc != ERROR_SUCCESS)
  273. {
  274. bs_free(adapterInfo);
  275. return false;
  276. }
  277. if (GetAdaptersInfo(adapterInfo, &len) == NO_ERROR)
  278. {
  279. PIP_ADAPTER_INFO curAdapter = nullptr;
  280. curAdapter = adapterInfo;
  281. while (curAdapter)
  282. {
  283. if (curAdapter->Type == MIB_IF_TYPE_ETHERNET && curAdapter->AddressLength == sizeof(address))
  284. {
  285. std::memcpy(&address, curAdapter->Address, curAdapter->AddressLength);
  286. return true;
  287. }
  288. curAdapter = curAdapter->Next;
  289. }
  290. }
  291. bs_free(adapterInfo);
  292. return false;
  293. }
  294. double Platform::queryPerformanceTimerMs()
  295. {
  296. LARGE_INTEGER counterValue;
  297. QueryPerformanceCounter(&counterValue);
  298. LARGE_INTEGER counterFreq;
  299. QueryPerformanceFrequency(&counterFreq);
  300. return (double)counterValue.QuadPart / (counterFreq.QuadPart * 0.001);
  301. }
  302. OSDropTarget& Platform::createDropTarget(const RenderWindow* window, int x, int y, unsigned int width, unsigned int height)
  303. {
  304. Win32DropTarget* win32DropTarget = nullptr;
  305. auto iterFind = mDropTargets.data->dropTargetsPerWindow.find(window);
  306. if(iterFind == mDropTargets.data->dropTargetsPerWindow.end())
  307. {
  308. HWND hwnd;
  309. window->getCustomAttribute("WINDOW", &hwnd);
  310. win32DropTarget = bs_new<Win32DropTarget>(hwnd);
  311. mDropTargets.data->dropTargetsPerWindow[window] = win32DropTarget;
  312. {
  313. BS_LOCK_MUTEX(mSync);
  314. mDropTargets.data->dropTargetsToInitialize.push_back(win32DropTarget);
  315. }
  316. }
  317. else
  318. win32DropTarget = iterFind->second;
  319. OSDropTarget* newDropTarget = new (bs_alloc<OSDropTarget>()) OSDropTarget(window, x, y, width, height);
  320. win32DropTarget->registerDropTarget(newDropTarget);
  321. return *newDropTarget;
  322. }
  323. void Platform::destroyDropTarget(OSDropTarget& target)
  324. {
  325. auto iterFind = mDropTargets.data->dropTargetsPerWindow.find(target.getOwnerWindow());
  326. if(iterFind == mDropTargets.data->dropTargetsPerWindow.end())
  327. {
  328. LOGWRN("Attempting to destroy a drop target but cannot find its parent window.");
  329. }
  330. else
  331. {
  332. Win32DropTarget* win32DropTarget = iterFind->second;
  333. win32DropTarget->unregisterDropTarget(&target);
  334. if(win32DropTarget->getNumDropTargets() == 0)
  335. {
  336. mDropTargets.data->dropTargetsPerWindow.erase(iterFind);
  337. {
  338. BS_LOCK_MUTEX(mSync);
  339. mDropTargets.data->dropTargetsToDestroy.push_back(win32DropTarget);
  340. }
  341. }
  342. }
  343. BS_PVT_DELETE(OSDropTarget, &target);
  344. }
  345. void Platform::_messagePump()
  346. {
  347. MSG msg;
  348. while(PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
  349. {
  350. TranslateMessage(&msg);
  351. DispatchMessage(&msg);
  352. }
  353. }
  354. void Platform::_startUp()
  355. {
  356. BS_LOCK_MUTEX(mSync);
  357. mRequiresStartUp = true;
  358. }
  359. void Platform::_update()
  360. {
  361. Vector<RenderWindow*> windowsCopy;
  362. {
  363. BS_LOCK_MUTEX(mSync);
  364. windowsCopy = mMouseLeftWindows;
  365. mMouseLeftWindows.clear();
  366. }
  367. for(auto& window : windowsCopy)
  368. {
  369. if(!onMouseLeftWindow.empty())
  370. onMouseLeftWindow(window);
  371. }
  372. for(auto& dropTarget : mDropTargets.data->dropTargetsPerWindow)
  373. {
  374. dropTarget.second->update();
  375. }
  376. }
  377. void Platform::_coreUpdate()
  378. {
  379. {
  380. BS_LOCK_MUTEX(mSync);
  381. if(mRequiresStartUp)
  382. {
  383. OleInitialize(nullptr);
  384. mRequiresStartUp = false;
  385. }
  386. }
  387. {
  388. BS_LOCK_MUTEX(mSync);
  389. for(auto& dropTargetToInit : mDropTargets.data->dropTargetsToInitialize)
  390. {
  391. dropTargetToInit->registerWithOS();
  392. }
  393. mDropTargets.data->dropTargetsToInitialize.clear();
  394. }
  395. {
  396. BS_LOCK_MUTEX(mSync);
  397. for(auto& dropTargetToDestroy : mDropTargets.data->dropTargetsToDestroy)
  398. {
  399. dropTargetToDestroy->unregisterWithOS();
  400. dropTargetToDestroy->Release();
  401. }
  402. mDropTargets.data->dropTargetsToDestroy.clear();
  403. }
  404. _messagePump();
  405. {
  406. BS_LOCK_MUTEX(mSync);
  407. if(mRequiresShutDown)
  408. {
  409. OleUninitialize();
  410. mRequiresShutDown = false;
  411. }
  412. }
  413. }
  414. void Platform::_shutDown()
  415. {
  416. BS_LOCK_MUTEX(mSync);
  417. mRequiresShutDown = true;
  418. }
  419. void Platform::windowFocusReceived(RenderWindow* window)
  420. {
  421. if(!onWindowFocusReceived.empty())
  422. onWindowFocusReceived(window);
  423. }
  424. void Platform::windowFocusLost(RenderWindow* window)
  425. {
  426. if(!onWindowFocusLost.empty())
  427. onWindowFocusLost(window);
  428. }
  429. void Platform::windowMovedOrResized(RenderWindow* window)
  430. {
  431. if(!onWindowMovedOrResized.empty())
  432. onWindowMovedOrResized(window);
  433. }
  434. void Platform::win32ShowCursor()
  435. {
  436. SetCursor(mCursor.data->cursor);
  437. }
  438. void Platform::win32HideCursor()
  439. {
  440. SetCursor(nullptr);
  441. }
  442. }