refactoring.
This commit is contained in:
Binary file not shown.
@@ -47,7 +47,7 @@ public class Cursor : MonoBehaviour
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (monitor.isPointerVisible) {
|
||||
if (monitor.isCursorVisible) {
|
||||
UpdatePosition();
|
||||
UpdateTexture();
|
||||
UpdateMaterial();
|
||||
@@ -76,7 +76,7 @@ public class Cursor : MonoBehaviour
|
||||
pointerTextures_.Add(scale, texture);
|
||||
}
|
||||
var pointerTexture = pointerTextures_[scale];
|
||||
monitor.UpdatePointerTexture(pointerTexture.GetNativeTexturePtr());
|
||||
monitor.UpdateCursorTexture(pointerTexture.GetNativeTexturePtr());
|
||||
cursorMaterial_.SetTexture("_MainTex", pointerTexture);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ using System.Runtime.InteropServices;
|
||||
namespace uDesktopDuplication
|
||||
{
|
||||
|
||||
public enum PointerShapeType
|
||||
public enum CursorShapeType
|
||||
{
|
||||
MonoChrome = 1,
|
||||
Color = 2,
|
||||
@@ -29,27 +29,23 @@ public static class Lib
|
||||
[DllImport("uDesktopDuplication")]
|
||||
public static extern bool IsPrimary(int id);
|
||||
[DllImport("uDesktopDuplication")]
|
||||
public static extern bool IsPointerVisible(int id);
|
||||
public static extern bool IsCursorVisible(int id);
|
||||
[DllImport("uDesktopDuplication")]
|
||||
public static extern int GetPointerX(int id);
|
||||
public static extern int GetCursorX(int id);
|
||||
[DllImport("uDesktopDuplication")]
|
||||
public static extern int GetPointerY(int id);
|
||||
public static extern int GetCursorY(int id);
|
||||
[DllImport("uDesktopDuplication")]
|
||||
public static extern int GetPointerShapeWidth(int id);
|
||||
public static extern int GetCursorShapeWidth(int id);
|
||||
[DllImport("uDesktopDuplication")]
|
||||
public static extern int GetPointerShapeHeight(int id);
|
||||
public static extern int GetCursorShapeHeight(int id);
|
||||
[DllImport("uDesktopDuplication")]
|
||||
public static extern int GetPointerShapePitch(int id);
|
||||
public static extern int GetCursorShapePitch(int id);
|
||||
[DllImport("uDesktopDuplication")]
|
||||
public static extern PointerShapeType GetPointerShapeType(int id);
|
||||
public static extern CursorShapeType GetCursorShapeType(int id);
|
||||
[DllImport("uDesktopDuplication")]
|
||||
public static extern void UpdatePointerTexture(int id, System.IntPtr ptr);
|
||||
public static extern void UpdateCursorTexture(int id, System.IntPtr ptr);
|
||||
[DllImport("uDesktopDuplication")]
|
||||
public static extern int SetTexturePtr(int id, IntPtr ptr);
|
||||
[DllImport("uDesktopDuplication")]
|
||||
public static extern int GetErrorCode();
|
||||
[DllImport("uDesktopDuplication")]
|
||||
public static extern void GetErrorMessage(StringBuilder buf, int len);
|
||||
|
||||
public static string GetName(int id)
|
||||
{
|
||||
@@ -57,13 +53,6 @@ public static class Lib
|
||||
GetName(id, buf, buf.Capacity);
|
||||
return buf.ToString();
|
||||
}
|
||||
|
||||
public static string GetErrorMessage()
|
||||
{
|
||||
var buf = new StringBuilder(64);
|
||||
GetErrorMessage(buf, buf.Capacity);
|
||||
return buf.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -40,9 +40,6 @@ public class Manager : MonoBehaviour
|
||||
[SerializeField, Tooltip("Set Desktop Duplication API timeout (milliseconds).")]
|
||||
int timeout = 0;
|
||||
|
||||
[SerializeField, Tooltip("Output logs given by the plugin.")]
|
||||
bool outputDebugLog = false;
|
||||
|
||||
private Coroutine renderCoroutine_ = null;
|
||||
|
||||
void Awake()
|
||||
@@ -81,10 +78,6 @@ public class Manager : MonoBehaviour
|
||||
}
|
||||
monitor.shouldBeUpdated = false;
|
||||
}
|
||||
if (outputDebugLog && Lib.GetErrorCode() != 0)
|
||||
{
|
||||
Debug.Log(Lib.GetErrorMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,34 +51,34 @@ public class Monitor
|
||||
get { return height > width; }
|
||||
}
|
||||
|
||||
public bool isPointerVisible
|
||||
public bool isCursorVisible
|
||||
{
|
||||
get { return Lib.IsPointerVisible(id); }
|
||||
get { return Lib.IsCursorVisible(id); }
|
||||
}
|
||||
|
||||
public int pointerX
|
||||
{
|
||||
get { return Lib.GetPointerX(id); }
|
||||
get { return Lib.GetCursorX(id); }
|
||||
}
|
||||
|
||||
public int pointerY
|
||||
{
|
||||
get { return Lib.GetPointerY(id); }
|
||||
get { return Lib.GetCursorY(id); }
|
||||
}
|
||||
|
||||
public int pointerShapeWidth
|
||||
{
|
||||
get { return Lib.GetPointerShapeWidth(id); }
|
||||
get { return Lib.GetCursorShapeWidth(id); }
|
||||
}
|
||||
|
||||
public int pointerShapeHeight
|
||||
{
|
||||
get { return Lib.GetPointerShapeHeight(id); }
|
||||
get { return Lib.GetCursorShapeHeight(id); }
|
||||
}
|
||||
|
||||
public PointerShapeType pointerShapeType
|
||||
public CursorShapeType pointerShapeType
|
||||
{
|
||||
get { return Lib.GetPointerShapeType(id); }
|
||||
get { return Lib.GetCursorShapeType(id); }
|
||||
}
|
||||
|
||||
public bool shouldBeUpdated
|
||||
@@ -107,9 +107,9 @@ public class Monitor
|
||||
GL.IssuePluginEvent(Lib.GetRenderEventFunc(), id);
|
||||
}
|
||||
|
||||
public void UpdatePointerTexture(System.IntPtr ptr)
|
||||
public void UpdateCursorTexture(System.IntPtr ptr)
|
||||
{
|
||||
Lib.UpdatePointerTexture(id, ptr);
|
||||
Lib.UpdateCursorTexture(id, ptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
#include <memory>
|
||||
#include "IUnityInterface.h"
|
||||
|
||||
class MonitorManager;
|
||||
|
||||
IUnityInterfaces* GetUnity();
|
||||
ID3D11Device* GetDevice();
|
||||
const std::unique_ptr<MonitorManager>& GetMonitorManager();
|
||||
@@ -0,0 +1,259 @@
|
||||
#include <d3d11.h>
|
||||
#include "Common.h"
|
||||
#include "MonitorManager.h"
|
||||
#include "Monitor.h"
|
||||
#include "Cursor.h"
|
||||
|
||||
|
||||
Cursor::Cursor(Monitor* monitor)
|
||||
: monitor_(monitor)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Cursor::~Cursor()
|
||||
{
|
||||
if (apiBuffer_ != nullptr)
|
||||
{
|
||||
delete[] apiBuffer_;
|
||||
apiBuffer_ = nullptr;
|
||||
}
|
||||
if (bgra32Buffer_ != nullptr)
|
||||
{
|
||||
delete[] bgra32Buffer_;
|
||||
bgra32Buffer_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Cursor::Update(const DXGI_OUTDUPL_FRAME_INFO& frameInfo)
|
||||
{
|
||||
isVisible_ = frameInfo.PointerPosition.Visible != 0;
|
||||
x_ = frameInfo.PointerPosition.Position.x;
|
||||
y_ = frameInfo.PointerPosition.Position.y;
|
||||
|
||||
// TODO: see more information to check where the cursor is.
|
||||
if (isVisible_)
|
||||
{
|
||||
GetMonitorManager()->SetCursorMonitorId(monitor_->GetId());
|
||||
}
|
||||
|
||||
if (GetMonitorManager()->GetCursorMonitorId() != monitor_->GetId()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Increase the buffer size if needed
|
||||
if (frameInfo.PointerShapeBufferSize > apiBufferSize_)
|
||||
{
|
||||
if (apiBuffer_) delete[] apiBuffer_;
|
||||
apiBuffer_ = new BYTE[frameInfo.PointerShapeBufferSize];
|
||||
apiBufferSize_ = frameInfo.PointerShapeBufferSize;
|
||||
}
|
||||
if (apiBuffer_ == nullptr) return;
|
||||
|
||||
// Get information about the mouse pointer if needed
|
||||
if (frameInfo.PointerShapeBufferSize != 0)
|
||||
{
|
||||
UINT bufferSize;
|
||||
monitor_->GetDeskDupl()->GetFramePointerShape(
|
||||
frameInfo.PointerShapeBufferSize,
|
||||
reinterpret_cast<void*>(apiBuffer_),
|
||||
&bufferSize,
|
||||
&shapeInfo_);
|
||||
}
|
||||
|
||||
// cursor type
|
||||
const auto cursorType = shapeInfo_.Type;
|
||||
const bool isMono = cursorType == DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MONOCHROME;
|
||||
const bool isColorMask = cursorType == DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MASKED_COLOR;
|
||||
|
||||
// Size
|
||||
const auto w = shapeInfo_.Width;
|
||||
const auto h = shapeInfo_.Height / (isMono ? 2 : 1);
|
||||
const auto p = shapeInfo_.Pitch;
|
||||
|
||||
// Convert the buffer given by API into BGRA32
|
||||
const auto bgraBufferSize = w * h * 4;
|
||||
if (bgraBufferSize > bgra32BufferSize_)
|
||||
{
|
||||
if (bgra32Buffer_) delete[] bgra32Buffer_;
|
||||
bgra32Buffer_ = new BYTE[bgraBufferSize];
|
||||
bgra32BufferSize_ = bgraBufferSize;
|
||||
}
|
||||
if (bgra32Buffer_ == nullptr) return;
|
||||
|
||||
// If masked, copy the desktop image and merge it with masked image.
|
||||
if (isMono || isColorMask)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
D3D11_TEXTURE2D_DESC desc;
|
||||
desc.Width = w;
|
||||
desc.Height = h;
|
||||
desc.MipLevels = 1;
|
||||
desc.ArraySize = 1;
|
||||
desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||
desc.SampleDesc.Count = 1;
|
||||
desc.SampleDesc.Quality = 0;
|
||||
desc.Usage = D3D11_USAGE_STAGING;
|
||||
desc.BindFlags = 0;
|
||||
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
|
||||
desc.MiscFlags = 0;
|
||||
|
||||
ID3D11Texture2D* texture = nullptr;
|
||||
hr = GetDevice()->CreateTexture2D(&desc, nullptr, &texture);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
D3D11_BOX box;
|
||||
box.front = 0;
|
||||
box.back = 1;
|
||||
box.left = x_;
|
||||
box.top = y_;
|
||||
box.right = x_ + w;
|
||||
box.bottom = y_ + h;
|
||||
|
||||
ID3D11DeviceContext* context;
|
||||
GetDevice()->GetImmediateContext(&context);
|
||||
context->CopySubresourceRegion(texture, 0, 0, 0, 0, monitor_->GetUnityTexture(), 0, &box);
|
||||
context->Release();
|
||||
|
||||
IDXGISurface* surface = nullptr;
|
||||
hr = texture->QueryInterface(__uuidof(IDXGISurface), (void**)&surface);
|
||||
texture->Release();
|
||||
if (FAILED(hr))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
DXGI_MAPPED_RECT mappedSurface;
|
||||
hr = surface->Map(&mappedSurface, DXGI_MAP_READ);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
surface->Release();
|
||||
return;
|
||||
}
|
||||
|
||||
// Finally, get the texture behind the mouse cursor.
|
||||
const auto desktop32 = reinterpret_cast<UINT*>(mappedSurface.pBits);
|
||||
const UINT desktopPitch = mappedSurface.Pitch / sizeof(UINT);
|
||||
|
||||
// Access RGBA values at the same time
|
||||
auto output32 = reinterpret_cast<UINT*>(bgra32Buffer_);
|
||||
|
||||
if (isMono)
|
||||
{
|
||||
for (UINT row = 0; row < h; ++row)
|
||||
{
|
||||
BYTE mask = 0x80;
|
||||
for (UINT col = 0; col < w; ++col)
|
||||
{
|
||||
const int i = row * w + col;
|
||||
const BYTE andMask = apiBuffer_[col / 8 + row * p] & mask;
|
||||
const BYTE xorMask = apiBuffer_[col / 8 + (row + h) * p] & mask;
|
||||
const UINT andMask32 = andMask ? 0xFFFFFFFF : 0xFF000000;
|
||||
const UINT xorMask32 = xorMask ? 0x00FFFFFF : 0x00000000;
|
||||
output32[i] = (desktop32[row * desktopPitch + col] & andMask32) ^ xorMask32;
|
||||
mask = (mask == 0x01) ? 0x80 : (mask >> 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else // DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MASKED_COLOR
|
||||
{
|
||||
const auto buffer32 = reinterpret_cast<UINT*>(apiBuffer_);
|
||||
|
||||
for (UINT row = 0; row < h; ++row)
|
||||
{
|
||||
for (UINT col = 0; col < w; ++col)
|
||||
{
|
||||
const int i = row * w + col;
|
||||
const int j = row * p / sizeof(UINT) + col;
|
||||
|
||||
UINT mask = 0xFF000000 & buffer32[j];
|
||||
if (mask)
|
||||
{
|
||||
output32[i] = (desktop32[row * desktopPitch + col] ^ buffer32[j]) | 0xFF000000;
|
||||
}
|
||||
else
|
||||
{
|
||||
output32[i] = buffer32[j] | 0xFF000000;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hr = surface->Unmap();
|
||||
surface->Release();
|
||||
if (FAILED(hr))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
else // DXGI_OUTDUPL_POINTER_SHAPE_TYPE_COLOR
|
||||
{
|
||||
auto output32 = reinterpret_cast<UINT*>(bgra32Buffer_);
|
||||
const auto buffer32 = reinterpret_cast<UINT*>(apiBuffer_);
|
||||
for (UINT i = 0; i < w * h; ++i)
|
||||
{
|
||||
output32[i] = buffer32[i];
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void Cursor::UpdateTexture(ID3D11Texture2D* texture)
|
||||
{
|
||||
if (bgra32Buffer_ == nullptr) return;
|
||||
ID3D11DeviceContext* context;
|
||||
GetDevice()->GetImmediateContext(&context);
|
||||
context->UpdateSubresource(texture, 0, nullptr, bgra32Buffer_, shapeInfo_.Width * 4, 0);
|
||||
context->Release();
|
||||
}
|
||||
|
||||
|
||||
bool Cursor::IsVisible() const
|
||||
{
|
||||
return isVisible_;
|
||||
}
|
||||
|
||||
|
||||
int Cursor::GetX() const
|
||||
{
|
||||
return x_;
|
||||
}
|
||||
|
||||
|
||||
int Cursor::GetY() const
|
||||
{
|
||||
return y_;
|
||||
}
|
||||
|
||||
|
||||
int Cursor::GetWidth() const
|
||||
{
|
||||
return shapeInfo_.Width;
|
||||
}
|
||||
|
||||
|
||||
int Cursor::GetHeight() const
|
||||
{
|
||||
return (shapeInfo_.Type == DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MONOCHROME) ?
|
||||
shapeInfo_.Height / 2 :
|
||||
shapeInfo_.Height;
|
||||
}
|
||||
|
||||
|
||||
int Cursor::GetPitch() const
|
||||
{
|
||||
return shapeInfo_.Pitch;
|
||||
}
|
||||
|
||||
|
||||
int Cursor::GetType() const
|
||||
{
|
||||
return shapeInfo_.Type;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
#include <d3d11.h>
|
||||
#include <dxgi1_2.h>
|
||||
#include <memory>
|
||||
|
||||
class Monitor;
|
||||
|
||||
class Cursor
|
||||
{
|
||||
public:
|
||||
explicit Cursor(Monitor* monitor);
|
||||
~Cursor();
|
||||
void Update(const DXGI_OUTDUPL_FRAME_INFO& frameInfo);
|
||||
void UpdateTexture(ID3D11Texture2D* texture);
|
||||
|
||||
bool IsVisible() const;
|
||||
int GetX() const;
|
||||
int GetY() const;
|
||||
int GetWidth() const;
|
||||
int GetHeight() const;
|
||||
int GetPitch() const;
|
||||
int GetType() const;
|
||||
|
||||
private:
|
||||
Monitor* monitor_;
|
||||
bool isVisible_ = false;
|
||||
int x_ = -1;
|
||||
int y_ = -1;
|
||||
BYTE* apiBuffer_ = nullptr;
|
||||
UINT apiBufferSize_ = 0;
|
||||
BYTE* bgra32Buffer_ = nullptr;
|
||||
UINT bgra32BufferSize_ = 0;
|
||||
DXGI_OUTDUPL_POINTER_SHAPE_INFO shapeInfo_;
|
||||
};
|
||||
@@ -1,424 +0,0 @@
|
||||
#include <d3d11.h>
|
||||
#include <dxgi1_2.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "IUnityInterface.h"
|
||||
#include "IUnityGraphicsD3D11.h"
|
||||
#include "Duplication.h"
|
||||
|
||||
|
||||
Duplication::Duplication(IUnityInterfaces* unity)
|
||||
: unity_(unity)
|
||||
, device_(unity->Get<IUnityGraphicsD3D11>()->GetDevice())
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
|
||||
Duplication::~Duplication()
|
||||
{
|
||||
Finalize();
|
||||
unity_ = nullptr;
|
||||
}
|
||||
|
||||
|
||||
void Duplication::Initialize()
|
||||
{
|
||||
Finalize();
|
||||
|
||||
// Get factory
|
||||
IDXGIFactory1* factory;
|
||||
CreateDXGIFactory1(__uuidof(IDXGIFactory1), reinterpret_cast<void**>(&factory));
|
||||
|
||||
// Check all display adapters
|
||||
int id = 0;
|
||||
IDXGIAdapter1* adapter;
|
||||
for (int i = 0; (factory->EnumAdapters1(i, &adapter) != DXGI_ERROR_NOT_FOUND); ++i)
|
||||
{
|
||||
// Search the main monitor from all outputs
|
||||
IDXGIOutput* output;
|
||||
for (int j = 0; (adapter->EnumOutputs(j, &output) != DXGI_ERROR_NOT_FOUND); ++j)
|
||||
{
|
||||
Monitor monitor;
|
||||
monitor.id = id++;
|
||||
|
||||
output->GetDesc(&monitor.outputDesc);
|
||||
monitor.monitorInfo.cbSize = sizeof(MONITORINFOEX);
|
||||
GetMonitorInfo(monitor.outputDesc.Monitor, &monitor.monitorInfo);
|
||||
|
||||
auto output1 = reinterpret_cast<IDXGIOutput1*>(output);
|
||||
output1->DuplicateOutput(device_, &monitor.deskDupl);
|
||||
output->Release();
|
||||
|
||||
monitors_.push_back(monitor);
|
||||
}
|
||||
|
||||
adapter->Release();
|
||||
}
|
||||
|
||||
factory->Release();
|
||||
}
|
||||
|
||||
|
||||
void Duplication::Finalize()
|
||||
{
|
||||
// Release all duplicaitons
|
||||
for (auto& monitor : monitors_)
|
||||
{
|
||||
monitor.deskDupl->Release();
|
||||
}
|
||||
monitors_.clear();
|
||||
}
|
||||
|
||||
|
||||
bool Duplication::IsValidId(int id) const
|
||||
{
|
||||
return id >= 0 && id < monitors_.size();
|
||||
}
|
||||
|
||||
|
||||
void Duplication::OnRender(int id)
|
||||
{
|
||||
errorCode_ = 0;
|
||||
errorMessage_ = "";
|
||||
|
||||
if (!IsValidId(id)) return;
|
||||
auto& monitor = monitors_[id];
|
||||
|
||||
if (monitor.deskDupl == nullptr || monitor.texture == nullptr) return;
|
||||
|
||||
IDXGIResource* resource = nullptr;
|
||||
DXGI_OUTDUPL_FRAME_INFO frameInfo;
|
||||
|
||||
errorCode_ = monitor.deskDupl->AcquireNextFrame(timeout_, &frameInfo, &resource);
|
||||
if (FAILED(errorCode_))
|
||||
{
|
||||
if (errorCode_ == DXGI_ERROR_ACCESS_LOST)
|
||||
{
|
||||
Initialize();
|
||||
errorMessage_ = "[IDXGIOutputDuplication::AcquireNextFrame()] Access lost.";
|
||||
}
|
||||
else
|
||||
{
|
||||
errorMessage_ = "[IDXGIOutputDuplication::AcquireNextFrame()] Maybe timeout.";
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
ID3D11Texture2D* texture;
|
||||
resource->QueryInterface(__uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&texture));
|
||||
|
||||
ID3D11DeviceContext* context;
|
||||
device_->GetImmediateContext(&context);
|
||||
context->CopyResource(monitor.texture, texture);
|
||||
|
||||
if (!UpdateMouse(frameInfo, monitor))
|
||||
{
|
||||
errorCode_ = -999;
|
||||
errorMessage_ = "[UpdateMouse()] failed.";
|
||||
}
|
||||
|
||||
resource->Release();
|
||||
monitor.deskDupl->ReleaseFrame();
|
||||
}
|
||||
|
||||
|
||||
bool Duplication::UpdateMouse(const DXGI_OUTDUPL_FRAME_INFO& frameInfo, Monitor& monitor)
|
||||
{
|
||||
auto& pointer = monitor.pointer;
|
||||
pointer.isVisible = frameInfo.PointerPosition.Visible != 0;
|
||||
pointer.x = frameInfo.PointerPosition.Position.x;
|
||||
pointer.y = frameInfo.PointerPosition.Position.y;
|
||||
|
||||
// Pointer type
|
||||
const auto pointerType = pointer.shapeInfo.Type;
|
||||
const bool isMono = pointerType == DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MONOCHROME;
|
||||
const bool isColorMask = pointerType == DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MASKED_COLOR;
|
||||
|
||||
if (pointer.isVisible)
|
||||
{
|
||||
mouseMonitor_ = monitor.id;
|
||||
}
|
||||
|
||||
if (mouseMonitor_ != monitor.id) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Increase the buffer size if needed
|
||||
if (frameInfo.PointerShapeBufferSize > pointer.apiBufferSize)
|
||||
{
|
||||
if (pointer.apiBuffer) delete[] pointer.apiBuffer;
|
||||
pointer.apiBuffer = new BYTE[frameInfo.PointerShapeBufferSize];
|
||||
pointer.apiBufferSize = frameInfo.PointerShapeBufferSize;
|
||||
}
|
||||
if (!pointer.apiBuffer) return true;
|
||||
|
||||
// Get information about the mouse pointer if needed
|
||||
if (frameInfo.PointerShapeBufferSize != 0)
|
||||
{
|
||||
UINT bufferSize;
|
||||
monitor.deskDupl->GetFramePointerShape(
|
||||
frameInfo.PointerShapeBufferSize,
|
||||
reinterpret_cast<void*>(pointer.apiBuffer),
|
||||
&bufferSize,
|
||||
&pointer.shapeInfo);
|
||||
}
|
||||
|
||||
// Size
|
||||
const auto w = pointer.shapeInfo.Width;
|
||||
const auto h = pointer.shapeInfo.Height / (isMono ? 2 : 1);
|
||||
const auto p = pointer.shapeInfo.Pitch;
|
||||
|
||||
// Convert the buffer given by API into BGRA32
|
||||
const auto bgraBufferSize = w * h * 4;
|
||||
if (bgraBufferSize > pointer.bgra32BufferSize)
|
||||
{
|
||||
if (pointer.bgra32Buffer) delete[] pointer.bgra32Buffer;
|
||||
pointer.bgra32Buffer = new BYTE[bgraBufferSize];
|
||||
pointer.bgra32BufferSize = bgraBufferSize;
|
||||
}
|
||||
if (!pointer.bgra32Buffer) return true;
|
||||
|
||||
// If masked, copy the desktop image and merge it with masked image.
|
||||
if (isMono || isColorMask)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
D3D11_TEXTURE2D_DESC desc;
|
||||
desc.Width = w;
|
||||
desc.Height = h;
|
||||
desc.MipLevels = 1;
|
||||
desc.ArraySize = 1;
|
||||
desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||
desc.SampleDesc.Count = 1;
|
||||
desc.SampleDesc.Quality = 0;
|
||||
desc.Usage = D3D11_USAGE_STAGING;
|
||||
desc.BindFlags = 0;
|
||||
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
|
||||
desc.MiscFlags = 0;
|
||||
|
||||
ID3D11DeviceContext* context;
|
||||
device_->GetImmediateContext(&context);
|
||||
|
||||
ID3D11Texture2D* texture = nullptr;
|
||||
hr = device_->CreateTexture2D(&desc, nullptr, &texture);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
D3D11_BOX box;
|
||||
box.front = 0;
|
||||
box.back = 1;
|
||||
box.left = pointer.x;
|
||||
box.top = pointer.y;
|
||||
box.right = pointer.x + w;
|
||||
box.bottom = pointer.y + h;
|
||||
context->CopySubresourceRegion(texture, 0, 0, 0, 0, monitor.texture, 0, &box);
|
||||
|
||||
IDXGISurface* surface = nullptr;
|
||||
hr = texture->QueryInterface(__uuidof(IDXGISurface), (void**)&surface);
|
||||
texture->Release();
|
||||
if (FAILED(hr))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
DXGI_MAPPED_RECT mappedSurface;
|
||||
hr = surface->Map(&mappedSurface, DXGI_MAP_READ);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
surface->Release();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Finally, get the texture behind the mouse pointer.
|
||||
const auto desktop32 = reinterpret_cast<UINT*>(mappedSurface.pBits);
|
||||
const UINT desktopPitch = mappedSurface.Pitch / sizeof(UINT);
|
||||
|
||||
// Access RGBA values at the same time
|
||||
auto output32 = reinterpret_cast<UINT*>(pointer.bgra32Buffer);
|
||||
|
||||
if (isMono)
|
||||
{
|
||||
for (UINT row = 0; row < h; ++row)
|
||||
{
|
||||
BYTE mask = 0x80;
|
||||
for (UINT col = 0; col < w; ++col)
|
||||
{
|
||||
const int i = row * w + col;
|
||||
const BYTE andMask = pointer.apiBuffer[col / 8 + row * p] & mask;
|
||||
const BYTE xorMask = pointer.apiBuffer[col / 8 + (row + h) * p] & mask;
|
||||
const UINT andMask32 = andMask ? 0xFFFFFFFF : 0xFF000000;
|
||||
const UINT xorMask32 = xorMask ? 0x00FFFFFF : 0x00000000;
|
||||
output32[i] = (desktop32[row * desktopPitch + col] & andMask32) ^ xorMask32;
|
||||
mask = (mask == 0x01) ? 0x80 : (mask >> 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else // DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MASKED_COLOR
|
||||
{
|
||||
const auto buffer32 = reinterpret_cast<UINT*>(pointer.apiBuffer);
|
||||
|
||||
for (UINT row = 0; row < h; ++row)
|
||||
{
|
||||
for (UINT col = 0; col < w; ++col)
|
||||
{
|
||||
const int i = row * w + col;
|
||||
const int j = row * p / sizeof(UINT) + col;
|
||||
|
||||
UINT mask = 0xFF000000 & buffer32[j];
|
||||
if (mask)
|
||||
{
|
||||
output32[i] = (desktop32[row * desktopPitch + col] ^ buffer32[j]) | 0xFF000000;
|
||||
}
|
||||
else
|
||||
{
|
||||
output32[i] = buffer32[j] | 0xFF000000;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hr = surface->Unmap();
|
||||
surface->Release();
|
||||
if (FAILED(hr))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else // DXGI_OUTDUPL_POINTER_SHAPE_TYPE_COLOR
|
||||
{
|
||||
auto output32 = reinterpret_cast<UINT*>(pointer.bgra32Buffer);
|
||||
const auto buffer32 = reinterpret_cast<UINT*>(pointer.apiBuffer);
|
||||
for (UINT i = 0; i < w * h; ++i)
|
||||
{
|
||||
output32[i] = buffer32[i];
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void Duplication::UpdatePointerTexture(int id, ID3D11Texture2D* ptr)
|
||||
{
|
||||
if (!IsValidId(id)) return;
|
||||
const auto& pointer = monitors_[id].pointer;
|
||||
if (!pointer.bgra32Buffer) return;
|
||||
ID3D11DeviceContext* context;
|
||||
device_->GetImmediateContext(&context);
|
||||
context->UpdateSubresource(ptr, 0, nullptr, pointer.bgra32Buffer, pointer.shapeInfo.Width * 4, 0);
|
||||
}
|
||||
|
||||
|
||||
void Duplication::SetTimeout(int timeout)
|
||||
{
|
||||
timeout_ = timeout;
|
||||
}
|
||||
|
||||
|
||||
void Duplication::SetTexturePtr(int id, void* texture)
|
||||
{
|
||||
if (!IsValidId(id)) return;
|
||||
monitors_[id].texture = reinterpret_cast<ID3D11Texture2D*>(texture);
|
||||
}
|
||||
|
||||
|
||||
int Duplication::GetMonitorCount() const
|
||||
{
|
||||
return static_cast<int>(monitors_.size());
|
||||
}
|
||||
|
||||
|
||||
void Duplication::GetName(int id, char* buf, int len) const
|
||||
{
|
||||
if (!IsValidId(id)) return;
|
||||
strcpy_s(buf, len, monitors_[id].monitorInfo.szDevice);
|
||||
}
|
||||
|
||||
|
||||
bool Duplication::IsPrimary(int id) const
|
||||
{
|
||||
if (!IsValidId(id)) return false;
|
||||
return monitors_[id].monitorInfo.dwFlags == MONITORINFOF_PRIMARY;
|
||||
}
|
||||
|
||||
|
||||
int Duplication::GetWidth(int id) const
|
||||
{
|
||||
if (!IsValidId(id)) return -1;
|
||||
const auto rect = monitors_[id].monitorInfo.rcMonitor;
|
||||
return rect.right - rect.left;
|
||||
}
|
||||
|
||||
|
||||
int Duplication::GetHeight(int id) const
|
||||
{
|
||||
if (!IsValidId(id)) return -1;
|
||||
const auto rect = monitors_[id].monitorInfo.rcMonitor;
|
||||
return rect.bottom - rect.top;
|
||||
}
|
||||
|
||||
|
||||
int Duplication::IsPointerVisible(int id) const
|
||||
{
|
||||
if (!IsValidId(id)) return false;
|
||||
return monitors_[id].pointer.isVisible;
|
||||
}
|
||||
|
||||
|
||||
int Duplication::GetPointerX(int id) const
|
||||
{
|
||||
if (!IsValidId(id)) return -1;
|
||||
return monitors_[id].pointer.x;
|
||||
}
|
||||
|
||||
|
||||
int Duplication::GetPointerY(int id) const
|
||||
{
|
||||
if (!IsValidId(id)) return -1;
|
||||
return monitors_[id].pointer.y;
|
||||
}
|
||||
|
||||
|
||||
int Duplication::GetPointerShapeWidth(int id) const
|
||||
{
|
||||
if (!IsValidId(id)) return -1;
|
||||
return monitors_[id].pointer.shapeInfo.Width;
|
||||
}
|
||||
|
||||
|
||||
int Duplication::GetPointerShapeHeight(int id) const
|
||||
{
|
||||
if (!IsValidId(id)) return -1;
|
||||
const auto& info = monitors_[id].pointer.shapeInfo;
|
||||
return (info.Type == DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MONOCHROME) ? info.Height / 2 : info.Height;
|
||||
}
|
||||
|
||||
|
||||
int Duplication::GetPointerShapePitch(int id) const
|
||||
{
|
||||
if (!IsValidId(id)) return -1;
|
||||
return monitors_[id].pointer.shapeInfo.Pitch;
|
||||
}
|
||||
|
||||
|
||||
int Duplication::GetPointerShapeType(int id) const
|
||||
{
|
||||
if (!IsValidId(id)) return -1;
|
||||
return monitors_[id].pointer.shapeInfo.Type;
|
||||
}
|
||||
|
||||
|
||||
int Duplication::GetErrorCode() const
|
||||
{
|
||||
return errorCode_;
|
||||
}
|
||||
|
||||
|
||||
void Duplication::GetErrorMessage(char* buf, int len) const
|
||||
{
|
||||
strcpy_s(buf, len, errorMessage_.c_str());
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
#include <d3d11.h>
|
||||
#include <dxgi1_2.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
struct IUnityInterfaces;
|
||||
|
||||
struct Pointer
|
||||
{
|
||||
bool isVisible = false;
|
||||
int x = -1;
|
||||
int y = -1;
|
||||
BYTE* apiBuffer = nullptr;
|
||||
UINT apiBufferSize = 0;
|
||||
BYTE* bgra32Buffer = nullptr;
|
||||
UINT bgra32BufferSize = 0;
|
||||
DXGI_OUTDUPL_POINTER_SHAPE_INFO shapeInfo;
|
||||
};
|
||||
|
||||
struct Monitor
|
||||
{
|
||||
int id = -1;
|
||||
IDXGIOutputDuplication* deskDupl = nullptr;
|
||||
ID3D11Texture2D* texture = nullptr;
|
||||
DXGI_OUTPUT_DESC outputDesc;
|
||||
MONITORINFOEX monitorInfo;
|
||||
Pointer pointer;
|
||||
};
|
||||
|
||||
class Duplication
|
||||
{
|
||||
public:
|
||||
explicit Duplication(IUnityInterfaces* unity);
|
||||
~Duplication();
|
||||
void OnRender(int id);
|
||||
|
||||
public:
|
||||
void UpdatePointerTexture(int id, ID3D11Texture2D* ptr);
|
||||
void SetTimeout(int timeout);
|
||||
void SetTexturePtr(int id, void* texture);
|
||||
|
||||
public:
|
||||
int GetMonitorCount() const;
|
||||
void GetName(int id, char* buf, int len) const;
|
||||
bool IsPrimary(int id) const;
|
||||
int GetWidth(int id) const;
|
||||
int GetHeight(int id) const;
|
||||
int IsPointerVisible(int id) const;
|
||||
int GetPointerX(int id) const;
|
||||
int GetPointerY(int id) const;
|
||||
int GetPointerShapeWidth(int id) const;
|
||||
int GetPointerShapeHeight(int id) const;
|
||||
int GetPointerShapePitch(int id) const;
|
||||
int GetPointerShapeType(int id) const;
|
||||
int GetErrorCode() const;
|
||||
void GetErrorMessage(char* buf, int len) const;
|
||||
|
||||
private:
|
||||
void Initialize();
|
||||
void Finalize();
|
||||
bool UpdateMouse(const DXGI_OUTDUPL_FRAME_INFO& frameInfo, Monitor& monitor);
|
||||
|
||||
bool IsValidId(int id) const;
|
||||
|
||||
IUnityInterfaces* unity_ = nullptr;
|
||||
ID3D11Device* device_ = nullptr;
|
||||
int mouseMonitor_ = 0;
|
||||
int timeout_ = 10;
|
||||
HRESULT errorCode_ = 0;
|
||||
std::string errorMessage_ = "";
|
||||
std::vector<Monitor> monitors_;
|
||||
};
|
||||
@@ -0,0 +1,118 @@
|
||||
#include <d3d11.h>
|
||||
#include "Common.h"
|
||||
#include "Cursor.h"
|
||||
#include "MonitorManager.h"
|
||||
#include "Monitor.h"
|
||||
|
||||
|
||||
Monitor::Monitor(int id, IDXGIOutput* output)
|
||||
: id_(id)
|
||||
{
|
||||
// MEMO: 'output' will be released automatically after this ctor.
|
||||
output->GetDesc(&outputDesc_);
|
||||
monitorInfo_.cbSize = sizeof(MONITORINFOEX);
|
||||
GetMonitorInfo(outputDesc_.Monitor, &monitorInfo_);
|
||||
|
||||
auto output1 = reinterpret_cast<IDXGIOutput1*>(output);
|
||||
output1->DuplicateOutput(GetDevice(), &deskDupl_);
|
||||
|
||||
cursor_ = std::make_unique<Cursor>(this);
|
||||
}
|
||||
|
||||
|
||||
Monitor::~Monitor()
|
||||
{
|
||||
deskDupl_->Release();
|
||||
}
|
||||
|
||||
|
||||
HRESULT Monitor::Render(UINT timeout)
|
||||
{
|
||||
if (deskDupl_ == nullptr || unityTexture_ == nullptr) return 0;
|
||||
|
||||
IDXGIResource* resource = nullptr;
|
||||
DXGI_OUTDUPL_FRAME_INFO frameInfo;
|
||||
|
||||
const auto hr = deskDupl_->AcquireNextFrame(timeout, &frameInfo, &resource);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
|
||||
ID3D11Texture2D* texture;
|
||||
resource->QueryInterface(__uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&texture));
|
||||
|
||||
ID3D11DeviceContext* context;
|
||||
GetDevice()->GetImmediateContext(&context);
|
||||
context->CopyResource(unityTexture_, texture);
|
||||
context->Release();
|
||||
|
||||
cursor_->Update(frameInfo);
|
||||
|
||||
resource->Release();
|
||||
deskDupl_->ReleaseFrame();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int Monitor::GetId() const
|
||||
{
|
||||
return id_;
|
||||
}
|
||||
|
||||
|
||||
void Monitor::SetUnityTexture(ID3D11Texture2D* texture)
|
||||
{
|
||||
unityTexture_ = texture;
|
||||
}
|
||||
|
||||
|
||||
ID3D11Texture2D* Monitor::GetUnityTexture() const
|
||||
{
|
||||
return unityTexture_;
|
||||
}
|
||||
|
||||
|
||||
IDXGIOutputDuplication* Monitor::GetDeskDupl()
|
||||
{
|
||||
return deskDupl_;
|
||||
}
|
||||
|
||||
|
||||
const std::unique_ptr<Cursor>& Monitor::GetCursor()
|
||||
{
|
||||
return cursor_;
|
||||
}
|
||||
|
||||
|
||||
void Monitor::UpdateCursorTexture(ID3D11Texture2D* texture)
|
||||
{
|
||||
cursor_->UpdateTexture(texture);
|
||||
}
|
||||
|
||||
|
||||
void Monitor::GetName(char* buf, int len) const
|
||||
{
|
||||
strcpy_s(buf, len, monitorInfo_.szDevice);
|
||||
}
|
||||
|
||||
|
||||
bool Monitor::IsPrimary() const
|
||||
{
|
||||
return monitorInfo_.dwFlags == MONITORINFOF_PRIMARY;
|
||||
}
|
||||
|
||||
|
||||
int Monitor::GetWidth() const
|
||||
{
|
||||
const auto rect = monitorInfo_.rcMonitor;
|
||||
return rect.right - rect.left;
|
||||
}
|
||||
|
||||
|
||||
int Monitor::GetHeight() const
|
||||
{
|
||||
const auto rect = monitorInfo_.rcMonitor;
|
||||
return rect.bottom - rect.top;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
#include <d3d11.h>
|
||||
#include <dxgi1_2.h>
|
||||
#include <memory>
|
||||
|
||||
class Cursor;
|
||||
|
||||
class Monitor
|
||||
{
|
||||
public:
|
||||
Monitor(int id, IDXGIOutput* output);
|
||||
~Monitor();
|
||||
HRESULT Render(UINT timeout = 0);
|
||||
void UpdateCursorTexture(ID3D11Texture2D* texture);
|
||||
|
||||
public:
|
||||
int GetId() const;
|
||||
void SetUnityTexture(ID3D11Texture2D* texture);
|
||||
ID3D11Texture2D* GetUnityTexture() const;
|
||||
void GetName(char* buf, int len) const;
|
||||
bool IsPrimary() const;
|
||||
int GetWidth() const;
|
||||
int GetHeight() const;
|
||||
IDXGIOutputDuplication* GetDeskDupl();
|
||||
const std::unique_ptr<Cursor>& GetCursor();
|
||||
|
||||
private:
|
||||
int id_ = -1;
|
||||
std::unique_ptr<Cursor> cursor_;
|
||||
IDXGIOutputDuplication* deskDupl_ = nullptr;
|
||||
ID3D11Texture2D* unityTexture_ = nullptr;
|
||||
DXGI_OUTPUT_DESC outputDesc_;
|
||||
MONITORINFOEX monitorInfo_;
|
||||
};
|
||||
@@ -0,0 +1,221 @@
|
||||
#include <d3d11.h>
|
||||
#include <dxgi1_2.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "IUnityInterface.h"
|
||||
#include "IUnityGraphicsD3D11.h"
|
||||
|
||||
#include "Monitor.h"
|
||||
#include "Cursor.h"
|
||||
#include "MonitorManager.h"
|
||||
|
||||
|
||||
MonitorManager::MonitorManager()
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
|
||||
MonitorManager::~MonitorManager()
|
||||
{
|
||||
Finalize();
|
||||
}
|
||||
|
||||
|
||||
void MonitorManager::Initialize()
|
||||
{
|
||||
Finalize();
|
||||
|
||||
// Get factory
|
||||
IDXGIFactory1* factory;
|
||||
CreateDXGIFactory1(__uuidof(IDXGIFactory1), reinterpret_cast<void**>(&factory));
|
||||
|
||||
// Check all display adapters
|
||||
int id = 0;
|
||||
IDXGIAdapter1* adapter;
|
||||
for (int i = 0; (factory->EnumAdapters1(i, &adapter) != DXGI_ERROR_NOT_FOUND); ++i)
|
||||
{
|
||||
// Search the main monitor from all outputs
|
||||
IDXGIOutput* output;
|
||||
for (int j = 0; (adapter->EnumOutputs(j, &output) != DXGI_ERROR_NOT_FOUND); ++j)
|
||||
{
|
||||
auto monitor = std::make_shared<Monitor>(id++, output);
|
||||
monitors_.push_back(monitor);
|
||||
output->Release();
|
||||
}
|
||||
adapter->Release();
|
||||
}
|
||||
factory->Release();
|
||||
}
|
||||
|
||||
|
||||
void MonitorManager::Finalize()
|
||||
{
|
||||
monitors_.clear();
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<Monitor> MonitorManager::GetMonitor(int id) const
|
||||
{
|
||||
if (id >= 0 && id < monitors_.size())
|
||||
{
|
||||
return monitors_[id];
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
void MonitorManager::OnRender(int id)
|
||||
{
|
||||
if (auto monitor = GetMonitor(id))
|
||||
{
|
||||
// If any monitor setting has changed (e.g. monitor size has changed),
|
||||
// it is necessary to re-initialize monitors.
|
||||
const auto hr = monitor->Render(timeout_);
|
||||
if (hr == DXGI_ERROR_ACCESS_LOST)
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MonitorManager::UpdateCursorTexture(int id, ID3D11Texture2D* texture)
|
||||
{
|
||||
if (auto monitor = GetMonitor(id))
|
||||
{
|
||||
monitor->UpdateCursorTexture(texture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MonitorManager::SetTimeout(int timeout)
|
||||
{
|
||||
timeout_ = timeout;
|
||||
}
|
||||
|
||||
|
||||
void MonitorManager::SetTexturePtr(int id, void* texture)
|
||||
{
|
||||
if (auto monitor = GetMonitor(id))
|
||||
{
|
||||
auto d3d11Texture = reinterpret_cast<ID3D11Texture2D*>(texture);
|
||||
monitor->SetUnityTexture(d3d11Texture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int MonitorManager::GetMonitorCount() const
|
||||
{
|
||||
return static_cast<int>(monitors_.size());
|
||||
}
|
||||
|
||||
|
||||
void MonitorManager::GetName(int id, char* buf, int len) const
|
||||
{
|
||||
if (auto monitor = GetMonitor(id))
|
||||
{
|
||||
monitor->GetName(buf, len);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool MonitorManager::IsPrimary(int id) const
|
||||
{
|
||||
if (auto monitor = GetMonitor(id))
|
||||
{
|
||||
return monitor->IsPrimary();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
int MonitorManager::GetWidth(int id) const
|
||||
{
|
||||
if (auto monitor = GetMonitor(id))
|
||||
{
|
||||
return monitor->GetWidth();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int MonitorManager::GetHeight(int id) const
|
||||
{
|
||||
if (auto monitor = GetMonitor(id))
|
||||
{
|
||||
return monitor->GetHeight();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int MonitorManager::IsCursorVisible(int id) const
|
||||
{
|
||||
if (auto monitor = GetMonitor(id))
|
||||
{
|
||||
return monitor->GetCursor()->IsVisible();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
int MonitorManager::GetCursorX(int id) const
|
||||
{
|
||||
if (auto monitor = GetMonitor(id))
|
||||
{
|
||||
return monitor->GetCursor()->GetX();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int MonitorManager::GetCursorY(int id) const
|
||||
{
|
||||
if (auto monitor = GetMonitor(id))
|
||||
{
|
||||
return monitor->GetCursor()->GetY();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int MonitorManager::GetCursorShapeWidth(int id) const
|
||||
{
|
||||
if (auto monitor = GetMonitor(id))
|
||||
{
|
||||
return monitor->GetCursor()->GetWidth();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int MonitorManager::GetCursorShapeHeight(int id) const
|
||||
{
|
||||
if (auto monitor = GetMonitor(id))
|
||||
{
|
||||
return monitor->GetCursor()->GetHeight();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int MonitorManager::GetCursorShapePitch(int id) const
|
||||
{
|
||||
if (auto monitor = GetMonitor(id))
|
||||
{
|
||||
return monitor->GetCursor()->GetPitch();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int MonitorManager::GetCursorShapeType(int id) const
|
||||
{
|
||||
if (auto monitor = GetMonitor(id))
|
||||
{
|
||||
return monitor->GetCursor()->GetType();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
#include <d3d11.h>
|
||||
#include <dxgi1_2.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
struct IUnityInterfaces;
|
||||
class Monitor;
|
||||
class Cursor;
|
||||
|
||||
class MonitorManager
|
||||
{
|
||||
public:
|
||||
explicit MonitorManager();
|
||||
~MonitorManager();
|
||||
|
||||
void SetCursorMonitorId(int id) { cursorMonitorId_ = id; }
|
||||
int GetCursorMonitorId() const { return cursorMonitorId_; }
|
||||
std::shared_ptr<Monitor> GetMonitor(int id) const;
|
||||
|
||||
private:
|
||||
void Initialize();
|
||||
void Finalize();
|
||||
|
||||
// Setters from Unity
|
||||
public:
|
||||
void OnRender(int id);
|
||||
void UpdateCursorTexture(int id, ID3D11Texture2D* ptr);
|
||||
void SetTimeout(int timeout);
|
||||
void SetTexturePtr(int id, void* texture);
|
||||
|
||||
// Getters from Unity
|
||||
public:
|
||||
int GetMonitorCount() const;
|
||||
void GetName(int id, char* buf, int len) const;
|
||||
bool IsPrimary(int id) const;
|
||||
int GetWidth(int id) const;
|
||||
int GetHeight(int id) const;
|
||||
int IsCursorVisible(int id) const;
|
||||
int GetCursorX(int id) const;
|
||||
int GetCursorY(int id) const;
|
||||
int GetCursorShapeWidth(int id) const;
|
||||
int GetCursorShapeHeight(int id) const;
|
||||
int GetCursorShapePitch(int id) const;
|
||||
int GetCursorShapeType(int id) const;
|
||||
|
||||
private:
|
||||
int timeout_ = 10;
|
||||
std::vector<std::shared_ptr<Monitor>> monitors_;
|
||||
std::shared_ptr<Cursor> cursor_;
|
||||
int cursorMonitorId_ = -1;
|
||||
};
|
||||
@@ -6,14 +6,35 @@
|
||||
|
||||
#include "IUnityInterface.h"
|
||||
#include "IUnityGraphics.h"
|
||||
#include "Duplication.h"
|
||||
#include "IUnityGraphicsD3D11.h"
|
||||
|
||||
#include "Common.h"
|
||||
#include "MonitorManager.h"
|
||||
|
||||
#pragma comment(lib, "dxgi.lib")
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
std::unique_ptr<Duplication> g_dupl;
|
||||
IUnityInterfaces* g_unity = nullptr;
|
||||
std::unique_ptr<MonitorManager> g_manager;
|
||||
}
|
||||
|
||||
|
||||
IUnityInterfaces* GetUnity()
|
||||
{
|
||||
return g_unity;
|
||||
}
|
||||
|
||||
|
||||
ID3D11Device* GetDevice()
|
||||
{
|
||||
return GetUnity()->Get<IUnityGraphicsD3D11>()->GetDevice();
|
||||
}
|
||||
|
||||
const std::unique_ptr<MonitorManager>& GetMonitorManager()
|
||||
{
|
||||
return g_manager;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,17 +42,18 @@ extern "C"
|
||||
{
|
||||
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API UnityPluginLoad(IUnityInterfaces* unityInterfaces)
|
||||
{
|
||||
g_dupl = std::make_unique<Duplication>(unityInterfaces);
|
||||
g_unity = unityInterfaces;
|
||||
g_manager = std::make_unique<MonitorManager>();
|
||||
}
|
||||
|
||||
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API UnityPluginUnload()
|
||||
{
|
||||
g_dupl.reset();
|
||||
g_manager.reset();
|
||||
}
|
||||
|
||||
void UNITY_INTERFACE_API OnRenderEvent(int id)
|
||||
{
|
||||
g_dupl->OnRender(id);
|
||||
g_manager->OnRender(id);
|
||||
}
|
||||
|
||||
UNITY_INTERFACE_EXPORT UnityRenderingEvent UNITY_INTERFACE_API GetRenderEventFunc()
|
||||
@@ -41,87 +63,76 @@ extern "C"
|
||||
|
||||
UNITY_INTERFACE_EXPORT size_t UNITY_INTERFACE_API GetMonitorCount()
|
||||
{
|
||||
return g_dupl->GetMonitorCount();
|
||||
return g_manager->GetMonitorCount();
|
||||
}
|
||||
|
||||
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API SetTimeout(int timeout)
|
||||
{
|
||||
g_dupl->SetTimeout(timeout);
|
||||
g_manager->SetTimeout(timeout);
|
||||
}
|
||||
|
||||
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API GetName(int id, char* buf, int len)
|
||||
{
|
||||
g_dupl->GetName(id, buf, len);
|
||||
g_manager->GetName(id, buf, len);
|
||||
}
|
||||
|
||||
UNITY_INTERFACE_EXPORT bool UNITY_INTERFACE_API IsPrimary(int id)
|
||||
{
|
||||
return g_dupl->IsPrimary(id);
|
||||
return g_manager->IsPrimary(id);
|
||||
}
|
||||
|
||||
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetWidth(int id)
|
||||
{
|
||||
return g_dupl->GetWidth(id);
|
||||
return g_manager->GetWidth(id);
|
||||
}
|
||||
|
||||
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetHeight(int id)
|
||||
{
|
||||
return g_dupl->GetHeight(id);
|
||||
return g_manager->GetHeight(id);
|
||||
}
|
||||
|
||||
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API IsPointerVisible(int id)
|
||||
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API IsCursorVisible(int id)
|
||||
{
|
||||
return g_dupl->IsPointerVisible(id);
|
||||
return g_manager->IsCursorVisible(id);
|
||||
}
|
||||
|
||||
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetPointerX(int id)
|
||||
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetCursorX(int id)
|
||||
{
|
||||
return g_dupl->GetPointerX(id);
|
||||
return g_manager->GetCursorX(id);
|
||||
}
|
||||
|
||||
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetPointerY(int id)
|
||||
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetCursorY(int id)
|
||||
{
|
||||
return g_dupl->GetPointerY(id);
|
||||
return g_manager->GetCursorY(id);
|
||||
}
|
||||
|
||||
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetPointerShapeWidth(int id)
|
||||
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetCursorShapeWidth(int id)
|
||||
{
|
||||
return g_dupl->GetPointerShapeWidth(id);
|
||||
return g_manager->GetCursorShapeWidth(id);
|
||||
}
|
||||
|
||||
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetPointerShapeHeight(int id)
|
||||
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetCursorShapeHeight(int id)
|
||||
{
|
||||
return g_dupl->GetPointerShapeHeight(id);
|
||||
return g_manager->GetCursorShapeHeight(id);
|
||||
}
|
||||
|
||||
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetPointerShapePitch(int id)
|
||||
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetCursorShapePitch(int id)
|
||||
{
|
||||
return g_dupl->GetPointerShapePitch(id);
|
||||
return g_manager->GetCursorShapePitch(id);
|
||||
}
|
||||
|
||||
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetPointerShapeType(int id)
|
||||
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetCursorShapeType(int id)
|
||||
{
|
||||
return g_dupl->GetPointerShapeType(id);
|
||||
return g_manager->GetCursorShapeType(id);
|
||||
}
|
||||
|
||||
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API UpdatePointerTexture(int id, ID3D11Texture2D* ptr)
|
||||
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API UpdateCursorTexture(int id, ID3D11Texture2D* ptr)
|
||||
{
|
||||
g_dupl->UpdatePointerTexture(id, ptr);
|
||||
g_manager->UpdateCursorTexture(id, ptr);
|
||||
}
|
||||
|
||||
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API SetTexturePtr(int id, void* texture)
|
||||
{
|
||||
g_dupl->SetTexturePtr(id, texture);
|
||||
g_manager->SetTexturePtr(id, texture);
|
||||
}
|
||||
|
||||
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetErrorCode()
|
||||
{
|
||||
return g_dupl->GetErrorCode();
|
||||
}
|
||||
|
||||
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API GetErrorMessage(char* buf, int len)
|
||||
{
|
||||
g_dupl->GetErrorMessage(buf, len);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -69,8 +69,12 @@
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);include</IncludePath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);include</IncludePath>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
@@ -122,14 +126,19 @@
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Duplication.cpp" />
|
||||
<ClCompile Include="main.cpp" />
|
||||
<ClCompile Include="MonitorManager.cpp" />
|
||||
<ClCompile Include="Main.cpp" />
|
||||
<ClCompile Include="Monitor.cpp" />
|
||||
<ClCompile Include="Cursor.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Duplication.h" />
|
||||
<ClInclude Include="IUnityGraphics.h" />
|
||||
<ClInclude Include="IUnityGraphicsD3D11.h" />
|
||||
<ClInclude Include="IUnityInterface.h" />
|
||||
<ClInclude Include="Common.h" />
|
||||
<ClInclude Include="MonitorManager.h" />
|
||||
<ClInclude Include="include\IUnityGraphics.h" />
|
||||
<ClInclude Include="include\IUnityGraphicsD3D11.h" />
|
||||
<ClInclude Include="include\IUnityInterface.h" />
|
||||
<ClInclude Include="Monitor.h" />
|
||||
<ClInclude Include="Cursor.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Include">
|
||||
<UniqueIdentifier>{a820eab3-2c2a-4d56-9670-064198e6a1cf}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="include\IUnityInterface.h">
|
||||
<Filter>Include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\IUnityGraphics.h">
|
||||
<Filter>Include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\IUnityGraphicsD3D11.h">
|
||||
<Filter>Include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Monitor.h" />
|
||||
<ClInclude Include="Cursor.h" />
|
||||
<ClInclude Include="Common.h" />
|
||||
<ClInclude Include="MonitorManager.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Monitor.cpp" />
|
||||
<ClCompile Include="Cursor.cpp" />
|
||||
<ClCompile Include="Main.cpp" />
|
||||
<ClCompile Include="MonitorManager.cpp" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
Reference in New Issue
Block a user