问题
This is my virgin post so please go easy on me !
I am writing a program in C# which I want to run maximized and always-on-top. The app will be translucent so that a user can still see everything that's going on behind my maximized application.
I am aiming to achieve a scenario where a user can (despite my app having focus) still interact as normal with all other running programs - as if it was a piece of coloured glass which merely redirects all user input to another intended application, eg what ever exists at a given x,y mouse click behind the overlay.
The basic idea is to create an overlay over everything other than the task bar to apply a tint or tone to everything the user sees on screen.
Please bare in mind I am an undergrad so have limited knowledge - hence why I am here.
I have also considered some methodology of talking to perhaps a graphics driver to make these colour changes but I am unsure of the way forward?
Is my initial idea of redirecting user input feasible? Or should I go down the route of drivers and windows color profiles etc?
So with regard to the gammaramp idea I tried out he following but not performing as expected ...
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Runtime.InteropServices;
using System.Drawing;
namespace GammaRAMP
{
public class Program
{
[DllImport("user32.dll")]
public static extern IntPtr GetDC(IntPtr hWnd);
[DllImport("gdi32.dll")]
public static extern bool SetDeviceGammaRamp(IntPtr hDC, ref RAMP lpRamp);
[DllImport("gdi32.dll")]
public static extern int GetDeviceGammaRamp(IntPtr hDC, ref RAMP lpRamp);
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
public struct RAMP
{
[ MarshalAs(UnmanagedType.ByValArray, SizeConst=256)]
public UInt16[] Red;
[ MarshalAs(UnmanagedType.ByValArray, SizeConst=256)]
public UInt16[] Green;
[ MarshalAs(UnmanagedType.ByValArray, SizeConst=256)]
public UInt16[] Blue;
}
public static void SetGamma(int gamma)
{
if (gamma <= 256 && gamma >= 1)
{
RAMP ramp = new RAMP();
ramp.Red = new ushort[256];
ramp.Green = new ushort[256];
ramp.Blue = new ushort[256];
for( int i=1; i<256; i++ )
{
int iArrayValue = i * (gamma + 128);
if (iArrayValue > 65535) // I assume this is a max value.
iArrayValue = 65535;
// So here I purposfully set red to max all the time expecting
// a lot of extra red but hardly any change occurs?
//ramp.Red[i] = 65535;
// However if I do this:
ramp.Red[i] = (ushort)iArrayValue;
// I get VERY noticable changes?
ramp.Blue[i] = ramp.Green[i] = (ushort)iArrayValue;
}
SetDeviceGammaRamp(GetDC(IntPtr.Zero), ref ramp);
}
}
public static void Main(string[] args)
{
string ent = "";
int g=0;
// A RAMP struct to store initial values.
RAMP r = new RAMP();
// Store initial values.
GetDeviceGammaRamp(GetDC(IntPtr.Zero),ref r);
while (ent != "EXIT")
{
Console.WriteLine("Enter new Gamma (or 'EXIT' to quit):");
ent = Console.ReadLine();
try
{
g=int.Parse(ent);
SetGamma(g);
}
catch
{
//Here only to catch errors where input is not a number (EXIT, for example, is a string)
}
}
// Reset any RAMP changes.
SetDeviceGammaRamp(GetDC(IntPtr.Zero), ref r);
Console.ReadLine();
}
}
}
Looking forward to responses and thanks very much for your time!
Ok so I played around with the above code and found that if you change a given red / green / blue ramp member by a factor of the gamma value passed in to public static void SetGamma(int gamma)
and set values you do not want to change as iArrayValue = i * 128;
you get the desired effect. All that remains to be done now is map specific rgb scalars to slider controls or maybe a colordialog. Thanks to everyone for your responses!
回答1:
I am not sure if you are wanting to do this with WinForms or WPF. With WPF you can do something like the following:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525" Background="Transparent"
AllowsTransparency="True" WindowStyle="None" Topmost="True" WindowState="Maximized">
</Window>
This will give you a completely transparent window, and all clicks etc will go to the underlying screen. You can then put controls on the window, and they will be seen and respond to clicks. Then you could, for example, have Opacity="0.2" if you want those controls to be partly transparent.
Look here for a WinForms solution.
Edit: To just have a colored tint over the screen that always stays on top and has no mouse or keyboard effect, use...
this.TopMost = true;
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.WindowState = FormWindowState.Maximized;
this.Opacity = 0.5;
int initialStyle = GetWindowLong(this.Handle, -20);
SetWindowLong(this.Handle, -20, initialStyle | 0x20);
回答2:
You might try looking at something like :
http://www.pinvoke.net/default.aspx/gdi32.setdevicegammaramp
http://www.pinvoke.net/default.aspx/gdi32/getdevicegammaramp.html
These are easily accessible gamma modifiers - you should be able to put together a quick application to see how they work. It's not exactly like an overlay but it will allow you to modify the entire screen at a low level.
来源:https://stackoverflow.com/questions/11198353/redirect-any-user-input-to-a-separate-underlying-program