I have a Windows store app that draws an image under the system's cursor. I capture all the cursor movements using:
var window = Window.Current .Content;
window .AddHandler(PointerMovedEvent, new PointerEventHandler (window_PointerMoved), true);
And this is working fine if I use my mouse to move the cursor.
However, I have another application - a desktop application -, that changes the position of the system's cursor. I'm using this method to set the position of the cursor programatically:
[DllImport("user32")]
private static extern int SetCursorPos(int x, int y);
However, when the cursor is moved programatically, the PointerMovedEvent on the store app does not fire!
Does anyone know how I can solve this problem?
I thought I could not use System.Runtime .InteropServices on Windows store apps, but it is allowed. Therefore, I've managed to achieve the desired behavior by having a thread that actively checks the cursor's current position using:
[ DllImport("user32.dll" )]
private static extern bool GetCursorPos(ref Win32Point pt);
It's not the most elegant solution, but it works!
Related
private void MoveCursor()
{
// Set the Current cursor, move the cursor's Position,
// and set its clipping rectangle to the form.
this.Cursor = new Cursor(Cursor.Current.Handle);
Cursor.Position = new Point(Cursor.Position.X - 50, Cursor.Position.Y - 50);
Cursor.Clip = new Rectangle(this.Location, this.Size);
}
I am using the above code to Restrict the movement but still I am able to move the mouse outside the form?
Can I restrict the mouse movement to a specified area in the form? Please advise...
Updated answer:
ClipCursor is the API function you require. You will need to supply screen-based coordinates.
BOOL WINAPI ClipCursor(RECT *lpRect);
take a look at this link for the Win32 API code, and this one for pinvoke from C#.
There is pair of Win32 API functions called SetCapture/ReleaseCapture that will restrict the mouse to a certain window bounds.
You will need to use PInvoke to use them, but this will work.
[DllImport("user32.dll")]
static extern IntPtr SetCapture(long hWnd);
SetCapture(Control.Handle);
One thing to bear in mind, is that if used incorrectly, it's possible that the user will not be able to click the [X] to shut down your application because the mouse will not be able to get to the title bar.
I'm using the Windows API method MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST) as part of some overridden maximize functionality in my WPF application. One issue we've had with it is that the "nearest" window does not updating during drag operations (triggered by DragMove on the Window instance).
Suppose you drag the window between two screens of differing resolution and trigger the Aero Snap functionality on the second screen. This triggers a query on the window size (message WM_GETMINMAXINFO). Using MonitorFromWindow in this scenario returns the wrong screen. It's as if the data used by MONITOR_DEFAULTTONEAREST is not updated until the drag operation completes, and that doesn't complete until the resize function triggered by the Aero Snap completes. Is there some way to flush the current window position before answering the WM_GETMINMAXINFO query?
Since snapping is based on the mouse position, a solution to the problem would be to use GetCursorPos to get the current mouse position. Then pass that point to MonitorFromPoint to obtain the handle for the monitor that currently contains the mouse pointer.
A simple example:
[DllImport("User32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetCursorPos(ref Point lpPoint);
public const int MONITOR_DEFAULTTONEAREST = 2;
[DllImport("User32.dll")]
public static extern IntPtr MonitorFromPoint(Point pt, UInt32 dwFlags);
public IntPtr GetCurrentMonitor()
{
Point p = new Point(0,0);
if (!GetCursorPos(ref p))
{
// Decide what to do here.
}
IntPtr hMonitor = MonitorFromPoint(p, MONITOR_DEFAULTTONEAREST);
// validate hMonitor
return hMonitor;
}
I require the ability to get the height of the on screen keyboard for Windows 8.1, "TabTip.exe." So far I've managed to open and close it at will, but now I also need to get it's height so I can compensate for it in my app. I have TextBox controls near the very bottom of the Window that get covered up by the keyboard.
All attempts to utilize the Win API call "GetWindowRect" have failed.
Code placed just inside the beginning of the class definition:
private const string OnScreenKeyboardName = "TabTip";
DllImport("user32.dll")]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetWindowRect(HandleRef hWnd, ref RECT lpRect);
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int Left; // x position of upper-left corner
public int Top; // y position of upper-left corner
public int Right; // x position of lower-right corner
public int Bottom; // y position of lower-right corner
}
code placed inside one of the event handlers in the Window:
RECT rct = new RECT();
if (Process.GetProcessesByName(OnScreenKeyboardName).Length > 0)
{
Process[] Processes = Process.GetProcessesByName(OnScreenKeyboardName);
foreach (Process pOnScreenKeyboard in Processes)
{
if (!GetWindowRect(new HandleRef(this, pOnScreenKeyboard.Handle), ref rct))
{
MessageBox.Show("ERROR");
return;
}
MessageBox.Show(rct.ToString());
}
}
Consistent with most examples, I had originally been using a call to "FindWindow" to get the handle for the TabTip.exe Window. That seemed to work great for a while, but it stopped working all of a sudden within the last few days, and so I switched to "Process.FindByName..."
My test case involves placing the code (second part) above into the Window's "MouseMove" event handler. Then I make sure the on screen keyboard is showing, and then I move the mouse. This causes the event to fire and then it always shows the "ERROR" MessageBox, which indicates that "GetWindowRect" returns false (or has some kind of error?
I've spent a lot of time on Google searches, p/invoke, etc. This is frustrating because there seem to be very few examples of how to properly do this. And it seems there is some new thing called a HandleRef (am I using that properly? - there are basically no examples for that either!!!)
I really need to get this working. Can someone please tell me where I'm going wrong? Thanks!
You are passing the process handle (pOnScreenKeyboard.Handle) to GetWindowRect where GetWindowRect expects a window handle (HWND). Finding the process isn't sufficient - a process can create many windows, so you need to find the onscreen keyboard's window handle. You can try using pOnScreenKeyboard.MainWindowHandle, but from this post, you might find that it's null. You said you had a previous solution using FindWindow. I would go back to that and figure out why it stopped working.
BACKGROUND:
I'm trying to create a "mouse hiding" application that hides the user's mouse from the screen after a set amount of time.
I've tried many things, and using SetCursor only hides the mouse from the current application, mine must be able to sit in the tray (for example) and still function.
I think I've found a solution with SetSystemCursor except for one problem.
MY PROBLEM:
I need to be able to capture any kind of mouse cursor, and replace the exact same kind of mouse cursor.
When replacing the mouse, I need to provide the id of the type of mouse I'd like to replace with the mouse referenced by the handle, but none of the functions I'm using provide me with the copied mouse's id (or type).
MY QUESTION:
Would it be sufficient to continue doing it this way, but move the mouse to 0,0 first, hiding it, and moving it back to it's original location upon un-hiding? (Unhiding is accomplished by simply moving the mouse)
Would a mouse at 0,0 always be an OCR_NORMAL mouse? (The standard arrow.)
If not, how could the mouse type/id be found to enable me to replace the proper mouse with the proper handle?
SOURCE:
[DllImport("user32.dll")]
public static extern IntPtr LoadCursorFromFile(string lpFileName);
[DllImport("user32.dll")]
public static extern bool SetSystemCursor(IntPtr hcur, uint id);
[DllImport("user32.dll")]
static extern bool GetCursorInfo(out CURSORINFO pci);
[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
public Int32 x;
public Int32 y;
}
[StructLayout(LayoutKind.Sequential)]
struct CURSORINFO
{
public Int32 cbSize; // Specifies the size, in bytes, of the structure.
// The caller must set this to Marshal.SizeOf(typeof(CURSORINFO)).
public Int32 flags; // Specifies the cursor state. This parameter can be one of the following values:
// 0 The cursor is hidden.
// CURSOR_SHOWING The cursor is showing.
public IntPtr hCursor; // Handle to the cursor.
public POINT ptScreenPos; // A POINT structure that receives the screen coordinates of the cursor.
}
private POINT cursorPosition;
private IntPtr cursorHandle;
private bool mouseVisible = false;
private const uint OCR_NORMAL = 32512;
//Get the current mouse, so we can replace it once we want to show the mouse again.
CURSORINFO pci;
pci.cbSize = Marshal.SizeOf(typeof(CURSORINFO));
GetCursorInfo(out pci);
cursorPosition = pci.ptScreenPos;
cursorHandle = CopyIcon(pci.hCursor);
//Overwrite the current normal cursor with a blank cursor to "hide" it.
IntPtr cursor = LoadCursorFromFile(#"./Resources/Cursors/blank.cur");
SetSystemCursor(cursor, OCR_NORMAL);
mouseVisible = false;
//PROCESSING...
//Show the mouse with the mouse handle we copied earlier.
bool retval = SetSystemCursor(cursorHandle, OCR_NORMAL);
mouseVisible = true;
One application can't affect another applications cursor. You'd have to write a mouse driver of some sort in order to do this.
I found a good workaround for hiding system cursor temporarily that doesn't involve screwing around with setsystemcursor().
SetSystemCursor() is dangerous, because if the app crashes or otherwise throws a bug, the cursor will be changed permanently until the next reboot.
Instead, I implemented a transparent window over the whole desktop, and that window hides the cursor when needed. The method to use is ShowCursor from Win32.
The transparent window can be something like this:
http://www.codeproject.com/Articles/12597/OSD-window-with-animation-effect-in-C
[DllImport("user32.dll")]
static extern int ShowCursor(bool bShow);
ShowCursor(false);
I'm working on my own software to operate the mouse on my computer using C# and the kinect SDK. I really want to try using it to play a game like Red Alert, or some sort of RTS, or even just for general navigation.
The problem that I've found is that when using a program with a different mouse, like red alert or going into a virtual machine where mouse integration isn't supported, the program will not pick up on the calls that the C# program is making to the System.Windows.Forms.Cursor calls, let alone the mouse_event calls. I'm new to interfacing with windows and what is happening here, can someone explain/pose a solution?
--UPDATE--
As an update, I'm still not entirely sure what's going on, but I seem to have found a workaround for red alert in particular;
Since red alert is a fairly low graphics program, it is trivial to run it within a virtual machine specifically for me, vmware workstation with an XP client. If you use the mouse_event code it works well, HOWEVER, something that I struggled with was finding the correct code to represent mouse movement. It would seem that the MOVE flag moves the mouse relatively, which I didn't want, and the absolute tag didn't move the mouse at all. It is, in fact, the OR of them that produces absolute movement on the screen, so my code for mouse movement and clicking emulation ended up looking like this:
mouse_event((int)0x00000002, cursor.X, cursor.Y, 0, 0);
for clicking and
mouse_event((int)(0x00000001 | 0x00008000), x, y, 0 0);
for mouse movement, where x and y are the new coordinates out of 65535 (the absolute range). Is it perfect? Nah. But it works for now. I think there's something to do with the way windows ignores certain programs when it runs ra, maybe because of compatibility mode? I don't have another game to test it with right now, but I'll post results with a non-compatibility mode in the future.
Pete
(It wouldn't let me post as an answer for another two hours and I have to sleep to catch a flight in the morning!)
You will have to do some low level windows messages to get this to work properly. Games using DirectX like Red Alert will not look at the System.Windows.Forms.Cursor at all. You will need to interface with the Windows User32.dll to send the appropriate messages to windows so it can route them appropriately to the other applications.
Here is some code to get you started looking in to sending messages via the User32 DLL in C#:
[DllImport("USER32.DLL")]
public static extern IntPtr FindWindow(string lpClassName,
string lpWindowName);
// Activate an application window.
[DllImport("USER32.DLL")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern int SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
I hope this gets you started, but I don't have the time to go through each mouse message, what the wParam and lParam are, and what the Msg should be for each. I'm sure if you search around you can find the specific messages to send for each event such as mouse move, left click and right click.
Good luck.