2108 lines
79 KiB
C++
2108 lines
79 KiB
C++
/********************************************************************************
|
|
Copyright (C) 2012 Hugh Bailey <obs.jim@gmail.com>
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
|
|
********************************************************************************/
|
|
|
|
|
|
#include "Main.h"
|
|
#include <dwmapi.h>
|
|
|
|
|
|
#define NUM_CAPTURE_TEXTURES 2
|
|
|
|
class DesktopImageSource : public ImageSource
|
|
{
|
|
Texture *renderTextures[NUM_CAPTURE_TEXTURES];
|
|
Texture *lastRendered;
|
|
|
|
UINT captureType;
|
|
String strWindow, strWindowClass;
|
|
BOOL bClientCapture, bCaptureMouse, bCaptureLayered;
|
|
HWND hwndFoundWindow;
|
|
|
|
Shader *colorKeyShader, *alphaIgnoreShader;
|
|
|
|
int width, height;
|
|
RECT captureRect;
|
|
UINT frameTime;
|
|
int curCaptureTexture;
|
|
XElement *data;
|
|
|
|
UINT warningID;
|
|
|
|
bool bUseColorKey, bUsePointFiltering;
|
|
DWORD keyColor;
|
|
UINT keySimilarity, keyBlend;
|
|
|
|
UINT opacity;
|
|
int gamma;
|
|
|
|
float rotateDegrees;
|
|
|
|
//-------------------------
|
|
// stuff for compatibility mode
|
|
bool bCompatibilityMode;
|
|
HDC hdcCompatible;
|
|
HBITMAP hbmpCompatible, hbmpOld;
|
|
BYTE *captureBits;
|
|
|
|
//-------------------------
|
|
// win 8 capture stuff
|
|
Texture *cursorTexture;
|
|
int xHotspot, yHotspot;
|
|
UINT monitor;
|
|
UINT deviceOutputID;
|
|
float retryAcquire;
|
|
bool bWindows8MonitorCapture;
|
|
MonitorInfo monitorData;
|
|
bool bMouseCaptured;
|
|
POINT cursorPos;
|
|
HCURSOR hCurrentCursor;
|
|
bool bInInit;
|
|
|
|
OutputDuplicator *duplicator;
|
|
|
|
public:
|
|
DesktopImageSource(UINT frameTime, XElement *data)
|
|
{
|
|
this->data = data;
|
|
duplicator = NULL;
|
|
|
|
bInInit = true;
|
|
|
|
UpdateSettings();
|
|
|
|
bInInit = false;
|
|
|
|
curCaptureTexture = 0;
|
|
this->frameTime = frameTime;
|
|
|
|
colorKeyShader = CreatePixelShaderFromFile(TEXT("shaders\\ColorKey_RGB.pShader"));
|
|
alphaIgnoreShader = CreatePixelShaderFromFile(TEXT("shaders\\AlphaIgnore.pShader"));
|
|
|
|
if(captureType == 0)
|
|
Log(TEXT("Using Monitor Capture"));
|
|
else if(captureType == 1)
|
|
Log(TEXT("Using Window Capture"));
|
|
}
|
|
|
|
~DesktopImageSource()
|
|
{
|
|
for(int i=0; i<NUM_CAPTURE_TEXTURES; i++)
|
|
delete renderTextures[i];
|
|
|
|
if(warningID)
|
|
App->RemoveStreamInfo(warningID);
|
|
|
|
delete duplicator;
|
|
delete cursorTexture;
|
|
delete alphaIgnoreShader;
|
|
delete colorKeyShader;
|
|
|
|
if(bCompatibilityMode)
|
|
{
|
|
SelectObject(hdcCompatible, hbmpOld);
|
|
DeleteDC(hdcCompatible);
|
|
DeleteObject(hbmpCompatible);
|
|
}
|
|
}
|
|
|
|
void BeginScene()
|
|
{
|
|
if(bWindows8MonitorCapture && !duplicator)
|
|
duplicator = GS->CreateOutputDuplicator(deviceOutputID);
|
|
}
|
|
|
|
void EndScene()
|
|
{
|
|
if(bWindows8MonitorCapture && duplicator)
|
|
{
|
|
delete duplicator;
|
|
duplicator = NULL;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------
|
|
// TODO - have win8 monitor capture behave even when using it as a global source
|
|
|
|
void GlobalSourceEnterScene()
|
|
{
|
|
}
|
|
|
|
void GlobalSourceLeaveScene()
|
|
{
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------
|
|
|
|
void Tick(float fSeconds)
|
|
{
|
|
if(bWindows8MonitorCapture && !duplicator)
|
|
{
|
|
retryAcquire += fSeconds;
|
|
if(retryAcquire > 1.0f)
|
|
{
|
|
retryAcquire = 0.0f;
|
|
|
|
lastRendered = NULL;
|
|
duplicator = GS->CreateOutputDuplicator(deviceOutputID);
|
|
}
|
|
}
|
|
}
|
|
|
|
void PreprocessWindows8MonitorCapture()
|
|
{
|
|
//----------------------------------------------------------
|
|
// capture monitor
|
|
|
|
if(duplicator)
|
|
{
|
|
switch(duplicator->AcquireNextFrame(0))
|
|
{
|
|
case DuplicatorInfo_Lost:
|
|
{
|
|
delete duplicator;
|
|
lastRendered = NULL;
|
|
duplicator = GS->CreateOutputDuplicator(deviceOutputID);
|
|
return;
|
|
}
|
|
|
|
case DuplicatorInfo_Error:
|
|
delete duplicator;
|
|
duplicator = NULL;
|
|
lastRendered = NULL;
|
|
return;
|
|
|
|
case DuplicatorInfo_Timeout:
|
|
return;
|
|
}
|
|
|
|
lastRendered = duplicator->GetCopyTexture();
|
|
}
|
|
|
|
//----------------------------------------------------------
|
|
// capture mouse
|
|
|
|
bMouseCaptured = false;
|
|
if(bCaptureMouse)
|
|
{
|
|
CURSORINFO ci;
|
|
zero(&ci, sizeof(ci));
|
|
ci.cbSize = sizeof(ci);
|
|
|
|
if(GetCursorInfo(&ci))
|
|
{
|
|
mcpy(&cursorPos, &ci.ptScreenPos, sizeof(cursorPos));
|
|
|
|
if(ci.flags & CURSOR_SHOWING)
|
|
{
|
|
if(ci.hCursor == hCurrentCursor)
|
|
bMouseCaptured = true;
|
|
else
|
|
{
|
|
HICON hIcon = CopyIcon(ci.hCursor);
|
|
hCurrentCursor = ci.hCursor;
|
|
|
|
delete cursorTexture;
|
|
cursorTexture = NULL;
|
|
|
|
if(hIcon)
|
|
{
|
|
ICONINFO ii;
|
|
if(GetIconInfo(hIcon, &ii))
|
|
{
|
|
xHotspot = int(ii.xHotspot);
|
|
yHotspot = int(ii.yHotspot);
|
|
|
|
UINT width, height;
|
|
LPBYTE lpData = GetCursorData(hIcon, ii, width, height);
|
|
if(lpData && width && height)
|
|
{
|
|
cursorTexture = CreateTexture(width, height, GS_BGRA, lpData, FALSE);
|
|
if(cursorTexture)
|
|
bMouseCaptured = true;
|
|
|
|
Free(lpData);
|
|
}
|
|
|
|
DeleteObject(ii.hbmColor);
|
|
DeleteObject(ii.hbmMask);
|
|
}
|
|
|
|
DestroyIcon(hIcon);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
HDC GetCurrentHDC()
|
|
{
|
|
HDC hDC = NULL;
|
|
|
|
Texture *captureTexture = renderTextures[curCaptureTexture];
|
|
|
|
if(bCompatibilityMode)
|
|
{
|
|
hDC = hdcCompatible;
|
|
//zero(captureBits, width*height*4);
|
|
}
|
|
else if(captureTexture)
|
|
captureTexture->GetDC(hDC);
|
|
|
|
return hDC;
|
|
}
|
|
|
|
void ReleaseCurrentHDC(HDC hDC)
|
|
{
|
|
Texture *captureTexture = renderTextures[curCaptureTexture];
|
|
|
|
if(!bCompatibilityMode)
|
|
captureTexture->ReleaseDC();
|
|
}
|
|
|
|
void EndPreprocess()
|
|
{
|
|
if(bCompatibilityMode)
|
|
{
|
|
renderTextures[0]->SetImage(captureBits, GS_IMAGEFORMAT_BGRA, width*4);
|
|
lastRendered = renderTextures[0];
|
|
}
|
|
else
|
|
{
|
|
lastRendered = renderTextures[curCaptureTexture];
|
|
|
|
if(++curCaptureTexture == NUM_CAPTURE_TEXTURES)
|
|
curCaptureTexture = 0;
|
|
}
|
|
}
|
|
|
|
void Preprocess()
|
|
{
|
|
if(bWindows8MonitorCapture)
|
|
{
|
|
PreprocessWindows8MonitorCapture();
|
|
return;
|
|
}
|
|
|
|
HDC hDC;
|
|
if(hDC = GetCurrentHDC())
|
|
{
|
|
//----------------------------------------------------------
|
|
// capture screen
|
|
|
|
CURSORINFO ci;
|
|
zero(&ci, sizeof(ci));
|
|
ci.cbSize = sizeof(ci);
|
|
BOOL bMouseCaptured;
|
|
|
|
bMouseCaptured = bCaptureMouse && GetCursorInfo(&ci);
|
|
|
|
bool bWindowNotFound = false;
|
|
HWND hwndCapture = NULL;
|
|
if(captureType == 1)
|
|
{
|
|
if(hwndFoundWindow && IsWindow(hwndFoundWindow))
|
|
{
|
|
TCHAR lpClassName[256];
|
|
BOOL bSuccess = GetClassName(hwndFoundWindow, lpClassName, 255);
|
|
|
|
if(bSuccess && scmpi(lpClassName, strWindowClass) == 0)
|
|
hwndCapture = hwndFoundWindow;
|
|
else
|
|
{
|
|
hwndCapture = FindWindow(strWindowClass, strWindow);
|
|
if(!hwndCapture)
|
|
hwndCapture = FindWindow(strWindowClass, NULL);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hwndCapture = FindWindow(strWindowClass, strWindow);
|
|
if(!hwndCapture)
|
|
hwndCapture = FindWindow(strWindowClass, NULL);
|
|
}
|
|
|
|
//note to self - hwndFoundWindow is used to make sure it doesn't pick up another window unintentionally if the title changes
|
|
hwndFoundWindow = hwndCapture;
|
|
|
|
if(!hwndCapture)
|
|
bWindowNotFound = true;
|
|
if(hwndCapture && (IsIconic(hwndCapture) || !IsWindowVisible(hwndCapture)))
|
|
{
|
|
ReleaseCurrentHDC(hDC);
|
|
//bWindowMinimized = true;
|
|
|
|
if(!warningID)
|
|
{
|
|
String strWarning;
|
|
|
|
strWarning << Str("Sources.SoftwareCaptureSource.WindowMinimized");
|
|
warningID = App->AddStreamInfo(strWarning, bWindowNotFound ? StreamInfoPriority_High : StreamInfoPriority_Medium);
|
|
}
|
|
return;
|
|
}
|
|
else if(!bWindowNotFound)
|
|
{
|
|
if(warningID)
|
|
{
|
|
App->RemoveStreamInfo(warningID);
|
|
warningID = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
HDC hCaptureDC;
|
|
if(hwndCapture && captureType == 1 && !bClientCapture)
|
|
hCaptureDC = GetWindowDC(hwndCapture);
|
|
else
|
|
hCaptureDC = GetDC(hwndCapture);
|
|
|
|
if(bWindowNotFound)
|
|
{
|
|
RECT rc = {0, 0, width, height};
|
|
FillRect(hDC, &rc, (HBRUSH)GetStockObject(BLACK_BRUSH));
|
|
|
|
if(!warningID)
|
|
warningID = App->AddStreamInfo(Str("Sources.SoftwareCaptureSource.WindowNotFound"), StreamInfoPriority_High);
|
|
}
|
|
else
|
|
{
|
|
//CAPTUREBLT causes mouse flicker, so make capturing layered optional
|
|
if(!BitBlt(hDC, 0, 0, width, height, hCaptureDC, captureRect.left, captureRect.top, bCaptureLayered ? SRCCOPY|CAPTUREBLT : SRCCOPY))
|
|
{
|
|
RUNONCE AppWarning(TEXT("Capture BitBlt failed (%d).. just so you know"), GetLastError());
|
|
}
|
|
}
|
|
|
|
ReleaseDC(hwndCapture, hCaptureDC);
|
|
|
|
//----------------------------------------------------------
|
|
// capture mouse
|
|
|
|
if(bMouseCaptured && (captureType == 0 || (captureType == 1 && hwndFoundWindow == GetForegroundWindow())))
|
|
{
|
|
if(ci.flags & CURSOR_SHOWING)
|
|
{
|
|
HICON hIcon = CopyIcon(ci.hCursor);
|
|
|
|
if(hIcon)
|
|
{
|
|
ICONINFO ii;
|
|
if(GetIconInfo(hIcon, &ii))
|
|
{
|
|
POINT capturePos = {captureRect.left, captureRect.top};
|
|
|
|
if(captureType == 1)
|
|
{
|
|
if(bClientCapture)
|
|
ClientToScreen(hwndCapture, &capturePos);
|
|
else
|
|
{
|
|
RECT windowRect;
|
|
GetWindowRect(hwndCapture, &windowRect);
|
|
capturePos.x += windowRect.left;
|
|
capturePos.y += windowRect.top;
|
|
}
|
|
}
|
|
|
|
int x = ci.ptScreenPos.x - int(ii.xHotspot) - capturePos.x;
|
|
int y = ci.ptScreenPos.y - int(ii.yHotspot) - capturePos.y;
|
|
|
|
DrawIcon(hDC, x, y, hIcon);
|
|
|
|
DeleteObject(ii.hbmColor);
|
|
DeleteObject(ii.hbmMask);
|
|
}
|
|
|
|
DestroyIcon(hIcon);
|
|
}
|
|
}
|
|
}
|
|
|
|
ReleaseCurrentHDC(hDC);
|
|
}
|
|
else
|
|
{
|
|
RUNONCE AppWarning(TEXT("Failed to get DC from capture surface"));
|
|
}
|
|
|
|
EndPreprocess();
|
|
}
|
|
|
|
void Render(const Vect2 &pos, const Vect2 &size)
|
|
{
|
|
SamplerState *sampler = NULL;
|
|
/*if(bWindows8MonitorCapture)
|
|
{
|
|
RenderWindows8MonitorCapture(pos, size);
|
|
return;
|
|
}*/
|
|
|
|
Vect2 ulCoord = Vect2(0.0f, 0.0f),
|
|
lrCoord = Vect2(1.0f, 1.0f);
|
|
|
|
if(captureType == 1 && !hwndFoundWindow) {
|
|
// Don't render a giant black rectangle if the window isn't found.
|
|
return;
|
|
}
|
|
|
|
if(bWindows8MonitorCapture)
|
|
{
|
|
LONG monitorWidth = monitorData.rect.right-monitorData.rect.left;
|
|
LONG monitorHeight = monitorData.rect.bottom-monitorData.rect.top;
|
|
RECT captureArea = {captureRect.left-monitorData.rect.left,
|
|
captureRect.top-monitorData.rect.top,
|
|
captureRect.right-monitorData.rect.left,
|
|
captureRect.bottom-monitorData.rect.top};
|
|
|
|
ulCoord.x = float(double(captureArea.left)/double(monitorWidth));
|
|
ulCoord.y = float(double(captureArea.top)/double(monitorHeight));
|
|
|
|
lrCoord.x = float(double(captureArea.right)/double(monitorWidth));
|
|
lrCoord.y = float(double(captureArea.bottom)/double(monitorHeight));
|
|
}
|
|
|
|
if(lastRendered)
|
|
{
|
|
float fGamma = float(-(gamma-100) + 100) * 0.01f;
|
|
|
|
Shader *lastPixelShader = GetCurrentPixelShader();
|
|
|
|
float fOpacity = float(opacity)*0.01f;
|
|
DWORD opacity255 = DWORD(fOpacity*255.0f);
|
|
|
|
if(bUseColorKey)
|
|
{
|
|
LoadPixelShader(colorKeyShader);
|
|
HANDLE hGamma = colorKeyShader->GetParameterByName(TEXT("gamma"));
|
|
if(hGamma)
|
|
colorKeyShader->SetFloat(hGamma, fGamma);
|
|
|
|
float fSimilarity = float(keySimilarity)*0.01f;
|
|
float fBlend = float(keyBlend)*0.01f;
|
|
|
|
colorKeyShader->SetColor(colorKeyShader->GetParameter(2), keyColor);
|
|
colorKeyShader->SetFloat(colorKeyShader->GetParameter(3), fSimilarity);
|
|
colorKeyShader->SetFloat(colorKeyShader->GetParameter(4), fBlend);
|
|
|
|
}
|
|
else
|
|
{
|
|
LoadPixelShader(alphaIgnoreShader);
|
|
HANDLE hGamma = alphaIgnoreShader->GetParameterByName(TEXT("gamma"));
|
|
if(hGamma)
|
|
alphaIgnoreShader->SetFloat(hGamma, fGamma);
|
|
}
|
|
|
|
if(bUsePointFiltering) {
|
|
SamplerInfo samplerinfo;
|
|
samplerinfo.filter = GS_FILTER_POINT;
|
|
sampler = CreateSamplerState(samplerinfo);
|
|
LoadSamplerState(sampler, 0);
|
|
}
|
|
|
|
if(bCompatibilityMode)
|
|
DrawSpriteEx(lastRendered, (opacity255<<24) | 0xFFFFFF,
|
|
pos.x, pos.y+size.y, pos.x+size.x, pos.y,
|
|
ulCoord.x, ulCoord.y,
|
|
lrCoord.x, lrCoord.y);
|
|
else
|
|
GS->DrawSpriteExRotate(lastRendered, (opacity255<<24) | 0xFFFFFF,
|
|
pos.x, pos.y, pos.x+size.x, pos.y+size.y, 0.0f,
|
|
ulCoord.x, ulCoord.y,
|
|
lrCoord.x, lrCoord.y, rotateDegrees);
|
|
|
|
if(bUsePointFiltering) delete(sampler);
|
|
|
|
LoadPixelShader(lastPixelShader);
|
|
|
|
//draw mouse
|
|
if(bWindows8MonitorCapture && cursorTexture && bMouseCaptured && bCaptureMouse)
|
|
{
|
|
POINT newPos = {cursorPos.x-xHotspot, cursorPos.y-yHotspot};
|
|
|
|
if( newPos.x >= captureRect.left && newPos.y >= captureRect.top &&
|
|
newPos.x < captureRect.right && newPos.y < captureRect.bottom)
|
|
{
|
|
Vect2 newCursorPos = Vect2(float(newPos.x-captureRect.left), float(newPos.y-captureRect.top));
|
|
Vect2 newCursorSize = Vect2(float(cursorTexture->Width()), float(cursorTexture->Height()));
|
|
|
|
Vect2 sizeMultiplier = size/GetSize();
|
|
newCursorPos *= sizeMultiplier;
|
|
newCursorPos += pos;
|
|
newCursorSize *= sizeMultiplier;
|
|
|
|
GS->SetCropping(0.0f, 0.0f, 0.0f, 0.0f);
|
|
DrawSprite(cursorTexture, 0xFFFFFFFF, newCursorPos.x, newCursorPos.y, newCursorPos.x+newCursorSize.x, newCursorPos.y+newCursorSize.y);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Vect2 GetSize() const
|
|
{
|
|
return Vect2(float(width), float(height));
|
|
}
|
|
|
|
void UpdateSettings()
|
|
{
|
|
App->EnterSceneMutex();
|
|
|
|
UINT newCaptureType = data->GetInt(TEXT("captureType"));
|
|
String strNewWindow = data->GetString(TEXT("window"));
|
|
String strNewWindowClass= data->GetString(TEXT("windowClass"));
|
|
BOOL bNewClientCapture = data->GetInt(TEXT("innerWindow"), 1);
|
|
|
|
bCaptureMouse = data->GetInt(TEXT("captureMouse"), 1);
|
|
bCaptureLayered = data->GetInt(TEXT("captureLayered"), 0);
|
|
|
|
bool bNewUsePointFiltering = data->GetInt(TEXT("usePointFiltering"), 0) != 0;
|
|
|
|
int x = data->GetInt(TEXT("captureX"));
|
|
int y = data->GetInt(TEXT("captureY"));
|
|
int cx = data->GetInt(TEXT("captureCX"), 32);
|
|
int cy = data->GetInt(TEXT("captureCY"), 32);
|
|
|
|
bool bNewCompatibleMode = data->GetInt(TEXT("compatibilityMode")) != 0;
|
|
if(bNewCompatibleMode && (OSGetVersion() >= 8 && newCaptureType == 0))
|
|
bNewCompatibleMode = false;
|
|
|
|
gamma = data->GetInt(TEXT("gamma"), 100);
|
|
if(gamma < 50) gamma = 50;
|
|
else if(gamma > 175) gamma = 175;
|
|
|
|
UINT newMonitor = data->GetInt(TEXT("monitor"));
|
|
if(newMonitor > App->NumMonitors())
|
|
newMonitor = 0;
|
|
|
|
if( captureRect.left != x || captureRect.right != (x+cx) || captureRect.top != cy || captureRect.bottom != (y+cy) ||
|
|
newCaptureType != captureType || !strNewWindowClass.CompareI(strWindowClass) || !strNewWindow.CompareI(strWindow) ||
|
|
bNewClientCapture != bClientCapture || (OSGetVersion() >= 8 && newMonitor != monitor) ||
|
|
bNewCompatibleMode != bCompatibilityMode)
|
|
{
|
|
for(int i=0; i<NUM_CAPTURE_TEXTURES; i++)
|
|
{
|
|
delete renderTextures[i];
|
|
renderTextures[i] = NULL;
|
|
}
|
|
|
|
if(duplicator)
|
|
{
|
|
delete duplicator;
|
|
duplicator = NULL;
|
|
}
|
|
|
|
if(cursorTexture)
|
|
{
|
|
delete cursorTexture;
|
|
cursorTexture = NULL;
|
|
}
|
|
|
|
if(bCompatibilityMode)
|
|
{
|
|
SelectObject(hdcCompatible, hbmpOld);
|
|
DeleteDC(hdcCompatible);
|
|
DeleteObject(hbmpCompatible);
|
|
|
|
hdcCompatible = NULL;
|
|
hbmpCompatible = NULL;
|
|
captureBits = NULL;
|
|
}
|
|
|
|
hCurrentCursor = NULL;
|
|
|
|
captureType = newCaptureType;
|
|
strWindow = strNewWindow;
|
|
strWindowClass = strNewWindowClass;
|
|
bClientCapture = bNewClientCapture;
|
|
|
|
bCompatibilityMode = bNewCompatibleMode;
|
|
bUsePointFiltering = bNewUsePointFiltering;
|
|
|
|
captureRect.left = x;
|
|
captureRect.top = y;
|
|
captureRect.right = x+cx;
|
|
captureRect.bottom = y+cy;
|
|
|
|
monitor = newMonitor;
|
|
const MonitorInfo &monitorInfo = App->GetMonitor(monitor);
|
|
mcpy(&monitorData, &monitorInfo, sizeof(monitorInfo));
|
|
|
|
rotateDegrees = 0.0f;
|
|
|
|
if(captureType == 0 && OSGetVersion() >= 8)
|
|
{
|
|
LONG monitorWidth = monitorInfo.rect.right-monitorInfo.rect.left;
|
|
LONG monitorHeight = monitorInfo.rect.bottom-monitorInfo.rect.top;
|
|
|
|
DeviceOutputs outputs;
|
|
GetDisplayDevices(outputs);
|
|
|
|
bWindows8MonitorCapture = false;
|
|
|
|
if(outputs.devices.Num())
|
|
{
|
|
const MonitorInfo &info = App->GetMonitor(monitor);
|
|
for(UINT j=0; j<outputs.devices[0].monitors.Num(); j++)
|
|
{
|
|
if(outputs.devices[0].monitors[j].hMonitor == info.hMonitor)
|
|
{
|
|
deviceOutputID = j;
|
|
rotateDegrees = outputs.devices[0].monitors[j].rotationDegrees;
|
|
bWindows8MonitorCapture = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
width = cx;
|
|
height = cy;
|
|
|
|
if(bCompatibilityMode)
|
|
{
|
|
hdcCompatible = CreateCompatibleDC(NULL);
|
|
|
|
BITMAPINFO bi;
|
|
zero(&bi, sizeof(bi));
|
|
|
|
BITMAPINFOHEADER &bih = bi.bmiHeader;
|
|
bih.biSize = sizeof(bih);
|
|
bih.biBitCount = 32;
|
|
bih.biWidth = width;
|
|
bih.biHeight = height;
|
|
bih.biPlanes = 1;
|
|
|
|
hbmpCompatible = CreateDIBSection(hdcCompatible, &bi, DIB_RGB_COLORS, (void**)&captureBits, NULL, 0);
|
|
hbmpOld = (HBITMAP)SelectObject(hdcCompatible, hbmpCompatible);
|
|
}
|
|
|
|
if(bWindows8MonitorCapture && !bInInit)
|
|
duplicator = GS->CreateOutputDuplicator(deviceOutputID);
|
|
else if(bCompatibilityMode)
|
|
renderTextures[0] = CreateTexture(width, height, GS_BGRA, NULL, FALSE, FALSE);
|
|
else
|
|
{
|
|
for(UINT i=0; i<NUM_CAPTURE_TEXTURES; i++)
|
|
renderTextures[i] = CreateGDITexture(width, height);
|
|
}
|
|
|
|
lastRendered = NULL;
|
|
}
|
|
|
|
bool bNewUseColorKey = data->GetInt(TEXT("useColorKey"), 0) != 0;
|
|
keyColor = data->GetInt(TEXT("keyColor"), 0xFFFFFFFF);
|
|
keySimilarity = data->GetInt(TEXT("keySimilarity"), 10);
|
|
keyBlend = data->GetInt(TEXT("keyBlend"), 0);
|
|
bUsePointFiltering = data->GetInt(TEXT("usePointFiltering"), 0) != 0;
|
|
|
|
bUseColorKey = bNewUseColorKey;
|
|
|
|
opacity = data->GetInt(TEXT("opacity"), 100);
|
|
|
|
App->LeaveSceneMutex();
|
|
}
|
|
|
|
void SetInt(CTSTR lpName, int iVal)
|
|
{
|
|
if(scmpi(lpName, TEXT("useColorKey")) == 0)
|
|
{
|
|
bool bNewVal = iVal != 0;
|
|
bUseColorKey = bNewVal;
|
|
}
|
|
else if(scmpi(lpName, TEXT("keyColor")) == 0)
|
|
{
|
|
keyColor = (DWORD)iVal;
|
|
}
|
|
else if(scmpi(lpName, TEXT("keySimilarity")) == 0)
|
|
{
|
|
keySimilarity = iVal;
|
|
}
|
|
else if(scmpi(lpName, TEXT("keyBlend")) == 0)
|
|
{
|
|
keyBlend = iVal;
|
|
}
|
|
else if(scmpi(lpName, TEXT("opacity")) == 0)
|
|
{
|
|
opacity = (UINT)iVal;
|
|
}
|
|
else if(scmpi(lpName, TEXT("gamma")) == 0)
|
|
{
|
|
gamma = iVal;
|
|
if(gamma < 50) gamma = 50;
|
|
else if(gamma > 175) gamma = 175;
|
|
}
|
|
}
|
|
};
|
|
|
|
ImageSource* STDCALL CreateDesktopSource(XElement *data)
|
|
{
|
|
if(!data)
|
|
return NULL;
|
|
|
|
return new DesktopImageSource(App->GetFrameTime(), data);
|
|
}
|
|
|
|
void RefreshWindowList(HWND hwndCombobox, StringList &classList)
|
|
{
|
|
SendMessage(hwndCombobox, CB_RESETCONTENT, 0, 0);
|
|
classList.Clear();
|
|
|
|
HWND hwndCurrent = GetWindow(GetDesktopWindow(), GW_CHILD);
|
|
do
|
|
{
|
|
if(IsWindowVisible(hwndCurrent) && !IsIconic(hwndCurrent))
|
|
{
|
|
RECT clientRect;
|
|
GetClientRect(hwndCurrent, &clientRect);
|
|
|
|
String strWindowName;
|
|
strWindowName.SetLength(GetWindowTextLength(hwndCurrent));
|
|
GetWindowText(hwndCurrent, strWindowName, strWindowName.Length()+1);
|
|
|
|
DWORD exStyles = (DWORD)GetWindowLongPtr(hwndCurrent, GWL_EXSTYLE);
|
|
DWORD styles = (DWORD)GetWindowLongPtr(hwndCurrent, GWL_STYLE);
|
|
|
|
if (strWindowName.IsValid() && sstri(strWindowName, L"battlefield") != nullptr)
|
|
exStyles &= ~WS_EX_TOOLWINDOW;
|
|
|
|
if( (exStyles & WS_EX_TOOLWINDOW) == 0 && (styles & WS_CHILD) == 0 &&
|
|
clientRect.bottom != 0 && clientRect.right != 0 /*&& hwndParent == NULL*/)
|
|
{
|
|
//-------
|
|
|
|
DWORD processID;
|
|
GetWindowThreadProcessId(hwndCurrent, &processID);
|
|
if(processID == GetCurrentProcessId())
|
|
continue;
|
|
|
|
TCHAR fileName[MAX_PATH+1];
|
|
scpy(fileName, TEXT("unknown"));
|
|
|
|
HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, processID);
|
|
if(hProcess)
|
|
{
|
|
DWORD dwSize = MAX_PATH;
|
|
QueryFullProcessImageName(hProcess, 0, fileName, &dwSize);
|
|
CloseHandle(hProcess);
|
|
}
|
|
|
|
//-------
|
|
|
|
String strFileName = fileName;
|
|
strFileName.FindReplace(TEXT("\\"), TEXT("/"));
|
|
|
|
String strText;
|
|
strText << TEXT("[") << GetPathFileName(strFileName) << TEXT("]: ") << strWindowName;
|
|
|
|
if(strWindowName.IsEmpty()) strWindowName = GetPathFileName(strFileName);
|
|
|
|
int id = (int)SendMessage(hwndCombobox, CB_ADDSTRING, 0, (LPARAM)strWindowName.Array());
|
|
SendMessage(hwndCombobox, CB_SETITEMDATA, id, (LPARAM)hwndCurrent);
|
|
|
|
String strClassName;
|
|
strClassName.SetLength(256);
|
|
GetClassName(hwndCurrent, strClassName.Array(), 255);
|
|
strClassName.SetLength(slen(strClassName));
|
|
|
|
classList << strClassName;
|
|
}
|
|
}
|
|
} while (hwndCurrent = GetNextWindow(hwndCurrent, GW_HWNDNEXT));
|
|
}
|
|
|
|
struct ConfigDesktopSourceInfo
|
|
{
|
|
CTSTR lpName;
|
|
XElement *data;
|
|
int dialogID;
|
|
StringList strClasses;
|
|
int prevCX, prevCY;
|
|
bool sizeSet;
|
|
|
|
inline ConfigDesktopSourceInfo()
|
|
{
|
|
zero(this, sizeof(*this));
|
|
}
|
|
};
|
|
|
|
void SetDesktopCaptureType(HWND hwnd, UINT type)
|
|
{
|
|
SendMessage(GetDlgItem(hwnd, IDC_MONITORCAPTURE), BM_SETCHECK, type == 0 ? BST_CHECKED : BST_UNCHECKED, 0);
|
|
SendMessage(GetDlgItem(hwnd, IDC_WINDOWCAPTURE), BM_SETCHECK, type == 1 ? BST_CHECKED : BST_UNCHECKED, 0);
|
|
|
|
EnableWindow(GetDlgItem(hwnd, IDC_MONITOR), type == 0);
|
|
|
|
EnableWindow(GetDlgItem(hwnd, IDC_WINDOW), type == 1);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_REFRESH), type == 1);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_OUTERWINDOW), type == 1);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_INNERWINDOW), type == 1);
|
|
}
|
|
|
|
void SelectTargetWindow(HWND hwnd, bool bRefresh)
|
|
{
|
|
HWND hwndWindowList = GetDlgItem(hwnd, IDC_WINDOW);
|
|
UINT windowID = (UINT)SendMessage(hwndWindowList, CB_GETCURSEL, 0, 0);
|
|
if(windowID == CB_ERR)
|
|
return;
|
|
|
|
String strWindow = GetCBText(hwndWindowList, windowID);
|
|
|
|
ConfigDesktopSourceInfo *info = (ConfigDesktopSourceInfo*)GetWindowLongPtr(hwnd, DWLP_USER);
|
|
|
|
if(windowID >= info->strClasses.Num())
|
|
return;
|
|
|
|
HWND hwndTarget = FindWindow(info->strClasses[windowID], strWindow);
|
|
if(!hwndTarget)
|
|
{
|
|
HWND hwndLastKnownHWND = (HWND)SendMessage(hwndWindowList, CB_GETITEMDATA, windowID, 0);
|
|
if(IsWindow(hwndLastKnownHWND))
|
|
hwndTarget = hwndLastKnownHWND;
|
|
else
|
|
hwndTarget = FindWindow(info->strClasses[windowID], NULL);
|
|
}
|
|
|
|
if(!hwndTarget)
|
|
return;
|
|
|
|
//------------------------------------------
|
|
|
|
BOOL bInnerWindow = SendMessage(GetDlgItem(hwnd, IDC_INNERWINDOW), BM_GETCHECK, 0, 0) == BST_CHECKED;
|
|
|
|
RECT rc;
|
|
if(bInnerWindow)
|
|
GetClientRect(hwndTarget, &rc);
|
|
else
|
|
{
|
|
GetWindowRect(hwndTarget, &rc);
|
|
|
|
rc.bottom -= rc.top;
|
|
rc.right -= rc.left;
|
|
rc.left = rc.top = 0;
|
|
}
|
|
|
|
//------------------------------------------
|
|
|
|
rc.bottom -= rc.top;
|
|
rc.right -= rc.left;
|
|
|
|
if(rc.right < 16)
|
|
rc.right = 16;
|
|
if(rc.bottom < 16)
|
|
rc.bottom = 16;
|
|
|
|
BOOL bRegion = SendMessage(GetDlgItem(hwnd, IDC_REGIONCAPTURE), BM_GETCHECK, 0, 0) == BST_CHECKED;
|
|
if(!bRegion || bRefresh)
|
|
{
|
|
SetWindowText(GetDlgItem(hwnd, IDC_POSX), IntString(rc.left).Array());
|
|
SetWindowText(GetDlgItem(hwnd, IDC_POSY), IntString(rc.top).Array());
|
|
SetWindowText(GetDlgItem(hwnd, IDC_SIZEX), IntString(rc.right).Array());
|
|
SetWindowText(GetDlgItem(hwnd, IDC_SIZEY), IntString(rc.bottom).Array());
|
|
}
|
|
}
|
|
|
|
struct RegionWindowData
|
|
{
|
|
HWND hwndConfigDialog, hwndCaptureWindow;
|
|
POINT startPos;
|
|
RECT captureRect;
|
|
bool bMovingWindow;
|
|
bool bInnerWindowRegion;
|
|
|
|
inline RegionWindowData()
|
|
{
|
|
bMovingWindow = false;
|
|
bInnerWindowRegion = false;
|
|
}
|
|
};
|
|
|
|
RegionWindowData regionWindowData;
|
|
|
|
#define CAPTUREREGIONCLASS TEXT("CaptureRegionThingy")
|
|
|
|
LRESULT WINAPI RegionWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
if(message == WM_MOUSEMOVE)
|
|
{
|
|
RECT client;
|
|
GetClientRect(hwnd, &client);
|
|
|
|
POINT pos;
|
|
pos.x = (long)(short)LOWORD(lParam);
|
|
pos.y = (long)(short)HIWORD(lParam);
|
|
|
|
if(regionWindowData.bMovingWindow)
|
|
{
|
|
RECT rc;
|
|
GetWindowRect(hwnd, &rc);
|
|
|
|
POINT posOffset = {pos.x-regionWindowData.startPos.x, pos.y-regionWindowData.startPos.y};
|
|
POINT newPos = {rc.left+posOffset.x, rc.top+posOffset.y};
|
|
SIZE windowSize = {rc.right-rc.left, rc.bottom-rc.top};
|
|
|
|
if(newPos.x < regionWindowData.captureRect.left)
|
|
newPos.x = regionWindowData.captureRect.left;
|
|
if(newPos.y < regionWindowData.captureRect.top)
|
|
newPos.y = regionWindowData.captureRect.top;
|
|
|
|
POINT newBottomRight = {rc.right+posOffset.x, rc.bottom+posOffset.y};
|
|
|
|
if(newBottomRight.x > regionWindowData.captureRect.right)
|
|
newPos.x -= (newBottomRight.x-regionWindowData.captureRect.right);
|
|
if(newBottomRight.y > regionWindowData.captureRect.bottom)
|
|
newPos.y -= (newBottomRight.y-regionWindowData.captureRect.bottom);
|
|
|
|
SetWindowPos(hwnd, NULL, newPos.x, newPos.y, 0, 0, SWP_NOSIZE|SWP_NOZORDER);
|
|
}
|
|
else
|
|
{
|
|
BOOL bLeft = (pos.x < 6);
|
|
BOOL bTop = (pos.y < 6);
|
|
BOOL bRight = (!bLeft && (pos.x > client.right-6));
|
|
BOOL bBottom = (!bTop && (pos.y > client.bottom-6));
|
|
|
|
if(bLeft)
|
|
{
|
|
if(bTop)
|
|
SetCursor(LoadCursor(NULL, IDC_SIZENWSE));
|
|
else if(bBottom)
|
|
SetCursor(LoadCursor(NULL, IDC_SIZENESW));
|
|
else
|
|
SetCursor(LoadCursor(NULL, IDC_SIZEWE));
|
|
}
|
|
else if(bRight)
|
|
{
|
|
if(bTop)
|
|
SetCursor(LoadCursor(NULL, IDC_SIZENESW));
|
|
else if(bBottom)
|
|
SetCursor(LoadCursor(NULL, IDC_SIZENWSE));
|
|
else
|
|
SetCursor(LoadCursor(NULL, IDC_SIZEWE));
|
|
}
|
|
else if(bTop || bBottom)
|
|
SetCursor(LoadCursor(NULL, IDC_SIZENS));
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
else if(message == WM_LBUTTONDOWN)
|
|
{
|
|
RECT client;
|
|
GetClientRect(hwnd, &client);
|
|
|
|
POINT pos;
|
|
pos.x = (long)LOWORD(lParam);
|
|
pos.y = (long)HIWORD(lParam);
|
|
|
|
BOOL bLeft = (pos.x < 6);
|
|
BOOL bTop = (pos.y < 6);
|
|
BOOL bRight = (!bLeft && (pos.x > client.right-6));
|
|
BOOL bBottom = (!bTop && (pos.y > client.bottom-6));
|
|
|
|
ClientToScreen(hwnd, &pos);
|
|
|
|
POINTS newPos;
|
|
newPos.x = (SHORT)pos.x;
|
|
newPos.y = (SHORT)pos.y;
|
|
|
|
SendMessage(hwnd, WM_MOUSEMOVE, 0, lParam);
|
|
|
|
if(bLeft)
|
|
{
|
|
if(bTop)
|
|
SendMessage(hwnd, WM_NCLBUTTONDOWN, HTTOPLEFT, (LPARAM)&newPos);
|
|
else if(bBottom)
|
|
SendMessage(hwnd, WM_NCLBUTTONDOWN, HTBOTTOMLEFT, (LPARAM)&newPos);
|
|
else
|
|
SendMessage(hwnd, WM_NCLBUTTONDOWN, HTLEFT, (LPARAM)&newPos);
|
|
}
|
|
else if(bRight)
|
|
{
|
|
if(bTop)
|
|
SendMessage(hwnd, WM_NCLBUTTONDOWN, HTTOPRIGHT, (LPARAM)&newPos);
|
|
else if(bBottom)
|
|
SendMessage(hwnd, WM_NCLBUTTONDOWN, HTBOTTOMRIGHT, (LPARAM)&newPos);
|
|
else
|
|
SendMessage(hwnd, WM_NCLBUTTONDOWN, HTRIGHT, (LPARAM)&newPos);
|
|
}
|
|
else if(bTop)
|
|
SendMessage(hwnd, WM_NCLBUTTONDOWN, HTTOP, (LPARAM)&newPos);
|
|
else if(bBottom)
|
|
SendMessage(hwnd, WM_NCLBUTTONDOWN, HTBOTTOM, (LPARAM)&newPos);
|
|
else
|
|
{
|
|
regionWindowData.bMovingWindow = true; //can't use HTCAPTION -- if holding down long enough, other windows minimize
|
|
|
|
pos.x = (long)(short)LOWORD(lParam);
|
|
pos.y = (long)(short)HIWORD(lParam);
|
|
mcpy(®ionWindowData.startPos, &pos, sizeof(pos));
|
|
SetCapture(hwnd);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
else if(message == WM_LBUTTONUP)
|
|
{
|
|
if(regionWindowData.bMovingWindow)
|
|
{
|
|
regionWindowData.bMovingWindow = false;
|
|
ReleaseCapture();
|
|
}
|
|
}
|
|
else if(message == WM_PAINT)
|
|
{
|
|
PAINTSTRUCT ps;
|
|
HDC hDC = BeginPaint(hwnd, &ps);
|
|
if(hDC)
|
|
{
|
|
RECT clientRect;
|
|
GetClientRect(hwnd, &clientRect);
|
|
|
|
//-----------------------------------------
|
|
|
|
HPEN oldPen = (HPEN)SelectObject(hDC, GetStockObject(BLACK_PEN));
|
|
|
|
MoveToEx(hDC, 0, 0, NULL);
|
|
LineTo(hDC, clientRect.right-1, 0);
|
|
LineTo(hDC, clientRect.right-1, clientRect.bottom-1);
|
|
LineTo(hDC, 0, clientRect.bottom-1);
|
|
LineTo(hDC, 0, 0);
|
|
|
|
MoveToEx(hDC, 5, 5, NULL);
|
|
LineTo(hDC, clientRect.right-6, 5);
|
|
LineTo(hDC, clientRect.right-6, clientRect.bottom-6);
|
|
LineTo(hDC, 5, clientRect.bottom-6);
|
|
LineTo(hDC, 5, 5);
|
|
|
|
SelectObject(hDC, oldPen);
|
|
|
|
//-----------------------------------------
|
|
|
|
CTSTR lpStr = Str("Sources.SoftwareCaptureSource.RegionWindowText");
|
|
|
|
HFONT hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
|
|
HFONT hfontOld = (HFONT)SelectObject(hDC, hFont);
|
|
|
|
SIZE textExtent;
|
|
GetTextExtentPoint32(hDC, lpStr, slen(lpStr), &textExtent);
|
|
|
|
SetBkMode(hDC, TRANSPARENT);
|
|
SetTextAlign(hDC, TA_CENTER);
|
|
TextOut(hDC, clientRect.right/2, (clientRect.bottom - textExtent.cy)/2, lpStr, slen(lpStr));
|
|
|
|
//-----------------------------------------
|
|
|
|
SelectObject(hDC, hfontOld);
|
|
|
|
EndPaint(hwnd, &ps);
|
|
}
|
|
}
|
|
else if(message == WM_KEYDOWN)
|
|
{
|
|
if(wParam == VK_ESCAPE || wParam == VK_RETURN || wParam == 'Q')
|
|
DestroyWindow(hwnd);
|
|
}
|
|
else if(message == WM_SIZING)
|
|
{
|
|
RECT &rc = *(RECT*)lParam;
|
|
|
|
bool bTop = wParam == WMSZ_TOPLEFT || wParam == WMSZ_TOPRIGHT || wParam == WMSZ_TOP;
|
|
bool bLeft = wParam == WMSZ_TOPLEFT || wParam == WMSZ_LEFT || wParam == WMSZ_BOTTOMLEFT;
|
|
|
|
if(bLeft)
|
|
{
|
|
if(rc.right-rc.left < 16)
|
|
rc.left = rc.right-16;
|
|
}
|
|
else
|
|
{
|
|
if(rc.right-rc.left < 16)
|
|
rc.right = rc.left+16;
|
|
}
|
|
|
|
if(bTop)
|
|
{
|
|
if(rc.bottom-rc.top < 16)
|
|
rc.top = rc.bottom-16;
|
|
}
|
|
else
|
|
{
|
|
if(rc.bottom-rc.top < 16)
|
|
rc.bottom = rc.top+16;
|
|
}
|
|
|
|
if(regionWindowData.hwndCaptureWindow)
|
|
{
|
|
if(rc.left < regionWindowData.captureRect.left)
|
|
rc.left = regionWindowData.captureRect.left;
|
|
if(rc.top < regionWindowData.captureRect.top)
|
|
rc.top = regionWindowData.captureRect.top;
|
|
|
|
if(rc.right > regionWindowData.captureRect.right)
|
|
rc.right = regionWindowData.captureRect.right;
|
|
if(rc.bottom > regionWindowData.captureRect.bottom)
|
|
rc.bottom = regionWindowData.captureRect.bottom;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
else if(message == WM_SIZE || message == WM_MOVE)
|
|
{
|
|
RECT rc;
|
|
GetWindowRect(hwnd, &rc);
|
|
|
|
if(rc.right-rc.left < 16)
|
|
rc.right = rc.left+16;
|
|
if(rc.bottom-rc.top < 16)
|
|
rc.bottom = rc.top+16;
|
|
|
|
SetWindowText(GetDlgItem(regionWindowData.hwndConfigDialog, IDC_SIZEX), IntString(rc.right-rc.left).Array());
|
|
SetWindowText(GetDlgItem(regionWindowData.hwndConfigDialog, IDC_SIZEY), IntString(rc.bottom-rc.top).Array());
|
|
|
|
if(regionWindowData.hwndCaptureWindow)
|
|
{
|
|
rc.left -= regionWindowData.captureRect.left;
|
|
rc.top -= regionWindowData.captureRect.top;
|
|
}
|
|
|
|
SetWindowText(GetDlgItem(regionWindowData.hwndConfigDialog, IDC_POSX), IntString(rc.left).Array());
|
|
SetWindowText(GetDlgItem(regionWindowData.hwndConfigDialog, IDC_POSY), IntString(rc.top).Array());
|
|
|
|
if(message == WM_SIZE)
|
|
RedrawWindow(hwnd, NULL, NULL, RDW_INTERNALPAINT|RDW_ERASE|RDW_INVALIDATE);
|
|
}
|
|
else if(message == WM_ACTIVATE)
|
|
{
|
|
if(wParam == WA_INACTIVE)
|
|
DestroyWindow(hwnd);
|
|
}
|
|
|
|
return DefWindowProc(hwnd, message, wParam, lParam);
|
|
}
|
|
|
|
struct ColorSelectionData
|
|
{
|
|
HDC hdcDesktop;
|
|
HDC hdcDestination;
|
|
HBITMAP hBitmap;
|
|
bool bValid;
|
|
|
|
inline ColorSelectionData() : hdcDesktop(NULL), hdcDestination(NULL), hBitmap(NULL), bValid(false) {}
|
|
inline ~ColorSelectionData() {Clear();}
|
|
|
|
inline bool Init()
|
|
{
|
|
hdcDesktop = GetDC(NULL);
|
|
if(!hdcDesktop)
|
|
return false;
|
|
|
|
hdcDestination = CreateCompatibleDC(hdcDesktop);
|
|
if(!hdcDestination)
|
|
return false;
|
|
|
|
hBitmap = CreateCompatibleBitmap(hdcDesktop, 1, 1);
|
|
if(!hBitmap)
|
|
return false;
|
|
|
|
SelectObject(hdcDestination, hBitmap);
|
|
bValid = true;
|
|
|
|
return true;
|
|
}
|
|
|
|
inline void Clear()
|
|
{
|
|
if(hdcDesktop)
|
|
{
|
|
ReleaseDC(NULL, hdcDesktop);
|
|
hdcDesktop = NULL;
|
|
}
|
|
|
|
if(hdcDestination)
|
|
{
|
|
DeleteDC(hdcDestination);
|
|
hdcDestination = NULL;
|
|
}
|
|
|
|
if(hBitmap)
|
|
{
|
|
DeleteObject(hBitmap);
|
|
hBitmap = NULL;
|
|
}
|
|
|
|
bValid = false;
|
|
}
|
|
|
|
inline DWORD GetColor()
|
|
{
|
|
POINT p;
|
|
if(GetCursorPos(&p))
|
|
{
|
|
BITMAPINFO data;
|
|
zero(&data, sizeof(data));
|
|
|
|
data.bmiHeader.biSize = sizeof(data.bmiHeader);
|
|
data.bmiHeader.biWidth = 1;
|
|
data.bmiHeader.biHeight = 1;
|
|
data.bmiHeader.biPlanes = 1;
|
|
data.bmiHeader.biBitCount = 24;
|
|
data.bmiHeader.biCompression = BI_RGB;
|
|
data.bmiHeader.biSizeImage = 4;
|
|
|
|
if(BitBlt(hdcDestination, 0, 0, 1, 1, hdcDesktop, p.x, p.y, SRCCOPY|CAPTUREBLT))
|
|
{
|
|
DWORD buffer;
|
|
if(GetDIBits(hdcDestination, hBitmap, 0, 1, &buffer, &data, DIB_RGB_COLORS))
|
|
return 0xFF000000|buffer;
|
|
}
|
|
else
|
|
{
|
|
int err = GetLastError();
|
|
nop();
|
|
}
|
|
}
|
|
|
|
return 0xFF000000;
|
|
}
|
|
};
|
|
|
|
INT_PTR CALLBACK ConfigDesktopSourceProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
static bool bSelectingColor = false;
|
|
static bool bMouseDown = false;
|
|
static ColorSelectionData colorData;
|
|
HWND hwndTemp;
|
|
|
|
switch(message)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR)lParam);
|
|
LocalizeWindow(hwnd);
|
|
|
|
//--------------------------------------------
|
|
|
|
HWND hwndToolTip = CreateWindowEx(NULL, TOOLTIPS_CLASS, NULL, WS_POPUP|TTS_NOPREFIX|TTS_ALWAYSTIP,
|
|
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
|
|
hwnd, NULL, hinstMain, NULL);
|
|
|
|
TOOLINFO ti;
|
|
zero(&ti, sizeof(ti));
|
|
ti.cbSize = sizeof(ti);
|
|
ti.uFlags = TTF_SUBCLASS|TTF_IDISHWND;
|
|
ti.hwnd = hwnd;
|
|
|
|
if (LocaleIsRTL())
|
|
ti.uFlags |= TTF_RTLREADING;
|
|
|
|
SendMessage(hwndToolTip, TTM_SETMAXTIPWIDTH, 0, 500);
|
|
SendMessage(hwndToolTip, TTM_SETDELAYTIME, TTDT_AUTOPOP, 8000);
|
|
|
|
//-----------------------------------------------------
|
|
|
|
ConfigDesktopSourceInfo *info = (ConfigDesktopSourceInfo*)lParam;
|
|
XElement *data = info->data;
|
|
|
|
info->prevCX = AppConfig->GetInt(TEXT("Video"), TEXT("BaseWidth"));
|
|
info->prevCY = AppConfig->GetInt(TEXT("Video"), TEXT("BaseHeight"));
|
|
|
|
if (info->dialogID == IDD_CONFIGUREMONITORCAPTURE || info->dialogID == IDD_CONFIGUREDESKTOPSOURCE) {
|
|
hwndTemp = GetDlgItem(hwnd, IDC_MONITOR);
|
|
for(UINT i=0; i<App->NumMonitors(); i++)
|
|
SendMessage(hwndTemp, CB_ADDSTRING, 0, (LPARAM)UIntString(i+1).Array());
|
|
SendMessage(hwndTemp, CB_SETCURSEL, 0, 0);
|
|
|
|
if (OSGetVersion() > 7) {
|
|
EnableWindow(GetDlgItem(hwnd, IDC_CAPTURELAYERED), FALSE);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_COMPATIBILITYMODE), (info->dialogID != IDD_CONFIGUREMONITORCAPTURE));
|
|
}
|
|
}
|
|
|
|
UINT captureType = data->GetInt(TEXT("captureType"), 0);
|
|
|
|
if (info->dialogID == IDD_CONFIGUREDESKTOPSOURCE)
|
|
SetDesktopCaptureType(hwnd, captureType);
|
|
|
|
//-----------------------------------------------------
|
|
|
|
if (info->dialogID == IDD_CONFIGUREMONITORCAPTURE || info->dialogID == IDD_CONFIGUREDESKTOPSOURCE) {
|
|
hwndTemp = GetDlgItem(hwnd, IDC_MONITOR);
|
|
UINT monitor = data->GetInt(TEXT("monitor"));
|
|
SendMessage(hwndTemp, CB_SETCURSEL, monitor, 0);
|
|
}
|
|
|
|
//-----------------------------------------------------
|
|
|
|
if (info->dialogID == IDD_CONFIGUREMONITORCAPTURE) {
|
|
String strWarnings;
|
|
if (OSGetVersion() < 8) {
|
|
strWarnings << Str("Sources.SoftwareCaptureSource.Warning");
|
|
|
|
BOOL bComposition;
|
|
DwmIsCompositionEnabled(&bComposition);
|
|
if (bComposition)
|
|
strWarnings << TEXT("\r\n") << Str("Sources.SoftwareCaptureSource.WarningAero");
|
|
}
|
|
|
|
SetWindowText(GetDlgItem(hwnd, IDC_WARNING), strWarnings);
|
|
}
|
|
|
|
//-----------------------------------------------------
|
|
|
|
bool bFoundWindow = false;
|
|
if (info->dialogID == IDD_CONFIGUREWINDOWCAPTURE || info->dialogID == IDD_CONFIGUREDESKTOPSOURCE) {
|
|
HWND hwndWindowList = GetDlgItem(hwnd, IDC_WINDOW);
|
|
|
|
CTSTR lpWindowName = data->GetString(TEXT("window"));
|
|
CTSTR lpWindowClass = data->GetString(TEXT("windowClass"));
|
|
BOOL bInnerWindow = (BOOL)data->GetInt(TEXT("innerWindow"), 1);
|
|
|
|
RefreshWindowList(hwndWindowList, info->strClasses);
|
|
|
|
UINT windowID = 0;
|
|
if(lpWindowName)
|
|
windowID = (UINT)SendMessage(hwndWindowList, CB_FINDSTRINGEXACT, -1, (LPARAM)lpWindowName);
|
|
|
|
bFoundWindow = (windowID != CB_ERR);
|
|
if(!bFoundWindow)
|
|
windowID = 0;
|
|
|
|
SendMessage(hwndWindowList, CB_SETCURSEL, windowID, 0);
|
|
|
|
if(bInnerWindow)
|
|
SendMessage(GetDlgItem(hwnd, IDC_INNERWINDOW), BM_SETCHECK, BST_CHECKED, 0);
|
|
else
|
|
SendMessage(GetDlgItem(hwnd, IDC_OUTERWINDOW), BM_SETCHECK, BST_CHECKED, 0);
|
|
}
|
|
|
|
//-----------------------------------------------------
|
|
|
|
bool bMouseCapture = data->GetInt(TEXT("captureMouse"), 1) != 0;
|
|
SendMessage(GetDlgItem(hwnd, IDC_CAPTUREMOUSE), BM_SETCHECK, (bMouseCapture) ? BST_CHECKED : BST_UNCHECKED, 0);
|
|
|
|
bool bCaptureLayered = data->GetInt(TEXT("captureLayered"), 0) != 0;
|
|
SendMessage(GetDlgItem(hwnd, IDC_CAPTURELAYERED), BM_SETCHECK, (bCaptureLayered) ? BST_CHECKED : BST_UNCHECKED, 0);
|
|
|
|
ti.lpszText = (LPWSTR)Str("Sources.SoftwareCaptureSource.CaptureLayeredTip");
|
|
ti.uId = (UINT_PTR)GetDlgItem(hwnd, IDC_CAPTURELAYERED);
|
|
SendMessage(hwndToolTip, TTM_ADDTOOL, 0, (LPARAM)&ti);
|
|
|
|
bool bCompatibilityMode = data->GetInt(TEXT("compatibilityMode"), 0) != 0;
|
|
SendMessage(GetDlgItem(hwnd, IDC_COMPATIBILITYMODE), BM_SETCHECK, (bCompatibilityMode) ? BST_CHECKED : BST_UNCHECKED, 0);
|
|
|
|
//-----------------------------------------------------
|
|
|
|
bool bRegion = data->GetInt(TEXT("regionCapture")) != FALSE;
|
|
if(captureType == 1 && !bFoundWindow)
|
|
bRegion = false;
|
|
|
|
SendMessage(GetDlgItem(hwnd, IDC_REGIONCAPTURE), BM_SETCHECK, (bRegion) ? BST_CHECKED : BST_UNCHECKED, 0);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_POSX), bRegion);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_POSY), bRegion);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_SIZEX), bRegion);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_SIZEY), bRegion);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_SELECTREGION), bRegion);
|
|
|
|
int posX = 0, posY = 0, sizeX = 32, sizeY = 32;
|
|
if(!data->GetBaseItem(TEXT("captureX")) || !bRegion)
|
|
{
|
|
if(captureType == 0)
|
|
PostMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDC_MONITOR, 0), 0);
|
|
else if(captureType == 1)
|
|
PostMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDC_WINDOW, 0), 0);
|
|
}
|
|
else
|
|
{
|
|
posX = data->GetInt(TEXT("captureX"));
|
|
posY = data->GetInt(TEXT("captureY"));
|
|
sizeX = data->GetInt(TEXT("captureCX"), 32);
|
|
sizeY = data->GetInt(TEXT("captureCY"), 32);
|
|
|
|
if(sizeX < 16)
|
|
sizeX = 16;
|
|
if(sizeY < 16)
|
|
sizeY = 16;
|
|
|
|
SetWindowText(GetDlgItem(hwnd, IDC_POSX), IntString(posX).Array());
|
|
SetWindowText(GetDlgItem(hwnd, IDC_POSY), IntString(posY).Array());
|
|
SetWindowText(GetDlgItem(hwnd, IDC_SIZEX), IntString(sizeX).Array());
|
|
SetWindowText(GetDlgItem(hwnd, IDC_SIZEY), IntString(sizeY).Array());
|
|
}
|
|
|
|
ti.lpszText = (LPWSTR)Str("Sources.SoftwareCaptureSource.SelectRegionTooltip");
|
|
ti.uId = (UINT_PTR)GetDlgItem(hwnd, IDC_SELECTREGION);
|
|
SendMessage(hwndToolTip, TTM_ADDTOOL, 0, (LPARAM)&ti);
|
|
|
|
//------------------------------------------
|
|
|
|
BOOL bUseColorKey = data->GetInt(TEXT("useColorKey"), 0);
|
|
DWORD keyColor = data->GetInt(TEXT("keyColor"), 0xFFFFFFFF);
|
|
UINT similarity = data->GetInt(TEXT("keySimilarity"), 10);
|
|
UINT blend = data->GetInt(TEXT("keyBlend"), 0);
|
|
|
|
BOOL bUsePointFiltering = data->GetInt(TEXT("usePointFiltering"), 0);
|
|
SendMessage(GetDlgItem(hwnd, IDC_POINTFILTERING), BM_SETCHECK, bUsePointFiltering ? BST_CHECKED : BST_UNCHECKED, 0);
|
|
|
|
SendMessage(GetDlgItem(hwnd, IDC_USECOLORKEY), BM_SETCHECK, bUseColorKey ? BST_CHECKED : BST_UNCHECKED, 0);
|
|
CCSetColor(GetDlgItem(hwnd, IDC_COLOR), keyColor);
|
|
|
|
SendMessage(GetDlgItem(hwnd, IDC_BASETHRESHOLD), UDM_SETRANGE32, 0, 100);
|
|
SendMessage(GetDlgItem(hwnd, IDC_BASETHRESHOLD), UDM_SETPOS32, 0, similarity);
|
|
|
|
SendMessage(GetDlgItem(hwnd, IDC_BLEND), UDM_SETRANGE32, 0, 100);
|
|
SendMessage(GetDlgItem(hwnd, IDC_BLEND), UDM_SETPOS32, 0, blend);
|
|
|
|
EnableWindow(GetDlgItem(hwnd, IDC_COLOR), bUseColorKey);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_SELECT), bUseColorKey);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_BASETHRESHOLD_EDIT), bUseColorKey);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_BASETHRESHOLD), bUseColorKey);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_BLEND_EDIT), bUseColorKey);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_BLEND), bUseColorKey);
|
|
|
|
//------------------------------------------
|
|
|
|
UINT opacity = data->GetInt(TEXT("opacity"), 100);
|
|
|
|
SendMessage(GetDlgItem(hwnd, IDC_OPACITY2), UDM_SETRANGE32, 0, 100);
|
|
SendMessage(GetDlgItem(hwnd, IDC_OPACITY2), UDM_SETPOS32, 0, opacity);
|
|
|
|
//------------------------------------------
|
|
|
|
int gammaVal = data->GetInt(TEXT("gamma"), 100);
|
|
|
|
hwndTemp = GetDlgItem(hwnd, IDC_GAMMA);
|
|
SendMessage(hwndTemp, TBM_CLEARTICS, FALSE, 0);
|
|
SendMessage(hwndTemp, TBM_SETRANGE, FALSE, MAKELPARAM(50, 175));
|
|
SendMessage(hwndTemp, TBM_SETTIC, 0, 100);
|
|
SendMessage(hwndTemp, TBM_SETPOS, TRUE, gammaVal);
|
|
|
|
SetSliderText(hwnd, IDC_GAMMA, IDC_GAMMAVAL);
|
|
|
|
//--------------------------------------------
|
|
|
|
if (info->dialogID == IDD_CONFIGUREWINDOWCAPTURE)
|
|
PostMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDC_WINDOW, 0), 0);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
case WM_DESTROY:
|
|
if(colorData.bValid)
|
|
{
|
|
CCSetColor(GetDlgItem(hwnd, IDC_COLOR), colorData.GetColor());
|
|
colorData.Clear();
|
|
}
|
|
break;
|
|
|
|
case WM_LBUTTONDOWN:
|
|
if(bSelectingColor)
|
|
{
|
|
bMouseDown = true;
|
|
CCSetColor(GetDlgItem(hwnd, IDC_COLOR), colorData.GetColor());
|
|
ConfigDesktopSourceProc(hwnd, WM_COMMAND, MAKEWPARAM(IDC_COLOR, CCN_CHANGED), (LPARAM)GetDlgItem(hwnd, IDC_COLOR));
|
|
}
|
|
break;
|
|
|
|
case WM_MOUSEMOVE:
|
|
if(bSelectingColor && bMouseDown)
|
|
{
|
|
CCSetColor(GetDlgItem(hwnd, IDC_COLOR), colorData.GetColor());
|
|
ConfigDesktopSourceProc(hwnd, WM_COMMAND, MAKEWPARAM(IDC_COLOR, CCN_CHANGED), (LPARAM)GetDlgItem(hwnd, IDC_COLOR));
|
|
}
|
|
break;
|
|
|
|
case WM_LBUTTONUP:
|
|
if(bSelectingColor)
|
|
{
|
|
colorData.Clear();
|
|
ReleaseCapture();
|
|
bMouseDown = false;
|
|
bSelectingColor = false;
|
|
|
|
ConfigDesktopSourceInfo *configData = (ConfigDesktopSourceInfo*)GetWindowLongPtr(hwnd, DWLP_USER);
|
|
ImageSource *source = API->GetSceneImageSource(configData->lpName);
|
|
if(source)
|
|
source->SetInt(TEXT("useColorKey"), true);
|
|
}
|
|
break;
|
|
|
|
case WM_CAPTURECHANGED:
|
|
if(bSelectingColor)
|
|
{
|
|
if(colorData.bValid)
|
|
{
|
|
CCSetColor(GetDlgItem(hwnd, IDC_COLOR), colorData.GetColor());
|
|
ConfigDesktopSourceProc(hwnd, WM_COMMAND, MAKEWPARAM(IDC_COLOR, CCN_CHANGED), (LPARAM)GetDlgItem(hwnd, IDC_COLOR));
|
|
colorData.Clear();
|
|
}
|
|
|
|
ReleaseCapture();
|
|
bMouseDown = false;
|
|
bSelectingColor = false;
|
|
|
|
ConfigDesktopSourceInfo *configData = (ConfigDesktopSourceInfo*)GetWindowLongPtr(hwnd, DWLP_USER);
|
|
ImageSource *source = API->GetSceneImageSource(configData->lpName);
|
|
if(source)
|
|
source->SetInt(TEXT("useColorKey"), true);
|
|
}
|
|
break;
|
|
|
|
case WM_HSCROLL:
|
|
{
|
|
if(GetDlgCtrlID((HWND)lParam) == IDC_GAMMA)
|
|
{
|
|
int gamma = SetSliderText(hwnd, IDC_GAMMA, IDC_GAMMAVAL);
|
|
|
|
ConfigDesktopSourceInfo *configData = (ConfigDesktopSourceInfo*)GetWindowLongPtr(hwnd, DWLP_USER);
|
|
ImageSource *source = API->GetSceneImageSource(configData->lpName);
|
|
if(source)
|
|
source->SetInt(TEXT("gamma"), gamma);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
switch(LOWORD(wParam))
|
|
{
|
|
case IDC_MONITORCAPTURE:
|
|
SetDesktopCaptureType(hwnd, 0);
|
|
PostMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDC_MONITOR, 0), 0);
|
|
|
|
if(OSGetVersion() >= 8)
|
|
{
|
|
EnableWindow(GetDlgItem(hwnd, IDC_COMPATIBILITYMODE), FALSE);
|
|
SendMessage(GetDlgItem(hwnd, IDC_COMPATIBILITYMODE), BM_SETCHECK, BST_UNCHECKED, 0);
|
|
}
|
|
break;
|
|
|
|
case IDC_WINDOWCAPTURE:
|
|
SetDesktopCaptureType(hwnd, 1);
|
|
PostMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDC_WINDOW, 0), 0);
|
|
|
|
if(OSGetVersion() >= 8)
|
|
EnableWindow(GetDlgItem(hwnd, IDC_COMPATIBILITYMODE), TRUE);
|
|
break;
|
|
|
|
case IDC_REGIONCAPTURE:
|
|
{
|
|
ConfigDesktopSourceInfo *info = (ConfigDesktopSourceInfo*)GetWindowLongPtr(hwnd, DWLP_USER);
|
|
|
|
UINT captureType = 0;
|
|
|
|
if (info->dialogID == IDD_CONFIGUREDESKTOPSOURCE)
|
|
captureType = (SendMessage(GetDlgItem(hwnd, IDC_WINDOWCAPTURE), BM_GETCHECK, 0, 0) == BST_CHECKED) ? 1 : 0;
|
|
else if (info->dialogID == IDD_CONFIGUREMONITORCAPTURE)
|
|
captureType = 0;
|
|
else
|
|
captureType = 1;
|
|
|
|
BOOL bRegion = SendMessage((HWND)lParam, BM_GETCHECK, 0, 0) == BST_CHECKED;
|
|
|
|
EnableWindow(GetDlgItem(hwnd, IDC_POSX), bRegion);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_POSY), bRegion);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_SIZEX), bRegion);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_SIZEY), bRegion);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_SELECTREGION), bRegion);
|
|
|
|
if(!bRegion)
|
|
{
|
|
if(captureType == 0)
|
|
PostMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDC_MONITOR, 0), 0);
|
|
else
|
|
PostMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDC_WINDOW, 0), 0);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case IDC_SELECTREGION:
|
|
{
|
|
UINT posX, posY, sizeX, sizeY;
|
|
posX = GetEditText(GetDlgItem(hwnd, IDC_POSX)).ToInt();
|
|
posY = GetEditText(GetDlgItem(hwnd, IDC_POSY)).ToInt();
|
|
sizeX = GetEditText(GetDlgItem(hwnd, IDC_SIZEX)).ToInt();
|
|
sizeY = GetEditText(GetDlgItem(hwnd, IDC_SIZEY)).ToInt();
|
|
|
|
//--------------------------------------------
|
|
|
|
ConfigDesktopSourceInfo *info = (ConfigDesktopSourceInfo*)GetWindowLongPtr(hwnd, DWLP_USER);
|
|
|
|
UINT captureType = 0;
|
|
|
|
if (info->dialogID == IDD_CONFIGUREDESKTOPSOURCE)
|
|
captureType = (SendMessage(GetDlgItem(hwnd, IDC_WINDOWCAPTURE), BM_GETCHECK, 0, 0) == BST_CHECKED) ? 1 : 0;
|
|
else if (info->dialogID == IDD_CONFIGUREMONITORCAPTURE)
|
|
captureType = 0;
|
|
else
|
|
captureType = 1;
|
|
|
|
BOOL bRegion = (SendMessage(GetDlgItem(hwnd, IDC_REGIONCAPTURE), BM_GETCHECK, 0, 0) == BST_CHECKED);
|
|
|
|
if(bRegion && captureType == 1)
|
|
{
|
|
UINT windowID = (UINT)SendMessage(GetDlgItem(hwnd, IDC_WINDOW), CB_GETCURSEL, 0, 0);
|
|
if(windowID == CB_ERR) windowID = 0;
|
|
|
|
if(windowID >= info->strClasses.Num())
|
|
{
|
|
OBSMessageBox(hwnd, Str("Sources.SoftwareCaptureSource.WindowNotFound"), NULL, 0);
|
|
break;
|
|
}
|
|
|
|
String strWindow = GetCBText(GetDlgItem(hwnd, IDC_WINDOW), windowID);
|
|
|
|
zero(®ionWindowData, sizeof(regionWindowData));
|
|
|
|
regionWindowData.hwndCaptureWindow = FindWindow(info->strClasses[windowID], strWindow);
|
|
if(!regionWindowData.hwndCaptureWindow)
|
|
{
|
|
HWND hwndLastKnownHWND = (HWND)SendMessage(GetDlgItem(hwnd, IDC_WINDOW), CB_GETITEMDATA, windowID, 0);
|
|
if(IsWindow(hwndLastKnownHWND))
|
|
regionWindowData.hwndCaptureWindow = hwndLastKnownHWND;
|
|
else
|
|
regionWindowData.hwndCaptureWindow = FindWindow(info->strClasses[windowID], NULL);
|
|
}
|
|
|
|
if(!regionWindowData.hwndCaptureWindow)
|
|
{
|
|
OBSMessageBox(hwnd, Str("Sources.SoftwareCaptureSource.WindowNotFound"), NULL, 0);
|
|
break;
|
|
}
|
|
else if(IsIconic(regionWindowData.hwndCaptureWindow))
|
|
{
|
|
OBSMessageBox(hwnd, Str("Sources.SoftwareCaptureSource.WindowMinimized"), NULL, 0);
|
|
break;
|
|
}
|
|
|
|
regionWindowData.bInnerWindowRegion = SendMessage(GetDlgItem(hwnd, IDC_INNERWINDOW), BM_GETCHECK, 0, 0) == BST_CHECKED;
|
|
|
|
if(regionWindowData.bInnerWindowRegion)
|
|
{
|
|
GetClientRect(regionWindowData.hwndCaptureWindow, ®ionWindowData.captureRect);
|
|
ClientToScreen(regionWindowData.hwndCaptureWindow, (POINT*)®ionWindowData.captureRect);
|
|
ClientToScreen(regionWindowData.hwndCaptureWindow, (POINT*)®ionWindowData.captureRect.right);
|
|
}
|
|
else
|
|
GetWindowRect(regionWindowData.hwndCaptureWindow, ®ionWindowData.captureRect);
|
|
|
|
posX += regionWindowData.captureRect.left;
|
|
posY += regionWindowData.captureRect.top;
|
|
}
|
|
else
|
|
{
|
|
UINT monitorID = (UINT)SendMessage(GetDlgItem(hwnd, IDC_MONITOR), CB_GETCURSEL, 0, 0);
|
|
if(monitorID == CB_ERR) monitorID = 0;
|
|
|
|
const MonitorInfo &monitor = App->GetMonitor(monitorID);
|
|
regionWindowData.hwndCaptureWindow = NULL;
|
|
mcpy(®ionWindowData.captureRect, &monitor.rect, sizeof(RECT));
|
|
}
|
|
|
|
//--------------------------------------------
|
|
|
|
regionWindowData.hwndConfigDialog = hwnd;
|
|
HWND hwndRegion = CreateWindowEx(WS_EX_TOPMOST, CAPTUREREGIONCLASS, NULL, WS_POPUP|WS_VISIBLE, posX, posY, sizeX, sizeY, hwnd, NULL, hinstMain, NULL);
|
|
|
|
//everyone better thank homeworld for this
|
|
SetWindowLongW(hwndRegion, GWL_EXSTYLE, GetWindowLong(hwndRegion, GWL_EXSTYLE) | WS_EX_LAYERED);
|
|
SetLayeredWindowAttributes(hwndRegion, 0x000000, 0xC0, LWA_ALPHA);
|
|
break;
|
|
}
|
|
|
|
case IDC_SETSTREAMSIZE:
|
|
if (MessageBoxW(hwnd, Str("Sources.SoftwareCaptureSource.ResizeWarning"), Str("Sources.SoftwareCaptureSource.ResizeWarningTitle"), MB_YESNO | MB_ICONWARNING) == IDYES)
|
|
{
|
|
ConfigDesktopSourceInfo *info = (ConfigDesktopSourceInfo*)GetWindowLongPtr(hwnd, DWLP_USER);
|
|
|
|
UINT sizeX = (UINT)GetEditText(GetDlgItem(hwnd, IDC_SIZEX)).ToInt();
|
|
UINT sizeY = (UINT)GetEditText(GetDlgItem(hwnd, IDC_SIZEY)).ToInt();
|
|
|
|
if(sizeX < 128)
|
|
sizeX = 128;
|
|
else if(sizeX > 4096)
|
|
sizeX = 4096;
|
|
|
|
if(sizeY < 128)
|
|
sizeY = 128;
|
|
else if(sizeY > 4096)
|
|
sizeY = 4096;
|
|
|
|
AppConfig->SetInt(TEXT("Video"), TEXT("BaseWidth"), sizeX);
|
|
AppConfig->SetInt(TEXT("Video"), TEXT("BaseHeight"), sizeY);
|
|
|
|
if(!App->IsRunning())
|
|
App->ResizeWindow(false);
|
|
|
|
info->sizeSet = true;
|
|
}
|
|
break;
|
|
|
|
case IDC_MONITOR:
|
|
{
|
|
if (!lParam || HIWORD(wParam) == CBN_SELCHANGE) {
|
|
UINT id = (UINT) SendMessage(GetDlgItem(hwnd, IDC_MONITOR), CB_GETCURSEL, 0, 0);
|
|
const MonitorInfo &monitor = App->GetMonitor(id);
|
|
|
|
UINT x, y, cx, cy;
|
|
x = monitor.rect.left;
|
|
y = monitor.rect.top;
|
|
cx = monitor.rect.right - monitor.rect.left;
|
|
cy = monitor.rect.bottom - monitor.rect.top;
|
|
|
|
if (cx < 16)
|
|
cx = 16;
|
|
if (cy < 16)
|
|
cy = 16;
|
|
|
|
SetWindowText(GetDlgItem(hwnd, IDC_POSX), IntString(x).Array());
|
|
SetWindowText(GetDlgItem(hwnd, IDC_POSY), IntString(y).Array());
|
|
SetWindowText(GetDlgItem(hwnd, IDC_SIZEX), IntString(cx).Array());
|
|
SetWindowText(GetDlgItem(hwnd, IDC_SIZEY), IntString(cy).Array());
|
|
}
|
|
break;
|
|
}
|
|
|
|
case IDC_WINDOW:
|
|
case IDC_OUTERWINDOW:
|
|
case IDC_INNERWINDOW:
|
|
SelectTargetWindow(hwnd, HIWORD(wParam)==CBN_SELCHANGE);
|
|
break;
|
|
|
|
case IDC_REFRESH:
|
|
{
|
|
ConfigDesktopSourceInfo *info = (ConfigDesktopSourceInfo*)GetWindowLongPtr(hwnd, DWLP_USER);
|
|
XElement *data = info->data;
|
|
|
|
CTSTR lpWindowName = data->GetString(TEXT("window"));
|
|
|
|
HWND hwndWindowList = GetDlgItem(hwnd, IDC_WINDOW);
|
|
RefreshWindowList(hwndWindowList, info->strClasses);
|
|
|
|
UINT windowID = 0;
|
|
if(lpWindowName)
|
|
windowID = (UINT)SendMessage(hwndWindowList, CB_FINDSTRINGEXACT, -1, (LPARAM)lpWindowName);
|
|
|
|
if(windowID != CB_ERR)
|
|
SendMessage(hwndWindowList, CB_SETCURSEL, windowID, 0);
|
|
else
|
|
{
|
|
SendMessage(hwndWindowList, CB_INSERTSTRING, 0, (LPARAM)lpWindowName);
|
|
SendMessage(hwndWindowList, CB_SETCURSEL, 0, 0);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case IDC_USECOLORKEY:
|
|
{
|
|
HWND hwndUseColorKey = (HWND)lParam;
|
|
BOOL bUseColorKey = SendMessage(hwndUseColorKey, BM_GETCHECK, 0, 0) == BST_CHECKED;
|
|
|
|
ConfigDesktopSourceInfo *configData = (ConfigDesktopSourceInfo*)GetWindowLongPtr(hwnd, DWLP_USER);
|
|
ImageSource *source = API->GetSceneImageSource(configData->lpName);
|
|
if(source)
|
|
source->SetInt(TEXT("useColorKey"), bUseColorKey);
|
|
|
|
EnableWindow(GetDlgItem(hwnd, IDC_COLOR), bUseColorKey);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_SELECT), bUseColorKey);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_BASETHRESHOLD_EDIT), bUseColorKey);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_BASETHRESHOLD), bUseColorKey);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_BLEND_EDIT), bUseColorKey);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_BLEND), bUseColorKey);
|
|
break;
|
|
}
|
|
|
|
case IDC_COLOR:
|
|
{
|
|
ConfigDesktopSourceInfo *configData = (ConfigDesktopSourceInfo*)GetWindowLongPtr(hwnd, DWLP_USER);
|
|
ImageSource *source = API->GetSceneImageSource(configData->lpName);
|
|
|
|
if(source)
|
|
{
|
|
DWORD color = CCGetColor((HWND)lParam);
|
|
source->SetInt(TEXT("keyColor"), color);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case IDC_SELECT:
|
|
{
|
|
if(!bSelectingColor)
|
|
{
|
|
if(colorData.Init())
|
|
{
|
|
bMouseDown = false;
|
|
bSelectingColor = true;
|
|
SetCapture(hwnd);
|
|
HCURSOR hCursor = (HCURSOR)LoadImage(hinstMain, MAKEINTRESOURCE(IDC_COLORPICKER), IMAGE_CURSOR, 32, 32, 0);
|
|
SetCursor(hCursor);
|
|
|
|
ConfigDesktopSourceInfo *configData = (ConfigDesktopSourceInfo*)GetWindowLongPtr(hwnd, DWLP_USER);
|
|
ImageSource *source = API->GetSceneImageSource(configData->lpName);
|
|
if(source)
|
|
source->SetInt(TEXT("useColorKey"), false);
|
|
}
|
|
else
|
|
colorData.Clear();
|
|
}
|
|
break;
|
|
}
|
|
|
|
case IDC_OPACITY_EDIT:
|
|
case IDC_BASETHRESHOLD_EDIT:
|
|
case IDC_BLEND_EDIT:
|
|
if(HIWORD(wParam) == EN_CHANGE)
|
|
{
|
|
ConfigDesktopSourceInfo *configData = (ConfigDesktopSourceInfo*)GetWindowLongPtr(hwnd, DWLP_USER);
|
|
if(configData)
|
|
{
|
|
ImageSource *source = API->GetSceneImageSource(configData->lpName);
|
|
|
|
if(source)
|
|
{
|
|
HWND hwndVal = NULL;
|
|
switch(LOWORD(wParam))
|
|
{
|
|
case IDC_BASETHRESHOLD_EDIT: hwndVal = GetDlgItem(hwnd, IDC_BASETHRESHOLD); break;
|
|
case IDC_BLEND_EDIT: hwndVal = GetDlgItem(hwnd, IDC_BLEND); break;
|
|
case IDC_OPACITY_EDIT: hwndVal = GetDlgItem(hwnd, IDC_OPACITY2); break;
|
|
}
|
|
|
|
int val = (int)SendMessage(hwndVal, UDM_GETPOS32, 0, 0);
|
|
switch(LOWORD(wParam))
|
|
{
|
|
case IDC_BASETHRESHOLD_EDIT: source->SetInt(TEXT("keySimilarity"), val); break;
|
|
case IDC_BLEND_EDIT: source->SetInt(TEXT("keyBlend"), val); break;
|
|
case IDC_OPACITY_EDIT: source->SetInt(TEXT("opacity"), val); break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case IDOK:
|
|
{
|
|
ConfigDesktopSourceInfo *info = (ConfigDesktopSourceInfo*)GetWindowLongPtr(hwnd, DWLP_USER);
|
|
|
|
UINT captureType = 0;
|
|
|
|
if (info->dialogID == IDD_CONFIGUREDESKTOPSOURCE) {
|
|
if(SendMessage(GetDlgItem(hwnd, IDC_MONITORCAPTURE), BM_GETCHECK, 0, 0) == BST_CHECKED)
|
|
captureType = 0;
|
|
else if(SendMessage(GetDlgItem(hwnd, IDC_WINDOWCAPTURE), BM_GETCHECK, 0, 0) == BST_CHECKED)
|
|
captureType = 1;
|
|
} else if (info->dialogID == IDD_CONFIGUREMONITORCAPTURE) {
|
|
captureType = 0;
|
|
} else { //IDD_CONFIGUREWINDOWCAPTURE
|
|
captureType = 1;
|
|
}
|
|
|
|
BOOL bRegion = (SendMessage(GetDlgItem(hwnd, IDC_REGIONCAPTURE), BM_GETCHECK, 0, 0) == BST_CHECKED);
|
|
|
|
UINT monitorID = 0;
|
|
|
|
if (info->dialogID == IDD_CONFIGUREDESKTOPSOURCE || info->dialogID == IDD_CONFIGUREMONITORCAPTURE)
|
|
monitorID = (UINT)SendMessage(GetDlgItem(hwnd, IDC_MONITOR), CB_GETCURSEL, 0, 0);
|
|
if(monitorID == CB_ERR) monitorID = 0;
|
|
|
|
UINT windowID = 0;
|
|
if (info->dialogID == IDD_CONFIGUREDESKTOPSOURCE || info->dialogID == IDD_CONFIGUREWINDOWCAPTURE)
|
|
windowID = (UINT)SendMessage(GetDlgItem(hwnd, IDC_WINDOW), CB_GETCURSEL, 0, 0);
|
|
if(windowID == CB_ERR) windowID = 0;
|
|
|
|
if(captureType == 1 && windowID >= info->strClasses.Num())
|
|
break;
|
|
|
|
BOOL bInnerWindow = FALSE;
|
|
String strWindow;
|
|
|
|
if (info->dialogID == IDD_CONFIGUREDESKTOPSOURCE || info->dialogID == IDD_CONFIGUREWINDOWCAPTURE) {
|
|
strWindow = GetCBText(GetDlgItem(hwnd, IDC_WINDOW), windowID);
|
|
bInnerWindow = SendMessage(GetDlgItem(hwnd, IDC_INNERWINDOW), BM_GETCHECK, 0, 0) == BST_CHECKED;
|
|
}
|
|
|
|
UINT posX, posY, sizeX, sizeY;
|
|
posX = GetEditText(GetDlgItem(hwnd, IDC_POSX)).ToInt();
|
|
posY = GetEditText(GetDlgItem(hwnd, IDC_POSY)).ToInt();
|
|
sizeX = GetEditText(GetDlgItem(hwnd, IDC_SIZEX)).ToInt();
|
|
sizeY = GetEditText(GetDlgItem(hwnd, IDC_SIZEY)).ToInt();
|
|
|
|
if(sizeX < 16)
|
|
sizeX = 16;
|
|
if(sizeY < 16)
|
|
sizeY = 16;
|
|
|
|
BOOL bCaptureLayered = FALSE;
|
|
BOOL bCaptureMouse = SendMessage(GetDlgItem(hwnd, IDC_CAPTUREMOUSE), BM_GETCHECK, 0, 0) == BST_CHECKED;
|
|
//if (info->dialogID == IDD_CONFIGUREDESKTOPSOURCE || info->dialogID == IDD_CONFIGUREMONITORCAPTURE)
|
|
bCaptureLayered = SendMessage(GetDlgItem(hwnd, IDC_CAPTURELAYERED), BM_GETCHECK, 0, 0) == BST_CHECKED;
|
|
BOOL bCompatibilityMode = SendMessage(GetDlgItem(hwnd, IDC_COMPATIBILITYMODE), BM_GETCHECK, 0, 0) == BST_CHECKED;
|
|
BOOL bUsePointFiltering = SendMessage(GetDlgItem(hwnd, IDC_POINTFILTERING), BM_GETCHECK, 0, 0) == BST_CHECKED;
|
|
|
|
//---------------------------------
|
|
|
|
XElement *data = info->data;
|
|
|
|
data->SetInt(TEXT("captureType"), captureType);
|
|
|
|
data->SetInt(TEXT("monitor"), monitorID);
|
|
|
|
if(captureType == 1)
|
|
{
|
|
data->SetString(TEXT("window"), strWindow);
|
|
data->SetString(TEXT("windowClass"),info->strClasses[windowID]);
|
|
}
|
|
|
|
data->SetInt(TEXT("innerWindow"), bInnerWindow);
|
|
|
|
data->SetInt(TEXT("regionCapture"), bRegion);
|
|
|
|
data->SetInt(TEXT("captureMouse"), bCaptureMouse);
|
|
|
|
data->SetInt(TEXT("captureLayered"), bCaptureLayered);
|
|
|
|
data->SetInt(TEXT("compatibilityMode"), bCompatibilityMode);
|
|
|
|
data->SetInt(TEXT("usePointFiltering"), bUsePointFiltering);
|
|
|
|
data->SetInt(TEXT("captureX"), posX);
|
|
data->SetInt(TEXT("captureY"), posY);
|
|
data->SetInt(TEXT("captureCX"), sizeX);
|
|
data->SetInt(TEXT("captureCY"), sizeY);
|
|
|
|
//---------------------------------
|
|
|
|
BOOL bUseColorKey = SendMessage(GetDlgItem(hwnd, IDC_USECOLORKEY), BM_GETCHECK, 0, 0) == BST_CHECKED;
|
|
DWORD keyColor = CCGetColor(GetDlgItem(hwnd, IDC_COLOR));
|
|
UINT keySimilarity = (UINT)SendMessage(GetDlgItem(hwnd, IDC_BASETHRESHOLD), UDM_GETPOS32, 0, 0);
|
|
UINT keyBlend = (UINT)SendMessage(GetDlgItem(hwnd, IDC_BLEND), UDM_GETPOS32, 0, 0);
|
|
|
|
data->SetInt(TEXT("useColorKey"), bUseColorKey);
|
|
data->SetInt(TEXT("keyColor"), keyColor);
|
|
data->SetInt(TEXT("keySimilarity"), keySimilarity);
|
|
data->SetInt(TEXT("keyBlend"), keyBlend);
|
|
|
|
//---------------------------------
|
|
|
|
UINT opacity = (UINT)SendMessage(GetDlgItem(hwnd, IDC_OPACITY2), UDM_GETPOS32, 0, 0);
|
|
data->SetInt(TEXT("opacity"), opacity);
|
|
|
|
//---------------------------------
|
|
|
|
int gamma = (int)SendMessage(GetDlgItem(hwnd, IDC_GAMMA), TBM_GETPOS, 0, 0);
|
|
data->SetInt(TEXT("gamma"), gamma);
|
|
|
|
if (captureType == 0 && OSGetVersion() < 8)
|
|
{
|
|
BOOL bComposition;
|
|
DwmIsCompositionEnabled(&bComposition);
|
|
|
|
if (bComposition)
|
|
OBSMessageBox (hwnd, Str("Sources.SoftwareCaptureSource.WarningAero"), TEXT("Warning"), MB_ICONEXCLAMATION);
|
|
}
|
|
}
|
|
|
|
case IDCANCEL:
|
|
if(LOWORD(wParam) == IDCANCEL)
|
|
{
|
|
ConfigDesktopSourceInfo *info = (ConfigDesktopSourceInfo*)GetWindowLongPtr(hwnd, DWLP_USER);
|
|
ImageSource *source = API->GetSceneImageSource(info->lpName);
|
|
if(source)
|
|
{
|
|
XElement *data = info->data;
|
|
source->SetInt(TEXT("useColorKey"), data->GetInt(TEXT("useColorKey"), 0));
|
|
source->SetInt(TEXT("keyColor"), data->GetInt(TEXT("keyColor"), 0xFFFFFFFF));
|
|
source->SetInt(TEXT("keySimilarity"), data->GetInt(TEXT("keySimilarity"), 10));
|
|
source->SetInt(TEXT("keyBlend"), data->GetInt(TEXT("keyBlend"), 0));
|
|
source->SetInt(TEXT("opacity"), data->GetInt(TEXT("opacity"), 100));
|
|
source->SetInt(TEXT("gamma"), data->GetInt(TEXT("gamma"), 100));
|
|
}
|
|
}
|
|
|
|
EndDialog(hwnd, LOWORD(wParam));
|
|
break;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
bool bMadeCaptureRegionClass = false;
|
|
|
|
static bool STDCALL ConfigureDesktopSource2(XElement *element, bool bInitialize, int dialogID)
|
|
{
|
|
if(!bMadeCaptureRegionClass)
|
|
{
|
|
WNDCLASS wc;
|
|
zero(&wc, sizeof(wc));
|
|
wc.hInstance = hinstMain;
|
|
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
wc.lpszClassName = CAPTUREREGIONCLASS;
|
|
wc.lpfnWndProc = (WNDPROC)RegionWindowProc;
|
|
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
|
|
RegisterClass(&wc);
|
|
|
|
bMadeCaptureRegionClass = true;
|
|
}
|
|
|
|
if(!element)
|
|
{
|
|
AppWarning(TEXT("ConfigureDesktopSource: NULL element"));
|
|
return false;
|
|
}
|
|
|
|
XElement *data = element->GetElement(TEXT("data"));
|
|
if(!data)
|
|
data = element->CreateElement(TEXT("data"));
|
|
|
|
ConfigDesktopSourceInfo info;
|
|
info.data = data;
|
|
info.lpName = element->GetName();
|
|
info.dialogID = dialogID;
|
|
|
|
if(OBSDialogBox(hinstMain, MAKEINTRESOURCE(dialogID), hwndMain, ConfigDesktopSourceProc, (LPARAM)&info) == IDOK)
|
|
{
|
|
element->SetInt(TEXT("cx"), data->GetInt(TEXT("captureCX")));
|
|
element->SetInt(TEXT("cy"), data->GetInt(TEXT("captureCY")));
|
|
return true;
|
|
} else {
|
|
if (info.sizeSet) {
|
|
AppConfig->SetInt(TEXT("Video"), TEXT("BaseWidth"), info.prevCX);
|
|
AppConfig->SetInt(TEXT("Video"), TEXT("BaseHeight"), info.prevCY);
|
|
|
|
if(!App->IsRunning())
|
|
App->ResizeWindow(false);
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool STDCALL ConfigureDesktopSource(XElement *element, bool bInitialize)
|
|
{
|
|
return ConfigureDesktopSource2(element, bInitialize, IDD_CONFIGUREDESKTOPSOURCE);
|
|
}
|
|
|
|
bool STDCALL ConfigureWindowCaptureSource(XElement *element, bool bInitialize)
|
|
{
|
|
return ConfigureDesktopSource2(element, bInitialize, IDD_CONFIGUREWINDOWCAPTURE);
|
|
}
|
|
|
|
bool STDCALL ConfigureMonitorCaptureSource(XElement *element, bool bInitialize)
|
|
{
|
|
return ConfigureDesktopSource2(element, bInitialize, IDD_CONFIGUREMONITORCAPTURE);
|
|
}
|