How do I detect if software keyboard is visible - c#

Is there a way in Windows 8 to detect if the virtual keyboard is visible on screen? I use tabtip.exe

After a brief search on google , I could do something that might help you. The code below exposes a function of the windows API and uses it to know the current state of a given process. Understand state as Minimized , Maximized, Hidden or Normal.
The ProccesIsRunningNotMinimized method returns true if the program is running and is not minimized or hidden.
I do not know if this will help you, but it's a start .
public bool ProccesIsRunningNotMinimized(string exeName)
{
Process[] processes = Process.GetProcesses();
foreach (Process p in processes)
{
if (p.ProcessName.ToLower() == exeName.ToLower())
{
var placement = GetPlacement(p.MainWindowHandle);
if (placement.showCmd.ToString().ToLower() != "minimized" && placement.showCmd.ToString().ToLower() != "hide")
return true;
}
}
return false;
}
// Get the placement of the target process
private static WINDOWPLACEMENT GetPlacement(IntPtr hwnd)
{
WINDOWPLACEMENT placement = new WINDOWPLACEMENT();
placement.length = Marshal.SizeOf(placement);
GetWindowPlacement(hwnd, ref placement);
return placement;
}
//Exposes the function of Windows API
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool GetWindowPlacement(
IntPtr hWnd, ref WINDOWPLACEMENT lpwndpl);
//Create a struct to receive the data
[Serializable]
[StructLayout(LayoutKind.Sequential)]
internal struct WINDOWPLACEMENT
{
public int length;
public int flags;
public ShowWindowCommands showCmd;
public System.Drawing.Point ptMinPosition;
public System.Drawing.Point ptMaxPosition;
public System.Drawing.Rectangle rcNormalPosition;
}
internal enum ShowWindowCommands : int
{
Hide = 0,
Normal = 1,
Minimized = 2,
Maximized = 3,
}
To check if the VK is running and visible in the screen, do:
if (this.ProccesIsRunningNotMinimized("tabtip"))
{
// do something
}

This code works fine on Windows 7. On windows 8 will not work.

Related

GetClientRect is not giving the correct Rectangle

