440 строки
13 KiB
C++
440 строки
13 KiB
C++
//--------------------------------------------------------------------------------------
|
|
// Main.cpp
|
|
//
|
|
// Entry point for Universal Windows Platform (UWP) app.
|
|
//
|
|
// Advanced Technology Group (ATG)
|
|
// Copyright (C) Microsoft Corporation. All rights reserved.
|
|
//--------------------------------------------------------------------------------------
|
|
|
|
#include "pch.h"
|
|
#include "SimpleWASAPICaptureUWP.h"
|
|
|
|
#include <ppltasks.h>
|
|
|
|
#include "Telemetry.h"
|
|
|
|
using namespace concurrency;
|
|
using namespace Windows::ApplicationModel;
|
|
using namespace Windows::ApplicationModel::Core;
|
|
using namespace Windows::ApplicationModel::Activation;
|
|
using namespace Windows::UI::Core;
|
|
using namespace Windows::UI::Input;
|
|
using namespace Windows::UI::ViewManagement;
|
|
using namespace Windows::System;
|
|
using namespace Windows::Foundation;
|
|
using namespace Windows::Graphics::Display;
|
|
using namespace DirectX;
|
|
|
|
ref class ViewProvider sealed : public IFrameworkView
|
|
{
|
|
public:
|
|
ViewProvider() :
|
|
m_exit(false),
|
|
m_visible(true),
|
|
m_in_sizemove(false),
|
|
m_DPI(96.f),
|
|
m_logicalWidth(800.f),
|
|
m_logicalHeight(600.f),
|
|
m_nativeOrientation(DisplayOrientations::None),
|
|
m_currentOrientation(DisplayOrientations::None)
|
|
{
|
|
}
|
|
|
|
// IFrameworkView methods
|
|
virtual void Initialize(CoreApplicationView^ applicationView)
|
|
{
|
|
applicationView->Activated +=
|
|
ref new TypedEventHandler<CoreApplicationView^, IActivatedEventArgs^>(this, &ViewProvider::OnActivated);
|
|
|
|
CoreApplication::Suspending +=
|
|
ref new EventHandler<SuspendingEventArgs^>(this, &ViewProvider::OnSuspending);
|
|
|
|
CoreApplication::Resuming +=
|
|
ref new EventHandler<Platform::Object^>(this, &ViewProvider::OnResuming);
|
|
|
|
m_sample = std::make_unique<Sample>();
|
|
|
|
// Sample Usage Telemetry
|
|
//
|
|
// Disable or remove this code block to opt-out of sample usage telemetry
|
|
//
|
|
if (ATG::EventRegisterATGSampleTelemetry() == ERROR_SUCCESS)
|
|
{
|
|
wchar_t exeName[MAX_PATH + 1] = {};
|
|
if (!GetModuleFileNameW(nullptr, exeName, MAX_PATH))
|
|
{
|
|
wcscpy_s(exeName, L"Unknown");
|
|
}
|
|
wchar_t fname[_MAX_FNAME] = {};
|
|
wchar_t ext[_MAX_EXT] = {};
|
|
(void)_wsplitpath_s(exeName, nullptr, 0, nullptr, 0, fname, _MAX_FNAME, ext, _MAX_EXT);
|
|
(void)_wmakepath_s(exeName, nullptr, nullptr, fname, ext); // keep only the filename + extension
|
|
|
|
ATG::EventWriteSampleLoaded(exeName);
|
|
}
|
|
}
|
|
|
|
virtual void Uninitialize()
|
|
{
|
|
m_sample.reset();
|
|
}
|
|
|
|
virtual void SetWindow(CoreWindow^ window)
|
|
{
|
|
window->SizeChanged +=
|
|
ref new TypedEventHandler<CoreWindow^, WindowSizeChangedEventArgs^>(this, &ViewProvider::OnWindowSizeChanged);
|
|
|
|
#if defined(NTDDI_WIN10_RS2) && (NTDDI_VERSION >= NTDDI_WIN10_RS2)
|
|
try
|
|
{
|
|
window->ResizeStarted +=
|
|
ref new TypedEventHandler<CoreWindow^, Object^>(this, &ViewProvider::OnResizeStarted);
|
|
|
|
window->ResizeCompleted +=
|
|
ref new TypedEventHandler<CoreWindow^, Object^>(this, &ViewProvider::OnResizeCompleted);
|
|
}
|
|
catch (...)
|
|
{
|
|
// Requires Windows 10 Creators Update (10.0.15063) or later
|
|
}
|
|
#endif
|
|
|
|
window->VisibilityChanged +=
|
|
ref new TypedEventHandler<CoreWindow^, VisibilityChangedEventArgs^>(this, &ViewProvider::OnVisibilityChanged);
|
|
|
|
window->Closed +=
|
|
ref new TypedEventHandler<CoreWindow^, CoreWindowEventArgs^>(this, &ViewProvider::OnWindowClosed);
|
|
|
|
auto dispatcher = CoreWindow::GetForCurrentThread()->Dispatcher;
|
|
|
|
dispatcher->AcceleratorKeyActivated +=
|
|
ref new TypedEventHandler<CoreDispatcher^, AcceleratorKeyEventArgs^>(this, &ViewProvider::OnAcceleratorKeyActivated);
|
|
|
|
auto navigation = Windows::UI::Core::SystemNavigationManager::GetForCurrentView();
|
|
|
|
navigation->BackRequested +=
|
|
ref new EventHandler<BackRequestedEventArgs^>(this, &ViewProvider::OnBackRequested);
|
|
|
|
auto currentDisplayInformation = DisplayInformation::GetForCurrentView();
|
|
|
|
currentDisplayInformation->DpiChanged +=
|
|
ref new TypedEventHandler<DisplayInformation^, Object^>(this, &ViewProvider::OnDpiChanged);
|
|
|
|
currentDisplayInformation->OrientationChanged +=
|
|
ref new TypedEventHandler<DisplayInformation^, Object^>(this, &ViewProvider::OnOrientationChanged);
|
|
|
|
DisplayInformation::DisplayContentsInvalidated +=
|
|
ref new TypedEventHandler<DisplayInformation^, Object^>(this, &ViewProvider::OnDisplayContentsInvalidated);
|
|
|
|
m_DPI = currentDisplayInformation->LogicalDpi;
|
|
|
|
m_logicalWidth = window->Bounds.Width;
|
|
m_logicalHeight = window->Bounds.Height;
|
|
|
|
m_nativeOrientation = currentDisplayInformation->NativeOrientation;
|
|
m_currentOrientation = currentDisplayInformation->CurrentOrientation;
|
|
|
|
int outputWidth = ConvertDipsToPixels(m_logicalWidth);
|
|
int outputHeight = ConvertDipsToPixels(m_logicalHeight);
|
|
|
|
DXGI_MODE_ROTATION rotation = ComputeDisplayRotation();
|
|
|
|
if (rotation == DXGI_MODE_ROTATION_ROTATE90 || rotation == DXGI_MODE_ROTATION_ROTATE270)
|
|
{
|
|
std::swap(outputWidth, outputHeight);
|
|
}
|
|
|
|
m_sample->Initialize(reinterpret_cast<IUnknown*>(window),
|
|
outputWidth, outputHeight, rotation );
|
|
}
|
|
|
|
virtual void Load(Platform::String^ entryPoint)
|
|
{
|
|
}
|
|
|
|
virtual void Run()
|
|
{
|
|
while (!m_exit)
|
|
{
|
|
if (m_visible)
|
|
{
|
|
m_sample->Tick();
|
|
|
|
CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent);
|
|
}
|
|
else
|
|
{
|
|
CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending);
|
|
}
|
|
}
|
|
}
|
|
|
|
protected:
|
|
// Event handlers
|
|
void OnActivated(CoreApplicationView^ applicationView, IActivatedEventArgs^ args)
|
|
{
|
|
if (args->Kind == ActivationKind::Launch)
|
|
{
|
|
auto launchArgs = static_cast<LaunchActivatedEventArgs^>(args);
|
|
|
|
if (launchArgs->PrelaunchActivated)
|
|
{
|
|
// Opt-out of Prelaunch
|
|
CoreApplication::Exit();
|
|
return;
|
|
}
|
|
}
|
|
|
|
int w, h;
|
|
m_sample->GetDefaultSize(w, h);
|
|
|
|
m_DPI = DisplayInformation::GetForCurrentView()->LogicalDpi;
|
|
|
|
ApplicationView::PreferredLaunchWindowingMode = ApplicationViewWindowingMode::PreferredLaunchViewSize;
|
|
// Change to ApplicationViewWindowingMode::FullScreen to default to full screen
|
|
|
|
auto desiredSize = Size(ConvertPixelsToDips(w), ConvertPixelsToDips(h));
|
|
|
|
ApplicationView::PreferredLaunchViewSize = desiredSize;
|
|
|
|
auto view = ApplicationView::GetForCurrentView();
|
|
|
|
auto minSize = Size(ConvertPixelsToDips(320), ConvertPixelsToDips(200));
|
|
|
|
view->SetPreferredMinSize(minSize);
|
|
|
|
CoreWindow::GetForCurrentThread()->Activate();
|
|
|
|
view->FullScreenSystemOverlayMode = FullScreenSystemOverlayMode::Minimal;
|
|
|
|
view->TryResizeView(desiredSize);
|
|
}
|
|
|
|
void OnSuspending(Platform::Object^ sender, SuspendingEventArgs^ args)
|
|
{
|
|
auto deferral = args->SuspendingOperation->GetDeferral();
|
|
|
|
create_task([this, deferral]()
|
|
{
|
|
m_sample->OnSuspending();
|
|
|
|
deferral->Complete();
|
|
});
|
|
}
|
|
|
|
void OnResuming(Platform::Object^ sender, Platform::Object^ args)
|
|
{
|
|
m_sample->OnResuming();
|
|
}
|
|
|
|
void OnWindowSizeChanged(CoreWindow^ sender, WindowSizeChangedEventArgs^ args)
|
|
{
|
|
m_logicalWidth = sender->Bounds.Width;
|
|
m_logicalHeight = sender->Bounds.Height;
|
|
|
|
if (m_in_sizemove)
|
|
return;
|
|
|
|
HandleWindowSizeChanged();
|
|
}
|
|
|
|
#if defined(NTDDI_WIN10_RS2) && (NTDDI_VERSION >= NTDDI_WIN10_RS2)
|
|
void OnResizeStarted(CoreWindow^ sender, Platform::Object^ args)
|
|
{
|
|
m_in_sizemove = true;
|
|
}
|
|
|
|
void OnResizeCompleted(CoreWindow^ sender, Platform::Object^ args)
|
|
{
|
|
m_in_sizemove = false;
|
|
|
|
HandleWindowSizeChanged();
|
|
}
|
|
#endif
|
|
|
|
void OnVisibilityChanged(CoreWindow^ sender, VisibilityChangedEventArgs^ args)
|
|
{
|
|
m_visible = args->Visible;
|
|
if (m_visible)
|
|
m_sample->OnActivated();
|
|
else
|
|
m_sample->OnDeactivated();
|
|
}
|
|
|
|
void OnWindowClosed(CoreWindow^ sender, CoreWindowEventArgs^ args)
|
|
{
|
|
m_exit = true;
|
|
}
|
|
|
|
void OnAcceleratorKeyActivated(CoreDispatcher^, AcceleratorKeyEventArgs^ args)
|
|
{
|
|
if (args->EventType == CoreAcceleratorKeyEventType::SystemKeyDown
|
|
&& args->VirtualKey == VirtualKey::Enter
|
|
&& args->KeyStatus.IsMenuKeyDown
|
|
&& !args->KeyStatus.WasKeyDown)
|
|
{
|
|
// Implements the classic ALT+ENTER fullscreen toggle
|
|
auto view = ApplicationView::GetForCurrentView();
|
|
|
|
if (view->IsFullScreenMode)
|
|
view->ExitFullScreenMode();
|
|
else
|
|
view->TryEnterFullScreenMode();
|
|
|
|
args->Handled = true;
|
|
}
|
|
}
|
|
|
|
void OnBackRequested(Platform::Object^, Windows::UI::Core::BackRequestedEventArgs^ args)
|
|
{
|
|
// UWP on Xbox One triggers a back request whenever the B button is pressed
|
|
// which can result in the app being suspended if unhandled
|
|
args->Handled = true;
|
|
}
|
|
|
|
void OnDpiChanged(DisplayInformation^ sender, Object^ args)
|
|
{
|
|
m_DPI = sender->LogicalDpi;
|
|
|
|
HandleWindowSizeChanged();
|
|
}
|
|
|
|
void OnOrientationChanged(DisplayInformation^ sender, Object^ args)
|
|
{
|
|
auto resizeManager = CoreWindowResizeManager::GetForCurrentView();
|
|
resizeManager->ShouldWaitForLayoutCompletion = true;
|
|
|
|
m_currentOrientation = sender->CurrentOrientation;
|
|
|
|
HandleWindowSizeChanged();
|
|
|
|
resizeManager->NotifyLayoutCompleted();
|
|
}
|
|
|
|
void OnDisplayContentsInvalidated(DisplayInformation^ sender, Object^ args)
|
|
{
|
|
m_sample->ValidateDevice();
|
|
}
|
|
|
|
private:
|
|
bool m_exit;
|
|
bool m_visible;
|
|
bool m_in_sizemove;
|
|
float m_DPI;
|
|
float m_logicalWidth;
|
|
float m_logicalHeight;
|
|
std::unique_ptr<Sample> m_sample;
|
|
|
|
Windows::Graphics::Display::DisplayOrientations m_nativeOrientation;
|
|
Windows::Graphics::Display::DisplayOrientations m_currentOrientation;
|
|
|
|
inline int ConvertDipsToPixels(float dips) const
|
|
{
|
|
return int(dips * m_DPI / 96.f + 0.5f);
|
|
}
|
|
|
|
inline float ConvertPixelsToDips(int pixels) const
|
|
{
|
|
return (float(pixels) * 96.f / m_DPI);
|
|
}
|
|
|
|
DXGI_MODE_ROTATION ComputeDisplayRotation() const
|
|
{
|
|
DXGI_MODE_ROTATION rotation = DXGI_MODE_ROTATION_UNSPECIFIED;
|
|
|
|
switch (m_nativeOrientation)
|
|
{
|
|
case DisplayOrientations::Landscape:
|
|
switch (m_currentOrientation)
|
|
{
|
|
case DisplayOrientations::Landscape:
|
|
rotation = DXGI_MODE_ROTATION_IDENTITY;
|
|
break;
|
|
|
|
case DisplayOrientations::Portrait:
|
|
rotation = DXGI_MODE_ROTATION_ROTATE270;
|
|
break;
|
|
|
|
case DisplayOrientations::LandscapeFlipped:
|
|
rotation = DXGI_MODE_ROTATION_ROTATE180;
|
|
break;
|
|
|
|
case DisplayOrientations::PortraitFlipped:
|
|
rotation = DXGI_MODE_ROTATION_ROTATE90;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case DisplayOrientations::Portrait:
|
|
switch (m_currentOrientation)
|
|
{
|
|
case DisplayOrientations::Landscape:
|
|
rotation = DXGI_MODE_ROTATION_ROTATE90;
|
|
break;
|
|
|
|
case DisplayOrientations::Portrait:
|
|
rotation = DXGI_MODE_ROTATION_IDENTITY;
|
|
break;
|
|
|
|
case DisplayOrientations::LandscapeFlipped:
|
|
rotation = DXGI_MODE_ROTATION_ROTATE270;
|
|
break;
|
|
|
|
case DisplayOrientations::PortraitFlipped:
|
|
rotation = DXGI_MODE_ROTATION_ROTATE180;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return rotation;
|
|
}
|
|
|
|
void HandleWindowSizeChanged()
|
|
{
|
|
int outputWidth = ConvertDipsToPixels(m_logicalWidth);
|
|
int outputHeight = ConvertDipsToPixels(m_logicalHeight);
|
|
|
|
DXGI_MODE_ROTATION rotation = ComputeDisplayRotation();
|
|
|
|
if (rotation == DXGI_MODE_ROTATION_ROTATE90 || rotation == DXGI_MODE_ROTATION_ROTATE270)
|
|
{
|
|
std::swap(outputWidth, outputHeight);
|
|
}
|
|
|
|
m_sample->OnWindowSizeChanged(outputWidth, outputHeight, rotation);
|
|
}
|
|
};
|
|
|
|
ref class ViewProviderFactory : IFrameworkViewSource
|
|
{
|
|
public:
|
|
virtual IFrameworkView^ CreateView()
|
|
{
|
|
return ref new ViewProvider();
|
|
}
|
|
};
|
|
|
|
|
|
// Entry point
|
|
[Platform::MTAThread]
|
|
int __cdecl main(Platform::Array<Platform::String^>^ /*argv*/)
|
|
{
|
|
if (!XMVerifyCPUSupport())
|
|
{
|
|
throw std::exception("XMVerifyCPUSupport");
|
|
}
|
|
|
|
auto viewProviderFactory = ref new ViewProviderFactory();
|
|
CoreApplication::Run(viewProviderFactory);
|
|
return 0;
|
|
}
|
|
|
|
|
|
// Exit helper
|
|
void ExitSample() noexcept
|
|
{
|
|
Windows::ApplicationModel::Core::CoreApplication::Exit();
|
|
}
|