/******************************************************************************** Copyright (C) 2012 Hugh Bailey 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 #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; //------------------------- // 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; OutputDuplicator *duplicator; public: DesktopImageSource(UINT frameTime, XElement *data) { this->data = data; UpdateSettings(); 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; iRemoveStreamInfo(warningID); delete duplicator; delete cursorTexture; delete alphaIgnoreShader; delete colorKeyShader; if(bCompatibilityMode) { SelectObject(hdcCompatible, hbmpOld); DeleteDC(hdcCompatible); DeleteObject(hbmpCompatible); } } void Tick(float fSeconds) { if(bWindows8MonitorCapture && !duplicator) { retryAcquire += fSeconds; if(retryAcquire > 3.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"), bWindowNotFound ? StreamInfoPriority_High : StreamInfoPriority_Medium); } 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(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 DrawSpriteEx(lastRendered, (opacity255<<24) | 0xFFFFFF, pos.x, pos.y, pos.x+size.x, pos.y+size.y, ulCoord.x, ulCoord.y, lrCoord.x, lrCoord.y); 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; 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; iGetMonitor(monitor); mcpy(&monitorData, &monitorInfo, sizeof(monitorInfo)); if(captureType == 0 && OSGetVersion() >= 8) { DeviceOutputs outputs; GetDisplayDevices(outputs); if(outputs.devices.Num()) { const MonitorInfo &info = App->GetMonitor(monitor); for(UINT j=0; jCreateOutputDuplicator(deviceOutputID); else if(bCompatibilityMode) renderTextures[0] = CreateTexture(width, height, GS_BGRA, NULL, FALSE, FALSE); else { for(UINT i=0; iGetInt(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); DWORD exStyles = (DWORD)GetWindowLongPtr(hwndCurrent, GWL_EXSTYLE); DWORD styles = (DWORD)GetWindowLongPtr(hwndCurrent, GWL_STYLE); if( (exStyles & WS_EX_TOOLWINDOW) == 0 && (styles & WS_CHILD) == 0 && clientRect.bottom != 0 && clientRect.right != 0 /*&& hwndParent == NULL*/) { String strWindowName; strWindowName.SetLength(GetWindowTextLength(hwndCurrent)); GetWindowText(hwndCurrent, strWindowName, strWindowName.Length()+1); //------- 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; 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; }; 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; SendMessage(hwndToolTip, TTM_SETMAXTIPWIDTH, 0, 500); SendMessage(hwndToolTip, TTM_SETDELAYTIME, TTDT_AUTOPOP, 8000); //----------------------------------------------------- ConfigDesktopSourceInfo *info = (ConfigDesktopSourceInfo*)lParam; XElement *data = info->data; if (info->dialogID == IDD_CONFIGUREMONITORCAPTURE || info->dialogID == IDD_CONFIGUREDESKTOPSOURCE) { hwndTemp = GetDlgItem(hwnd, IDC_MONITOR); for(UINT i=0; iNumMonitors(); 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()) { MessageBox(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) { MessageBox(hwnd, Str("Sources.SoftwareCaptureSource.WindowNotFound"), NULL, 0); break; } else if(IsIconic(regionWindowData.hwndCaptureWindow)) { MessageBox(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: { 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); } break; case IDC_MONITOR: { 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) MessageBox (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(DialogBoxParam(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; } 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); }