I am trying to create an overlay form that overlays the contents of an external window (excluding the borders etc). I believe that GetClientRect is the correct winapi for that purpose however it does not seem to be working.
I created an example where I load up a form as a black box and display it over an open Notepad.
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace WinFormsApp2
{
public partial class Form1 : Form
{
private Process? targetProc = null;
public struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
[DllImport("user32.dll", SetLastError = true)]
public static extern bool GetClientRect(IntPtr hwnd, out RECT lpRect);
[DllImport("user32.dll")]
public static extern bool ClientToScreen(IntPtr hWnd, ref Point lpPoint);
public static Rectangle GetWindowRectangle(IntPtr hWnd)
{
Point point = new Point();
GetClientRect(hWnd, out RECT rect);
ClientToScreen(hWnd, ref point);
return new Rectangle(point.X, point.Y, rect.Right, rect.Bottom);
}
private IntPtr notepadhWnd;
public Form1()
{
InitializeComponent();
this.FormBorderStyle = FormBorderStyle.None;
this.WindowState = FormWindowState.Normal;
this.BackColor = Color.Black;
StartPosition = FormStartPosition.Manual;
targetProc = Process.GetProcessesByName("notepad").FirstOrDefault(p => p != null);
try
{
if (targetProc != null)
{
notepadhWnd = targetProc.MainWindowHandle;
if (notepadhWnd != IntPtr.Zero)
{
Rectangle rect = GetWindowRectangle(notepadhWnd);
Location = new Point(rect.Left, rect.Top);
Size = new Size(rect.Width, rect.Height);
}
}
}
catch (Exception ex)
{
// Log and message or
throw;
}
}
}
}
The output of this is:
I expected the output to be:
From all my searches I believe that the GetClientRect API should only return the client area but not sure what I am missing.
Grab coffee, this will be a long answer.
First, take a look at the image of notepad below. From the wording of your question it sounds like you are expecting GetClientRect to return the area marked in red. GetClientRect returns the dimensions of the window handle you provide but without the borders or scroll bars. In other words, it will give you the interior area of the green rectangle.
There is no single "client window" - in the screenshot below the menu bar is a child window. So is the status bar at the bottom of the screen. So is the editor space which seems to be what you are interested in.
So, how do you get the hWnd of the editor space? I'm not aware of any answer to that question that doesn't rely on the dark magic. It is all fraught with peril... do you iterate through all the child windows and pick the biggest? Pick a point in the dead center of the window and use API calls to find the hWnd at that location? No matter what you do, it will not be an exact science. For purposes of this question, though, I'll show one approach.
Every window has a Class name associated with it. In the image below I'm using a tool called Spy++ to reveal information about the various windows. As you can see, the window that makes up the editor space has a class name of "RichEditD2DPT"
I want to stress again how brittle this solution is. You could have more than one child window of the given class. The application developer could change to a different control with a different class name without warning. Nevertheless, below is code to enumerate through the child windows until the desired class is found. After that, I'm simply passing that hWnd into the code you already had and it seems to work.
public partial class Form1 : Form
{
private readonly StringBuilder _buffer = new StringBuilder(1024);
private IntPtr _notepadMainhWnd;
private IntPtr _notepadEditorhWnd;
public struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetClientRect(IntPtr hwnd, out RECT lpRect);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool ClientToScreen(IntPtr hWnd, ref Point lpPoint);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool EnumChildWindows(IntPtr hwnd, WindowEnumProc func, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
private delegate bool WindowEnumProc(IntPtr hwnd, IntPtr lparam);
public static Rectangle GetWindowRectangle(IntPtr hWnd)
{
Point point = new Point();
GetClientRect(hWnd, out RECT rect);
bool ret = ClientToScreen(hWnd, ref point);
Debug.WriteLine($"{point.X},{point.Y}");
return new Rectangle(point.X, point.Y, rect.Right - rect.Left, rect.Bottom - rect.Top);
}
public Form1()
{
InitializeComponent();
this.FormBorderStyle = FormBorderStyle.None;
this.WindowState = FormWindowState.Normal;
this.BackColor = Color.Black;
StartPosition = FormStartPosition.Manual;
var targetProcess = Process.GetProcessesByName("notepad").FirstOrDefault(p => p != null);
if (targetProcess != null)
{
// Get the main application window
_notepadMainhWnd = targetProcess.MainWindowHandle;
if (_notepadMainhWnd != IntPtr.Zero)
{
// Looks for child windows having the class name "RichEditD2DPT"
EnumChildWindows(_notepadMainhWnd, callback, IntPtr.Zero);
if (_notepadEditorhWnd != IntPtr.Zero)
{
Rectangle rect = GetWindowRectangle(_notepadEditorhWnd);
Location = new Point(rect.Left, rect.Top);
Size = new Size(rect.Width, rect.Height);
}
}
}
}
private bool callback(IntPtr hWnd, IntPtr lParam)
{
if (GetClassName(hWnd, _buffer, _buffer.Capacity) != 0)
{
if (string.CompareOrdinal(_buffer.ToString(), "RichEditD2DPT") == 0)
{
_notepadEditorhWnd = hWnd;
return false;
}
}
return true;
}
}

Get window state of another process

How do I get the window state(maximized, minimized) of another process that's running?
I'd tried by using this:
Process[] procs = Process.GetProcesses();
foreach (Process proc in procs)
{
if (proc.ProcessName == "notepad")
{
MessageBox.Show(proc.StartInfo.WindowStyle.ToString());
}
}
But if process is Maximized or Minimized,it ever returns Normal.
How to fix this?
You’ll need to use Win32 through P/Invoke for checking the state of another window. Here is some sample code:
static void Main(string[] args)
{
Process[] procs = Process.GetProcesses();
foreach (Process proc in procs)
{
if (proc.ProcessName == "notepad")
{
var placement = GetPlacement(proc.MainWindowHandle);
MessageBox.Show(placement.showCmd.ToString());
}
}
}
private static WINDOWPLACEMENT GetPlacement(IntPtr hwnd)
{
WINDOWPLACEMENT placement = new WINDOWPLACEMENT();
placement.length = Marshal.SizeOf(placement);
GetWindowPlacement(hwnd, ref placement);
return placement;
}
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool GetWindowPlacement(
IntPtr hWnd, ref WINDOWPLACEMENT lpwndpl);
[Serializable]
[StructLayout(LayoutKind.Sequential)]
internal struct WINDOWPLACEMENT
{
public int length;
public int flags;
public ShowWindowCommands showCmd;
public System.Drawing.Point ptMinPosition;
public System.Drawing.Point ptMaxPosition;
public System.Drawing.Rectangle rcNormalPosition;
}
internal enum ShowWindowCommands : int
{
Hide = 0,
Normal = 1,
Minimized = 2,
Maximized = 3,
}
Definition courtesy of pinvoke.net.
You're using proc.StartInfo, which is incorrect. It does not reflect the runtime window style of the target process. It is just startup info you can set and can then be passed on to the process when it starts up.
The C# signature is:
[DllImport("user32.dll", SetLastError=true)]
static extern int GetWindowLong(IntPtr hWnd, int nIndex);
You need to use p/invoke and call GetWindowLong(hWnd, GWL_STYLE), and pass proc.MainWindowHandle as the hWnd parameter.
You can check if the window is minimized/maximized by doing something like:
int style = GetWindowLong(proc.MainWindowHandle, GWL_STYLE);
if((style & WS_MAXIMIZE) == WS_MAXIMIZE)
{
//It's maximized
}
else if((style & WS_MINIMIZE) == WS_MINIMIZE)
{
//It's minimized
}
NOTE: The values for the flags (WS_MINIMIZE, etc), can be found in this page: http://www.pinvoke.net/default.aspx/user32.getwindowlong
Thanks to Kakashi for pointing our the error in testing the result.
In Windows PowerShell you can do this by following code:
Add-Type -AssemblyName UIAutomationClient
$prList = Get-Process -Name "<ProcessNamesWhichHaveWindow>"
$prList | % {
try {
$ae = [System.Windows.Automation.AutomationElement]::FromHandle($_.MainWindowHandle)
$wp = $ae.GetCurrentPattern([System.Windows.Automation.WindowPatternIdentifiers]::Pattern)
echo "Window title: $($_.MainWindowTitle)"
echo "Window visual state: $($wp.Current.WindowVisualState)"
}
catch { }
}
Two Window States (maximized / minimized) can be gotten by calling WinAPI IsIconic() / IsZoomed() like this:
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool IsIconic(IntPtr hWnd);
[DllImport("user32.dll")]
public static extern bool ShowWindowAsync(IntPtr hWnd, ShowWindowCommands cmdShow);
if (IsIconic(_helpWindow.MainWindowHandle)) {
ShowWindowAsync(_helpWindow.MainWindowHandle, ShowWindowCommands.SW_RESTORE);
}
Definition of enum ShowWindowCommands and other functions were taken from www.PInvoke.net

How to measure system idle time in C#, excluding when watching movies, etc?

I am looking for a program that measures system idle time on Windows. I have found many codes that do this. For example,
http://www.codeproject.com/KB/cs/GetIdleTimeWithCS.aspx
However, I also want to take into account user watching movies, videos, etc. That time no input is given, but still the system is not idle.
Is there anyway to do this?
This function detects if a process is running in fullscreen in forground, and returns name of the process if found so:
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", SetLastError = true)]
static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
[DllImport("user32.dll")]
private static extern Int32 GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
[DllImport("user32.dll")]
private static extern bool
GetWindowPlacement(IntPtr hWnd, ref WINDOWPLACEMENT lpwndpl);
private struct POINTAPI
{
public int x;
public int y;
}
private struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}
private struct WINDOWPLACEMENT
{
public int length;
public int flags;
public int showCmd;
public POINTAPI ptMinPosition;
public POINTAPI ptMaxPosition;
public RECT rcNormalPosition;
}
public string FullscreenProcess()
{
IntPtr foreWindow = GetForegroundWindow();
// get the placement
WINDOWPLACEMENT forePlacement = new WINDOWPLACEMENT();
forePlacement.length = Marshal.SizeOf(forePlacement);
GetWindowPlacement(foreWindow, ref forePlacement);
if (forePlacement.rcNormalPosition.top == 0 && forePlacement.rcNormalPosition.left == 0 && forePlacement.rcNormalPosition.right == Screen.PrimaryScreen.Bounds.Width && forePlacement.rcNormalPosition.bottom == Screen.PrimaryScreen.Bounds.Height)
{
uint processID;
GetWindowThreadProcessId(foreWindow, out processID);
Process proc = Process.GetProcessById((int)processID);
return proc.ProcessName;
}
return null;
}
After this, we just need to match the returned process name with a set of popular media players or other processes.
Limitation is that we have assumed user plays in fullscreen.
You can get the idle time for computer using this, however your problem is how to know weather a movie is playing, you can check the processes that is currently running on the computer System.Diagnostics.Process.GetProcesses(), and then check if one of them is a known movie player. However I don't think this will achieve what you locking for either, because even if you find out that for example a Gom player is running, you still don't know if it running a video or audio or just opened without any thing actually playing...
In case you watch videos in fullscreen:
You could use code like this do determine if there is an app running in fullscreen:
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", SetLastError = true)]
static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
[StructLayout(LayoutKind.Sequential)]
struct RECT
{
public int Left;
public int Top;
public int Width;
public int Height;
}
static bool IsBigWindowRunning()
{
foreach (Process proc in Process.GetProcesses())
{
RECT rect;
var success = GetWindowRect(proc.MainWindowHandle, out rect);
if(success && (r.Left + r.Width) >= Screen.PrimaryScreen.WorkingArea.Width)
{
return true;
}
}
return false;
}
I haven't tested it well and i would definetely play around with this line, add some limits:
if((r.Left + r.Width) >= Screen.PrimaryScreen.WorkingArea.Width)
Good luck!

