public void Update(Texture2D DesktopTexture, OutputDuplicateFrameInformation FrameInfo, OutputDuplication DeskDupl) { // No update if (FrameInfo.LastMouseUpdateTime == 0) { _pointerShape?.Update(DesktopTexture, _pointerPosition); return; } _pointerPosition = FrameInfo.PointerPosition; if (FrameInfo.PointerShapeBufferSize != 0) { if (FrameInfo.PointerShapeBufferSize > _ptrShapeBufferSize) { _ptrShapeBufferSize = FrameInfo.PointerShapeBufferSize; _ptrShapeBuffer = _ptrShapeBuffer != IntPtr.Zero ? Marshal.ReAllocCoTaskMem(_ptrShapeBuffer, _ptrShapeBufferSize) : Marshal.AllocCoTaskMem(_ptrShapeBufferSize); } DeskDupl.GetFramePointerShape(_ptrShapeBufferSize, _ptrShapeBuffer, out _, out _ptrShapeInfo); _pointerShape?.Dispose(); switch (_ptrShapeInfo.Type) { case PtrShapeMonochrome: _pointerShape = new MonochromePointerShape(_ptrShapeBuffer, _ptrShapeInfo, _editorSession); break; case PtrShapeMaskedColor: _pointerShape = new MaskedColorPointerShape(_ptrShapeBuffer, _ptrShapeInfo, _editorSession); break; case PtrShapeColor: _pointerShape = new ColorPointerShape(_ptrShapeBuffer, _ptrShapeInfo, _editorSession.RenderTarget); break; } } _pointerShape?.Update(DesktopTexture, _pointerPosition); }
public void Update(Texture2D DesktopTexture, OutputDuplicatePointerPosition PointerPosition) { _bmp?.Dispose(); var region = new ResourceRegion( PointerPosition.Position.X, PointerPosition.Position.Y, 0, PointerPosition.Position.X + Width, PointerPosition.Position.Y + Height, 1); _editorSession.Device.ImmediateContext.CopySubresourceRegion( DesktopTexture, 0, region, _copyTex, 0); var desktopMap = _editorSession.Device.ImmediateContext.MapSubresource( _copyTex, 0, MapMode.Read, MapFlags.None); try { Marshal.Copy(desktopMap.DataPointer, DesktopBuffer, 0, DesktopBuffer.Length); } finally { _editorSession.Device.ImmediateContext.UnmapSubresource(_copyTex, 0); } OnUpdate(); var gcPin = GCHandle.Alloc(ShapeBuffer, GCHandleType.Pinned); try { var pitch = Width * 4; _bmp = new Bitmap(_editorSession.RenderTarget, new Size2(Width, Height), new DataPointer(gcPin.AddrOfPinnedObject(), Height * pitch), pitch, new BitmapProperties(new PixelFormat(Format.B8G8R8A8_UNorm, AlphaMode.Premultiplied))); } finally { gcPin.Free(); } }
protected internal void GetCursor(Texture2D screenTexture, OutputDuplicateFrameInformation info, FrameInfo frame) { //Prepare buffer array to hold the cursor shape. if (CursorShapeBuffer == null || info.PointerShapeBufferSize > CursorShapeBuffer.Length) { CursorShapeBuffer = new byte[info.PointerShapeBufferSize]; } //If there's a cursor shape available to be captured. if (info.PointerShapeBufferSize > 0) { //Pin the buffer in order to pass the address as parameter later. var pinnedBuffer = GCHandle.Alloc(CursorShapeBuffer, GCHandleType.Pinned); var cursorBufferAddress = pinnedBuffer.AddrOfPinnedObject(); //Load the cursor shape into the buffer. DuplicatedOutput.GetFramePointerShape(info.PointerShapeBufferSize, cursorBufferAddress, out _, out CursorShapeInfo); //If the cursor is monochrome, it will return the cursor shape twice, one is the mask. if (CursorShapeInfo.Type == 1) { CursorShapeInfo.Height /= 2; } //The buffer must be unpinned, to free resources. pinnedBuffer.Free(); } //Store the current cursor position, if it was moved. if (info.LastMouseUpdateTime != 0) { PreviousPosition = info.PointerPosition; } //TODO: In a future version, don't merge the cursor image in here, let the editor do that. //Saves the position of the cursor, so the editor can add the mouse clicks overlay later. frame.CursorX = PreviousPosition.Position.X - Left; frame.CursorY = PreviousPosition.Position.Y - Top; //If the method is supposed to simply the get the cursor shape no shape was loaded before, there's nothing else to do. //if (CursorShapeBuffer?.Length == 0 || (info.LastPresentTime == 0 && info.LastMouseUpdateTime == 0) || !info.PointerPosition.Visible) if (screenTexture == null || CursorShapeBuffer?.Length == 0)// || !info.PointerPosition.Visible) { return; } //Don't let it bleed beyond the top-left corner. var left = Math.Max(frame.CursorX, 0); var top = Math.Max(frame.CursorY, 0); var offsetX = Math.Abs(Math.Min(0, frame.CursorX)); var offsetY = Math.Abs(Math.Min(0, frame.CursorY)); //Adjust the offset, so it's possible to add the highlight correctly later. frame.CursorX += CursorShapeInfo.HotSpot.X; frame.CursorY += CursorShapeInfo.HotSpot.Y; if (CursorShapeInfo.Width - offsetX < 0 || CursorShapeInfo.Height - offsetY < 0) { return; } //The staging texture must be able to hold all pixels. if (CursorStagingTexture == null || CursorStagingTexture.Description.Width < CursorShapeInfo.Width - offsetX || CursorStagingTexture.Description.Height < CursorShapeInfo.Height - offsetY) { //In order to change the size of the texture, I need to instantiate it again with the new size. CursorStagingTexture?.Dispose(); CursorStagingTexture = new Texture2D(Device, new Texture2DDescription { ArraySize = 1, BindFlags = BindFlags.None, CpuAccessFlags = CpuAccessFlags.Write, Height = CursorShapeInfo.Height - offsetY, Format = Format.B8G8R8A8_UNorm, Width = CursorShapeInfo.Width - offsetX, MipLevels = 1, OptionFlags = ResourceOptionFlags.None, SampleDescription = new SampleDescription(1, 0), Usage = ResourceUsage.Staging }); } //The region where the cursor is located is copied to the staging texture to act as the background when dealing with masks and transparency. var region = new ResourceRegion { Left = left, Top = top, Front = 0, Right = left + CursorStagingTexture.Description.Width, Bottom = top + CursorStagingTexture.Description.Height, Back = 1 }; //Copy from the screen the region in which the cursor is located. Device.ImmediateContext.CopySubresourceRegion(screenTexture, 0, region, CursorStagingTexture, 0); //Get cursor details and draw it to the staging texture. DrawCursorShape(CursorStagingTexture, CursorShapeInfo, CursorShapeBuffer, offsetX, offsetY); //Copy back the cursor texture to the screen texture. Device.ImmediateContext.CopySubresourceRegion(CursorStagingTexture, 0, null, screenTexture, 0, left, top); }
protected internal bool GetCursor(Texture2D screenTexture, OutputDuplicateFrameInformation info, FrameInfo frame) { //Prepare buffer array to hold the cursor shape. if (CursorShapeBuffer == null || info.PointerShapeBufferSize > CursorShapeBuffer.Length) { CursorShapeBuffer = new byte[info.PointerShapeBufferSize]; } //If there's a cursor shape available to be captured. if (info.PointerShapeBufferSize > 0) { //Pin the buffer in order to pass the address as parameter later. var pinnedBuffer = GCHandle.Alloc(CursorShapeBuffer, GCHandleType.Pinned); var cursorBufferAddress = pinnedBuffer.AddrOfPinnedObject(); //Load the cursor shape into the buffer. DuplicatedOutput.GetFramePointerShape(info.PointerShapeBufferSize, cursorBufferAddress, out _, out CursorShapeInfo); //If the cursor is monochrome, it will return the cursor shape twice, one is the mask. if (CursorShapeInfo.Type == 1) { CursorShapeInfo.Height /= 2; } //The buffer must be unpinned, to free resources. pinnedBuffer.Free(); } //Store the current cursor position, if it was moved. if (info.LastMouseUpdateTime != 0) { PreviousPosition = info.PointerPosition; } //TODO: In a future version, don't merge the cursor image in here, let the editor do that. //Saves the position of the cursor, so the editor can add the mouse clicks overlay later. frame.CursorX = PreviousPosition.Position.X - (Left - OffsetLeft); frame.CursorY = PreviousPosition.Position.Y - (Top - OffsetTop); //If the method is supposed to simply the get the cursor shape no shape was loaded before, there's nothing else to do. //if (CursorShapeBuffer?.Length == 0 || (info.LastPresentTime == 0 && info.LastMouseUpdateTime == 0) || !info.PointerPosition.Visible) if (screenTexture == null || CursorShapeBuffer?.Length == 0)// || !info.PointerPosition.Visible) { //FallbackCursorCapture(frame); //if (CursorShapeBuffer != null) return(false); } //Don't let it bleed beyond the top-left corner, calculate the dimensions of the portion of the cursor that will appear. var leftCut = frame.CursorX; var topCut = frame.CursorY; var rightCut = screenTexture.Description.Width - (frame.CursorX + CursorShapeInfo.Width); var bottomCut = screenTexture.Description.Height - (frame.CursorY + CursorShapeInfo.Height); //Adjust to the hotspot offset, so it's possible to add the highlight correctly later. frame.CursorX += CursorShapeInfo.HotSpot.X; frame.CursorY += CursorShapeInfo.HotSpot.Y; //Don't try merging the textures if the cursor is out of bounds. if (leftCut + CursorShapeInfo.Width < 1 || topCut + CursorShapeInfo.Height < 1 || rightCut + CursorShapeInfo.Width < 1 || bottomCut + CursorShapeInfo.Height < 1) { return(false); } var cursorLeft = Math.Max(leftCut, 0); var cursorTop = Math.Max(topCut, 0); var cursorWidth = leftCut < 0 ? CursorShapeInfo.Width + leftCut : rightCut < 0 ? CursorShapeInfo.Width + rightCut : CursorShapeInfo.Width; var cursorHeight = topCut < 0 ? CursorShapeInfo.Height + topCut : bottomCut < 0 ? CursorShapeInfo.Height + bottomCut : CursorShapeInfo.Height; //The staging texture must be able to hold all pixels. if (CursorStagingTexture == null || CursorStagingTexture.Description.Width != cursorWidth || CursorStagingTexture.Description.Height != cursorHeight) { //In order to change the size of the texture, I need to instantiate it again with the new size. CursorStagingTexture?.Dispose(); CursorStagingTexture = new Texture2D(Device, new Texture2DDescription { ArraySize = 1, BindFlags = BindFlags.None, CpuAccessFlags = CpuAccessFlags.Write, Height = cursorHeight, Format = Format.B8G8R8A8_UNorm, Width = cursorWidth, MipLevels = 1, OptionFlags = ResourceOptionFlags.None, SampleDescription = new SampleDescription(1, 0), Usage = ResourceUsage.Staging }); } //The region where the cursor is located is copied to the staging texture to act as the background when dealing with masks and transparency. //The cutout must be the exact region needed and it can't overflow. It's not allowed to try to cut outside of the screenTexture region. var region = new ResourceRegion { Left = cursorLeft, Top = cursorTop, Front = 0, Right = cursorLeft + cursorWidth, Bottom = cursorTop + cursorHeight, Back = 1 }; //Copy from the screen the region in which the cursor is located. Device.ImmediateContext.CopySubresourceRegion(screenTexture, 0, region, CursorStagingTexture, 0); //Get cursor details and draw it to the staging texture. DrawCursorShape(CursorStagingTexture, CursorShapeInfo, CursorShapeBuffer, leftCut < 0 ? leftCut * -1 : 0, topCut < 0 ? topCut * -1 : 0, cursorWidth, cursorHeight); //Copy back the cursor texture to the screen texture. Device.ImmediateContext.CopySubresourceRegion(CursorStagingTexture, 0, null, screenTexture, 0, cursorLeft, cursorTop); return(true); }
public void Update(Texture2D DesktopTexture, OutputDuplicatePointerPosition PointerPosition) { }