diff --git a/CPF.Linux/X11Window.cs b/CPF.Linux/X11Window.cs index 4938b05..054efe0 100644 --- a/CPF.Linux/X11Window.cs +++ b/CPF.Linux/X11Window.cs @@ -108,10 +108,10 @@ namespace CPF.Linux var depth = 32;// (int)x11info.TransparentVisualInfo.depth; attr.colormap = XCreateColormap(x11info.Display, x11info.RootWindow, x11info.TransparentVisualInfo.visual, 0); valueMask |= SetWindowValuemask.ColorMap; - size = new PixelSize(300, 200); - position = new PixelPoint(10, 10); + size = new PixelSize(1, 1); + position = new PixelPoint(0, 0); - Handle = XCreateWindow(x11info.Display, x11info.RootWindow, 10, 10, size.Width, size.Height, 0, depth, (int)CreateWindowArgs.InputOutput, x11info.TransparentVisualInfo.visual, new UIntPtr((uint)valueMask), ref attr); + Handle = XCreateWindow(x11info.Display, x11info.RootWindow, position.X, position.Y, size.Width, size.Height, 0, depth, (int)CreateWindowArgs.InputOutput, x11info.TransparentVisualInfo.visual, new UIntPtr((uint)valueMask), ref attr); // var attributes = new XSetWindowAttributes(); // attributes.background_pixel = XWhitePixel(x11info.Display, x11info.DefaultScreen); @@ -438,9 +438,9 @@ namespace CPF.Linux activate = false; //Console.WriteLine("Deactivated"); Deactivated?.Invoke(); - XUnsetICFocus(xic); if (xic != IntPtr.Zero) { + XUnsetICFocus(xic); //if (have_Xutf8ResetIC) //{ // try diff --git a/CPF.Windows/ScreenImpl.cs b/CPF.Windows/ScreenImpl.cs index d03cbbd..6136a05 100644 --- a/CPF.Windows/ScreenImpl.cs +++ b/CPF.Windows/ScreenImpl.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; +using System.IO; using System.Runtime.InteropServices; +using System.Runtime.InteropServices.ComTypes; using System.Text; using CPF.Drawing; using CPF.Platform; @@ -60,32 +62,94 @@ namespace CPF.Windows public override Bitmap Screenshot() { - var srcDC = GetDC(IntPtr.Zero); - var bounds = Bounds; + IntPtr desktopHwnd = GetDesktopWindow(); + IntPtr desktopDc = GetWindowDC(desktopHwnd); + IntPtr memDc = CreateCompatibleDC(desktopDc); - IntPtr memDc = CreateCompatibleDC(srcDC); - BITMAPINFOHEADER info = new BITMAPINFOHEADER(); - info.biSize = (uint)Marshal.SizeOf(typeof(BITMAPINFOHEADER)); - info.biBitCount = 32; - info.biHeight = -(int)bounds.Height; - info.biWidth = (int)bounds.Width; - info.biPlanes = 1; - var hBitmap = CreateDIBSection(memDc, ref info, 0, out var ppvBits, IntPtr.Zero, 0); - var oldBits = SelectObject(memDc, hBitmap); + try + { + // 3. 创建DIBSection (24位真彩色位图) + BITMAPINFOHEADER bmi = new BITMAPINFOHEADER + { + biSize = (uint)Marshal.SizeOf(typeof(BITMAPINFOHEADER)), + biWidth = (int)Bounds.Width, + biHeight = -(int)Bounds.Height, // 负值表示自顶向下DIB + biPlanes = 1, + biBitCount = 24, + biCompression = 0, // BI_RGB + biSizeImage = (uint)(((int)Bounds.Width * 3 + 3) & ~3) * (uint)Bounds.Height // 行对齐到4字节 + } + ; - BitBlt(memDc, 0, 0, (int)bounds.Width, - (int)bounds.Height, srcDC, (int)bounds.X, (int)bounds.Y, TernaryRasterOperations.SRCCOPY); - Bitmap temp = new Bitmap((int)bounds.Width, (int)bounds.Height, (int)bounds.Width * 4, PixelFormat.Bgra, ppvBits); + IntPtr hBitmap = CreateDIBSection(desktopDc, ref bmi, 0, out var bitsPtr, IntPtr.Zero, 0); - Bitmap bitmap = (Bitmap)temp.Clone(); - temp.Dispose(); + // 4. 将屏幕内容复制到位图 + IntPtr oldBitmap = SelectObject(memDc, hBitmap); + BitBlt(memDc, 0, 0, (int)Bounds.Width, (int)Bounds.Height, desktopDc, 0, 0, TernaryRasterOperations.SRCCOPY | TernaryRasterOperations.CAPTUREBLT); + SelectObject(memDc, oldBitmap); - SelectObject(memDc, oldBits); - DeleteObject(hBitmap); - DeleteDC(memDc); + // 5. 构造BMP文件 + using (MemoryStream ms = new MemoryStream()) + { + // 5.1 计算文件大小 + uint pixelDataSize = bmi.biSizeImage; + uint fileSize = (uint)(Marshal.SizeOf(typeof(BITMAPFILEHEADER)) + + (Marshal.SizeOf(typeof(BITMAPINFOHEADER))) + + pixelDataSize); - ReleaseDC(IntPtr.Zero, srcDC); - return bitmap; + // 5.2 创建文件头 + BITMAPFILEHEADER fileHeader = new BITMAPFILEHEADER + { + bfType = 0x4D42, // "BM" + bfSize = fileSize, + bfOffBits = (uint)(Marshal.SizeOf(typeof(BITMAPFILEHEADER)) + +(Marshal.SizeOf(typeof(BITMAPINFOHEADER)))) + } + ; + + // 5.3 写入文件头 + byte[] fileHeaderBytes = StructureToBytes(fileHeader); + ms.Write(fileHeaderBytes, 0, fileHeaderBytes.Length); + + // 5.4 写入信息头 + byte[] infoHeaderBytes = StructureToBytes(bmi); + ms.Write(infoHeaderBytes, 0, infoHeaderBytes.Length); + + // 5.5 写入像素数据 (直接从DIBSection内存复制) + byte[] pixelData = new byte[pixelDataSize]; + Marshal.Copy(bitsPtr, pixelData, 0, (int)pixelDataSize); + ms.Write(pixelData, 0, pixelData.Length); + + ms.Position = 0; + + Bitmap bitmap = new Bitmap(ms); + return bitmap; + } + } + finally + { + // 6. 清理资源 + ReleaseDC(desktopHwnd, desktopDc); + DeleteDC(memDc); + } + } + + // 辅助方法:结构体转字节数组 + private static byte[] StructureToBytes(T structure) where T : struct + { + int size = Marshal.SizeOf(typeof(T)); + byte[] bytes = new byte[size]; + IntPtr ptr = Marshal.AllocHGlobal(size); + try + { + Marshal.StructureToPtr(structure, ptr, false); + Marshal.Copy(ptr, bytes, 0, size); + return bytes; + } + finally + { + Marshal.FreeHGlobal(ptr); + } } } } diff --git a/CPF.Windows/UnmanagedMethods.cs b/CPF.Windows/UnmanagedMethods.cs index 22d53eb..1cb26e0 100644 --- a/CPF.Windows/UnmanagedMethods.cs +++ b/CPF.Windows/UnmanagedMethods.cs @@ -880,7 +880,11 @@ namespace CPF.Windows [DllImport("gdi32.dll", SetLastError = true, ExactSpelling = true, CharSet = CharSet.Auto)] public static extern int GetDeviceCaps(IntPtr hDC, int nIndex); + [DllImport("user32.dll")] + public static extern IntPtr GetDesktopWindow(); + [DllImport("user32.dll")] + public static extern IntPtr GetWindowDC(IntPtr hWnd); [DllImport("user32.dll", SetLastError = true)] public static extern IntPtr GetDC(IntPtr hWnd); [DllImport("gdi32.dll", EntryPoint = "BitBlt", SetLastError = true)] diff --git a/CPF.Windows/WindowImpl.cs b/CPF.Windows/WindowImpl.cs index 2ba29b1..c123360 100644 --- a/CPF.Windows/WindowImpl.cs +++ b/CPF.Windows/WindowImpl.cs @@ -90,10 +90,6 @@ namespace CPF.Windows { isLayered = true; } - if ((v.Major == 6 && v.Minor < 2)) - { - touchMsg = RegisterTouchWindow(handle, RegisterTouchFlags.TWF_NONE); - } _className = "CPFWindow-" + Guid.NewGuid(); // 初始化窗口类结构 wc.cbSize = Marshal.SizeOf(typeof(WNDCLASSEX)); @@ -113,6 +109,10 @@ namespace CPF.Windows handle = CreateWindowEx((int)ExStyle, _className, "窗体标题", (uint)Style, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, IntPtr.Zero, IntPtr.Zero, ModuleHandle, null); + if ((v.Major == 6 && v.Minor < 2)) + { + touchMsg = RegisterTouchWindow(handle, RegisterTouchFlags.TWF_NONE); + } //timer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(1), IsEnabled = true }; //timer.Tick += Timer_Tick; diff --git a/CPF/Controls/Picture.cs b/CPF/Controls/Picture.cs index d9cf09c..30081c8 100644 --- a/CPF/Controls/Picture.cs +++ b/CPF/Controls/Picture.cs @@ -276,7 +276,7 @@ namespace CPF.Controls { timer = new Threading.DispatcherTimer(); timer.Tick += Timer_Tick; - timer.Interval = TimeSpan.FromMilliseconds(50); + timer.Interval = TimeSpan.FromMilliseconds(25); } timer.Start(); diff --git a/CPF/Input/KeyboardDevice.cs b/CPF/Input/KeyboardDevice.cs index 43f35a5..9485211 100644 --- a/CPF/Input/KeyboardDevice.cs +++ b/CPF/Input/KeyboardDevice.cs @@ -75,7 +75,7 @@ namespace CPF.Input } } - internal void SetFocus(UIElement e) + public void SetFocus(UIElement e) { focusedElement = e; //if (focusedElement != null)