Windows Platform.cpp 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. /******************************************************************************/
  4. namespace EE{
  5. /******************************************************************************/
  6. #if WINDOWS_NEW
  7. using namespace concurrency;
  8. using namespace Platform;
  9. using namespace Windows::ApplicationModel;
  10. using namespace Windows::ApplicationModel::Core;
  11. using namespace Windows::ApplicationModel::Activation;
  12. using namespace Windows::Devices;
  13. using namespace Windows::Devices::Input;
  14. using namespace Windows::Devices::Sensors;
  15. using namespace Windows::Foundation;
  16. using namespace Windows::Foundation::Collections;
  17. using namespace Windows::Gaming::Input;
  18. using namespace Windows::Graphics::Display;
  19. using namespace Windows::System;
  20. using namespace Windows::UI::Core;
  21. using namespace Windows::UI::Input;
  22. using namespace Windows::UI::ViewManagement;
  23. // must hold global refs, otherwise events will not be called
  24. static Sensors::Accelerometer ^accelerometer;
  25. static Sensors:: Gyrometer ^ gyrometer;
  26. static Sensors:: Magnetometer ^ magnetometer;
  27. static EventRegistrationToken MagnetometerToken, MouseToken;
  28. static TypedEventHandler<Sensors::Magnetometer^, MagnetometerReadingChangedEventArgs^> ^MagnetometerHandler;
  29. /******************************************************************************/
  30. static void Kb_push(KB_KEY key, Int scan_code)
  31. {
  32. Kb.push(key, scan_code);
  33. // !! queue characters after push !!
  34. if(Kb.anyCtrl() && !Kb.anyAlt()) // if Control with no Alt is on, then 'OnCharacterReceived' will not be called, so we must add this char here
  35. {
  36. if(key>='A' && key<='Z')Kb.queue(Char(key + (Kb.anyShift() ? 0 : 'a'-'A')), scan_code);else
  37. if(key>='0' && key<='9')Kb.queue(Char(key ), scan_code);
  38. }
  39. }
  40. struct AppEvent
  41. {
  42. enum TYPE : Byte
  43. {
  44. KEY_DOWN,
  45. CHAR ,
  46. KEY_UP ,
  47. };
  48. TYPE type;
  49. union
  50. {
  51. Char c ;
  52. KB_KEY key;
  53. Byte scan_code;
  54. };
  55. void keyDown(KB_KEY key, Byte scan_code) {type=KEY_DOWN; T.key=key; T.scan_code=scan_code;}
  56. void chr (Char c , Byte scan_code) {type=CHAR ; T.c =c ; T.scan_code=scan_code;}
  57. void keyUp (KB_KEY key ) {type=KEY_UP ; T.key=key;}
  58. void execute()
  59. {
  60. switch(type)
  61. {
  62. case KEY_DOWN: Kb_push (key, scan_code); break;
  63. case CHAR : Kb.queue (c , scan_code); break;
  64. case KEY_UP : Kb.release(key ); break;
  65. }
  66. }
  67. AppEvent() {} // needed because of union
  68. };
  69. static Memc<AppEvent> Events;
  70. void Application::ExecuteRecordedEvents()
  71. {
  72. FREPAO(Events).execute(); // run in order
  73. Events.clear();
  74. }
  75. /******************************************************************************/
  76. Bool Application::Fullscreen() {return Windows::UI::ViewManagement::ApplicationView::GetForCurrentView()->IsFullScreenMode;}
  77. void SetMagnetometerRefresh(Flt interval)
  78. {
  79. if(magnetometer)
  80. {
  81. magnetometer->ReadingChanged -= MagnetometerToken;
  82. if(interval>=0) // enable
  83. {
  84. magnetometer->ReportInterval=Max(RoundU(interval*1000), accelerometer->MinimumReportInterval);
  85. MagnetometerToken=(magnetometer->ReadingChanged += MagnetometerHandler);
  86. }else
  87. {
  88. magnetometer->ReportInterval=0;
  89. }
  90. }
  91. }
  92. #define KEY_EVENTS 1 // 1=better (can catch key events that occur when ALT is pressed) 0=(can't catch ALT+keys)
  93. ref struct FrameworkView sealed : IFrameworkView
  94. {
  95. // IFrameworkView methods
  96. virtual void Initialize(CoreApplicationView^ applicationView)
  97. {
  98. applicationView->Activated += ref new TypedEventHandler<CoreApplicationView^, IActivatedEventArgs^>(this, &FrameworkView::OnActivated );
  99. CoreApplication::Suspending += ref new EventHandler<SuspendingEventArgs^ >(this, &FrameworkView::OnSuspending);
  100. CoreApplication::Resuming += ref new EventHandler< Object^ >(this, &FrameworkView::OnResuming );
  101. }
  102. virtual void SetWindow(CoreWindow^ window) // called before 'Load'
  103. {
  104. App._hwnd=reinterpret_cast<Ptr>(window);
  105. DisplayInformation^ display_info = DisplayInformation::GetForCurrentView();
  106. ScreenScale=display_info->RawPixelsPerViewPixel;
  107. window->SizeChanged += ref new TypedEventHandler<CoreWindow^, WindowSizeChangedEventArgs^>(this, &FrameworkView::OnWindowSizeChanged);
  108. window->VisibilityChanged += ref new TypedEventHandler<CoreWindow^, VisibilityChangedEventArgs^>(this, &FrameworkView::OnVisibilityChanged);
  109. window->Closed += ref new TypedEventHandler<CoreWindow^, CoreWindowEventArgs^>(this, &FrameworkView::OnWindowClosed );
  110. window->Activated += ref new TypedEventHandler<CoreWindow^, WindowActivatedEventArgs^>(this, &FrameworkView::OnWindowActivated );
  111. display_info-> DpiChanged += ref new TypedEventHandler<DisplayInformation^, Object^>(this, &FrameworkView::OnDpiChanged );
  112. display_info-> OrientationChanged += ref new TypedEventHandler<DisplayInformation^, Object^>(this, &FrameworkView::OnOrientationChanged );
  113. DisplayInformation::DisplayContentsInvalidated += ref new TypedEventHandler<DisplayInformation^, Object^>(this, &FrameworkView::OnDisplayContentsInvalidated);
  114. MouseToken = (MouseDevice::GetForCurrentView()->MouseMoved += ref new TypedEventHandler<MouseDevice^, MouseEventArgs^>(this, &FrameworkView::OnMouseMoved));
  115. window->PointerMoved += ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &FrameworkView::OnPointerMoved);
  116. window->PointerEntered += ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &FrameworkView::OnPointerEntered);
  117. window->PointerExited += ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &FrameworkView::OnPointerExited);
  118. window->PointerCaptureLost += ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &FrameworkView::OnPointerExited);
  119. window->PointerPressed += ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &FrameworkView::OnPointerPressed);
  120. window->PointerReleased += ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &FrameworkView::OnPointerReleased);
  121. window->PointerWheelChanged += ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &FrameworkView::OnPointerWheelChanged);
  122. #if KEY_EVENTS
  123. window->Dispatcher->AcceleratorKeyActivated += ref new TypedEventHandler<CoreDispatcher^, AcceleratorKeyEventArgs^>(this, &FrameworkView::OnAcceleratorKeyActivated);
  124. #else
  125. window->KeyDown += ref new TypedEventHandler<CoreWindow^, KeyEventArgs^>(this, &FrameworkView::OnKeyDown);
  126. window->KeyUp += ref new TypedEventHandler<CoreWindow^, KeyEventArgs^>(this, &FrameworkView::OnKeyUp);
  127. window->CharacterReceived += ref new TypedEventHandler<CoreWindow^, CharacterReceivedEventArgs^>(this, &FrameworkView::OnCharacterReceived);
  128. #endif
  129. Gamepad::GamepadAdded += ref new EventHandler<Gamepad^>(this, &FrameworkView::OnGamepadAdded);
  130. Gamepad::GamepadRemoved += ref new EventHandler<Gamepad^>(this, &FrameworkView::OnGamepadRemoved);
  131. if(accelerometer=Accelerometer::GetDefault())
  132. {
  133. accelerometer->ReportInterval = Max(16, accelerometer->MinimumReportInterval);
  134. accelerometer->ReadingChanged += ref new TypedEventHandler<Sensors::Accelerometer^, AccelerometerReadingChangedEventArgs^>(this, &FrameworkView::OnAccelerometerChanged);
  135. }
  136. if(gyrometer=Gyrometer::GetDefault())
  137. {
  138. gyrometer->ReportInterval = Max(16, gyrometer->MinimumReportInterval);
  139. gyrometer->ReadingChanged += ref new TypedEventHandler<Sensors::Gyrometer^, GyrometerReadingChangedEventArgs^>(this, &FrameworkView::OnGyrometerChanged);
  140. }
  141. if(magnetometer=Magnetometer::GetDefault())
  142. {
  143. MagnetometerHandler=ref new TypedEventHandler<Sensors::Magnetometer^, MagnetometerReadingChangedEventArgs^>(this, &FrameworkView::OnMagnetometerChanged);
  144. }
  145. //SystemNavigationManager::GetForCurrentView()->AppViewBackButtonVisibility = Windows::UI::Core::AppViewBackButtonVisibility::Visible; // display back button on app title bar
  146. SystemNavigationManager::GetForCurrentView()->BackRequested += ref new EventHandler<BackRequestedEventArgs^>(this, &FrameworkView::OnBackRequested);
  147. ApplicationView::GetForCurrentView()->SetPreferredMinSize(Size(Max(1, PixelsToDips(1)), Max(1, PixelsToDips(1)))); // using <1 means to use system default min size, so use Max 1 to always set a custom size
  148. setOrientation(display_info->CurrentOrientation, display_info->NativeOrientation); // !! call this before 'setMode' !!
  149. setMode();
  150. }
  151. virtual void Load(String^ entryPoint) // called after 'SetWindow'
  152. {
  153. }
  154. virtual void Run() // changing full screen mode 'TryEnterFullScreenMode' will work only here
  155. {
  156. if(!App._closed) // only if app didn't call 'Exit'
  157. {
  158. if(!App.create())App._close=true; // put app create here because only at this stage 'RequestDisplayMode' will work
  159. App.loop();
  160. }
  161. MouseDevice::GetForCurrentView()->MouseMoved -= MouseToken; // !! without this, app will crash on Windows Phone when closing the app !!
  162. }
  163. virtual void Uninitialize() // this is called only when app requested to finish (and NOT when user clicked the close box)
  164. {
  165. if(App._closed)return; // do nothing if app called 'Exit'
  166. App.del();
  167. }
  168. // custom callbacks
  169. void OnActivated(CoreApplicationView^ applicationView, IActivatedEventArgs^ args)
  170. {
  171. CoreWindow::GetForCurrentThread()->Activate();
  172. }
  173. void OnSuspending(Object^ sender, SuspendingEventArgs^ args)
  174. {
  175. if(App._closed)return; // do nothing if app called 'Exit'
  176. SuspendingDeferral^ deferral=args->SuspendingOperation->GetDeferral();
  177. create_task([this, deferral]()
  178. {
  179. if(!App._closed) // only if app didn't call 'Exit', check this again in case 'Exit' was called later
  180. {
  181. if(App.save_state)App.save_state(); // call this first as it's most important
  182. //App.setActive(false); just use 'OnWindowActivated'
  183. PauseSound();
  184. App.lowMemory(); // reduce memory usage (this is optional)
  185. }
  186. if(D3D)
  187. {
  188. IDXGIDevice3 *device; if(OK(D3D->QueryInterface(__uuidof(IDXGIDevice3), (Ptr*)&device)))
  189. {
  190. device->Trim ();
  191. device->Release();
  192. }
  193. }
  194. deferral->Complete();
  195. });
  196. }
  197. void OnResuming(Object^ sender, Object^ args)
  198. {
  199. if(App._closed)return; // do nothing if app called 'Exit'
  200. ResumeSound();
  201. //App.setActive(true); just use 'OnWindowActivated'
  202. }
  203. void OnWindowSizeChanged(CoreWindow^ sender, WindowSizeChangedEventArgs^ args)
  204. {
  205. setMode();
  206. }
  207. void OnVisibilityChanged(CoreWindow^ sender, VisibilityChangedEventArgs^ args)
  208. {
  209. App._minimized=!args->Visible;
  210. }
  211. void OnWindowClosed(CoreWindow^ sender, CoreWindowEventArgs^ args) {App._close=true;} // this is not called, but do this just in case, as the tutorial does
  212. void OnWindowActivated(CoreWindow^ sender, WindowActivatedEventArgs^ args)
  213. {
  214. if(App._closed)return; // do nothing if app called 'Exit'
  215. App.setActive(args->WindowActivationState!=CoreWindowActivationState::Deactivated);
  216. }
  217. void OnDpiChanged(DisplayInformation^ sender, Object^ args)
  218. {
  219. ScreenScale=sender->RawPixelsPerViewPixel;
  220. setMode();
  221. D.aspectRatioEx(false); // bug workaround: on Windows when app is started on a secondary monitor, then initially SwapChain output will point to the main monitor output, which will make the aspect calculation incorrect if app starts fullscreen, however it was noticed that 'OnDpiChanged' will be called soon after that, and at this point, output will be correct, so reset aspect ratio here with correct output
  222. }
  223. void OnOrientationChanged(DisplayInformation^ sender, Object^ args)
  224. {
  225. setOrientation(sender->CurrentOrientation, sender->NativeOrientation);
  226. setMode();
  227. }
  228. void OnDisplayContentsInvalidated(DisplayInformation^ sender, Object^ args)
  229. {
  230. /*// The D3D Device is no longer valid if the default adapter changed since the device
  231. // was created or if the device has been removed.
  232. // First, get the information for the default adapter from when the device was created.
  233. ComPtr<IDXGIDevice3> dxgiDevice;
  234. DX::ThrowIfFailed(m_d3dDevice.As(&dxgiDevice));
  235. ComPtr<IDXGIAdapter> deviceAdapter;
  236. DX::ThrowIfFailed(dxgiDevice->GetAdapter(&deviceAdapter));
  237. ComPtr<IDXGIFactory2> deviceFactory;
  238. DX::ThrowIfFailed(deviceAdapter->GetParent(IID_PPV_ARGS(&deviceFactory)));
  239. ComPtr<IDXGIAdapter1> previousDefaultAdapter;
  240. DX::ThrowIfFailed(deviceFactory->EnumAdapters1(0, &previousDefaultAdapter));
  241. DXGI_ADAPTER_DESC previousDesc;
  242. DX::ThrowIfFailed(previousDefaultAdapter->GetDesc(&previousDesc));
  243. // Next, get the information for the current default adapter.
  244. ComPtr<IDXGIFactory2> currentFactory;
  245. DX::ThrowIfFailed(CreateDXGIFactory1(IID_PPV_ARGS(&currentFactory)));
  246. ComPtr<IDXGIAdapter1> currentDefaultAdapter;
  247. DX::ThrowIfFailed(currentFactory->EnumAdapters1(0, &currentDefaultAdapter));
  248. DXGI_ADAPTER_DESC currentDesc;
  249. DX::ThrowIfFailed(currentDefaultAdapter->GetDesc(&currentDesc));
  250. // If the adapter LUIDs don't match, or if the device reports that it has been removed,
  251. // a new D3D device must be created.
  252. if (previousDesc.AdapterLuid.LowPart != currentDesc.AdapterLuid.LowPart ||
  253. previousDesc.AdapterLuid.HighPart != currentDesc.AdapterLuid.HighPart ||
  254. FAILED(m_d3dDevice->GetDeviceRemovedReason()))
  255. {
  256. // Release references to resources related to the old device.
  257. dxgiDevice = nullptr;
  258. deviceAdapter = nullptr;
  259. deviceFactory = nullptr;
  260. previousDefaultAdapter = nullptr;
  261. // Create a new device and swap chain.
  262. HandleDeviceLost();
  263. }*/
  264. }
  265. void OnMouseMoved(MouseDevice^ mouseDevice, MouseEventArgs^ args) // this is not clipped by desktop (if mouse is moved but the cursor remains in the same position, it will still generate move events). WINDOWS_NEW BUG: this will not be called if mouse hovers over title bar or border, but if mouse is moved quickly outside without touching the borders, then it will continue to receive data
  266. {
  267. Ms._delta_relative.x+=args->MouseDelta.X;
  268. Ms._delta_relative.y-=args->MouseDelta.Y;
  269. }
  270. void OnPointerMoved(CoreWindow^ sender, PointerEventArgs^ args)
  271. {
  272. PointerPoint ^pointer=args->CurrentPoint;
  273. switch(pointer->PointerDevice->PointerDeviceType)
  274. {
  275. case PointerDeviceType::Mouse:
  276. {
  277. // this is handled in 'Ms.update' because this is not called when mouse is outside the window
  278. }break;
  279. default: // pen, touch
  280. {
  281. if(Touch *touch=FindTouchByHandle(CPtr(pointer->PointerId)))
  282. {
  283. VecI2 posi(DipsToPixels(pointer->Position.X), DipsToPixels(pointer->Position.Y));
  284. touch->_deltai+=posi-touch->_posi;
  285. touch->_posi =posi;
  286. touch->_pos =D.windowPixelToScreen(posi);
  287. }
  288. }break;
  289. }
  290. }
  291. void OnPointerEntered(CoreWindow^ sender, PointerEventArgs^ args)
  292. {
  293. PointerPoint ^pointer=args->CurrentPoint;
  294. switch(pointer->PointerDevice->PointerDeviceType)
  295. {
  296. case PointerDeviceType::Mouse:
  297. {
  298. Ms._on_client=true;
  299. //Ms._deltai=Ms._window_posi-posi; don't calculate delta here to avoid big jumps
  300. //Ms._window_posi=posi; this is handled in 'Ms.update'
  301. }break;
  302. default: // pen, touch
  303. {
  304. CPtr id=CPtr(pointer->PointerId);
  305. VecI2 posi(DipsToPixels(pointer->Position.X), DipsToPixels(pointer->Position.Y));
  306. Vec2 pos=D.windowPixelToScreen(posi);
  307. Touch *touch=FindTouchByHandle(id);
  308. if( !touch)touch=&Touches.New().init(posi, pos, id, pointer->PointerDevice->PointerDeviceType==PointerDeviceType::Pen);else
  309. {
  310. touch->_remove=false; // disable 'remove' in case it was enabled (for example the same touch exited in same/previous frame)
  311. touch->_posi =posi;
  312. touch->_pos =pos;
  313. }
  314. }break;
  315. }
  316. }
  317. void OnPointerExited(CoreWindow^ sender, PointerEventArgs^ args)
  318. {
  319. PointerPoint ^pointer=args->CurrentPoint;
  320. switch(pointer->PointerDevice->PointerDeviceType)
  321. {
  322. case PointerDeviceType::Mouse:
  323. {
  324. Ms._on_client=false;
  325. //Ms._deltai=Ms._window_posi-posi; this is handled in 'Ms.update'
  326. //Ms._window_posi=posi; this is handled in 'Ms.update'
  327. }break;
  328. default: // pen, touch
  329. {
  330. if(Touch *touch=FindTouchByHandle(CPtr(pointer->PointerId)))
  331. {
  332. VecI2 posi(DipsToPixels(pointer->Position.X), DipsToPixels(pointer->Position.Y));
  333. touch->_deltai+=posi-touch->_posi;
  334. touch->_posi =posi;
  335. touch->_pos =D.windowPixelToScreen(posi);
  336. touch->_remove =true;
  337. if(touch->_state&BS_ON) // check for state in case it was manually eaten
  338. {
  339. touch->_state|= BS_RELEASED;
  340. touch->_state&=~BS_ON;
  341. }
  342. }
  343. }break;
  344. }
  345. }
  346. void OnPointerPressed(CoreWindow^ sender, PointerEventArgs^ args)
  347. {
  348. PointerPoint ^pointer=args->CurrentPoint;
  349. switch(pointer->PointerDevice->PointerDeviceType)
  350. {
  351. case PointerDeviceType::Mouse:
  352. {
  353. /* Handled in 'Ms.update' because this won't be called if there's already one button pressed
  354. if(pointer->Properties-> IsLeftButtonPressed)Ms.push(0);
  355. if(pointer->Properties-> IsRightButtonPressed)Ms.push(1);
  356. if(pointer->Properties->IsMiddleButtonPressed)Ms.push(2);
  357. if(pointer->Properties-> IsXButton1Pressed)Ms.push(3);
  358. if(pointer->Properties-> IsXButton2Pressed)Ms.push(4);*/
  359. }break;
  360. default: // pen, touch
  361. {
  362. if(Touch *touch=FindTouchByHandle(CPtr(pointer->PointerId)))
  363. {
  364. touch->_state=BS_ON|BS_PUSHED;
  365. touch->_force=1;
  366. }
  367. }break;
  368. }
  369. }
  370. void OnPointerReleased(CoreWindow^ sender, PointerEventArgs^ args)
  371. {
  372. PointerPoint ^pointer=args->CurrentPoint;
  373. switch(pointer->PointerDevice->PointerDeviceType)
  374. {
  375. case PointerDeviceType::Mouse:
  376. {
  377. /* Handled in 'Ms.update' because this won't be called if there's already one button pressed
  378. if(!pointer->Properties-> IsLeftButtonPressed)Ms.release(0);
  379. if(!pointer->Properties-> IsRightButtonPressed)Ms.release(1);
  380. if(!pointer->Properties->IsMiddleButtonPressed)Ms.release(2);
  381. if(!pointer->Properties-> IsXButton1Pressed)Ms.release(3);
  382. if(!pointer->Properties-> IsXButton2Pressed)Ms.release(4);*/
  383. }break;
  384. default: // pen, touch
  385. {
  386. if(Touch *touch=FindTouchByHandle(CPtr(pointer->PointerId)))
  387. if(touch->_state&BS_ON) // check for state in case it was manually eaten
  388. {
  389. touch->_state|= BS_RELEASED;
  390. touch->_state&=~BS_ON;
  391. }
  392. }break;
  393. }
  394. }
  395. void OnPointerWheelChanged(CoreWindow^ sender, PointerEventArgs^ args)
  396. {
  397. PointerPoint ^pointer=args->CurrentPoint;
  398. switch(pointer->PointerDevice->PointerDeviceType)
  399. {
  400. case PointerDeviceType::Mouse:
  401. {
  402. if(pointer->Properties->IsHorizontalMouseWheel)Ms._wheel.x+=Flt(pointer->Properties->MouseWheelDelta)/WHEEL_DELTA;
  403. else Ms._wheel.y+=Flt(pointer->Properties->MouseWheelDelta)/WHEEL_DELTA;
  404. }break;
  405. }
  406. }
  407. void OnBackRequested(Object^ sender, BackRequestedEventArgs ^args)
  408. {
  409. args->Handled=true; // disable app close on back press
  410. Kb.push (KB_NAV_BACK, -1);
  411. Kb.release(KB_NAV_BACK); // release immediately because there's no callback for a release
  412. }
  413. #if KEY_EVENTS
  414. void OnAcceleratorKeyActivated(CoreDispatcher^ sender, AcceleratorKeyEventArgs^ args)
  415. {
  416. // !! Warning: On International keyboards RightAlt (AltGr) also triggers LeftCtrl, there's no way to workaround this, LeftCtrl is pressed down, and notification of RightAlt can happen even a few frames later !!
  417. Int scan_code=args->KeyStatus.ScanCode;
  418. #if DEBUG && 0
  419. #pragma message("!! Warning: Use this only for debugging !!")
  420. Str s;
  421. switch(Windows::UI::Core::CoreAcceleratorKeyEventType type=args->EventType)
  422. {
  423. case Windows::UI::Core::CoreAcceleratorKeyEventType::Character : s=S+"Char "+Char(args->VirtualKey)+' '; break;
  424. case Windows::UI::Core::CoreAcceleratorKeyEventType::SystemCharacter : s=S+"SysChar "+Char(args->VirtualKey)+' '; break;
  425. case Windows::UI::Core::CoreAcceleratorKeyEventType::UnicodeCharacter : s="UniChar"; break;
  426. case Windows::UI::Core::CoreAcceleratorKeyEventType::KeyDown : s="KeyDown"; break;
  427. case Windows::UI::Core::CoreAcceleratorKeyEventType::KeyUp : s="KeyUp"; break;
  428. case Windows::UI::Core::CoreAcceleratorKeyEventType::SystemKeyDown : s="SysKeyDown"; break;
  429. case Windows::UI::Core::CoreAcceleratorKeyEventType::SystemKeyUp : s="SysKeyUp"; break;
  430. case Windows::UI::Core::CoreAcceleratorKeyEventType::DeadCharacter : s="DeadChar"; break;
  431. case Windows::UI::Core::CoreAcceleratorKeyEventType::SystemDeadCharacter: s="SysDeadChar"; break;
  432. }
  433. KB_KEY key=KB_KEY(args->VirtualKey);
  434. LogN(S+"frame:"+Time.frame()+", "+s+" scan_code:"+scan_code+' '+key+'('+Kb.keyName(key)+"), ext:"+args->KeyStatus.IsExtendedKey+", released:"+args->KeyStatus.IsKeyReleased+", wasDown:"+args->KeyStatus.WasKeyDown+", repeat:"+args->KeyStatus.RepeatCount);
  435. #endif
  436. switch(args->EventType)
  437. {
  438. case Windows::UI::Core::CoreAcceleratorKeyEventType::KeyDown :
  439. case Windows::UI::Core::CoreAcceleratorKeyEventType::SystemKeyDown:
  440. {
  441. KB_KEY key=KB_KEY(args->VirtualKey);
  442. switch(key)
  443. {
  444. case KB_CTRL : key=(args->KeyStatus.IsExtendedKey ? KB_RCTRL : KB_LCTRL ); break;
  445. case KB_SHIFT: key=((scan_code==42) ? KB_LSHIFT : KB_RSHIFT); break; // 42=KB_LSHIFT, 54=KB_RSHIFT
  446. case KB_ALT : key=(args->KeyStatus.IsExtendedKey ? KB_RALT : KB_LALT ); break;
  447. }
  448. if(App._loop)Events.New().keyDown(key, scan_code);else Kb.push(key, scan_code); // if app is in special loop, then we need to record events, and execute them later
  449. }break;
  450. case Windows::UI::Core::CoreAcceleratorKeyEventType::Character :
  451. case Windows::UI::Core::CoreAcceleratorKeyEventType::SystemCharacter:
  452. {
  453. Char c=(Char)args->VirtualKey;
  454. if(App._loop)Events.New().chr(c, scan_code);else Kb.queue(c, scan_code); // if app is in special loop, then we need to record events, and execute them later
  455. }break;
  456. case Windows::UI::Core::CoreAcceleratorKeyEventType::KeyUp :
  457. case Windows::UI::Core::CoreAcceleratorKeyEventType::SystemKeyUp:
  458. {
  459. KB_KEY key=KB_KEY(args->VirtualKey);
  460. switch(key)
  461. {
  462. case KB_CTRL : key=(args->KeyStatus.IsExtendedKey ? KB_RCTRL : KB_LCTRL ); break;
  463. case KB_SHIFT: key=((scan_code==42) ? KB_LSHIFT : KB_RSHIFT); break; // 42=KB_LSHIFT, 54=KB_RSHIFT
  464. case KB_ALT : key=(args->KeyStatus.IsExtendedKey ? KB_RALT : KB_LALT ); break;
  465. }
  466. if(App._loop)Events.New().keyUp(key);else Kb.release(key); // if app is in special loop, then we need to record events, and execute them later
  467. }break;
  468. }
  469. }
  470. #else
  471. void OnKeyDown(CoreWindow^ sender, KeyEventArgs^ args) // mouse buttons are not passed here
  472. {
  473. Int scan_code=args->KeyStatus.ScanCode;
  474. KB_KEY key =KB_KEY(args->VirtualKey);
  475. //LogN(S+"OnKeyDown: scan_code:"+scan_code+' '+key+'('+Kb.keyName(key)+"), ext:"+args->KeyStatus.IsExtendedKey+", released:"+args->KeyStatus.IsKeyReleased+", wasDown:"+args->KeyStatus.WasKeyDown+", repeat:"+args->KeyStatus.RepeatCount);
  476. switch(key)
  477. {
  478. case KB_CTRL : key=(args->KeyStatus.IsExtendedKey ? KB_RCTRL : KB_LCTRL ); break;
  479. case KB_SHIFT: key=((scan_code==42) ? KB_LSHIFT : KB_RSHIFT); break; // 42=KB_LSHIFT, 54=KB_RSHIFT
  480. case KB_ALT : key=(args->KeyStatus.IsExtendedKey ? KB_RALT : KB_LALT ); break;
  481. }
  482. if(App._loop)Events.New().keyDown(key, scan_code);else Kb_push(key, scan_code); // if app is in special loop, then we need to record events, and execute them later
  483. }
  484. void OnCharacterReceived(CoreWindow^ sender, CharacterReceivedEventArgs^ args)
  485. {
  486. Char c=Char(args->KeyCode);
  487. Int scan_code=args->KeyStatus.ScanCode;
  488. if(App._loop)Events.New().chr(c, scan_code);else Kb.queue(c, scan_code); // if app is in special loop, then we need to record events, and execute them later
  489. }
  490. void OnKeyUp(CoreWindow^ sender, KeyEventArgs^ args) // mouse buttons are not passed here
  491. {
  492. KB_KEY key=KB_KEY(args->VirtualKey);
  493. //LogN(S+"OnKeyUp: scan_code:"+(args->KeyStatus.ScanCode)+' '+key+'('+Kb.keyName(key)+"), ext:"+args->KeyStatus.IsExtendedKey+", released:"+args->KeyStatus.IsKeyReleased+", wasDown:"+args->KeyStatus.WasKeyDown+", repeat:"+args->KeyStatus.RepeatCount);
  494. switch(key)
  495. {
  496. case KB_CTRL : key=(args->KeyStatus.IsExtendedKey ? KB_RCTRL : KB_LCTRL ); break;
  497. case KB_SHIFT: key=((scan_code==42) ? KB_LSHIFT : KB_RSHIFT); break; // 42=KB_LSHIFT, 54=KB_RSHIFT
  498. case KB_ALT : key=(args->KeyStatus.IsExtendedKey ? KB_RALT : KB_LALT ); break;
  499. }
  500. if(App._loop)Events.New().keyUp(key);else Kb.release(key); // if app is in special loop, then we need to record events, and execute them later
  501. }
  502. #endif
  503. void OnGamepadAdded (Object^ sender, Gamepad ^gamepad) {ListJoypads();}
  504. void OnGamepadRemoved(Object^ sender, Gamepad ^gamepad) {ListJoypads();}
  505. void OnAccelerometerChanged(Sensors::Accelerometer^ accelerometer, AccelerometerReadingChangedEventArgs^ args)
  506. {
  507. AccelerometerValue.set(args->Reading->AccelerationX, args->Reading->AccelerationY, -args->Reading->AccelerationZ)*=9.80665f;
  508. }
  509. void OnGyrometerChanged(Sensors::Gyrometer^ Gyrometer, GyrometerReadingChangedEventArgs^ args)
  510. {
  511. GyroscopeValue.set(args->Reading->AngularVelocityX, args->Reading->AngularVelocityY, -args->Reading->AngularVelocityZ);
  512. }
  513. void OnMagnetometerChanged(Sensors::Magnetometer^ Magnetometer, MagnetometerReadingChangedEventArgs^ args)
  514. {
  515. MagnetometerValue.set(args->Reading->MagneticFieldX, args->Reading->MagneticFieldY, -args->Reading->MagneticFieldZ);
  516. }
  517. // custom methods
  518. void setOrientation(DisplayOrientations orientation, DisplayOrientations native_orientation)
  519. {
  520. DXGI_MODE_ROTATION rotation=DXGI_MODE_ROTATION_IDENTITY;
  521. switch(native_orientation) // this can only be Landscape or Portrait even though the DisplayOrientations enum has other values
  522. {
  523. case DisplayOrientations::Landscape: switch(orientation)
  524. {
  525. //case DisplayOrientations::Landscape : rotation=DXGI_MODE_ROTATION_IDENTITY ; break;
  526. case DisplayOrientations::Portrait : rotation=DXGI_MODE_ROTATION_ROTATE270; break;
  527. case DisplayOrientations::LandscapeFlipped: rotation=DXGI_MODE_ROTATION_ROTATE180; break;
  528. case DisplayOrientations::PortraitFlipped : rotation=DXGI_MODE_ROTATION_ROTATE90 ; break;
  529. }break;
  530. case DisplayOrientations::Portrait: switch(orientation)
  531. {
  532. case DisplayOrientations::Landscape : rotation=DXGI_MODE_ROTATION_ROTATE90 ; break;
  533. //case DisplayOrientations::Portrait : rotation=DXGI_MODE_ROTATION_IDENTITY ; break;
  534. case DisplayOrientations::LandscapeFlipped: rotation=DXGI_MODE_ROTATION_ROTATE270; break;
  535. case DisplayOrientations::PortraitFlipped : rotation=DXGI_MODE_ROTATION_ROTATE180; break;
  536. }break;
  537. }
  538. #if 0 // set based on absolute pose (this will return landscape for laptops)
  539. switch(orientation)
  540. {
  541. default : App._orientation=DIR_UP ; break; // DisplayOrientations::Portrait
  542. case DisplayOrientations::PortraitFlipped : App._orientation=DIR_DOWN ; break;
  543. case DisplayOrientations::Landscape : App._orientation=DIR_LEFT ; break;
  544. case DisplayOrientations::LandscapeFlipped: App._orientation=DIR_RIGHT; break;
  545. }
  546. #else // set based on relative rotation (this will return portrait for laptops)
  547. switch(rotation)
  548. {
  549. case DXGI_MODE_ROTATION_IDENTITY : App._orientation=DIR_UP ; break;
  550. case DXGI_MODE_ROTATION_ROTATE180: App._orientation=DIR_DOWN ; break;
  551. case DXGI_MODE_ROTATION_ROTATE90 : App._orientation=DIR_LEFT ; break;
  552. case DXGI_MODE_ROTATION_ROTATE270: App._orientation=DIR_RIGHT; break;
  553. }
  554. #endif
  555. }
  556. void setMode()
  557. {
  558. if(App._closed)return; // do nothing if app called 'Exit'
  559. VecI2 mode(DipsToPixels(App.Hwnd()->Bounds.Width), DipsToPixels(App.Hwnd()->Bounds.Height));
  560. D.modeSet(mode.x, mode.y, -1);
  561. }
  562. };
  563. ref struct FrameworkViewSource sealed : IFrameworkViewSource
  564. {
  565. virtual IFrameworkView^ CreateView()
  566. {
  567. return ref new FrameworkView();
  568. }
  569. };
  570. void Application::loopUntil(Bool &finished, Bool wait)
  571. {
  572. if(!finished) // first check if we already finished and don't need to do anything
  573. {
  574. _loop=true; // specify that we're inside this special loop, this is needed so if any events occur during callback processing, then we will record them and execute them at a later time, for example this is done so no key pushes are detected at this stage (which can occur in State Update or Draw) but they will be detected once Update and Draw are finished
  575. for(;;) // start loop
  576. {
  577. Windows::ApplicationModel::Core::CoreApplication::MainView->CoreWindow->Dispatcher->ProcessEvents(Windows::UI::Core::CoreProcessEventsOption::ProcessAllIfPresent); // this may call our callbacks, 'ProcessOneAndAllPending'= can't be used because apparently tasks don't count as events, and this will wait until some other events occur, even though we have tasks waiting
  578. if(finished)break;
  579. if(wait)Time.wait(1);
  580. }
  581. _loop=false;
  582. }
  583. }
  584. #endif
  585. /******************************************************************************/
  586. } // namespace EE
  587. /******************************************************************************/
  588. #if WINDOWS_OLD
  589. INT WINAPI WinMain(HINSTANCE hinstance, HINSTANCE, LPSTR cmd_line, Int)
  590. {
  591. if(CChar *cmd=WChar(GetCommandLine())) // need to use 'GetCommandLine' to get wide char, because 'cmd_line' is ANSI only
  592. {
  593. // can be:
  594. // c:\path\file.exe param
  595. // "c:\path\fi le.exe" param
  596. // file.exe param
  597. // "fi le.exe" param
  598. if(cmd[0]=='"'){if(cmd=TextPos(cmd+1, '"'))cmd+=((cmd[1]==' ') ? 2 : 1);}else // skip '"' and ' '
  599. if(cmd=TextPos(cmd, ' '))cmd++;
  600. App._cmd_line=cmd;
  601. }
  602. App._hinstance=hinstance;
  603. if(App.create())App.loop();
  604. App.del ();
  605. return 0;
  606. }
  607. #elif WINDOWS_NEW
  608. [MTAThread] int main(Array<String^> ^args)
  609. {
  610. /* TODO: WINDOWS_NEW setting initial window size and fullscreen mode - check in the future
  611. changing these didn't make any difference at this launch, only next launch got affected
  612. if(1)ApplicationView::PreferredLaunchViewSize = Size(300, 300);
  613. else ApplicationView::PreferredLaunchViewSize = Size(600, 600);
  614. ApplicationView::PreferredLaunchWindowingMode = ApplicationViewWindowingMode::PreferredLaunchViewSize;
  615. //ApplicationView::PreferredLaunchWindowingMode = ApplicationViewWindowingMode::Auto;
  616. //ApplicationView::PreferredLaunchWindowingMode = ApplicationViewWindowingMode::FullScreen;*/
  617. if(args)FREP(args->Length)
  618. {
  619. if(i>0)App._cmd_line+='\n'; // separate with new lines, to allow having arguments with spaces in value to be presented as one argument
  620. App._cmd_line+=args->get(i)->Data();
  621. }
  622. Windows::ApplicationModel::Core::CoreApplication::Run(ref new FrameworkViewSource());
  623. return 0;
  624. }
  625. #endif
  626. /******************************************************************************/