// rmtctrl.c
// Author: A.Fombaron / I-Maginer
// Version: v1.00 - SVoyager v5.01
// Date: 070925


#define _WIN32_WINNT 0x0501


#include <Windows.h>
#include <Winuser.h>

#include "x/Version.h"
#include "x/scolplugin.h"

#include "objects/rmtctrl.h"



// *****************************************************************************
// _RMTCTRL_MouseMove
// *****************************************************************************
int GR_RMTCTRL_MouseMove(mmachine m)
{
	int dx, dy, mode;
	int ret;
	
	MOUSEINPUT mi;
	INPUT pInputs[1];
	
	int originalSpeed;
	int neutralSpeed = 10;
	int data[3];
	int originalAcceleration;
	
	RECT r;
	
	mode = MMpull(m)>>1;
	if (mode != RMTCTRL_ABSOLUTEMOVE)
		mode = RMTCTRL_RELATIVEMOVE;		// Relative Move is default mode
	
	dy = MMpull(m)>>1;
	dx = MMpull(m)>>1;

	if (mode == RMTCTRL_RELATIVEMOVE)
	{
		//Saving current mouse speed
		SystemParametersInfo(SPI_GETMOUSESPEED, 0, &originalSpeed, 0);
		//Setting neutral mouse speed: 10
		SystemParametersInfo(SPI_SETMOUSESPEED, 0, &neutralSpeed, 0);
		//Retrieving mouse thresholds and acceleration
		SystemParametersInfo(SPI_GETMOUSE, 0, data, 0);
		//Saving original acceleration
		originalAcceleration = data[2];
		//Setting neutral acceleration
		data[2] = 0;
		SystemParametersInfo(SPI_SETMOUSE, 0, data, 0);
		//Filling MOUSEINPUT struct
		mi.dx = dx;
		mi.dy = dy;
		mi.mouseData = 0;
		mi.dwFlags = MOUSEEVENTF_MOVE;
		mi.time = 0;
		mi.dwExtraInfo = (ULONG_PTR)NULL;
	}
	else		// RMTCTRL_ABSOLUTEMOVE
	{
		//Retrieving screen size
		GetWindowRect(GetDesktopWindow(), &r);
		//Filling MOUSEINPUT struct
		mi.dx = (dx * 65535) / (r.right - r.left);
		mi.dy = (dy * 65535) / (r.bottom - r.top);
		mi.mouseData = 0;
		mi.dwFlags = MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_MOVE;
		mi.time = 0;
		mi.dwExtraInfo = (ULONG_PTR)NULL;
	}
	
	pInputs[0].type = INPUT_MOUSE;
	pInputs[0].mi = mi;
	
	SendInput(1, pInputs, sizeof(INPUT));
	
	if (mode == RMTCTRL_RELATIVEMOVE)
	{
		//Restoring original acceleration
		data[2] = originalAcceleration;
		SystemParametersInfo(SPI_SETMOUSE, 0, data, 0);
		//Restoring original mouse speed
		SystemParametersInfo(SPI_SETMOUSESPEED, 0, &originalSpeed, 0);	
	}
	
	ret = MMpush(m, 0);
	
	return ret;
}


// *****************************************************************************
// _RMTCTRL_MouseClick
// *****************************************************************************
int GR_RMTCTRL_HandleMouseClick(int but)
{
	MOUSEINPUT mi;
	INPUT pInputs[1];

	//MMechostr (0, "GR_RMTCTRL_HandleMouseClick\n");

	mi.dx = 0;
	mi.dy = 0;
	mi.mouseData = 0;
	if (but == MB_LBUTTON)
		mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
	else if (but == MB_RBUTTON)
		mi.dwFlags = MOUSEEVENTF_RIGHTDOWN;
	else
		mi.dwFlags = MOUSEEVENTF_MIDDLEDOWN;
	mi.time = 0;
	mi.dwExtraInfo = (ULONG_PTR)NULL;
	
	pInputs[0].type = INPUT_MOUSE;
	pInputs[0].mi = mi;
	
	SendInput(1, pInputs, sizeof(INPUT));
	
	return 0;
}