Screen.AllScreen is not giving the correct monitor count

I am doing something like this in my program:
Int32 currentMonitorCount = Screen.AllScreens.Length;
if (currentMonitorCount < 2)
{
//Put app in single screen mode.
}
else
{
//Put app in dual screen mode.
}
It is VERY important my application recognizes how many monitors are currently connected.
However, after I plug/unplug the monitor a couple of times, Screen.AllScreens.Length always returns '2'.
My monitor knows it's not connected (it has entered 'power save' mode), and the control panel knows that it's not connected (it shows only one monitor).
So what am I missing? How do I figure out that there's only one monitor?
I had a look at the source (remember we can do that using the MS Symbol servers). AllScreens uses an unmanaged API to get the screens on the first access, then stores the result in a static variable for later use.
The consequence of this, is that if the number of monitors changes while your program is running; then Screen.AllScreens will not pick up the change.
The easiest way to get around this would probably be to call the unmanaged API directly.
(Or you could be evil, and use reflection to set the static screens field to null before asking. Don't do that).
Edit:
If you just need to know the count, check whether you can use System.Windows.Forms.SystemInformation.MonitorCount (as suggested in the comments) before going the P/Invoke route. This calls GetSystemMetrics directly, and it is probably correctly updated.
If you find you need to do it using P/Invoke, here is a complete example that demonstrates the usage of the unmanaged API from C#:
using System;
using System.Runtime.InteropServices;
class Program
{
public static void Main()
{
int monCount = 0;
Rect r = new Rect();
MonitorEnumProc callback = (IntPtr hDesktop, IntPtr hdc, ref Rect prect, int d) => ++monCount > 0;
if (EnumDisplayMonitors(IntPtr.Zero, IntPtr.Zero, callback, 0))
Console.WriteLine("You have {0} monitors", monCount);
else
Console.WriteLine("An error occured while enumerating monitors");
}
[DllImport("user32")]
private static extern bool EnumDisplayMonitors(IntPtr hdc, IntPtr lpRect, MonitorEnumProc callback, int dwData);
private delegate bool MonitorEnumProc(IntPtr hDesktop, IntPtr hdc, ref Rect pRect, int dwData);
[StructLayout(LayoutKind.Sequential)]
private struct Rect
{
public int left;
public int top;
public int right;
public int bottom;
}
}
Building on the previous reply by driis, this is how I handled it. I should note that the following code lives in my Program.cs file.
First the links to external resources and data structures:
[DllImport("user32")]
private static extern bool EnumDisplayMonitors(IntPtr hdc, IntPtr lpRect, MonitorEnumProc callback, int dwData);
private delegate bool MonitorEnumProc(IntPtr hDesktop, IntPtr hdc, ref Rect pRect, int dwData);
[StructLayout(LayoutKind.Sequential)]
private struct Rect
{
public int left;
public int top;
public int right;
public int bottom;
}
Now create a simple object to contain monitor information:
public class MonitorInfo
{
public bool IsPrimary = false;
public Rectangle Bounds = new Rectangle();
}
And a container to hold these objects:
public static List<MonitorInfo> ActualScreens = new List<MonitorInfo>();
and a method to refresh the container:
public static void RefreshActualScreens()
{
ActualScreens.Clear();
MonitorEnumProc callback = (IntPtr hDesktop, IntPtr hdc, ref Rect prect, int d) =>
{
ActualScreens.Add(new MonitorInfo()
{
Bounds = new Rectangle()
{
X = prect.left,
Y = prect.top,
Width = prect.right - prect.left,
Height = prect.bottom - prect.top,
},
IsPrimary = (prect.left == 0) && (prect.top == 0),
});
return true;
};
EnumDisplayMonitors(IntPtr.Zero, IntPtr.Zero, callback, 0);
}
Then later on a Form, If I wanted to detect that a display had been added or removed ...
private const int WM_DISPLAYCHANGE = 0x007e;
protected override void WndProc(ref Message message)
{
base.WndProc(ref message);
if (message.Msg == WM_DISPLAYCHANGE)
{
Program.RefreshActualScreens();
// do something really interesting here
}
}
Might be a few typos in there, but that is the basic idea. Good luck!
I had a look at the code of the Screen class ( in here )
See line 120, Screen.AllScreens uses the field Screen.screens for cache.
In my solution, I use the reflection api to change the Screen class.
I clear Screens.screens before calling Screen.AllScreens.
// Code for clearing private field
typeof(Screen).GetField("screens", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic).SetValue(null, null);

How to check whether another app is minimized or not?

How can I check whether another application is minimized or not? For instance in a loop like this:
foreach(Process p in processes)
{
// Does a process have a window?
// If so, is it minimized, normal, or maximized
}
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetWindowPlacement(IntPtr hWnd, ref WINDOWPLACEMENT lpwndpl);
private struct WINDOWPLACEMENT {
public int length;
public int flags;
public int showCmd;
public System.Drawing.Point ptMinPosition;
public System.Drawing.Point ptMaxPosition;
public System.Drawing.Rectangle rcNormalPosition;
}
if (p.MainWindowHandle != IntPtr.Zero) {
if (p.MainWindowTitle.Contains("Notepad")) {
WINDOWPLACEMENT placement = new WINDOWPLACEMENT();
GetWindowPlacement(p.MainWindowHandle, ref placement);
switch (placement.showCmd) {
case 1:
Console.WriteLine("Normal");
break;
case 2:
Console.WriteLine("Minimized");
break;
case 3:
Console.WriteLine("Maximized");
break;
}
}
}
There is no such thing as a minimized "application." The best alternative would be to check whether the application's Main Window is Iconic (minimized).
IsIconic can be used to check for the iconic state of a window. It will return 1 if a window is minimized. You can call this with process.MainWindowHandle.
If a window is minimized (in Windows Forms at least) both Location.X and Location.Y values are -32000
you can use isZoomed for maximized and isIconic for minimized by injecting user32 dll
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool IsIconic(IntPtr hWnd);
[DllImport("user32.dll")]
static extern bool IsZoomed(IntPtr hWnd);
Instead of enumerating Processes, you should use the native EnumWindows() function and then call IsIconic.

Categories

Resources