I don't think that be warned if another process changed the cursor position by code and that is not the user that moved it is possible unless some WinAPI to move it by code has an event that can be registered.
I tested that if a code change the cursor position, no MouseMove is raised on a WinForm or by using a global hook.
So using GetLastInputInfo does not work and it seems that you can't detect if a process has changed the move position.
That said, you can use a timer with this MouseMove global hook.
https://www.codeproject.com/Articles/7294/Processing-Global-Mouse-and-Keyboard-Hooks-in-C
On app start you will save the mouse position as previous.
You start a timer having interval 100ms for example.
On MouseMove you will update this previous position and set a conditional variable to true.
On the timer tick, you will get the current position and compare it to previous and the conditional variable: if it is not the same, it is not the user that moves.
It is heavy but that works.
If the user moves the mouse same time a process, you will only get that it is the user that moves.
Using a WinForms Timer
public partial class FormTest : Form
{
Point PreviousMousePosition;
bool UserMovedMouse;
public FormTest()
{
InitializeComponent();
PreviousMousePosition = Cursor.Position;
TimerCheckMouseMove.Start();
TimerMoveMouse.Start();
HookManager.MouseMove += HookManager_MouseMove;
}
private void HookManager_MouseMove(object sender, MouseEventArgs e)
{
PreviousMousePosition = Cursor.Position;
UserMovedMouse = true;
}
private void TimerCheckMouseMove_Tick(object sender, EventArgs e)
{
TimerCheckMouseMove.Enabled = false;
try
{
var pos = Cursor.Position;
if ( !UserMovedMouse && pos != PreviousMousePosition)
MessageBox.Show("Mouse moved by a process");
PreviousMousePosition = Cursor.Position;
UserMovedMouse = false;
}
finally
{
TimerCheckMouseMove.Enabled = true;
}
}
private void TimerMoveMouse_Tick(object sender, EventArgs e)
{
Cursor.Position = new Point(100, 100);
}
}
Using a threaded timer
System.Threading.Timer TimerCheckMouseMove;
TimerCheckMouseMove = new System.Threading.Timer(TimerCheckMouseMove_Tick, null, 0, 100);
private bool TimerCheckMouseMoveMutex;
private void TimerCheckMouseMove_Tick(object state)
{
if ( TimerCheckMouseMoveMutex ) return;
TimerCheckMouseMoveMutex = true;
try
{
var pos = Cursor.Position;
if ( !UserMovedMouse && pos != PreviousMousePosition)
MessageBox.Show("Mouse moved by a process");
PreviousMousePosition = Cursor.Position;
UserMovedMouse = false;
}
finally
{
TimerCheckMouseMoveMutex = false;
}
}