int GR_RMTCTRL_MouseClick(mmachine m)
{
	int but;
	int ret;
	
	//MMechostr(0, "GR_RMTCTRL_MouseClick\n");
	
	but = MMpull(m)>>1;
  if ((but == NIL) || ((but != MB_LBUTTON) && (but != MB_RBUTTON) && (but != MB_MBUTTON)))
  {
    MMechostr (0, "GR_RMTCTRL_MouseClick: bad parameter\n");
    return MMpush(m,NIL);
  }	
	
	GR_RMTCTRL_HandleMouseClick(but);
	
	ret = MMpush(m, 0);
	
	return ret;
}


// *****************************************************************************
// _RMTCTRL_MouseUnClick
// *****************************************************************************
int GR_RMTCTRL_HandleMouseUnClick(int but)
{
	MOUSEINPUT mi;
	INPUT pInputs[1];

	//MMechostr (0, "GR_RMTCTRL_HandleMouseUnClick\n");

	mi.dx = 0;
	mi.dy = 0;
	mi.mouseData = 0;
	if (but == MB_LBUTTON)
		mi.dwFlags = MOUSEEVENTF_LEFTUP;
	else if (but == MB_RBUTTON)
		mi.dwFlags = MOUSEEVENTF_RIGHTUP;
	else
		mi.dwFlags = MOUSEEVENTF_MIDDLEUP;
	mi.time = 0;
	mi.dwExtraInfo = (ULONG_PTR)NULL;
	
	pInputs[0].type = INPUT_MOUSE;
	pInputs[0].mi = mi;
	
	SendInput(1, pInputs, sizeof(INPUT));
	
	return 0;
}


int GR_RMTCTRL_MouseUnClick(mmachine m)
{
	int but;
	int ret;
	
	//MMechostr(0, "GR_RMTCTRL_MouseUnClick\n");

	but = MMpull(m)>>1;
  if ((but == NIL) || ((but != MB_LBUTTON) && (but != MB_RBUTTON) && (but != MB_MBUTTON)))
  {
    MMechostr (1,"GR_RMTCTRL_MouseUnClick: bad parameter\n");
    return MMpush(m,NIL);
  }
	
	GR_RMTCTRL_HandleMouseUnClick(but);

	ret = MMpush(m, 0);
	
	return ret;	
}


// *****************************************************************************
// _RMTCTRL_MouseDClick
// *****************************************************************************
int GR_RMTCTRL_MouseDClick(mmachine m)
{
	int but;
	int ret;
	
	//MMechostr(0, "GR_RMTCTRL_MouseDClick\n");

	but = MMpull(m)>>1;
  if ((but == NIL) || ((but != MB_LBUTTON) && (but != MB_RBUTTON) && (but != MB_MBUTTON)))
  {
    MMechostr (1,"GR_RMTCTRL_MouseDClick: bad parameter\n");
    return MMpush(m,NIL);
  }
	
	GR_RMTCTRL_HandleMouseClick(but);
	GR_RMTCTRL_HandleMouseUnClick(but);
	GR_RMTCTRL_HandleMouseClick(but);

	ret = MMpush(m, 0);
	
	return ret;		
}


// *****************************************************************************
// _RMTCTRL_KeybdKeyDown
// *****************************************************************************
int GR_RMTCTRL_KeybdKeyDown(mmachine m)
{
	int chr;
	int ret;
	
	//MMechostr(0, "GR_RMTCTRL_KeybdKeyDown\n");
	
	KEYBDINPUT ki;
	INPUT pInputs[1];
	
	chr = MMpull(m)>>1;
	if ((chr < 0) || (chr > 255))
	{
    MMechostr (1,"GR_RMTCTRL_KeybdKeyDown: bad parameter\n");
    return MMpush(m,NIL);
  }
	
	ki.wVk = 0;
	ki.wScan = chr;
	ki.dwFlags = KEYEVENTF_UNICODE;
	ki.time = 0;
	ki.dwExtraInfo = (ULONG_PTR)NULL;
	
	pInputs[0].type = INPUT_KEYBOARD;
	pInputs[0].ki = ki;

	SendInput(1, pInputs,sizeof(INPUT));

	ret = MMpush(m, 0);
	
	return ret;
}