2007-08-06 21:38:35 +00:00
|
|
|
// Based on Apple in PC's mousecard.cpp
|
|
|
|
// - Permission given by Kyle Kim to reuse in AppleWin
|
|
|
|
|
|
|
|
#include "stdafx.h"
|
|
|
|
#pragma hdrstop
|
|
|
|
#include "..\resource\resource.h"
|
|
|
|
#include "MouseInterface.h"
|
|
|
|
|
|
|
|
// Sets mouse mode
|
|
|
|
#define MOUSE_SET 0x00
|
|
|
|
// Reads mouse position
|
|
|
|
#define MOUSE_READ 0x10
|
|
|
|
// Services mouse interrupt
|
|
|
|
#define MOUSE_SERV 0x20
|
|
|
|
// Clears mouse positions to 0 (for delta mode)
|
|
|
|
#define MOUSE_CLEAR 0x30
|
|
|
|
// Sets mouse position to a user-defined pos
|
|
|
|
#define MOUSE_POS 0x40
|
|
|
|
// Resets mouse clamps to default values
|
|
|
|
// Sets mouse position to 0,0
|
|
|
|
#define MOUSE_INIT 0x50
|
|
|
|
// Sets mouse bounds in a window
|
|
|
|
#define MOUSE_CLAMP 0x60
|
|
|
|
// Sets mouse to upper-left corner of clamp win
|
|
|
|
#define MOUSE_HOME 0x70
|
|
|
|
|
|
|
|
// Set VBL Timing : 0x90 is 60Hz, 0x91 is 50Hz
|
|
|
|
#define MOUSE_TIME 0x90
|
|
|
|
|
|
|
|
#define BIT0 0x01
|
|
|
|
#define BIT1 0x02
|
|
|
|
#define BIT2 0x04
|
|
|
|
#define BIT3 0x08
|
|
|
|
#define BIT4 0x10
|
|
|
|
#define BIT5 0x20
|
|
|
|
#define BIT6 0x40
|
|
|
|
#define BIT7 0x80
|
|
|
|
|
|
|
|
WRITE_HANDLER( M6821_Listener_B )
|
|
|
|
{
|
|
|
|
((CMouseInterface*)objTo)->On6821_B( byData );
|
|
|
|
}
|
|
|
|
|
|
|
|
WRITE_HANDLER( M6821_Listener_A )
|
|
|
|
{
|
|
|
|
((CMouseInterface*)objTo)->On6821_A( byData );
|
|
|
|
}
|
|
|
|
|
|
|
|
//CALLBACK_HANDLER( MouseHandler )
|
|
|
|
//{
|
|
|
|
// ((CMouseInterface*)objTo)->OnMouseEvent();
|
|
|
|
//}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
CMouseInterface::CMouseInterface() :
|
|
|
|
m_pSlotRom(NULL)
|
|
|
|
{
|
|
|
|
m_6821.SetListenerB( this, M6821_Listener_B );
|
|
|
|
m_6821.SetListenerA( this, M6821_Listener_A );
|
|
|
|
// g_cDIMouse.SetMouseListener( this, MouseHandler );
|
|
|
|
|
2007-12-01 21:21:40 +00:00
|
|
|
Uninitialize();
|
2007-08-06 21:38:35 +00:00
|
|
|
Reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
CMouseInterface::~CMouseInterface()
|
|
|
|
{
|
|
|
|
delete [] m_pSlotRom;
|
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
void CMouseInterface::Initialize(LPBYTE pCxRomPeripheral, UINT uSlot)
|
|
|
|
{
|
|
|
|
const UINT FW_SIZE = 2*1024;
|
|
|
|
|
|
|
|
HRSRC hResInfo = FindResource(NULL, MAKEINTRESOURCE(IDR_MOUSEINTERFACE_FW), "FIRMWARE");
|
|
|
|
if(hResInfo == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
DWORD dwResSize = SizeofResource(NULL, hResInfo);
|
|
|
|
if(dwResSize != FW_SIZE)
|
|
|
|
return;
|
|
|
|
|
|
|
|
HGLOBAL hResData = LoadResource(NULL, hResInfo);
|
|
|
|
if(hResData == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
BYTE* pData = (BYTE*) LockResource(hResData); // NB. Don't need to unlock resource
|
|
|
|
if(pData == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
m_uSlot = uSlot;
|
|
|
|
|
|
|
|
if (m_pSlotRom == NULL)
|
|
|
|
{
|
|
|
|
m_pSlotRom = new BYTE [FW_SIZE];
|
|
|
|
|
|
|
|
if (m_pSlotRom)
|
|
|
|
memcpy(m_pSlotRom, pData, FW_SIZE);
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
m_bActive = true;
|
2007-12-02 14:55:32 +00:00
|
|
|
SetSlotRom(); // Pre: m_bActive == true
|
|
|
|
RegisterIoHandler(uSlot, &CMouseInterface::IORead, &CMouseInterface::IOWrite, NULL, NULL, this, NULL);
|
2007-08-06 21:38:35 +00:00
|
|
|
}
|
|
|
|
|
2007-12-01 21:21:40 +00:00
|
|
|
void CMouseInterface::Uninitialize()
|
|
|
|
{
|
|
|
|
m_bActive = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CMouseInterface::Reset()
|
|
|
|
{
|
|
|
|
m_by6821A = 0;
|
|
|
|
m_by6821B = 0x40; // Set PB6
|
|
|
|
m_6821.SetPB(m_by6821B);
|
|
|
|
m_bVBL = FALSE;
|
|
|
|
|
|
|
|
//
|
|
|
|
|
2007-12-02 14:55:32 +00:00
|
|
|
m_nX = 0;
|
|
|
|
m_nY = 0;
|
|
|
|
|
2007-12-01 21:21:40 +00:00
|
|
|
m_iX = 0;
|
|
|
|
m_iMinX = 0;
|
|
|
|
m_iMaxX = 1023;
|
|
|
|
|
|
|
|
m_iY = 0;
|
|
|
|
m_iMinY = 0;
|
|
|
|
m_iMaxY = 1023;
|
|
|
|
|
|
|
|
m_bButtons[0] = m_bButtons[1] = FALSE;
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
Clear();
|
|
|
|
memset( m_byBuff, 0, sizeof( m_byBuff ) );
|
|
|
|
SetSlotRom();
|
|
|
|
}
|
|
|
|
|
2007-08-06 21:38:35 +00:00
|
|
|
void CMouseInterface::SetSlotRom()
|
|
|
|
{
|
2007-12-01 21:21:40 +00:00
|
|
|
if (!m_bActive)
|
|
|
|
return;
|
|
|
|
|
2007-08-06 21:38:35 +00:00
|
|
|
LPBYTE pCxRomPeripheral = MemGetCxRomPeripheral();
|
|
|
|
if (pCxRomPeripheral == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
UINT uOffset = (m_by6821B << 7) & 0x0700;
|
|
|
|
memcpy(pCxRomPeripheral+m_uSlot*256, m_pSlotRom+uOffset, 256);
|
|
|
|
if (mem)
|
|
|
|
memcpy(mem+0xC000+m_uSlot*256, m_pSlotRom+uOffset, 256);
|
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
BYTE __stdcall CMouseInterface::IORead(WORD PC, WORD uAddr, BYTE bWrite, BYTE uValue, ULONG nCyclesLeft)
|
|
|
|
{
|
|
|
|
UINT uSlot = ((uAddr & 0xff) >> 4) - 8;
|
|
|
|
CMouseInterface* pMouseIF = (CMouseInterface*) MemGetSlotParameters(uSlot);
|
|
|
|
|
|
|
|
BYTE byRS;
|
|
|
|
byRS = uAddr & 3;
|
|
|
|
return pMouseIF->m_6821.Read( byRS );
|
|
|
|
}
|
|
|
|
|
|
|
|
BYTE __stdcall CMouseInterface::IOWrite(WORD PC, WORD uAddr, BYTE bWrite, BYTE uValue, ULONG nCyclesLeft)
|
|
|
|
{
|
|
|
|
UINT uSlot = ((uAddr & 0xff) >> 4) - 8;
|
|
|
|
CMouseInterface* pMouseIF = (CMouseInterface*) MemGetSlotParameters(uSlot);
|
|
|
|
|
|
|
|
BYTE byRS;
|
|
|
|
byRS = uAddr & 3;
|
|
|
|
pMouseIF->m_6821.Write( byRS, uValue );
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
void CMouseInterface::On6821_A(BYTE byData)
|
|
|
|
{
|
|
|
|
m_by6821A = byData;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CMouseInterface::On6821_B(BYTE byData)
|
|
|
|
{
|
|
|
|
BYTE byDiff = ( m_by6821B ^ byData ) & 0x3E;
|
|
|
|
|
|
|
|
if ( byDiff )
|
|
|
|
{
|
|
|
|
m_by6821B &= ~0x3E;
|
|
|
|
m_by6821B |= byData & 0x3E;
|
|
|
|
if ( byDiff & BIT5 ) // Write to 0285 chip
|
|
|
|
{
|
|
|
|
if ( byData & BIT5 )
|
|
|
|
m_by6821B |= BIT7; // OK, I'm ready to read from MC6821
|
|
|
|
else // Clock Activate for read
|
|
|
|
{
|
|
|
|
m_byBuff[m_nBuffPos++] = m_by6821A;
|
|
|
|
if ( m_nBuffPos == 1 )
|
|
|
|
OnCommand();
|
|
|
|
if ( m_nBuffPos == m_nDataLen || m_nBuffPos > 7 )
|
|
|
|
{
|
|
|
|
OnWrite(); // Have written all, Commit the command.
|
|
|
|
m_nBuffPos = 0;
|
|
|
|
}
|
|
|
|
m_by6821B &= ~BIT7; // for next reading
|
|
|
|
m_6821.SetPB( m_by6821B );
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
if ( byDiff & BIT4 ) // Read from 0285 chip ?
|
|
|
|
{
|
|
|
|
if ( byData & BIT4 )
|
|
|
|
m_by6821B &= ~BIT6; // OK, I'll prepare next value
|
|
|
|
else // Clock Activate for write
|
|
|
|
{
|
|
|
|
if ( m_nBuffPos ) // if m_nBuffPos is 0, something goes wrong!
|
|
|
|
m_nBuffPos++;
|
|
|
|
if ( m_nBuffPos == m_nDataLen || m_nBuffPos > 7 )
|
|
|
|
m_nBuffPos = 0; // Have read all, ready for next command.
|
|
|
|
else
|
|
|
|
m_6821.SetPA( m_byBuff[m_nBuffPos] );
|
|
|
|
m_by6821B |= BIT6; // for next writing
|
|
|
|
}
|
|
|
|
}
|
|
|
|
m_6821.SetPB( m_by6821B );
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
SetSlotRom(); // Update Cn00 ROM page
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CMouseInterface::OnCommand()
|
|
|
|
{
|
|
|
|
switch( m_byBuff[0] & 0xF0 )
|
|
|
|
{
|
|
|
|
case MOUSE_SET:
|
|
|
|
m_nDataLen = 1;
|
|
|
|
m_byMode = m_byBuff[0] & 0x0F;
|
|
|
|
break;
|
|
|
|
case MOUSE_READ: // Read
|
|
|
|
m_nDataLen = 6;
|
|
|
|
m_byState &= 0x20;
|
|
|
|
m_nX = m_iX;
|
|
|
|
m_nY = m_iY;
|
|
|
|
if ( m_bBtn0 ) m_byState |= 0x40; // Previous Button 0
|
|
|
|
if ( m_bBtn1 ) m_byState |= 0x01; // Previous Button 1
|
|
|
|
m_bBtn0 = m_bButtons[0];
|
|
|
|
m_bBtn1 = m_bButtons[1];
|
|
|
|
if ( m_bBtn0 ) m_byState |= 0x80; // Current Button 0
|
|
|
|
if ( m_bBtn1 ) m_byState |= 0x10; // Current Button 1
|
|
|
|
m_byBuff[1] = m_nX & 0xFF;
|
|
|
|
m_byBuff[2] = ( m_nX >> 8 ) & 0xFF;
|
|
|
|
m_byBuff[3] = m_nY & 0xFF;
|
|
|
|
m_byBuff[4] = ( m_nY >> 8 ) & 0xFF;
|
|
|
|
m_byBuff[5] = m_byState; // button 0/1 interrupt status
|
|
|
|
m_byState &= ~0x20;
|
|
|
|
break;
|
|
|
|
case MOUSE_SERV:
|
|
|
|
m_nDataLen = 2;
|
|
|
|
m_byBuff[1] = m_byState & ~0x20; // reason of interrupt
|
|
|
|
CpuIrqDeassert(IS_MOUSE);
|
|
|
|
break;
|
|
|
|
case MOUSE_CLEAR:
|
2007-12-01 21:21:40 +00:00
|
|
|
Clear(); // [TC] NB. Don't reset clamp values (eg. Fantavision)
|
2007-08-06 21:38:35 +00:00
|
|
|
m_nDataLen = 1;
|
|
|
|
break;
|
|
|
|
case MOUSE_POS:
|
|
|
|
m_nDataLen = 5;
|
|
|
|
break;
|
|
|
|
case MOUSE_INIT:
|
|
|
|
m_nDataLen = 3;
|
|
|
|
m_byBuff[1] = 0xFF; // I don't know what it is
|
|
|
|
break;
|
|
|
|
case MOUSE_CLAMP:
|
|
|
|
m_nDataLen = 5;
|
|
|
|
break;
|
|
|
|
case MOUSE_HOME:
|
|
|
|
m_nDataLen = 1;
|
2007-12-02 14:55:32 +00:00
|
|
|
SetPositionAbs( 0, 0 );
|
2007-08-06 21:38:35 +00:00
|
|
|
break;
|
|
|
|
case MOUSE_TIME: // 0x90
|
|
|
|
switch( m_byBuff[0] & 0x0C )
|
|
|
|
{
|
|
|
|
case 0x00: m_nDataLen = 1; break; // write cmd ( #$90 is DATATIME 60Hz, #$91 is 50Hz )
|
|
|
|
case 0x04: m_nDataLen = 3; break; // write cmd, $0478, $04F8
|
|
|
|
case 0x08: m_nDataLen = 2; break; // write cmd, $0578
|
|
|
|
case 0x0C: m_nDataLen = 4; break; // write cmd, $0478, $04F8, $0578
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 0xA0:
|
|
|
|
m_nDataLen = 2;
|
|
|
|
break;
|
|
|
|
case 0xB0:
|
|
|
|
case 0xC0:
|
|
|
|
m_nDataLen = 1;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
m_nDataLen = 1;
|
|
|
|
//TRACE( "CMD : UNKNOWN CMD : #$%02X\n", m_byBuff[0] );
|
|
|
|
//_ASSERT(0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
m_6821.SetPA( m_byBuff[1] );
|
|
|
|
}
|
|
|
|
|
|
|
|
void CMouseInterface::OnWrite()
|
|
|
|
{
|
|
|
|
int nMin, nMax;
|
|
|
|
switch( m_byBuff[0] & 0xF0 )
|
|
|
|
{
|
|
|
|
case MOUSE_CLAMP:
|
|
|
|
nMin = ( m_byBuff[3] << 8 ) | m_byBuff[1];
|
|
|
|
nMax = ( m_byBuff[4] << 8 ) | m_byBuff[2];
|
|
|
|
if ( m_byBuff[0] & 1 ) // Clamp Y
|
2007-12-02 14:55:32 +00:00
|
|
|
SetClampY( nMin, nMax );
|
2007-08-06 21:38:35 +00:00
|
|
|
else // Clamp X
|
2007-12-02 14:55:32 +00:00
|
|
|
SetClampX( nMin, nMax );
|
2007-08-06 21:38:35 +00:00
|
|
|
break;
|
|
|
|
case MOUSE_POS:
|
|
|
|
m_nX = ( m_byBuff[2] << 8 ) | m_byBuff[1];
|
|
|
|
m_nY = ( m_byBuff[4] << 8 ) | m_byBuff[3];
|
2007-12-02 14:55:32 +00:00
|
|
|
SetPositionAbs( m_nX, m_nY );
|
2007-08-06 21:38:35 +00:00
|
|
|
break;
|
|
|
|
case MOUSE_INIT:
|
|
|
|
m_nX = 0;
|
|
|
|
m_nY = 0;
|
2007-12-02 14:55:32 +00:00
|
|
|
SetClampX( 0, 1023 );
|
|
|
|
SetClampY( 0, 1023 );
|
|
|
|
SetPositionAbs( 0, 0 );
|
2007-08-06 21:38:35 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CMouseInterface::OnMouseEvent()
|
|
|
|
{
|
|
|
|
int byState = 0;
|
|
|
|
|
|
|
|
if ( !( m_byMode & 1 ) ) // Mouse Off
|
|
|
|
return;
|
|
|
|
|
|
|
|
BOOL bBtn0 = m_bButtons[0];
|
|
|
|
BOOL bBtn1 = m_bButtons[1];
|
|
|
|
if ( m_nX != m_iX || m_nY != m_iY )
|
|
|
|
byState |= 0x22; // X/Y moved since last READMOUSE | Movement interrupt
|
|
|
|
if ( m_bBtn0 != bBtn0 || m_bBtn1 != bBtn1 )
|
|
|
|
byState |= 0x04; // Button 0/1 interrupt
|
|
|
|
if ( m_bVBL )
|
|
|
|
byState |= 0x08;
|
2007-08-08 21:24:28 +00:00
|
|
|
//byState &= m_byMode & 0x2E;
|
2007-12-01 21:21:40 +00:00
|
|
|
byState &= ((m_byMode & 0x0E) | 0x20); // [TC] Keep "X/Y moved since last READMOUSE" for next MOUSE_READ (Contiki v1.3 uses this)
|
2007-08-06 21:38:35 +00:00
|
|
|
|
|
|
|
if ( byState & 0x0E )
|
|
|
|
{
|
|
|
|
m_byState |= byState;
|
|
|
|
CpuIrqAssert(IS_MOUSE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CMouseInterface::SetVBlank(bool bVBL)
|
|
|
|
{
|
|
|
|
if ( m_bVBL != bVBL )
|
|
|
|
{
|
|
|
|
m_bVBL = bVBL;
|
|
|
|
if ( m_bVBL ) // Rising edge
|
|
|
|
OnMouseEvent();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-12-01 21:21:40 +00:00
|
|
|
void CMouseInterface::Clear()
|
2007-08-06 21:38:35 +00:00
|
|
|
{
|
|
|
|
m_nBuffPos = 0;
|
|
|
|
m_nDataLen = 1;
|
|
|
|
|
|
|
|
m_byMode = 0;
|
|
|
|
m_byState = 0;
|
|
|
|
m_nX = 0;
|
|
|
|
m_nY = 0;
|
|
|
|
m_bBtn0 = 0;
|
|
|
|
m_bBtn1 = 0;
|
2007-12-02 14:55:32 +00:00
|
|
|
SetPositionAbs( 0, 0 );
|
2007-08-06 21:38:35 +00:00
|
|
|
|
|
|
|
// CpuIrqDeassert(IS_MOUSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
|
2007-12-02 14:55:32 +00:00
|
|
|
void CMouseInterface::ClampX()
|
|
|
|
{
|
|
|
|
if ( m_iX > m_iMaxX )
|
|
|
|
m_iX = m_iMaxX;
|
|
|
|
else if ( m_iX < m_iMinX )
|
|
|
|
m_iX = m_iMinX;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CMouseInterface::ClampY()
|
|
|
|
{
|
|
|
|
if ( m_iY > m_iMaxY )
|
|
|
|
m_iY = m_iMaxY;
|
|
|
|
else if ( m_iY < m_iMinY )
|
|
|
|
m_iY = m_iMinY;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CMouseInterface::SetClampX(int iMinX, int iMaxX)
|
2007-08-06 21:38:35 +00:00
|
|
|
{
|
|
|
|
if ( iMinX < 0 || iMinX > iMaxX )
|
|
|
|
return;
|
|
|
|
m_iMaxX = iMaxX;
|
|
|
|
m_iMinX = iMinX;
|
2007-12-02 14:55:32 +00:00
|
|
|
ClampX();
|
2007-08-06 21:38:35 +00:00
|
|
|
}
|
|
|
|
|
2007-12-02 14:55:32 +00:00
|
|
|
void CMouseInterface::SetClampY(int iMinY, int iMaxY)
|
2007-08-06 21:38:35 +00:00
|
|
|
{
|
|
|
|
if ( iMinY < 0 || iMinY > iMaxY )
|
|
|
|
return;
|
|
|
|
m_iMaxY = iMaxY;
|
|
|
|
m_iMinY = iMinY;
|
2007-12-02 14:55:32 +00:00
|
|
|
ClampY();
|
2007-08-06 21:38:35 +00:00
|
|
|
}
|
|
|
|
|
2007-12-02 14:55:32 +00:00
|
|
|
void CMouseInterface::SetPositionAbs(int x, int y)
|
2007-08-06 21:38:35 +00:00
|
|
|
{
|
2007-12-02 14:55:32 +00:00
|
|
|
m_iX = x;
|
|
|
|
m_iY = y;
|
2007-08-06 21:38:35 +00:00
|
|
|
}
|
|
|
|
|
2007-12-02 14:55:32 +00:00
|
|
|
void CMouseInterface::SetPositionRel(int dx, int dy)
|
2007-08-06 21:38:35 +00:00
|
|
|
{
|
2007-12-02 14:55:32 +00:00
|
|
|
m_iX += dx;
|
|
|
|
ClampX();
|
2007-08-06 21:38:35 +00:00
|
|
|
|
2007-12-02 14:55:32 +00:00
|
|
|
m_iY += dy;
|
|
|
|
ClampY();
|
2007-12-01 21:21:40 +00:00
|
|
|
|
2007-08-06 21:38:35 +00:00
|
|
|
OnMouseEvent();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CMouseInterface::SetButton(eBUTTON Button, eBUTTONSTATE State)
|
|
|
|
{
|
|
|
|
m_bButtons[Button]= (State == BUTTON_DOWN) ? TRUE : FALSE;
|
|
|
|
OnMouseEvent();
|
|
|
|
}
|