// ###########################################################################
// #
// # OSCAMouse - Implementation of OSCA Mouse Emulation
// # Copyright (C) 2009-2011 Tony Friery [DialTone]
// #
// # ALL RIGHTS RESERVED
// #
// ###########################################################################

#pragma hdrstop

#include <stdio.h>
#include "OSCAMouse.h"
#include "FormDiag.h"

//---------------------------------------------------------------------------

void __fastcall TOSCAMouse::MousePressed(byte which)
{
	this->fButtons |= 1 << which;

	if (this->fDataEnabled)
	{
		InjectDataPacket();
   }
}

void __fastcall TOSCAMouse::MouseReleased(byte which)
{
	this->fButtons &= ~(1 << which);

	if (this->fDataEnabled)
	{
		InjectDataPacket();
	}
}

void __fastcall TOSCAMouse::MouseMoved(int x, int y, DWORD wheel)
{
	this->fCurrentX = x;
	this->fCurrentY = y;

	if (this->fDataEnabled)
	{
		InjectDataPacket();
	}
}

void __fastcall TOSCAMouse::InjectDataPacket()
{
	int deltaX = this->fCurrentX - this->fLastX;
	int deltaY = this->fLastY - this->fCurrentY;
	this->fLastX = this->fCurrentX;
	this->fLastY = this->fCurrentY;

	// 	buttons in bits 0 (L), 3 (R), 6 (M)
	byte status = 0x08 | (this->fButtons & 0x01);
	status |= (this->fButtons & 0x08) >> 2;
	status |= (this->fButtons & 0x40) >> 4;

	if (deltaX < 0)
	{
		status |= 0x10;
	}

	if (deltaY < 0)
	{
		status |= 0x20;
	}

	this->PushByte(status);
	this->PushByte(deltaX & 0xff);
	this->PushByte(deltaY & 0xff);
}

///////////////////////////////////////////////////////////////////////
//
//  FUNCTION:  TOSCAMouse::GotByte
//
//  PURPOSE:	Notification from the Base PS2 Handler that a byte
//					has been clocked in from the host processor to the PS2
//					device, so this now needs to be acted upon
//
//  INPUTS:		byte					Byte data which was clocked in
//
//  OUTPUT:		void
//
///////////////////////////////////////////////////////////////////////
void __fastcall TOSCAMouse::GotByte(byte Value)
{
	// This means that the host has sent a byte of
	// data to the mouse device
	if (this->fActiveCommand)
	{
		if ((DiagForm) && (DiagForm->IsActive(DIAG_KBMOUSE)))
		{
			DiagForm->AddMessage(DIAG_KBMOUSE, UnicodeString::Format(
				L"Active Mouse Command (Unknown): %2.2x", OPENARRAY(TVarRec, (this->fActiveCommand)))
			);
		}
	}
	else
	{
		switch(Value)
		{
			case MOUSE_RESET:
				if ((DiagForm) && (DiagForm->IsActive(DIAG_KBMOUSE)))
				{
					DiagForm->AddMessage(DIAG_KBMOUSE, L"Mouse Command: RESET");
				}

				this->PushByte(MOUSE_RESET);		// Echo command
				this->PushByte(0xfa);				// ACK
				this->PushByte(0xaa);				// BAT OK
				this->PushByte(0x00);				// Device ID
				break;
			case MOUSE_ENADATA:
				if ((DiagForm) && (DiagForm->IsActive(DIAG_KBMOUSE)))
				{
					DiagForm->AddMessage(DIAG_KBMOUSE, L"Mouse Command: ENABLE DATA REPORTING");
				}

				this->PushByte(MOUSE_ENADATA);	// Echo command
				this->PushByte(0xfa);				// ACK
				this->fDataEnabled = true;
				break;
			case MOUSE_GETDEVID:
				if ((DiagForm) && (DiagForm->IsActive(DIAG_KBMOUSE)))
				{
					DiagForm->AddMessage(DIAG_KBMOUSE, L"Mouse Command: GET DEVICE ID");
				}

				this->PushByte(MOUSE_GETDEVID);	// Echo command
				this->PushByte(0xfa);				// ACK

				// Now return 0x00 for standard mouse, 0x03 for IntelliMouse
				this->PushByte(this->fIntelliMouseEnabled ? 0x03 : 0x00);
				break;
			default:
				if ((DiagForm) && (DiagForm->IsActive(DIAG_KBMOUSE)))
				{
					DiagForm->AddMessage(DIAG_KBMOUSE, UnicodeString::Format(
						L"Mouse Command (Unknown): %2.2x", OPENARRAY(TVarRec, (Value)))
					);
				}
		}
   }
}

///////////////////////////////////////////////////////////////////////
//
//  FUNCTION:  TOSCAMouse::Reset
//
//  PURPOSE:	Perform a Power-On Reset of the Mouse Device
//
//  INPUTS:		void
//
//  OUTPUT:		void
//
///////////////////////////////////////////////////////////////////////
void __fastcall TOSCAMouse::Reset()
{
	if ((DiagForm) && (DiagForm->IsActive(DIAG_KBMOUSE)))
	{
		DiagForm->AddMessage(DIAG_KBMOUSE, L"Mouse Reset");
	}

	this->fIntelliMouseEnabled = false;
	this->fActiveCommand 		= 0x00;
	this->fButtons					= 0x00;
	this->fDataEnabled			= false;

	// This is fairly naughty - no real need to be a
	// virtual function, but it allows complete control over
	// the reset process if required whilst still allowing
	// the more conventional non-virtual way of doing things!
	TOSCAPS2Device::Reset();

	tagPOINT tp;
	GetCursorPos(&tp);
	this->fLastX = tp.x;
	this->fLastY = tp.y;

	this->fPrescaleTarget = 2500; // Slower than keyboard
}

///////////////////////////////////////////////////////////////////////
//
//  FUNCTION:  TOSCAMouse::TOSCAMouse [CONSTRUCTOR]
//
//  PURPOSE:	Constructor for the Mouse Handler Class
//
//  INPUTS:		none
//
//  OUTPUT:		none
//
///////////////////////////////////////////////////////////////////////
__fastcall TOSCAMouse::TOSCAMouse()
{
}

#pragma package(smart_init)

