Transparent window layer that is click-through and always stays on top

前端 未结 4 1540
梦谈多话
梦谈多话 2020-12-02 10:48

This is some code that I picked up which I tried to implement. Its purpose is to create a form layer which is transparent, full screen, borderless, clickthrough, and always

相关标签:
4条回答
  • 2020-12-02 11:02

    Change your extended window style to only WS_EX_LAYERED, window style to only WS_POPUP (NO WS_SIZEBOX) and make sure to use DwmExtendFrameIntoClientArea with all -1's and this will produce transparent windows with layered support: downside is you need to bltbit with GDI from an offscreen directx rendering. Not optimal but it works. This gives mouse click throughs + directx rendering + transparency. Downside is you'll need to inform GDI anytime, pull the directx buffer (all of it or just the damaged portions) and write them to the screem with bltbit.

    Setting the extended window style to WS_EX_COMPOSITED and DwmExtendedFrameIntoClientArea with all -1's (similar as above, WS_POPUP on the regular window style). This you can run directx from but no mouse clickthroughs. You can at this point define irregular paths for the hit mask and pass it to windows, its not perfect but if you know a general (non regular) area that can pass-through it'll work.

    Still trying to find a true way of using opengl/directx on mac or windows platforms that can pass through mouse clicks with out having to do a bitblt to a legacy rendering system.

    0 讨论(0)
  • 2020-12-02 11:06

    A little extension/modification to Jaska's code, which the form is transparent

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
    
            this.TopMost = true; // make the form always on top
            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None; // hidden border
            this.WindowState = FormWindowState.Maximized; // maximized
            this.MinimizeBox = this.MaximizeBox = false; // not allowed to be minimized
            this.MinimumSize = this.MaximumSize = this.Size; // not allowed to be resized
            this.TransparencyKey = this.BackColor = Color.Red; // the color key to transparent, choose a color that you don't use
        }
    
        protected override CreateParams CreateParams
        {
            get
            {
                CreateParams cp = base.CreateParams;
                // Set the form click-through
                cp.ExStyle |= 0x80000 /* WS_EX_LAYERED */ | 0x20 /* WS_EX_TRANSPARENT */;
                return cp;
            }
        }
    
        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            // draw what you want
            e.Graphics.FillEllipse(Brushes.Blue, 30, 30, 100, 100);
        }
    }
    
    0 讨论(0)
  • 2020-12-02 11:06

    I have a simple way use TransparentKey property and a 1x1 pixel label with the color of Form TransparentKey. On Form and all control MouseMouse event. Set label position to Mouse location.

    private void MoveHole()
    {
        var newLocation = PointToClient(MousePosition);
        lblHole.Location = newLocation;
    }
    
    0 讨论(0)
  • 2020-12-02 11:07

    Here's a refined full sample code for making a window topmost - click through - transparent (= alpha blended). The sample makes a rotating color wheel which is rendered with DirectX, or actually with XNA 4.0, because I believe Microsoft has discontinued developing the managed directx and favours XNA today.

    using System;
    using System.Windows.Forms;
    using System.Runtime.InteropServices;
    using Microsoft.Xna.Framework.Graphics;
    
    namespace ClickThroughXNA
    {
        public partial class Form1 : Form
        {
            // Directx graphics device
            GraphicsDevice dev = null;        
            BasicEffect effect = null;     
    
            // Wheel vertexes
            VertexPositionColor[] v = new VertexPositionColor[100];
    
            // Wheel rotation
            float rot = 0;
    
            public Form1()
            {
                InitializeComponent();
    
                StartPosition = FormStartPosition.CenterScreen;   
                Size = new System.Drawing.Size(500, 500);
                FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;  // no borders
    
                TopMost = true;        // make the form always on top                     
                Visible = true;        // Important! if this isn't set, then the form is not shown at all
    
                // Set the form click-through
                int initialStyle = GetWindowLong(this.Handle, -20);
                SetWindowLong(this.Handle, -20, initialStyle | 0x80000 | 0x20);
    
                // Create device presentation parameters
                PresentationParameters p = new PresentationParameters();
                p.IsFullScreen = false;
                p.DeviceWindowHandle = this.Handle;
                p.BackBufferFormat = SurfaceFormat.Vector4;
                p.PresentationInterval = PresentInterval.One;
    
                // Create XNA graphics device
                dev = new GraphicsDevice(GraphicsAdapter.DefaultAdapter, GraphicsProfile.Reach, p);
    
                // Init basic effect
                effect = new BasicEffect(dev);
    
                // Extend aero glass style on form init
                OnResize(null);
            }
    
    
            protected override void OnResize(EventArgs e)
            {
                int[] margins = new int[] { 0, 0, Width, Height };
    
                // Extend aero glass style to whole form
                DwmExtendFrameIntoClientArea(this.Handle, ref margins);  
            }
    
    
            protected override void OnPaintBackground(PaintEventArgs e)
            {
                // do nothing here to stop window normal background painting
            }
    
    
            protected override void OnPaint(PaintEventArgs e)
            {                
                // Clear device with fully transparent black
                dev.Clear(new Microsoft.Xna.Framework.Color(0, 0, 0, 0.0f));
    
                // Rotate wheel a bit
                rot+=0.1f;
    
                // Make the wheel vertexes and colors for vertexes
                for (int i = 0; i < v.Length; i++)
                {                    
                    if (i % 3 == 1)
                        v[i].Position = new Microsoft.Xna.Framework.Vector3((float)Math.Sin((i + rot) * (Math.PI * 2f / (float)v.Length)), (float)Math.Cos((i + rot) * (Math.PI * 2f / (float)v.Length)), 0);
                    else if (i % 3 == 2)
                        v[i].Position = new Microsoft.Xna.Framework.Vector3((float)Math.Sin((i + 2 + rot) * (Math.PI * 2f / (float)v.Length)), (float)Math.Cos((i + 2 + rot) * (Math.PI * 2f / (float)v.Length)), 0);
    
                    v[i].Color = new Microsoft.Xna.Framework.Color(1 - (i / (float)v.Length), i / (float)v.Length, 0, i / (float)v.Length);
                }
    
                // Enable position colored vertex rendering
                effect.VertexColorEnabled = true;
                foreach (EffectPass pass in effect.CurrentTechnique.Passes) pass.Apply();
    
                // Draw the primitives (the wheel)
                dev.DrawUserPrimitives(PrimitiveType.TriangleList, v, 0, v.Length / 3, VertexPositionColor.VertexDeclaration);
    
                // Present the device contents into form
                dev.Present();
    
                // Redraw immediatily
                Invalidate();            
            }
    
    
            [DllImport("user32.dll", SetLastError = true)]
            static extern int GetWindowLong(IntPtr hWnd, int nIndex);
    
            [DllImport("user32.dll")]
            static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
    
            [DllImport("dwmapi.dll")]
            static extern void DwmExtendFrameIntoClientArea(IntPtr hWnd, ref int[] pMargins);
    
        }
    }
    
    0 讨论(0)
提交回复
热议问题