WinBFApp.cpp 48 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025
  1. #include <dsound.h>
  2. #include "WinBFApp.h"
  3. #include "DXRenderDevice.h"
  4. #include <signal.h>
  5. #include "../../util/BeefPerf.h"
  6. #include "DSoundManager.h"
  7. #include "DInputManager.h"
  8. #include <dwmapi.h>
  9. #pragma comment(lib, "dwmapi.lib")
  10. #include "util/AllocDebug.h"
  11. USING_NS_BF;
  12. int Beefy::WinBFMenu::mMenuCount = 0;
  13. int PrintStuff()
  14. {
  15. OutputDebugStringA("Hey!\n");
  16. return 123;
  17. }
  18. WinBFMenu::WinBFMenu()
  19. {
  20. mIsPlaceholder = false;
  21. mMenu = NULL;
  22. mParent = NULL;
  23. mMenuId = 0;
  24. }
  25. ///
  26. static HICON gMainIcon = NULL;
  27. static BOOL CALLBACK BFEnumResNameProc(
  28. HMODULE hModule,
  29. LPCWSTR lpszType,
  30. LPWSTR lpszName,
  31. LONG_PTR lParam
  32. )
  33. {
  34. gMainIcon = ::LoadIconW(hModule, lpszName);
  35. return FALSE;
  36. }
  37. struct AdjustedMonRect
  38. {
  39. int mMonCount;
  40. int mX;
  41. int mY;
  42. int mWidth;
  43. int mHeight;
  44. };
  45. static BOOL ClipToMonitor(HMONITOR mon, HDC hdc, LPRECT monRect, LPARAM userArg)
  46. {
  47. AdjustedMonRect* outRect = (AdjustedMonRect*)userArg;
  48. MONITORINFO monitorInfo = { sizeof(MONITORINFO) };
  49. if (::GetMonitorInfo(mon, &monitorInfo) == 0)
  50. return TRUE;
  51. outRect->mMonCount++;
  52. if (outRect->mX < monitorInfo.rcWork.left)
  53. outRect->mX = monitorInfo.rcWork.left;
  54. else if (outRect->mX + outRect->mWidth >= monitorInfo.rcWork.right)
  55. outRect->mX = BF_MAX((int)monitorInfo.rcWork.left, monitorInfo.rcWork.right - outRect->mWidth);
  56. if (outRect->mY < monitorInfo.rcWork.top)
  57. outRect->mY = monitorInfo.rcWork.top;
  58. else if (outRect->mY + outRect->mHeight >= monitorInfo.rcWork.bottom)
  59. outRect->mY = BF_MAX((int)monitorInfo.rcWork.top, monitorInfo.rcWork.bottom - outRect->mHeight);
  60. return TRUE;
  61. }
  62. static BOOL KeyboardLayoutHasAltGr(HKL layout)
  63. {
  64. BOOL hasAltGr = FALSE;
  65. int scancode;
  66. for (WORD i = 32; i < 256; ++i)
  67. {
  68. scancode = VkKeyScanEx((TCHAR)i, layout);
  69. if ((scancode != -1) && ((scancode & 0x600) == 0x600))
  70. {
  71. hasAltGr = TRUE;
  72. break;
  73. }
  74. }
  75. return hasAltGr;
  76. }
  77. WinBFWindow::WinBFWindow(BFWindow* parent, const StringImpl& title, int x, int y, int width, int height, int windowFlags)
  78. {
  79. HINSTANCE hInstance = GetModuleHandle(NULL);
  80. mMinWidth = 128;
  81. mMinHeight = 128;
  82. WNDCLASSW wc;
  83. wc.style = 0;
  84. wc.cbClsExtra = 0;
  85. wc.cbWndExtra = 0;
  86. wc.hbrBackground = NULL;
  87. //wc.hbrBackground = ::CreateSolidBrush(::GetSysColor(COLOR_BTNFACE));
  88. wc.hCursor = NULL;
  89. //wc.hIcon = (HICON) ::LoadImageA(hInstance, "MainIcon", IMAGE_ICON, 0, 0, 0);
  90. //wc.hIcon = (HICON) ::LoadImageA(hInstance, MAKEINTRESOURCEA(32512), IMAGE_ICON, 0, 0, 0);
  91. if (gMainIcon != NULL)
  92. {
  93. wc.hIcon = gMainIcon;
  94. }
  95. else
  96. {
  97. wc.hIcon = (HICON) ::LoadIconA(hInstance, "MainIcon");
  98. if (wc.hIcon == NULL)
  99. {
  100. EnumResourceNamesW(hInstance, (LPCWSTR)RT_GROUP_ICON, BFEnumResNameProc, 0);
  101. wc.hIcon = gMainIcon;
  102. }
  103. }
  104. wc.hInstance = hInstance;
  105. wc.lpfnWndProc = WindowProcStub;
  106. wc.lpszClassName = L"BFWindow";
  107. wc.lpszMenuName = NULL;
  108. RegisterClassW(&wc);
  109. int requestedX = x;
  110. int requestedY = y;
  111. int aWindowFlags = 0;
  112. bool hasDestAlpha = (windowFlags & BFWINDOW_DEST_ALPHA) != 0;
  113. if (windowFlags & BFWINDOW_MENU)
  114. {
  115. WinBFMenu* aMenu = new WinBFMenu();
  116. aMenu->mMenu = ::CreateMenu();
  117. mHMenuMap[aMenu->mMenu] = aMenu;
  118. mMenu = aMenu;
  119. }
  120. int windowFlagsEx = /*WS_EX_COMPOSITED |*/ WS_EX_LAYERED;
  121. if (windowFlags & BFWINDOW_TOOLWINDOW)
  122. windowFlagsEx |= WS_EX_TOOLWINDOW;
  123. if (windowFlags & BFWINDOW_BORDER)
  124. aWindowFlags |= WS_BORDER;
  125. if (windowFlags & BFWINDOW_THICKFRAME)
  126. aWindowFlags |= WS_THICKFRAME;
  127. if ((windowFlags & BFWINDOW_RESIZABLE) && (!hasDestAlpha))
  128. aWindowFlags |= WS_SIZEBOX;
  129. if (windowFlags & BFWINDOW_SYSMENU)
  130. aWindowFlags |= WS_SYSMENU;
  131. if (windowFlags & BFWINDOW_CAPTION)
  132. aWindowFlags |= WS_CAPTION;
  133. else
  134. aWindowFlags |= WS_POPUP;
  135. if (windowFlags & BFWINDOW_MINIMIZE)
  136. aWindowFlags |= WS_MINIMIZEBOX;
  137. if (windowFlags & BFWINDOW_MAXIMIZE)
  138. aWindowFlags |= WS_MAXIMIZEBOX;
  139. if ((windowFlags & BFWINDOW_TOPMOST) && (parent == NULL))
  140. windowFlagsEx |= WS_EX_TOPMOST;
  141. if ((windowFlags & BFWINDOW_ACCEPTFILES))
  142. windowFlagsEx |= WS_EX_ACCEPTFILES;
  143. if (windowFlags & BFWINDOW_CLIENT_SIZED)
  144. {
  145. RECT rect = {0, 0, width, height};
  146. AdjustWindowRectEx(&rect, aWindowFlags, mMenu != NULL, windowFlagsEx);
  147. x += rect.left;
  148. y += rect.top;
  149. width = rect.right - rect.left;
  150. height = rect.bottom - rect.top;
  151. }
  152. if (windowFlags & BFWINDOW_POPUP_POSITION)
  153. {
  154. AdjustedMonRect adjustRect = { 0, x, y, width, height };
  155. RECT wantRect = { x, y, x + width, y + height };
  156. EnumDisplayMonitors(NULL, &wantRect, ClipToMonitor, (LPARAM)&adjustRect);
  157. if (adjustRect.mMonCount == 0)
  158. EnumDisplayMonitors(NULL, NULL, ClipToMonitor, (LPARAM)&adjustRect);
  159. x = adjustRect.mX;
  160. y = adjustRect.mY;
  161. width = adjustRect.mWidth;
  162. height = adjustRect.mHeight;
  163. }
  164. mFlags = windowFlags;
  165. mMouseVisible = true;
  166. mParent = parent;
  167. HWND parentHWnd = NULL;
  168. if (parent != NULL)
  169. parentHWnd = ((WinBFWindow*) parent)->mHWnd;
  170. if (mMenu != NULL)
  171. {
  172. WinBFMenu* placeholderMenu = (WinBFMenu*) AddMenuItem(mMenu, 0, ": Placeholder Menu Item :", NULL, NULL, false, -1, false);
  173. placeholderMenu->mIsPlaceholder = true;
  174. }
  175. mHWnd = CreateWindowExW(windowFlagsEx, L"BFWindow", UTF8Decode(title).c_str(),
  176. aWindowFlags,
  177. x, y,
  178. width,
  179. height,
  180. parentHWnd,
  181. (mMenu != NULL) ? ((WinBFMenu*) mMenu)->mMenu : NULL,
  182. hInstance,
  183. 0);
  184. if ((windowFlags & BFWINDOW_ALPHA_MASK) == 0)
  185. SetLayeredWindowAttributes(mHWnd, 0, 255, 0);
  186. HWND relativeWindow = NULL;
  187. if ((windowFlags & BFWINDOW_TOPMOST) && (parent == NULL))
  188. relativeWindow = HWND_TOP;
  189. int showFlags = SWP_SHOWWINDOW;
  190. // if (windowFlags & BFWINDOW_SHOWMINIMIZED)
  191. // showFlags = SWP_
  192. mHasFocus = true;
  193. mSoftHasFocus = true;
  194. if (windowFlags & BFWINDOW_FAKEFOCUS)
  195. {
  196. showFlags |= SWP_NOACTIVATE;
  197. if (windowFlags & BFWINDOW_NO_ACTIVATE)
  198. {
  199. mHasFocus = false;
  200. mSoftHasFocus = false;
  201. }
  202. }
  203. else if (windowFlags & BFWINDOW_NO_ACTIVATE)
  204. {
  205. showFlags |= SWP_NOACTIVATE;
  206. mHasFocus = false;
  207. mSoftHasFocus = false;
  208. }
  209. if (windowFlags & (BFWINDOW_SHOWMINIMIZED | BFWINDOW_SHOWMAXIMIZED))
  210. {
  211. WINDOWPLACEMENT wndPlacement = { sizeof(WINDOWPLACEMENT), 0 };
  212. ::GetWindowPlacement(mHWnd, &wndPlacement);
  213. if (windowFlags & BFWINDOW_SHOWMINIMIZED)
  214. wndPlacement.showCmd = SW_SHOWMINIMIZED;
  215. else if (windowFlags & BFWINDOW_SHOWMAXIMIZED)
  216. wndPlacement.showCmd = SW_SHOWMAXIMIZED;
  217. else
  218. wndPlacement.showCmd = SW_SHOWNORMAL;
  219. wndPlacement.rcNormalPosition.left = x;
  220. wndPlacement.rcNormalPosition.top = y;
  221. wndPlacement.rcNormalPosition.right = x + width;
  222. wndPlacement.rcNormalPosition.bottom = y + height;
  223. ::SetWindowPlacement(mHWnd, &wndPlacement);
  224. }
  225. else
  226. {
  227. SetWindowPos(mHWnd, relativeWindow, x, y, width, height, showFlags);
  228. }
  229. SetTimer(mHWnd, 0, 10, NULL);
  230. mIsMouseInside = false;
  231. mRenderWindow = new DXRenderWindow((DXRenderDevice*) gBFApp->mRenderDevice, this, (windowFlags & BFWINDOW_FULLSCREEN) == 0);
  232. gBFApp->mRenderDevice->AddRenderWindow(mRenderWindow);
  233. SetWindowLongPtr(mHWnd, GWLP_USERDATA, (LONG_PTR)this);
  234. mIsMenuKeyHandled = false;
  235. mAlphaMaskBitmap = NULL;
  236. mAlphaMaskDC = NULL;
  237. mAlphaMaskPixels = NULL;
  238. mAlphaMaskWidth = 0;
  239. mAlphaMaskHeight = 0;
  240. mNeedsStateReset = false;
  241. mAwaitKeyReleases = false;
  242. mAwaitKeyReleasesEventTick = 0;
  243. mAwaitKeyReleasesCheckIdx = 0;
  244. mFocusLostTick = ::GetTickCount();
  245. if (windowFlags & BFWINDOW_DEST_ALPHA)
  246. {
  247. MARGINS dWMMargins = {-1, -1, -1, -1};
  248. DwmExtendFrameIntoClientArea(mHWnd, &dWMMargins);
  249. }
  250. if (windowFlags & BFWINDOW_MODAL)
  251. {
  252. EnableWindow(parentHWnd, FALSE);
  253. }
  254. if (parent != NULL)
  255. {
  256. auto winParent = (WinBFWindow*)parent;
  257. BF_ASSERT(winParent->mHWnd);
  258. parent->mChildren.push_back(this);
  259. }
  260. HKL layout = GetKeyboardLayout(0);
  261. mKeyLayoutHasAltGr = (KeyboardLayoutHasAltGr(layout) == TRUE);
  262. }
  263. WinBFWindow::~WinBFWindow()
  264. {
  265. for (auto child : mChildren)
  266. {
  267. NOP;
  268. }
  269. if (mHWnd != NULL)
  270. Destroy();
  271. }
  272. void* WinBFWindow::GetUnderlying()
  273. {
  274. return mHWnd;
  275. }
  276. void WinBFWindow::Destroy()
  277. {
  278. if (mAlphaMaskDC != NULL)
  279. DeleteDC(mAlphaMaskDC);
  280. mAlphaMaskDC = NULL;
  281. if (mAlphaMaskBitmap != NULL)
  282. DeleteObject(mAlphaMaskBitmap);
  283. mAlphaMaskBitmap = NULL;
  284. for (auto& menu : mMenuIDMap)
  285. {
  286. delete menu.mValue;
  287. }
  288. mMenuIDMap.Clear();
  289. ::DestroyWindow(mHWnd);
  290. BF_ASSERT(mHWnd == NULL);
  291. }
  292. bool WinBFWindow::TryClose()
  293. {
  294. SendMessage(mHWnd, WM_CLOSE, 0, 0);
  295. return mHWnd == NULL;
  296. }
  297. void WinBFWindow::SetTitle(const char* title)
  298. {
  299. SetWindowTextA(mHWnd, title);
  300. }
  301. void WinBFWindow::LostFocus(BFWindow* newFocus)
  302. {
  303. ///OutputDebugStrF("Lost focus\n");
  304. mFocusLostTick = ::GetTickCount();
  305. WinBFWindow* bfNewFocus = (WinBFWindow*)newFocus;
  306. mSoftHasFocus = false;
  307. for (int i = 0; i < KEYCODE_MAX; i++)
  308. {
  309. // Only transfer mode keys
  310. if (mIsKeyDown[i])
  311. {
  312. mIsKeyDown[i] = false;
  313. mKeyUpFunc(this, i);
  314. if ((newFocus != NULL) &&
  315. ((i == VK_SHIFT) || (i == VK_CONTROL) || (i == VK_MENU)))
  316. {
  317. newFocus->mIsKeyDown[i] = true;
  318. newFocus->mKeyDownFunc(newFocus, i, 0);
  319. }
  320. }
  321. }
  322. }
  323. void WinBFWindow::GotFocus()
  324. {
  325. DWORD tickNow = ::GetTickCount();
  326. //OutputDebugStrF("GotFocus since lost %d\n", tickNow - mFocusLostTick);
  327. if (tickNow - mFocusLostTick >= 1000)
  328. {
  329. mAwaitKeyReleases = true;
  330. mAwaitKeyReleasesCheckIdx = 0;
  331. mAwaitKeyReleasesEventTick = ::GetTickCount();
  332. }
  333. }
  334. void WinBFWindow::SetForeground()
  335. {
  336. bool hadFocus = mHasFocus;
  337. DWORD prevFocusLostTick = mFocusLostTick;
  338. if (mFlags & BFWINDOW_FAKEFOCUS)
  339. {
  340. mHasFocus = true;
  341. mSoftHasFocus = true;
  342. return;
  343. }
  344. ::SetFocus(mHWnd);
  345. ::SetForegroundWindow(mHWnd);
  346. //OutputDebugStrF("SetForeground %p %d %d %d\n", mHWnd, hadFocus, ::GetTickCount() - prevFocusLostTick, mAwaitKeyReleases);
  347. }
  348. static POINT gLastScreenMouseCoords = { -1, -1 };
  349. void WinBFWindow::RehupMouseOver(bool isMouseOver)
  350. {
  351. if ((!mIsMouseInside) && (isMouseOver))
  352. {
  353. TRACKMOUSEEVENT tme;
  354. tme.cbSize = sizeof(TRACKMOUSEEVENT);
  355. tme.dwFlags = TME_LEAVE;
  356. tme.hwndTrack = mHWnd;
  357. TrackMouseEvent(&tme);
  358. mIsMouseInside = true;
  359. }
  360. if ((mIsMouseInside) && (!isMouseOver))
  361. {
  362. mIsMouseInside = false;
  363. mMouseLeaveFunc(this);
  364. }
  365. }
  366. bool WinBFWindow::CheckKeyReleases(bool isKeyDown)
  367. {
  368. if (!mHasFocus)
  369. GotFocus();
  370. if (!mAwaitKeyReleases)
  371. return true;
  372. // Time expired with no key presses
  373. if ((mAwaitKeyReleasesEventTick != 0) && (mAwaitKeyReleasesCheckIdx == 0) && (::GetTickCount() - mAwaitKeyReleasesEventTick > 150))
  374. {
  375. //OutputDebugStrF("CheckKeyReleases no initial key press\n");
  376. mAwaitKeyReleases = false;
  377. return true;
  378. }
  379. mAwaitKeyReleasesCheckIdx++;
  380. bool hasKeyDown = false;
  381. uint8 keysDown[256] = { 0 };
  382. ::GetKeyboardState((PBYTE)&keysDown);
  383. for (int i = 1; i < 256; i++)
  384. if (keysDown[i] & 0x80)
  385. hasKeyDown = true;
  386. if ((hasKeyDown) && (::GetTickCount() - mAwaitKeyReleasesEventTick >= 600))
  387. {
  388. // String dbgStr = "CheckKeyReleases timeout. Keys down:";
  389. // for (int i = 1; i < 256; i++)
  390. // if (keysDown[i] & 0x80)
  391. // dbgStr += StrFormat(" %2X", i);
  392. // dbgStr += "\n";
  393. // OutputDebugStr(dbgStr);
  394. hasKeyDown = false;
  395. }
  396. if (!hasKeyDown)
  397. {
  398. mAwaitKeyReleases = false;
  399. mAwaitKeyReleasesCheckIdx = 0;
  400. mAwaitKeyReleasesEventTick = 0;
  401. }
  402. return !mAwaitKeyReleases;
  403. }
  404. LRESULT WinBFWindow::WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  405. {
  406. WinBFApp* app = (WinBFApp*) gBFApp;
  407. if (app == NULL)
  408. {
  409. PrintStuff();
  410. }
  411. switch (uMsg)
  412. {
  413. case WM_KEYDOWN:
  414. case WM_KEYUP:
  415. case WM_SYSKEYDOWN:
  416. case WM_CHAR:
  417. for (auto child : mChildren)
  418. {
  419. auto childWindow = (WinBFWindow*)child;
  420. if ((childWindow->mSoftHasFocus) && (childWindow->mFlags & BFWINDOW_FAKEFOCUS))
  421. {
  422. return childWindow->WindowProc(hWnd, uMsg, wParam, lParam);
  423. }
  424. }
  425. break;
  426. }
  427. switch (uMsg)
  428. {
  429. case WM_CLOSE:
  430. {
  431. //OutputDebugStrF("WM_CLOSE %08X NewFocus:%08X\n", hWnd, GetFocus());
  432. if (mCloseQueryFunc(this) != 0)
  433. gBFApp->RemoveWindow(this);
  434. HWND newFocus = GetFocus();
  435. for (auto window : gBFApp->mWindowList)
  436. {
  437. WinBFWindow* winWindow = (WinBFWindow*)window;
  438. if (winWindow->mHWnd == newFocus)
  439. {
  440. while (true)
  441. {
  442. WinBFWindow* altFocusWindow = NULL;
  443. for (auto checkChild : winWindow->mChildren)
  444. {
  445. auto checkWinChild = (WinBFWindow*)checkChild;
  446. if (checkWinChild->mFlags & BFWINDOW_FAKEFOCUS)
  447. altFocusWindow = checkWinChild;
  448. }
  449. if (altFocusWindow == NULL)
  450. break;
  451. winWindow = altFocusWindow;
  452. }
  453. winWindow->mHasFocus = true;
  454. winWindow->mSoftHasFocus = true;
  455. winWindow->mGotFocusFunc(winWindow);
  456. }
  457. }
  458. return 0;
  459. }
  460. break;
  461. case WM_DESTROY:
  462. /*if (mFlags & BFWINDOW_QUIT_ON_CLOSE)
  463. {
  464. gBFApp->mRunning = false;
  465. }*/
  466. SetWindowLongPtr(mHWnd, GWLP_USERDATA, (LONG_PTR)0);
  467. mHWnd = NULL;
  468. if (!mChildren.IsEmpty())
  469. {
  470. NOP;
  471. }
  472. break;
  473. }
  474. LRESULT result = 0;
  475. bool doResult = false;
  476. if (!app->mInMsgProc)
  477. {
  478. if (mNeedsStateReset)
  479. {
  480. for (int i = 0; i < KEYCODE_MAX; i++)
  481. {
  482. if (mIsKeyDown[i])
  483. {
  484. mIsKeyDown[i] = false;
  485. mKeyUpFunc(this, i);
  486. }
  487. }
  488. POINT mousePoint;
  489. ::GetCursorPos(&mousePoint);
  490. ::ScreenToClient(hWnd, &mousePoint);
  491. for (int i = 0; i < MOUSEBUTTON_MAX; i++)
  492. {
  493. if (mIsMouseDown[i])
  494. {
  495. mMouseUpFunc(this, mousePoint.x, mousePoint.y, i);
  496. mIsMouseDown[i] = false;
  497. }
  498. }
  499. //OutputDebugStrF("Rehup ReleaseCapture()\n");
  500. ReleaseCapture();
  501. mNeedsStateReset = false;
  502. mIsMouseInside = false;
  503. }
  504. WinBFWindow* menuTarget = this;
  505. if (mFlags & BFWINDOW_USE_PARENT_MENU)
  506. menuTarget = ((WinBFWindow*)mParent);
  507. auto* menuIDMap = &menuTarget->mMenuIDMap;
  508. auto* hMenuMap = &menuTarget->mHMenuMap;
  509. app->mInMsgProc = true;
  510. switch (uMsg)
  511. {
  512. case WM_SIZE:
  513. mRenderWindow->Resized();
  514. if (mMovedFunc != NULL)
  515. mMovedFunc(this);
  516. break;
  517. case WM_PAINT:
  518. break;
  519. case WM_NCHITTEST:
  520. {
  521. //OutputDebugStrF("WM_NCHITTEST %X\n", mHWnd);
  522. int x = (short)LOWORD(lParam);
  523. int y = (short)HIWORD(lParam);
  524. result = mHitTestFunc(this, x, y);
  525. doResult = (result != -3);
  526. }
  527. break;
  528. case WM_LBUTTONDOWN:
  529. case WM_RBUTTONDOWN:
  530. case WM_MBUTTONDOWN:
  531. case WM_XBUTTONDOWN:
  532. case WM_LBUTTONDBLCLK:
  533. case WM_RBUTTONDBLCLK:
  534. case WM_LBUTTONUP:
  535. case WM_RBUTTONUP:
  536. case WM_MBUTTONUP:
  537. case WM_XBUTTONUP:
  538. case WM_MOUSEWHEEL:
  539. case WM_MOUSEHWHEEL:
  540. case WM_MOUSEMOVE:
  541. {
  542. int x = (short)LOWORD(lParam);
  543. int y = (short)HIWORD(lParam);
  544. bool releaseCapture = false;
  545. POINT point = {x, y};
  546. if ((uMsg != WM_MOUSEWHEEL) && (uMsg != WM_MOUSEHWHEEL))
  547. ::ClientToScreen(hWnd, &point);
  548. if ((uMsg == WM_MOUSEMOVE) && (point.x == gLastScreenMouseCoords.x) && (point.y == gLastScreenMouseCoords.y))
  549. {
  550. // Don't process a WM_MOUSEMOVE if it's at the same point at the last mouse event
  551. // This keeps us from getting a WM_MOUSEMOVE when we popup a window under the current cursor location.
  552. // This is important for keyboard cursor control - so the first down arrow keypress selects the first item in the list
  553. // irregardless of the mouse cursor position.
  554. break;
  555. }
  556. gLastScreenMouseCoords.x = point.x;
  557. gLastScreenMouseCoords.y = point.y;
  558. HWND windowAtPoint = ::WindowFromPoint(point);
  559. bool isMouseOver = windowAtPoint == hWnd;
  560. RehupMouseOver(isMouseOver);
  561. //OutputDebugStrF("HWnd: %X Focus Window: %X Capture: %X\n", hWnd, windowAtPoint, ::GetCapture());
  562. bool checkNonTransparentMousePosition = mNonExclusiveMouseCapture;
  563. auto _BtnDown = [&](int btn)
  564. {
  565. BF_ASSERT(btn < MOUSEBUTTON_MAX);
  566. if (btn >= MOUSEBUTTON_MAX)
  567. return;
  568. DWORD tickNow = BFTickCount();
  569. SetCapture(hWnd);
  570. mIsMouseDown[btn] = true;
  571. BFCoord mouseCoords = { x, y };
  572. if ((mouseCoords.mX != mMouseDownCoords[btn].mX) || (mouseCoords.mY != mMouseDownCoords[btn].mY) ||
  573. (tickNow - mMouseDownTicks[btn] > ::GetDoubleClickTime()))
  574. mMouseClickCount[btn] = 0;
  575. mMouseDownCoords[btn] = mouseCoords;
  576. mMouseClickCount[btn]++;
  577. mMouseDownTicks[btn] = tickNow;
  578. mMouseDownFunc(this, x, y, btn, mMouseClickCount[btn]);
  579. };
  580. auto _BtnUp = [&](int btn)
  581. {
  582. BF_ASSERT(btn < MOUSEBUTTON_MAX);
  583. if (btn >= MOUSEBUTTON_MAX)
  584. return;
  585. releaseCapture = true;
  586. mIsMouseDown[btn] = false;
  587. mMouseUpFunc(this, x, y, btn);
  588. };
  589. switch (uMsg)
  590. {
  591. case WM_LBUTTONDOWN:
  592. //OutputDebugStrF("WM_LBUTTONDOWN Capture HWnd: %X\n", hWnd);
  593. _BtnDown(0);
  594. break;
  595. case WM_RBUTTONDOWN:
  596. //OutputDebugStrF("WM_RBUTTONDOWN Capture HWnd: %X\n", hWnd);
  597. _BtnDown(1);
  598. break;
  599. case WM_MBUTTONDOWN:
  600. _BtnDown(2);
  601. break;
  602. case WM_XBUTTONDOWN:
  603. _BtnDown((int)(wParam >> 16) + 2);
  604. break;
  605. case WM_LBUTTONUP:
  606. _BtnUp(0);
  607. break;
  608. case WM_RBUTTONUP:
  609. _BtnUp(1);
  610. break;
  611. case WM_MBUTTONUP:
  612. _BtnUp(2);
  613. break;
  614. case WM_XBUTTONUP:
  615. _BtnUp((int)(wParam >> 16) + 2);
  616. break;
  617. case WM_MOUSEWHEEL:
  618. case WM_MOUSEHWHEEL:
  619. {
  620. WinBFWindow* cursorWindow = this;
  621. if ((gBFApp->mWindowList.size() > 1) && (GetCapture() == NULL))
  622. {
  623. // See if our mouse is down and has entered into another window's space
  624. POINT point = { x, y };
  625. HWND windowAtPoint = ::WindowFromPoint(point);
  626. BFWindowList::iterator itr = gBFApp->mWindowList.begin();
  627. while (itr != gBFApp->mWindowList.end())
  628. {
  629. WinBFWindow* aWindow = (WinBFWindow*) *itr;
  630. LONG targetStyle = ::GetWindowLong(aWindow->mHWnd, GWL_EXSTYLE);
  631. if ((::IsWindowEnabled(aWindow->mHWnd)) && ((targetStyle & WS_EX_TRANSPARENT) == 0))
  632. {
  633. if (aWindow->mHWnd == windowAtPoint)
  634. {
  635. aWindow->mIsMouseInside = true;
  636. cursorWindow = aWindow;
  637. }
  638. }
  639. ++itr;
  640. }
  641. }
  642. UINT ucNumLines = 0;
  643. SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &ucNumLines, 0);
  644. if (ucNumLines == 0)
  645. ucNumLines = 3; // Default
  646. if ((cursorWindow != this) && (mIsMouseInside))
  647. {
  648. mMouseLeaveFunc(this);
  649. mIsMouseInside = false;
  650. }
  651. POINT pt = {x, y};
  652. ScreenToClient(cursorWindow->mHWnd, &pt);
  653. if (uMsg == WM_MOUSEWHEEL)
  654. {
  655. float delta = ((int16)HIWORD(wParam)) / 120.0f * (float)ucNumLines;
  656. mMouseWheelFunc(cursorWindow, pt.x, pt.y, 0, delta);
  657. }
  658. else
  659. {
  660. float delta = ((int16)HIWORD(wParam)) / 120.0f;
  661. mMouseWheelFunc(cursorWindow, pt.x, pt.y, delta, 0);
  662. }
  663. }
  664. break;
  665. case WM_MOUSEMOVE:
  666. {
  667. //OutputDebugStrF("WM_MOUSEMOVE %d\n", hWnd);
  668. mMouseMoveFunc(this, x, y);
  669. // If we are dragging a transparent window then check for mouse positions under cursor
  670. HWND captureWindow = GetCapture();
  671. if (captureWindow != NULL)
  672. {
  673. LONG captureStyle = ::GetWindowLong(captureWindow, GWL_EXSTYLE);
  674. if ((captureStyle & WS_EX_TRANSPARENT) != 0)
  675. checkNonTransparentMousePosition = true;
  676. }
  677. }
  678. break;
  679. }
  680. if ((checkNonTransparentMousePosition) && (gBFApp->mWindowList.size() > 1))
  681. {
  682. // See if our mouse is down and has entered into another window's space
  683. POINT point = { x, y };
  684. ::ClientToScreen(hWnd, &point);
  685. HWND windowAtPoint = ::WindowFromPoint(point);
  686. BFWindowList::iterator itr = gBFApp->mWindowList.begin();
  687. while (itr != gBFApp->mWindowList.end())
  688. {
  689. WinBFWindow* aWindow = (WinBFWindow*) *itr;
  690. if (aWindow != this)
  691. {
  692. LONG myStyle = ::GetWindowLong(mHWnd, GWL_EXSTYLE);
  693. LONG targetStyle = ::GetWindowLong(aWindow->mHWnd, GWL_EXSTYLE);
  694. if ((targetStyle & WS_EX_TRANSPARENT) == 0)
  695. {
  696. if (aWindow->mHWnd == windowAtPoint)
  697. {
  698. POINT clientPt = point;
  699. ::ScreenToClient(aWindow->mHWnd, &clientPt);
  700. aWindow->mMouseProxyMoveFunc(aWindow, clientPt.x, clientPt.y);
  701. aWindow->mIsMouseInside = true;
  702. }
  703. else if (aWindow->mIsMouseInside)
  704. {
  705. aWindow->mMouseLeaveFunc(aWindow);
  706. aWindow->mIsMouseInside = false;
  707. }
  708. }
  709. }
  710. ++itr;
  711. }
  712. }
  713. if (releaseCapture)
  714. {
  715. for (int i = 0; i < MOUSEBUTTON_MAX; i++)
  716. if (mIsMouseDown[i])
  717. releaseCapture = false;
  718. }
  719. if (releaseCapture)
  720. {
  721. //OutputDebugStrF("ReleaseCapture\n");
  722. ReleaseCapture();
  723. BFWindowList::iterator itr = gBFApp->mWindowList.begin();
  724. while (itr != gBFApp->mWindowList.end())
  725. {
  726. WinBFWindow* aWindow = (WinBFWindow*) *itr;
  727. if ((aWindow != this) && (aWindow->mIsMouseInside))
  728. {
  729. aWindow->mMouseLeaveFunc(aWindow);
  730. aWindow->mIsMouseInside = false;
  731. }
  732. ++itr;
  733. }
  734. }
  735. }
  736. break;
  737. case WM_COMMAND:
  738. {
  739. WinBFMenu* aMenu = (*menuIDMap)[(uint32)wParam];
  740. if (aMenu != NULL)
  741. menuTarget->mMenuItemSelectedFunc(menuTarget, aMenu);
  742. }
  743. break;
  744. case WM_APPCOMMAND:
  745. {
  746. if ((mFlags & BFWINDOW_CAPTURE_MEDIA_KEYS) != 0)
  747. {
  748. int cmd = GET_APPCOMMAND_LPARAM(lParam);
  749. int uDevice = GET_DEVICE_LPARAM(lParam);
  750. int dwKeys = GET_KEYSTATE_LPARAM(lParam);
  751. int key = cmd | 0x1000;
  752. mKeyDownFunc(this, key, false);
  753. result = TRUE;
  754. doResult = true;
  755. }
  756. }
  757. break;
  758. case WM_INITMENUPOPUP:
  759. {
  760. if (mIsKeyDown[VK_MENU])
  761. {
  762. mKeyUpFunc(this, (int)VK_MENU);
  763. mIsKeyDown[VK_MENU] = false;
  764. }
  765. HMENU hMenu = (HMENU) wParam;
  766. WinBFMenu* aMenu = (*hMenuMap)[hMenu];
  767. if (aMenu != NULL)
  768. menuTarget->mMenuItemSelectedFunc(menuTarget, aMenu);
  769. }
  770. break;
  771. case WM_MOUSEACTIVATE:
  772. if (mFlags & BFWINDOW_NO_MOUSE_ACTIVATE)
  773. {
  774. doResult = true;
  775. result = MA_NOACTIVATE;
  776. }
  777. else if (mFlags & BFWINDOW_FAKEFOCUS)
  778. {
  779. doResult = true;
  780. result = MA_NOACTIVATE;
  781. SetForeground();
  782. }
  783. break;
  784. case WM_ACTIVATE:
  785. //OutputDebugStrF("WM_ACTIVATE %p\n", hWnd);
  786. break;
  787. case WM_KILLFOCUS:
  788. //OutputDebugStrF("WM_KILLFOCUS %p\n", hWnd);
  789. mHasFocus = false;
  790. mSoftHasFocus = false;
  791. LostFocus(NULL);
  792. mLostFocusFunc(this);
  793. break;
  794. case WM_SETFOCUS:
  795. //OutputDebugStrF("WM_SETFOCUS %p\n", hWnd);
  796. if (!mHasFocus)
  797. GotFocus();
  798. mHasFocus = true;
  799. mSoftHasFocus = true;
  800. mGotFocusFunc(this);
  801. break;
  802. case WM_ENTERMENULOOP:
  803. //OutputDebugStrF("WM_ENTERMENULOOP %08X\n", hWnd);
  804. if (mMenu != NULL)
  805. mNeedsStateReset = true;
  806. break;
  807. case WM_EXITMENULOOP:
  808. //OutputDebugStrF("WM_EXITMENULOOP %08X\n", hWnd);
  809. if (mMenu != NULL)
  810. mNeedsStateReset = true;
  811. break;
  812. case WM_NCMOUSELEAVE:
  813. mIsMouseInside = false;
  814. mMouseLeaveFunc(this);
  815. break;
  816. case WM_CHAR:
  817. {
  818. /*if (wParam == 'z')
  819. {
  820. ID3D11Debug* pD3DDebug = NULL;
  821. HRESULT hr = ((DXRenderDevice*)mRenderWindow->mRenderDevice)->mD3DDevice->QueryInterface(__uuidof(ID3D11Debug), (void**)&pD3DDebug);
  822. if (pD3DDebug != NULL)
  823. {
  824. pD3DDebug->ReportLiveDeviceObjects(D3D11_RLDO_DETAIL);
  825. pD3DDebug->Release();
  826. }
  827. }*/
  828. //NOTE: This line broke Alt+Gr for braces and such. Determine why this was needed.
  829. //if ((!mIsKeyDown[VK_MENU]) && (!mIsKeyDown[VK_CONTROL]))
  830. if (CheckKeyReleases(true))
  831. {
  832. for (int i = 0; i < (lParam & 0x7FFF); i++)
  833. mKeyCharFunc(this, (WCHAR)wParam);
  834. }
  835. }
  836. break;
  837. case WM_MENUCHAR:
  838. if (mIsMenuKeyHandled)
  839. {
  840. result = MNC_CLOSE << 16;
  841. doResult = true;
  842. }
  843. break;
  844. case WM_SYSKEYDOWN:
  845. case WM_KEYDOWN:
  846. {
  847. mIsMenuKeyHandled = false;
  848. int keyCode = (int) wParam;
  849. if (keyCode == VK_APPS)
  850. break; // This is handled in WM_CONTEXTMENU
  851. if ((mKeyLayoutHasAltGr) && (keyCode == VK_MENU) && ((lParam & 0x01000000) != 0))
  852. keyCode = VK_RMENU;
  853. mIsKeyDown[keyCode] = true;
  854. for (auto kv : *menuIDMap)
  855. {
  856. WinBFMenu* aMenu = kv.mValue;
  857. if ((aMenu->mKeyCode == keyCode) &&
  858. (aMenu->mKeyShift == mIsKeyDown[VK_SHIFT]) &&
  859. (aMenu->mKeyCtrl == mIsKeyDown[VK_CONTROL]) &&
  860. (aMenu->mKeyAlt == mIsKeyDown[VK_MENU]))
  861. {
  862. mIsMenuKeyHandled = true;
  863. menuTarget->mMenuItemSelectedFunc(menuTarget, aMenu);
  864. doResult = true;
  865. break;
  866. }
  867. }
  868. if (!mIsMenuKeyHandled)
  869. {
  870. if ((CheckKeyReleases(true)) && (mKeyDownFunc(this, keyCode, (lParam & 0x7FFF) != 0)))
  871. {
  872. mIsMenuKeyHandled = true;
  873. doResult = true;
  874. }
  875. }
  876. }
  877. break;
  878. case WM_SYSCHAR:
  879. {
  880. int keyCode = toupper((int) wParam);
  881. for (auto& menuKV : *menuIDMap)
  882. {
  883. WinBFMenu* aMenu = menuKV.mValue;
  884. if ((aMenu->mKeyCode == keyCode) &&
  885. (aMenu->mKeyShift == mIsKeyDown[VK_SHIFT]) &&
  886. (aMenu->mKeyCtrl == mIsKeyDown[VK_CONTROL]) &&
  887. (aMenu->mKeyAlt == mIsKeyDown[VK_MENU]))
  888. {
  889. if (CheckKeyReleases(true))
  890. doResult = true;
  891. break;
  892. }
  893. }
  894. if (!mIsKeyDown[VK_MENU])
  895. {
  896. // If we don't have the alt key down then we assume we must have
  897. // had keyups forced by losing focus from the mMenuItemSelectedFunc
  898. doResult = true;
  899. }
  900. }
  901. break;
  902. case WM_SYSKEYUP:
  903. case WM_KEYUP:
  904. {
  905. int keyCode = (int) wParam;
  906. if ((mKeyLayoutHasAltGr) && (keyCode == VK_MENU) && ((lParam & 0x01000000) != 0))
  907. keyCode = VK_RMENU;
  908. if (mIsKeyDown[keyCode])
  909. {
  910. mKeyUpFunc(this, keyCode);
  911. mIsKeyDown[keyCode] = false;
  912. }
  913. CheckKeyReleases(false);
  914. }
  915. break;
  916. case WM_SYSCOMMAND:
  917. // Ignore F10
  918. if ((wParam == SC_KEYMENU) && (lParam == 0))
  919. {
  920. doResult = true;
  921. result = 0;
  922. }
  923. break;
  924. case WM_CONTEXTMENU:
  925. {
  926. int x = (short)LOWORD(lParam);
  927. int y = (short)HIWORD(lParam);
  928. if ((x == -1) && (y == -1))
  929. {
  930. mKeyDownFunc(this, VK_APPS, false);
  931. mKeyUpFunc(this, VK_APPS);
  932. }
  933. }
  934. break;
  935. case WM_TIMER:
  936. if (gBFApp->mSysDialogCnt == 0)
  937. {
  938. auto checkNonFake = this;
  939. while (checkNonFake->mFlags & BFWINDOW_FAKEFOCUS)
  940. {
  941. checkNonFake = (WinBFWindow*)checkNonFake->mParent;
  942. }
  943. bool isFocused = GetForegroundWindow() == checkNonFake->mHWnd;
  944. if ((!isFocused) && (mHasFocus))
  945. {
  946. mSoftHasFocus = false;
  947. mHasFocus = false;
  948. LostFocus(NULL);
  949. mLostFocusFunc(this);
  950. //OutputDebugStrF("Timer detected lost focus %p\r\n", hWnd);
  951. }
  952. else if ((isFocused) && (!mHasFocus) && (checkNonFake == this))
  953. {
  954. //OutputDebugStrF("Timer detected got focus %p\r\n", hWnd);
  955. GotFocus();
  956. mHasFocus = true;
  957. mSoftHasFocus = true;
  958. mGotFocusFunc(this);
  959. }
  960. mSoftHasFocus = mHasFocus;
  961. gBFApp->Process();
  962. // Don't do anything with 'this' after Process, we may be deleted now
  963. doResult = true;
  964. result = 0;
  965. }
  966. break;
  967. case WM_SETCURSOR:
  968. gBFApp->PhysSetCursor();
  969. break;
  970. case WM_GETMINMAXINFO:
  971. {
  972. MINMAXINFO* minMaxInfo = (MINMAXINFO*)lParam;
  973. minMaxInfo->ptMinTrackSize.x = mMinWidth;
  974. minMaxInfo->ptMinTrackSize.y = mMinHeight;
  975. result = 0;
  976. doResult = true;
  977. }
  978. break;
  979. case WM_MOVE:
  980. case WM_MOVING:
  981. if (mMovedFunc != NULL)
  982. mMovedFunc(this);
  983. break;
  984. case WM_SIZING:
  985. mRenderWindow->Resized();
  986. if (mMovedFunc != NULL)
  987. mMovedFunc(this);
  988. if (gBFApp->mSysDialogCnt == 0)
  989. gBFApp->Process();
  990. break;
  991. case WM_INPUTLANGCHANGE:
  992. mKeyLayoutHasAltGr = (KeyboardLayoutHasAltGr((HKL)lParam) == TRUE);
  993. break;
  994. case WM_DROPFILES:
  995. {
  996. HDROP hDropInfo = (HDROP)wParam;
  997. char sItem[MAX_PATH];
  998. for(int i = 0; DragQueryFileA(hDropInfo, i, (LPSTR)sItem, sizeof(sItem)); i++)
  999. mDragDropFileFunc(this, sItem);
  1000. DragFinish(hDropInfo);
  1001. }
  1002. break;
  1003. }
  1004. app->mInMsgProc = false;
  1005. }
  1006. else
  1007. {
  1008. // We got messages we couldn't process (due to reentrancy)
  1009. switch (uMsg)
  1010. {
  1011. case WM_LBUTTONUP:
  1012. case WM_RBUTTONUP:
  1013. case WM_MBUTTONUP:
  1014. case WM_MOUSEMOVE:
  1015. case WM_KEYUP:
  1016. case WM_MOUSELEAVE:
  1017. mNeedsStateReset = true;
  1018. break;
  1019. }
  1020. }
  1021. if (doResult)
  1022. return result;
  1023. return DefWindowProc(hWnd, uMsg, wParam, lParam);
  1024. }
  1025. LRESULT CALLBACK WinBFWindow::WindowProcStub(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
  1026. {
  1027. WinBFWindow* aWindow = (WinBFWindow*) GetWindowLongPtr(hWnd, GWLP_USERDATA);
  1028. if (aWindow != NULL)
  1029. return aWindow->WindowProc(hWnd, Msg, wParam, lParam);
  1030. else
  1031. return DefWindowProc(hWnd, Msg, wParam, lParam);
  1032. }
  1033. //
  1034. static int WinBFReportHook( int reportType, char *message, int *returnValue )
  1035. {
  1036. if (reportType == 0)
  1037. return 0;
  1038. //__crtMessageWindowW(nRptType, szFile, (nLine ? szLineMessage : NULL), szModule, szUserMessage);;
  1039. if (gBFApp)
  1040. ((WinBFApp*) gBFApp)->mInMsgProc = true;
  1041. int nCode = ::MessageBoxA(NULL, message,
  1042. "Microsoft Visual C++ Debug Library",
  1043. MB_TASKMODAL|MB_ICONHAND|MB_ABORTRETRYIGNORE|MB_SETFOREGROUND);
  1044. if (gBFApp)
  1045. ((WinBFApp*) gBFApp)->mInMsgProc = false;
  1046. /* Abort: abort the program */
  1047. if (IDABORT == nCode)
  1048. {
  1049. /* note that it is better NOT to call abort() here, because the
  1050. * default implementation of abort() will call Watson
  1051. */
  1052. /* raise abort signal */
  1053. raise(SIGABRT);
  1054. /* We usually won't get here, but it's possible that
  1055. SIGABRT was ignored. So exit the program anyway. */
  1056. _exit(3);
  1057. }
  1058. /* Retry: return 1 to call the debugger */
  1059. if (IDRETRY == nCode)
  1060. return 1;
  1061. /* Ignore: continue execution */
  1062. return 0;
  1063. return 1;
  1064. }
  1065. extern HINSTANCE gDLLInstance;
  1066. typedef UINT(NTAPI *GetDpiForWindow_t)(HWND);
  1067. static GetDpiForWindow_t gGetDpiForWindow = NULL;
  1068. static HMODULE gUserDll = NULL;
  1069. WinBFApp::WinBFApp()
  1070. {
  1071. #ifndef BF_MINGW
  1072. //_CrtSetReportHook(WinBFReportHook);
  1073. #endif
  1074. if (gUserDll == NULL)
  1075. {
  1076. gUserDll = ::LoadLibraryA("user32.dll");
  1077. gGetDpiForWindow = (GetDpiForWindow_t)::GetProcAddress(gUserDll, "GetDpiForWindow");
  1078. }
  1079. mRunning = false;
  1080. mRenderDevice = NULL;
  1081. mInstallDir = "Hey";
  1082. WCHAR aStr[MAX_PATH];
  1083. GetModuleFileNameW(gDLLInstance, aStr, MAX_PATH);
  1084. mInstallDir = UTF8Encode(aStr);
  1085. int a2DArray[3][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};
  1086. int lastSlash = (int) mInstallDir.LastIndexOf(L'\\');
  1087. if (lastSlash != -1)
  1088. mInstallDir = mInstallDir.Substring(0, lastSlash + 1);
  1089. mDataDir = mInstallDir;
  1090. mInMsgProc = false;
  1091. mDSoundManager = NULL;
  1092. mDInputManager = NULL;
  1093. }
  1094. WinBFApp::~WinBFApp()
  1095. {
  1096. delete mRenderDevice;
  1097. delete mDSoundManager;
  1098. delete mDInputManager;
  1099. }
  1100. void WinBFApp::Init()
  1101. {
  1102. BP_ZONE("WinBFApp::Init");
  1103. mRunning = true;
  1104. mInMsgProc = false;
  1105. mRenderDevice = new DXRenderDevice();
  1106. mRenderDevice->Init(this);
  1107. }
  1108. void WinBFApp::Run()
  1109. {
  1110. MSG msg;
  1111. while (mRunning)
  1112. {
  1113. while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  1114. {
  1115. TranslateMessage(&msg);
  1116. DispatchMessage(&msg);
  1117. }
  1118. if (mRunning)
  1119. Process();
  1120. }
  1121. }
  1122. void WinBFApp::Draw()
  1123. {
  1124. mRenderDevice->FrameStart();
  1125. BFApp::Draw();
  1126. mRenderDevice->FrameEnd();
  1127. }
  1128. void WinBFApp::GetDesktopResolution(int& width, int& height)
  1129. {
  1130. width = ::GetSystemMetrics(SM_CXSCREEN);
  1131. height = ::GetSystemMetrics(SM_CYSCREEN);
  1132. }
  1133. static BOOL InflateRectToMonitor(HMONITOR mon, HDC hdc, LPRECT monRect, LPARAM userArg)
  1134. {
  1135. AdjustedMonRect* inflatedRect = (AdjustedMonRect*)userArg;
  1136. MONITORINFO monitorInfo = { sizeof(MONITORINFO) };
  1137. if (::GetMonitorInfo(mon, &monitorInfo) == 0)
  1138. return TRUE;
  1139. inflatedRect->mMonCount++;
  1140. if (inflatedRect->mMonCount == 1)
  1141. {
  1142. inflatedRect->mX = monitorInfo.rcWork.left;
  1143. inflatedRect->mY = monitorInfo.rcWork.top;
  1144. inflatedRect->mWidth = monitorInfo.rcWork.right - monitorInfo.rcWork.left;
  1145. inflatedRect->mHeight = monitorInfo.rcWork.bottom - monitorInfo.rcWork.top;
  1146. }
  1147. else
  1148. {
  1149. int minLeft = BF_MIN(inflatedRect->mX, monitorInfo.rcWork.left);
  1150. int minTop = BF_MIN(inflatedRect->mY, monitorInfo.rcWork.top);
  1151. int maxRight = BF_MAX(inflatedRect->mX + inflatedRect->mWidth, monitorInfo.rcWork.right);
  1152. int maxBottom = BF_MAX(inflatedRect->mY + inflatedRect->mHeight, monitorInfo.rcWork.bottom);
  1153. inflatedRect->mX = minLeft;
  1154. inflatedRect->mY = minTop;
  1155. inflatedRect->mWidth = maxRight - minLeft;
  1156. inflatedRect->mHeight = maxBottom - minTop;
  1157. }
  1158. return TRUE;
  1159. }
  1160. void WinBFApp::GetWorkspaceRect(int& x, int& y, int& width, int& height)
  1161. {
  1162. AdjustedMonRect inflateRect = { 0 };
  1163. EnumDisplayMonitors(NULL, NULL, InflateRectToMonitor, (LPARAM)&inflateRect);
  1164. x = inflateRect.mX;
  1165. y = inflateRect.mY;
  1166. width = inflateRect.mWidth;
  1167. height = inflateRect.mHeight;
  1168. }
  1169. void WinBFApp::GetWorkspaceRectFrom(int fromX, int fromY, int fromWidth, int fromHeight, int & outX, int & outY, int & outWidth, int & outHeight)
  1170. {
  1171. AdjustedMonRect inflateRect = { 0 };
  1172. RECT wantRect;
  1173. wantRect.left = fromX;
  1174. wantRect.top = fromY;
  1175. wantRect.right = fromX + BF_MAX(fromWidth, 1);
  1176. wantRect.bottom = fromY + BF_MAX(fromHeight, 1);
  1177. EnumDisplayMonitors(NULL, &wantRect, InflateRectToMonitor, (LPARAM)&inflateRect);
  1178. if (inflateRect.mMonCount == 0)
  1179. {
  1180. GetWorkspaceRect(outX, outY, outWidth, outHeight);
  1181. return;
  1182. }
  1183. outX = inflateRect.mX;
  1184. outY = inflateRect.mY;
  1185. outWidth = inflateRect.mWidth;
  1186. outHeight = inflateRect.mHeight;
  1187. }
  1188. BFWindow* WinBFApp::CreateNewWindow(BFWindow* parent, const StringImpl& title, int x, int y, int width, int height, int windowFlags)
  1189. {
  1190. BFWindow* aWindow = new WinBFWindow(parent, title, x, y, width, height, windowFlags);
  1191. mWindowList.push_back(aWindow);
  1192. return aWindow;
  1193. }
  1194. void WinBFApp::RehupMouse()
  1195. {
  1196. HWND windowAtPoint = ::WindowFromPoint(gLastScreenMouseCoords);
  1197. for (auto window : mWindowList)
  1198. {
  1199. auto winWindow = (WinBFWindow*)window;
  1200. winWindow->RehupMouseOver(winWindow->mHWnd == windowAtPoint);
  1201. }
  1202. }
  1203. String WinBFApp::EnumerateInputDevices()
  1204. {
  1205. if (mDInputManager == NULL)
  1206. mDInputManager = new DInputManager();
  1207. return mDInputManager->EnumerateDevices();
  1208. }
  1209. BFInputDevice* WinBFApp::CreateInputDevice(const StringImpl& guid)
  1210. {
  1211. if (mDInputManager == NULL)
  1212. mDInputManager = new DInputManager();
  1213. return mDInputManager->CreateInputDevice(guid);
  1214. }
  1215. void WinBFWindow::SetMinimumSize(int minWidth, int minHeight, bool clientSized)
  1216. {
  1217. if (clientSized)
  1218. {
  1219. DWORD windowFlags = ::GetWindowLong(mHWnd, GWL_STYLE);
  1220. DWORD windowFlagsEx = ::GetWindowLong(mHWnd, GWL_EXSTYLE);
  1221. RECT rect = { 0, 0, minWidth, minHeight };
  1222. AdjustWindowRectEx(&rect, windowFlags, mMenu != NULL, windowFlagsEx);
  1223. minWidth = rect.right - rect.left;
  1224. minHeight = rect.bottom - rect.top;
  1225. }
  1226. mMinWidth = minWidth;
  1227. mMinHeight = minHeight;
  1228. if (mHWnd != NULL)
  1229. {
  1230. RECT windowRect;
  1231. ::GetWindowRect(mHWnd, &windowRect);
  1232. bool resized = false;
  1233. if (windowRect.right - windowRect.left < minWidth)
  1234. {
  1235. windowRect.right = windowRect.left + minWidth;
  1236. resized = true;
  1237. }
  1238. if (windowRect.bottom - windowRect.top < minHeight)
  1239. {
  1240. windowRect.bottom = windowRect.top + minHeight;
  1241. resized = true;
  1242. }
  1243. if (resized)
  1244. {
  1245. ::MoveWindow(mHWnd, windowRect.left, windowRect.top, windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, TRUE);
  1246. mRenderWindow->Resized();
  1247. if (mMovedFunc != NULL)
  1248. mMovedFunc(this);
  1249. }
  1250. }
  1251. }
  1252. void WinBFWindow::GetPosition(int* x, int* y, int* width, int* height, int* clientX, int* clientY, int* clientWidth, int* clientHeight)
  1253. {
  1254. RECT windowRect;
  1255. ::GetWindowRect(mHWnd, &windowRect);
  1256. RECT clientRect;
  1257. ::GetClientRect(mHWnd, &clientRect);
  1258. if (clientRect.right <= clientRect.left)
  1259. return; // TODO: return failure?
  1260. *x = windowRect.left;
  1261. *y = windowRect.top;
  1262. *width = windowRect.right - windowRect.left;
  1263. *height = windowRect.bottom - windowRect.top;
  1264. *clientWidth = clientRect.right - clientRect.left;
  1265. *clientHeight = clientRect.bottom - clientRect.top;
  1266. POINT startPt = {0, 0};
  1267. ::ClientToScreen(mHWnd, &startPt);
  1268. *clientX = startPt.x;
  1269. *clientY = startPt.y;
  1270. }
  1271. void WinBFWindow::GetPlacement(int* normX, int* normY, int* normWidth, int* normHeight, int* showKind)
  1272. {
  1273. WINDOWPLACEMENT wndPlacement = { sizeof(WINDOWPLACEMENT), 0 };
  1274. ::GetWindowPlacement(mHWnd, &wndPlacement);
  1275. *normX = wndPlacement.rcNormalPosition.left;
  1276. *normY = wndPlacement.rcNormalPosition.top;
  1277. *normWidth = wndPlacement.rcNormalPosition.right - wndPlacement.rcNormalPosition.left;
  1278. *normHeight = wndPlacement.rcNormalPosition.bottom - wndPlacement.rcNormalPosition.top;
  1279. switch (wndPlacement.showCmd)
  1280. {
  1281. case SW_SHOWMINIMIZED:
  1282. *showKind = 1;
  1283. break;
  1284. case SW_SHOWMAXIMIZED:
  1285. *showKind = 2;
  1286. break;
  1287. default:
  1288. *showKind = 0;
  1289. break;
  1290. }
  1291. }
  1292. void WinBFWindow::Resize(int x, int y, int width, int height, int showKind)
  1293. {
  1294. WINDOWPLACEMENT wndPlacement = { sizeof(WINDOWPLACEMENT), 0 };
  1295. ::GetWindowPlacement(mHWnd, &wndPlacement);
  1296. switch (showKind)
  1297. {
  1298. case 1:
  1299. wndPlacement.showCmd = SW_SHOWMINIMIZED;
  1300. break;
  1301. case 2:
  1302. wndPlacement.showCmd = SW_SHOWMAXIMIZED;
  1303. break;
  1304. case 3:
  1305. wndPlacement.showCmd = SW_SHOWNORMAL;
  1306. break;
  1307. }
  1308. wndPlacement.rcNormalPosition.left = x;
  1309. wndPlacement.rcNormalPosition.top = y;
  1310. wndPlacement.rcNormalPosition.right = x + width;
  1311. wndPlacement.rcNormalPosition.bottom = y + height;
  1312. ::SetWindowPlacement(mHWnd, &wndPlacement);
  1313. //::MoveWindow(mHWnd, x, y, width, height, FALSE);
  1314. mRenderWindow->Resized();
  1315. if (mMovedFunc != NULL)
  1316. mMovedFunc(this);
  1317. }
  1318. void WinBFApp::PhysSetCursor()
  1319. {
  1320. static HCURSOR cursors [] =
  1321. {
  1322. ::LoadCursor(NULL, IDC_ARROW),
  1323. //TODO: mApp->mHandCursor);
  1324. ::LoadCursor(NULL, IDC_HAND),
  1325. //TODO: mApp->mDraggingCursor);
  1326. ::LoadCursor(NULL, IDC_SIZEALL),
  1327. ::LoadCursor(NULL, IDC_IBEAM),
  1328. ::LoadCursor(NULL, IDC_NO),
  1329. ::LoadCursor(NULL, IDC_SIZEALL),
  1330. ::LoadCursor(NULL, IDC_SIZENESW),
  1331. ::LoadCursor(NULL, IDC_SIZENS),
  1332. ::LoadCursor(NULL, IDC_SIZENWSE),
  1333. ::LoadCursor(NULL, IDC_SIZEWE),
  1334. ::LoadCursor(NULL, IDC_WAIT),
  1335. NULL
  1336. };
  1337. ::SetCursor(cursors[mCursor]);
  1338. }
  1339. void WinBFWindow::SetClientPosition(int x, int y)
  1340. {
  1341. RECT rect;
  1342. ::GetClientRect(mHWnd, &rect);
  1343. ::OffsetRect(&rect, x, y);
  1344. LONG aStyle = ::GetWindowLong(mHWnd, GWL_STYLE);
  1345. LONG exStyle = ::GetWindowLong(mHWnd, GWL_EXSTYLE);
  1346. ::AdjustWindowRectEx(&rect, aStyle, mMenu != NULL, exStyle);
  1347. ::MoveWindow(mHWnd, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, FALSE);
  1348. if (mMovedFunc != NULL)
  1349. mMovedFunc(this);
  1350. }
  1351. void WinBFWindow::SetMouseVisible(bool isMouseVisible)
  1352. {
  1353. mMouseVisible = isMouseVisible;
  1354. LONG aStyle = ::GetWindowLong(mHWnd, GWL_EXSTYLE);
  1355. if (!isMouseVisible)
  1356. aStyle |= WS_EX_TRANSPARENT;
  1357. else
  1358. aStyle &= ~WS_EX_TRANSPARENT;
  1359. ::SetWindowLong(mHWnd, GWL_EXSTYLE, aStyle);
  1360. }
  1361. void WinBFWindow::SetAlpha(float alpha, uint32 destAlphaSrcMask, bool isMouseVisible)
  1362. {
  1363. if (destAlphaSrcMask != 0)
  1364. {
  1365. if (mAlphaMaskBitmap == NULL)
  1366. {
  1367. RECT clientRect;
  1368. GetClientRect(mHWnd, &clientRect);
  1369. RECT windowRect;
  1370. GetWindowRect(mHWnd, &windowRect);
  1371. int aWidth = clientRect.right - clientRect.left;
  1372. int aHeight = clientRect.bottom - clientRect.top;
  1373. mAlphaMaskWidth = aWidth;
  1374. mAlphaMaskHeight = aHeight;
  1375. mAlphaMaskDC = CreateCompatibleDC(NULL);
  1376. BITMAPINFO bi = {};
  1377. bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  1378. bi.bmiHeader.biBitCount = 32;
  1379. bi.bmiHeader.biWidth = aWidth;
  1380. bi.bmiHeader.biHeight = -aHeight;
  1381. bi.bmiHeader.biCompression = BI_RGB;
  1382. bi.bmiHeader.biPlanes = 1;
  1383. mAlphaMaskBitmap = CreateDIBSection(mAlphaMaskDC, &bi,
  1384. DIB_RGB_COLORS, (void**)&mAlphaMaskPixels, NULL, 0);
  1385. GdiFlush();
  1386. }
  1387. HDC hdc = GetDC(mHWnd);
  1388. if (hdc)
  1389. {
  1390. DXRenderWindow* renderWindow = (DXRenderWindow*) mRenderWindow;
  1391. renderWindow->CopyBitsTo(mAlphaMaskPixels, mAlphaMaskWidth, mAlphaMaskHeight);
  1392. //for (int i = 0; i < mAlphaMaskWidth*mAlphaMaskHeight/2; i++)
  1393. //mAlphaMaskPixels[i] = 0x80FF8000;
  1394. HGDIOBJ hPrevObj = 0;
  1395. POINT ptDest = {0, 0};
  1396. POINT ptSrc = {0, 0};
  1397. SIZE client = {mAlphaMaskWidth, mAlphaMaskHeight};
  1398. BLENDFUNCTION blendFunc = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA};
  1399. hPrevObj = SelectObject(mAlphaMaskDC, mAlphaMaskBitmap);
  1400. ClientToScreen(mHWnd, &ptDest);
  1401. BOOL worked = ::UpdateLayeredWindow(mHWnd, hdc, NULL, &client,
  1402. mAlphaMaskDC, &ptSrc, 0, &blendFunc, ULW_ALPHA);
  1403. DWORD error = GetLastError();
  1404. SelectObject(mAlphaMaskDC, hPrevObj);
  1405. ReleaseDC(mHWnd, hdc);
  1406. }
  1407. }
  1408. else
  1409. {
  1410. ::SetLayeredWindowAttributes(mHWnd, 0, (int) (alpha * 255), LWA_ALPHA);
  1411. }
  1412. SetMouseVisible(isMouseVisible);
  1413. }
  1414. void WinBFWindow::CaptureMouse()
  1415. {
  1416. //OutputDebugStrF("CaptureMouse() Capture HWnd: %X\n", mHWnd);
  1417. ::SetCapture(mHWnd);
  1418. for (auto window : gBFApp->mWindowList)
  1419. {
  1420. if (window == this)
  1421. continue;
  1422. for (int i = 0; i < MOUSEBUTTON_MAX; i++)
  1423. {
  1424. if (window->mIsMouseDown[i])
  1425. {
  1426. window->mMouseUpFunc(window, -1, -1, i);
  1427. window->mIsMouseDown[i] = false;
  1428. }
  1429. }
  1430. }
  1431. }
  1432. bool WinBFWindow::IsMouseCaptured()
  1433. {
  1434. return (mHWnd != NULL) && (GetCapture() == mHWnd);
  1435. }
  1436. int WinBFWindow::GetDPI()
  1437. {
  1438. if (gGetDpiForWindow != NULL)
  1439. return (int)gGetDpiForWindow(mHWnd);
  1440. return 96; // Default DPI
  1441. }
  1442. uint32 WinBFApp::GetClipboardFormat(const StringImpl& format)
  1443. {
  1444. if (format == "text")
  1445. return CF_UNICODETEXT;
  1446. else if (format == "atext")
  1447. return CF_TEXT;
  1448. uint32 aFormat;
  1449. if (mClipboardFormatMap.TryGetValue(format, &aFormat))
  1450. return aFormat;
  1451. aFormat = ::RegisterClipboardFormatA(format.c_str());
  1452. mClipboardFormatMap[format] = aFormat;
  1453. return aFormat;
  1454. }
  1455. static String gClipboardData;
  1456. void* WinBFApp::GetClipboardData(const StringImpl& format, int* size)
  1457. {
  1458. HWND aWindow = NULL;
  1459. if (!mWindowList.empty())
  1460. aWindow = ((WinBFWindow*)mWindowList.front())->mHWnd;
  1461. uint32 aFormat = GetClipboardFormat(format);
  1462. if (aFormat != 0)
  1463. {
  1464. if (OpenClipboard(aWindow))
  1465. {
  1466. HGLOBAL globalHandle = ::GetClipboardData(aFormat);
  1467. if (globalHandle == NULL)
  1468. {
  1469. if (aFormat == CF_UNICODETEXT)
  1470. {
  1471. CloseClipboard();
  1472. // Return ascii text
  1473. return (char*)GetClipboardData("atext", size);
  1474. }
  1475. CloseClipboard();
  1476. *size = 0;
  1477. return NULL;
  1478. }
  1479. *size = (int)::GlobalSize(globalHandle);
  1480. void* aPtr = ::GlobalLock(globalHandle);
  1481. if (aFormat == CF_UNICODETEXT)
  1482. {
  1483. gClipboardData = UTF8Encode((WCHAR*)aPtr);
  1484. *size = (int)gClipboardData.length() + 1;
  1485. }
  1486. else
  1487. {
  1488. gClipboardData.Clear();
  1489. gClipboardData.Insert(0, (char*)aPtr, *size);
  1490. }
  1491. ::GlobalUnlock(globalHandle);
  1492. CloseClipboard();
  1493. return (void*)gClipboardData.c_str();
  1494. }
  1495. }
  1496. *size = 0;
  1497. return NULL;
  1498. }
  1499. void WinBFApp::ReleaseClipboardData(void* ptr)
  1500. {
  1501. }
  1502. void WinBFApp::SetClipboardData(const StringImpl& format, const void* ptr, int size, bool resetClipboard)
  1503. {
  1504. BP_ZONE("WinBFApp::SetClipboardData");
  1505. HWND aWindow = NULL;
  1506. if (!mWindowList.empty())
  1507. aWindow = ((WinBFWindow*) mWindowList.front())->mHWnd;
  1508. uint32 aFormat = GetClipboardFormat(format);
  1509. if (aFormat != 0)
  1510. {
  1511. if (OpenClipboard(aWindow))
  1512. {
  1513. if (resetClipboard)
  1514. {
  1515. BP_ZONE("WinBFApp::SetClipboardData:empty");
  1516. EmptyClipboard();
  1517. }
  1518. if (format == "text")
  1519. {
  1520. BP_ZONE("WinBFApp::SetClipboardData:text");
  1521. HGLOBAL globalHandle = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, size * 2);
  1522. char* data = (char*)GlobalLock(globalHandle);
  1523. UTF16String wString;
  1524. //
  1525. {
  1526. BP_ZONE("WinBFApp::SetClipboardData:utf8decode");
  1527. wString = UTF8Decode((char*)ptr);
  1528. }
  1529. memcpy(data, wString.c_str(), size * 2);
  1530. GlobalUnlock(globalHandle);
  1531. ::SetClipboardData(CF_UNICODETEXT, globalHandle);
  1532. }
  1533. else
  1534. {
  1535. HGLOBAL globalHandle = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, size);
  1536. char* data = (char*)GlobalLock(globalHandle);
  1537. memcpy(data, ptr, size);
  1538. GlobalUnlock(globalHandle);
  1539. ::SetClipboardData(aFormat, globalHandle);
  1540. }
  1541. CloseClipboard();
  1542. }
  1543. }
  1544. }
  1545. BFMenu* WinBFWindow::AddMenuItem(BFMenu* parent, int insertIdx, const char* text, const char* hotKey, BFSysBitmap* sysBitmap, bool enabled, int checkState, bool radioCheck)
  1546. {
  1547. UTF16String lText;
  1548. if (text != NULL)
  1549. lText = UTF8Decode(text);
  1550. UTF16String lHotKey;
  1551. if (hotKey != NULL)
  1552. lHotKey = UTF8Decode(hotKey);
  1553. bool wasEmpty = mMenu->mBFMenuList.size() == 0;
  1554. if (parent == NULL)
  1555. parent = mMenu;
  1556. if ((parent->mBFMenuList.size() == 1) && (((WinBFMenu*) parent->mBFMenuList.front())->mIsPlaceholder))
  1557. {
  1558. // Get rid of placeholder menu item
  1559. auto placeholderMenuItem = parent->mBFMenuList.front();
  1560. RemoveMenuItem(placeholderMenuItem);
  1561. delete placeholderMenuItem;
  1562. }
  1563. WinBFMenu* winBFMenuParent = (WinBFMenu*) parent;
  1564. WinBFMenu* newMenu = new WinBFMenu();
  1565. newMenu->mMenuId = ++WinBFMenu::mMenuCount;
  1566. newMenu->mParent = parent;
  1567. //static int allocIdx = 0;
  1568. //allocIdx++;
  1569. //OutputDebugStrF("MenuIdx %d %@\n", allocIdx, newMenu);
  1570. if ((winBFMenuParent != NULL) && (winBFMenuParent->mMenu == NULL))
  1571. {
  1572. winBFMenuParent->mMenu = ::CreateMenu();
  1573. mHMenuMap[winBFMenuParent->mMenu] = winBFMenuParent;
  1574. MENUITEMINFO menuItem;
  1575. memset(&menuItem, 0, sizeof(MENUITEMINFO));
  1576. menuItem.cbSize = sizeof(MENUITEMINFO);
  1577. menuItem.fMask = MIIM_SUBMENU;
  1578. menuItem.hSubMenu = winBFMenuParent->mMenu;
  1579. ::SetMenuItemInfo(((WinBFMenu*) winBFMenuParent->mParent)->mMenu, winBFMenuParent->mMenuId, FALSE, &menuItem);
  1580. }
  1581. mMenuIDMap[newMenu->mMenuId] = newMenu;
  1582. BF_ASSERT(insertIdx <= (int) parent->mBFMenuList.size());
  1583. ////
  1584. UTF16String lCombinedName;
  1585. MENUITEMINFOW menuItem;
  1586. memset(&menuItem, 0, sizeof(MENUITEMINFO));
  1587. menuItem.cbSize = sizeof(MENUITEMINFO);
  1588. menuItem.fMask = MIIM_FTYPE | MIIM_ID;
  1589. if (text != NULL)
  1590. {
  1591. menuItem.fMask |= MIIM_STRING;
  1592. menuItem.fType = MFT_STRING;
  1593. }
  1594. else
  1595. menuItem.fType = MFT_SEPARATOR;
  1596. menuItem.fState = enabled ? MFS_DEFAULT : MFS_GRAYED;
  1597. if (checkState == 0)
  1598. menuItem.fState |= MFS_UNCHECKED;
  1599. if (checkState == 1)
  1600. menuItem.fState |= MFS_CHECKED;
  1601. if (radioCheck)
  1602. menuItem.fType = MFT_RADIOCHECK;
  1603. menuItem.wID = newMenu->mMenuId;
  1604. if (text != NULL)
  1605. {
  1606. menuItem.dwTypeData = (WCHAR*)lText.c_str();
  1607. }
  1608. if (hotKey != NULL)
  1609. {
  1610. String combinedName = String(text);
  1611. combinedName += "\t";
  1612. if (hotKey[0] == '#')
  1613. {
  1614. combinedName += hotKey + 1;
  1615. }
  1616. else
  1617. {
  1618. combinedName += hotKey;
  1619. newMenu->ParseHotKey(hotKey);
  1620. }
  1621. lCombinedName = UTF8Decode(combinedName);
  1622. menuItem.dwTypeData = (WCHAR*)lCombinedName.c_str();
  1623. }
  1624. ::InsertMenuItemW(winBFMenuParent->mMenu, insertIdx, TRUE, &menuItem);
  1625. ////////
  1626. /*MENUITEMINFO menuItem;
  1627. memset(&menuItem, 0, sizeof(MENUITEMINFO));
  1628. menuItem.cbSize = sizeof(MENUITEMINFO);
  1629. menuItem.fMask = MIIM_ID;
  1630. menuItem.wID = newMenu->mMenuId;
  1631. ::InsertMenuItem(winBFMenuParent->mMenu, insertIdx, TRUE, &menuItem);*/
  1632. ModifyMenuItem(newMenu, text, hotKey, sysBitmap, enabled, checkState, radioCheck);
  1633. parent->mBFMenuList.push_back(newMenu);
  1634. return newMenu;
  1635. }
  1636. void WinBFWindow::ModifyMenuItem(BFMenu* item, const char* text, const char* hotKey, BFSysBitmap* sysBitmap, bool enabled, int checkState, bool radioCheck)
  1637. {
  1638. UTF16String lText;
  1639. if (text != NULL)
  1640. lText = UTF8Decode(text);
  1641. UTF16String lHotKey;
  1642. if (hotKey != NULL)
  1643. lHotKey = UTF8Decode(hotKey);
  1644. WinBFMenu* aMenu = (WinBFMenu*)item;
  1645. WinBFMenu* parentMenu = (WinBFMenu*) item->mParent;
  1646. UTF16String lCombinedName;
  1647. MENUITEMINFOW menuItem;
  1648. memset(&menuItem, 0, sizeof(MENUITEMINFO));
  1649. menuItem.cbSize = sizeof(MENUITEMINFO);
  1650. menuItem.fMask = MIIM_FTYPE | MIIM_ID;
  1651. ::GetMenuItemInfoW(parentMenu->mMenu, aMenu->mMenuId, FALSE, &menuItem);
  1652. menuItem.fMask |= MIIM_STATE;
  1653. if (text != NULL)
  1654. {
  1655. menuItem.fMask |= MIIM_STRING;
  1656. //menuItem.fType = MFT_STRING;
  1657. }
  1658. /*else
  1659. menuItem.fType = MFT_SEPARATOR;*/
  1660. menuItem.fState = enabled ? /*MFS_DEFAULT*/0 : MFS_GRAYED;
  1661. if (checkState != -1)
  1662. {
  1663. menuItem.fMask |= MIIM_CHECKMARKS;
  1664. }
  1665. if (checkState == 0)
  1666. menuItem.fState |= MFS_UNCHECKED;
  1667. if (checkState == 1)
  1668. menuItem.fState |= MFS_CHECKED;
  1669. if (radioCheck)
  1670. menuItem.fType = MFT_RADIOCHECK;
  1671. menuItem.wID = aMenu->mMenuId;
  1672. menuItem.dwTypeData = (WCHAR*)lText.c_str();
  1673. if (hotKey != NULL)
  1674. {
  1675. menuItem.fMask |= MIIM_DATA;
  1676. String combinedName = String(text);
  1677. combinedName += "\t";
  1678. if (hotKey[0] == '#')
  1679. {
  1680. combinedName += hotKey + 1;
  1681. }
  1682. else
  1683. {
  1684. combinedName += hotKey;
  1685. aMenu->ParseHotKey(hotKey);
  1686. }
  1687. lCombinedName = UTF8Decode(combinedName);
  1688. menuItem.dwTypeData = (WCHAR*)lCombinedName.c_str();
  1689. }
  1690. ::SetMenuItemInfoW(parentMenu->mMenu, aMenu->mMenuId, FALSE, &menuItem);
  1691. }
  1692. void WinBFWindow::RemoveMenuItem(BFMenu* item)
  1693. {
  1694. WinBFMenu* aMenu = (WinBFMenu*) item;
  1695. WinBFMenu* parentMenu = (WinBFMenu*) item->mParent;
  1696. //auto itr = mMenuIDMap.find(aMenu->mMenuId);
  1697. //mMenuIDMap.erase(itr);
  1698. mMenuIDMap.Remove(aMenu->mMenuId);
  1699. ::RemoveMenu(parentMenu->mMenu, aMenu->mMenuId, MF_BYCOMMAND);
  1700. }
  1701. BFSysBitmap* WinBFApp::LoadSysBitmap(const WCHAR* fileName)
  1702. {
  1703. return NULL;
  1704. }
  1705. BFSoundManager* WinBFApp::GetSoundManager()
  1706. {
  1707. if (mDSoundManager == NULL)
  1708. mDSoundManager = new DSoundManager(NULL);
  1709. return mDSoundManager;
  1710. }
  1711. void WinBFWindow::ModalsRemoved()
  1712. {
  1713. ::EnableWindow(mHWnd, TRUE);
  1714. if (mChildren.empty())
  1715. ::SetFocus(mHWnd);
  1716. }
  1717. DrawLayer* WinBFApp::CreateDrawLayer(BFWindow* window)
  1718. {
  1719. DXDrawLayer* drawLayer = new DXDrawLayer();
  1720. if (window != NULL)
  1721. {
  1722. drawLayer->mRenderWindow = window->mRenderWindow;
  1723. window->mRenderWindow->mDrawLayerList.push_back(drawLayer);
  1724. }
  1725. drawLayer->mRenderDevice = mRenderDevice;
  1726. return drawLayer;
  1727. }