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
2008-06-20 21:35:55 +00:00
/*
Contiki v1 .3 :
. I still see 2 cases of abnormal operation . These occur during boot up , during some period of disk access .
. See Contiki ' s IRQ ( ) in apple2 - stdmou . s
* * Normal operation * *
< VBL EVENT > : h / w asserts IRQ
< 6502 jumps to IRQ vector >
. MOUSE_SERVE : h / w deasserts IRQ
. MOUSE_READ
. RTS with C = 1
< VBL EVENT > : h / w asserts IRQ
< 6502 jumps to IRQ vector >
. MOUSE_SERVE : h / w deasserts IRQ
. MOUSE_READ
. RTS with C = 1
Etc .
* * Abnormal operation * *
< VBL EVENT > : h / w asserts IRQ
< 6502 jumps to IRQ vector >
. MOUSE_SERVE ( for VBL EVENT ) : h / w deasserts IRQ
< VBL EVENT > : h / w asserts IRQ
. MOUSE_READ
- this clears the mouse IRQ status byte in the mouse - card ' s " h/w "
. RTS with C = 1
< 6502 jumps to IRQ vector >
. MOUSE_SERVE ( for MOVEMENT EVENT ) : h / w deasserts IRQ
- but IRQ status byte is 0
. RTS with C = 0
*/
2018-02-24 15:12:40 +00:00
# include "StdAfx.h"
2015-02-13 22:40:53 +00:00
# include "SaveState_Structs_common.h"
2014-08-14 16:48:38 +00:00
# include "Common.h"
2010-02-14 21:11:26 +00:00
2014-08-13 20:30:35 +00:00
# include "CPU.h"
# include "Frame.h" // FrameSetCursorPosByMousePos()
# include "Log.h"
# include "Memory.h"
# include "MouseInterface.h"
2015-12-05 16:50:27 +00:00
# include "YamlHelper.h"
2014-08-13 20:30:35 +00:00
2018-02-24 15:12:40 +00:00
# include "../resource/resource.h"
2009-02-17 01:35:04 +00:00
# ifdef _DEBUG
# define _DEBUG_SPURIOUS_IRQ
# endif
2007-08-06 21:38:35 +00:00
// 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
2008-06-20 21:35:55 +00:00
// Interrupt status byte
//Bit 7 6 5 4 3 2 1 0
// | | | | | | | |
# define STAT_PREV_BUTTON1 (1<<0) // | | | | | | | \--- Previously, button 1 was up (0) or down (1)
# define STAT_INT_MOVEMENT (1<<1) // | | | | | | \----- Movement interrupt
# define STAT_INT_BUTTON (1<<2) // | | | | | \------- Button 0/1 interrupt
# define STAT_INT_VBL (1<<3) // | | | | \--------- VBL interrupt
# define STAT_CURR_BUTTON1 (1<<4) // | | | \----------- Currently, button 1 is up (0) or down (1)
# define STAT_MOVEMENT_SINCE_READMOUSE (1<<5) // | | \------------- X/Y moved since last READMOUSE
# define STAT_PREV_BUTTON0 (1<<6) // | \--------------- Previously, button 0 was up (0) or down (1)
# define STAT_CURR_BUTTON0 (1<<7) // \----------------- Currently, button 0 is up (0) or down (1)
# define STAT_INT_ALL (STAT_INT_VBL | STAT_INT_BUTTON | STAT_INT_MOVEMENT)
// Mode byte
//Bit 7 6 5 4 3 2 1 0
// | | | | | | | |
# define MODE_MOUSE_ON (1<<0) // | | | | | | | \--- Mouse off (0) or on (1)
# define MODE_INT_MOVEMENT (1<<1) // | | | | | | \----- Interrupt if mouse is moved
# define MODE_INT_BUTTON (1<<2) // | | | | | \------- Interrupt if button is pressed
# define MODE_INT_VBL (1<<3) // | | | | \--------- Interrupt on VBL
# define MODE_RESERVED4 (1<<4) // | | | \----------- Reserved
# define MODE_RESERVED5 (1<<5) // | | \------------- Reserved
# define MODE_RESERVED6 (1<<6) // | \--------------- Reserved
# define MODE_RESERVED7 (1<<7) // \----------------- Reserved
# define MODE_INT_ALL STAT_INT_ALL
2009-01-09 23:27:29 +00:00
//===========================================================================
2008-06-20 21:35:55 +00:00
2009-01-09 23:27:29 +00:00
void M6821_Listener_B ( void * objTo , BYTE byData )
2007-08-06 21:38:35 +00:00
{
( ( CMouseInterface * ) objTo ) - > On6821_B ( byData ) ;
}
2009-01-09 23:27:29 +00:00
void M6821_Listener_A ( void * objTo , BYTE byData )
2007-08-06 21:38:35 +00:00
{
( ( CMouseInterface * ) objTo ) - > On6821_A ( byData ) ;
}
//===========================================================================
CMouseInterface : : CMouseInterface ( ) :
m_pSlotRom ( NULL )
{
m_6821 . SetListenerB ( this , M6821_Listener_B ) ;
m_6821 . SetListenerA ( this , M6821_Listener_A ) ;
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 ;
2008-05-17 23:20:33 +00:00
SetEnabled ( 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 ) ;
2008-06-20 21:35:55 +00:00
m_bVBL = false ;
2014-09-29 21:43:15 +00:00
m_byMode = 0 ;
2007-12-01 21:21:40 +00:00
//
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 ;
2016-02-20 17:57:23 +00:00
m_bButtons [ 0 ] = m_bButtons [ 1 ] = false ;
2007-12-01 21:21:40 +00:00
//
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 ) ;
}
//===========================================================================
2018-03-03 21:27:50 +00:00
BYTE __stdcall CMouseInterface : : IORead ( WORD PC , WORD uAddr , BYTE bWrite , BYTE uValue , ULONG nExecutedCycles )
2007-08-06 21:38:35 +00:00
{
UINT uSlot = ( ( uAddr & 0xff ) > > 4 ) - 8 ;
CMouseInterface * pMouseIF = ( CMouseInterface * ) MemGetSlotParameters ( uSlot ) ;
BYTE byRS ;
byRS = uAddr & 3 ;
return pMouseIF - > m_6821 . Read ( byRS ) ;
}
2018-03-03 21:27:50 +00:00
BYTE __stdcall CMouseInterface : : IOWrite ( WORD PC , WORD uAddr , BYTE bWrite , BYTE uValue , ULONG nExecutedCycles )
2007-08-06 21:38:35 +00:00
{
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 ( )
{
2008-06-20 21:35:55 +00:00
# ifdef _DEBUG_SPURIOUS_IRQ
static UINT uSpuriousIrqCount = 0 ;
char szDbg [ 200 ] ;
BYTE byOldState = m_byState ;
# endif
2007-08-06 21:38:35 +00:00
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 ;
2008-06-20 21:35:55 +00:00
m_byState & = STAT_MOVEMENT_SINCE_READMOUSE ;
2007-08-06 21:38:35 +00:00
m_nX = m_iX ;
m_nY = m_iY ;
2008-06-20 21:35:55 +00:00
if ( m_bBtn0 ) m_byState | = STAT_PREV_BUTTON0 ; // Previous Button 0
if ( m_bBtn1 ) m_byState | = STAT_PREV_BUTTON1 ; // Previous Button 1
2007-08-06 21:38:35 +00:00
m_bBtn0 = m_bButtons [ 0 ] ;
m_bBtn1 = m_bButtons [ 1 ] ;
2008-06-20 21:35:55 +00:00
if ( m_bBtn0 ) m_byState | = STAT_CURR_BUTTON0 ; // Current Button 0
if ( m_bBtn1 ) m_byState | = STAT_CURR_BUTTON1 ; // Current Button 1
2007-08-06 21:38:35 +00:00
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 ;
2008-06-20 21:35:55 +00:00
m_byBuff [ 5 ] = m_byState ; // button 0/1 interrupt status
m_byState & = ~ STAT_MOVEMENT_SINCE_READMOUSE ;
# ifdef _DEBUG_SPURIOUS_IRQ
sprintf ( szDbg , " [MOUSE_READ] Old=%02X New=%02X \n " , byOldState , m_byState ) ; OutputDebugString ( szDbg ) ;
# endif
2007-08-06 21:38:35 +00:00
break ;
case MOUSE_SERV :
m_nDataLen = 2 ;
2008-06-20 21:35:55 +00:00
m_byBuff [ 1 ] = m_byState & ~ STAT_MOVEMENT_SINCE_READMOUSE ; // reason of interrupt
# ifdef _DEBUG_SPURIOUS_IRQ
if ( ( m_byMode & MODE_INT_ALL ) & & ( m_byBuff [ 1 ] & MODE_INT_ALL ) = = 0 )
{
uSpuriousIrqCount + + ;
sprintf ( szDbg , " [MOUSE_SERV] 0x%04X Buff[1]=0x%02X, *** \n " , uSpuriousIrqCount , m_byBuff [ 1 ] ) ; OutputDebugString ( szDbg ) ;
}
else
{
sprintf ( szDbg , " [MOUSE_SERV] ------ Buff[1]=0x%02X \n " , m_byBuff [ 1 ] ) ; OutputDebugString ( szDbg ) ;
}
# endif
2007-08-06 21:38:35 +00:00
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 :
2008-05-17 23:20:33 +00:00
// Blazing Paddles:
// . MOUSE_CLAMP(Y, 0xFFEC, 0x00D3)
// . MOUSE_CLAMP(X, 0xFFEC, 0x012B)
2007-08-06 21:38:35 +00:00
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 ;
}
}
2008-06-20 21:35:55 +00:00
void CMouseInterface : : OnMouseEvent ( bool bEventVBL )
2007-08-06 21:38:35 +00:00
{
int byState = 0 ;
2008-06-20 21:35:55 +00:00
if ( ! ( m_byMode & MODE_MOUSE_ON ) ) // Mouse Off
2007-08-06 21:38:35 +00:00
return ;
if ( m_nX ! = m_iX | | m_nY ! = m_iY )
2013-08-09 22:04:02 +00:00
{
2008-06-20 21:35:55 +00:00
byState | = STAT_INT_MOVEMENT | STAT_MOVEMENT_SINCE_READMOUSE ; // X/Y moved since last READMOUSE | Movement interrupt
2013-08-09 22:04:02 +00:00
m_byState | = STAT_MOVEMENT_SINCE_READMOUSE ; // [TC] Used by CopyII+9.1 and ProTERM3.1
}
2016-02-20 17:57:23 +00:00
if ( m_bBtn0 ! = m_bButtons [ 0 ] | | m_bBtn1 ! = m_bButtons [ 1 ] )
2008-06-20 21:35:55 +00:00
byState | = STAT_INT_BUTTON ; // Button 0/1 interrupt
if ( bEventVBL )
byState | = STAT_INT_VBL ;
2007-08-08 21:24:28 +00:00
//byState &= m_byMode & 0x2E;
2008-06-20 21:35:55 +00:00
byState & = ( ( m_byMode & MODE_INT_ALL ) | STAT_MOVEMENT_SINCE_READMOUSE ) ; // [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
2008-06-20 21:35:55 +00:00
if ( byState & STAT_INT_ALL )
2007-08-06 21:38:35 +00:00
{
m_byState | = byState ;
CpuIrqAssert ( IS_MOUSE ) ;
2008-06-20 21:35:55 +00:00
# ifdef _DEBUG_SPURIOUS_IRQ
char szDbg [ 200 ] ; sprintf ( szDbg , " [MOUSE EVNT] 0x%02X Mode=0x%02X \n " , m_byState , m_byMode ) ; OutputDebugString ( szDbg ) ;
# endif
2007-08-06 21:38:35 +00:00
}
}
void CMouseInterface : : SetVBlank ( bool bVBL )
{
2019-08-26 19:10:33 +00:00
_ASSERT ( m_bActive ) ; // Only called from CheckInterruptSources(), which is guarded by an: if (sg_Mouse.IsActive())
2014-09-29 21:43:15 +00:00
2007-08-06 21:38:35 +00:00
if ( m_bVBL ! = bVBL )
{
m_bVBL = bVBL ;
if ( m_bVBL ) // Rising edge
2008-06-20 21:35:55 +00:00
OnMouseEvent ( true ) ;
2007-08-06 21:38:35 +00:00
}
}
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 ;
2012-08-12 12:47:02 +00:00
// m_byMode = 0; // Not for BeagleWrite / MultiScribe
2007-08-06 21:38:35 +00:00
m_byState = 0 ;
m_nX = 0 ;
m_nY = 0 ;
2016-02-20 17:57:23 +00:00
m_bBtn0 = false ;
m_bBtn1 = false ;
2007-12-02 14:55:32 +00:00
SetPositionAbs ( 0 , 0 ) ;
2007-08-06 21:38:35 +00:00
// CpuIrqDeassert(IS_MOUSE);
}
//===========================================================================
2008-05-17 23:20:33 +00:00
int CMouseInterface : : ClampX ( )
2007-12-02 14:55:32 +00:00
{
if ( m_iX > m_iMaxX )
2008-05-17 23:20:33 +00:00
{
2007-12-02 14:55:32 +00:00
m_iX = m_iMaxX ;
2008-05-17 23:20:33 +00:00
return 1 ;
}
2007-12-02 14:55:32 +00:00
else if ( m_iX < m_iMinX )
2008-05-17 23:20:33 +00:00
{
2007-12-02 14:55:32 +00:00
m_iX = m_iMinX ;
2008-05-17 23:20:33 +00:00
return - 1 ;
}
return 0 ;
2007-12-02 14:55:32 +00:00
}
2008-05-17 23:20:33 +00:00
int CMouseInterface : : ClampY ( )
2007-12-02 14:55:32 +00:00
{
if ( m_iY > m_iMaxY )
2008-05-17 23:20:33 +00:00
{
2007-12-02 14:55:32 +00:00
m_iY = m_iMaxY ;
2008-05-17 23:20:33 +00:00
return 1 ;
}
2007-12-02 14:55:32 +00:00
else if ( m_iY < m_iMinY )
2008-05-17 23:20:33 +00:00
{
2007-12-02 14:55:32 +00:00
m_iY = m_iMinY ;
2008-05-17 23:20:33 +00:00
return - 1 ;
}
return 0 ;
2007-12-02 14:55:32 +00:00
}
void CMouseInterface : : SetClampX ( int iMinX , int iMaxX )
2007-08-06 21:38:35 +00:00
{
2008-05-17 23:20:33 +00:00
if ( ( UINT ) iMinX > 0xFFFF | | ( UINT ) iMaxX > 0xFFFF )
{
_ASSERT ( 0 ) ;
2007-08-06 21:38:35 +00:00
return ;
2008-05-17 23:20:33 +00:00
}
if ( iMinX > iMaxX )
{
// For Blazing Paddles
int iNewMaxX = ( iMinX + iMaxX ) & 0xFFFF ;
iMinX = 0 ;
iMaxX = iNewMaxX ;
}
2007-08-06 21:38:35 +00:00
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
{
2008-05-17 23:20:33 +00:00
if ( ( UINT ) iMinY > 0xFFFF | | ( UINT ) iMaxY > 0xFFFF )
{
_ASSERT ( 0 ) ;
2007-08-06 21:38:35 +00:00
return ;
2008-05-17 23:20:33 +00:00
}
if ( iMinY > iMaxY )
{
// For Blazing Paddles
int iNewMaxY = ( iMinY + iMaxY ) & 0xFFFF ;
iMinY = 0 ;
iMaxY = iNewMaxY ;
}
2007-08-06 21:38:35 +00:00
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 ;
2008-05-17 23:20:33 +00:00
FrameSetCursorPosByMousePos ( ) ;
2007-08-06 21:38:35 +00:00
}
2008-05-17 23:20:33 +00:00
void CMouseInterface : : SetPositionRel ( long dX , long dY , int * pOutOfBoundsX , int * pOutOfBoundsY )
2007-08-06 21:38:35 +00:00
{
2008-05-17 23:20:33 +00:00
m_iX + = dX ;
* pOutOfBoundsX = ClampX ( ) ;
2007-08-06 21:38:35 +00:00
2008-05-17 23:20:33 +00:00
m_iY + = dY ;
* pOutOfBoundsY = 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 )
{
2016-02-20 17:57:23 +00:00
m_bButtons [ Button ] = ( State = = BUTTON_DOWN ) ;
2007-08-06 21:38:35 +00:00
OnMouseEvent ( ) ;
}
2008-05-17 23:20:33 +00:00
2015-12-05 16:50:27 +00:00
# define SS_YAML_VALUE_CARD_MOUSE "Mouse Card"
# define SS_YAML_KEY_MC6821 "MC6821"
# define SS_YAML_KEY_PRA "PRA"
# define SS_YAML_KEY_DDRA "DDRA"
# define SS_YAML_KEY_CRA "CRA"
# define SS_YAML_KEY_PRB "PRB"
# define SS_YAML_KEY_DDRB "DDRB"
# define SS_YAML_KEY_CRB "CRB"
# define SS_YAML_KEY_IA "IA"
# define SS_YAML_KEY_IB "IB"
# define SS_YAML_KEY_DATALEN "DataLen"
# define SS_YAML_KEY_MODE "Mode"
# define SS_YAML_KEY_6821B "6821B"
# define SS_YAML_KEY_6821A "6821A"
# define SS_YAML_KEY_BUFF "Buffer"
# define SS_YAML_KEY_BUFFPOS "Buffer Position"
# define SS_YAML_KEY_MOUSESTATE "State"
# define SS_YAML_KEY_X "X"
# define SS_YAML_KEY_Y "Y"
# define SS_YAML_KEY_BTN0 "Btn0"
# define SS_YAML_KEY_BTN1 "Btn1"
# define SS_YAML_KEY_VBL "VBL"
# define SS_YAML_KEY_IX "iX"
# define SS_YAML_KEY_IMINX "iMinX"
# define SS_YAML_KEY_IMAXX "iMaxX"
# define SS_YAML_KEY_IY "iY"
# define SS_YAML_KEY_IMINY "iMinY"
# define SS_YAML_KEY_IMAXY "iMaxY"
# define SS_YAML_KEY_BUTTON0 "Button0"
# define SS_YAML_KEY_BUTTON1 "Button1"
# define SS_YAML_KEY_ENABLED "Enabled"
std : : string CMouseInterface : : GetSnapshotCardName ( void )
{
static const std : : string name ( SS_YAML_VALUE_CARD_MOUSE ) ;
return name ;
}
void CMouseInterface : : SaveSnapshotMC6821 ( YamlSaveHelper & yamlSaveHelper , std : : string key )
{
mc6821_t mc6821 ;
BYTE byIA ;
BYTE byIB ;
m_6821 . Get6821 ( mc6821 , byIA , byIB ) ;
YamlSaveHelper : : Label label ( yamlSaveHelper , " %s: \n " , key . c_str ( ) ) ;
2016-02-24 21:51:20 +00:00
yamlSaveHelper . SaveUint ( SS_YAML_KEY_PRA , mc6821 . pra ) ;
yamlSaveHelper . SaveUint ( SS_YAML_KEY_DDRA , mc6821 . ddra ) ;
yamlSaveHelper . SaveUint ( SS_YAML_KEY_CRA , mc6821 . cra ) ;
yamlSaveHelper . SaveUint ( SS_YAML_KEY_PRB , mc6821 . prb ) ;
yamlSaveHelper . SaveUint ( SS_YAML_KEY_DDRB , mc6821 . ddrb ) ;
yamlSaveHelper . SaveUint ( SS_YAML_KEY_CRB , mc6821 . crb ) ;
yamlSaveHelper . SaveUint ( SS_YAML_KEY_IA , byIA ) ;
yamlSaveHelper . SaveUint ( SS_YAML_KEY_IB , byIB ) ;
2015-12-05 16:50:27 +00:00
}
void CMouseInterface : : SaveSnapshot ( class YamlSaveHelper & yamlSaveHelper )
{
if ( ! m_bActive )
return ;
YamlSaveHelper : : Slot slot ( yamlSaveHelper , GetSnapshotCardName ( ) , m_uSlot , 1 ) ;
YamlSaveHelper : : Label state ( yamlSaveHelper , " %s: \n " , SS_YAML_KEY_STATE ) ;
SaveSnapshotMC6821 ( yamlSaveHelper , SS_YAML_KEY_MC6821 ) ;
yamlSaveHelper . Save ( " %s: %d \n " , SS_YAML_KEY_DATALEN , m_nDataLen ) ;
2016-03-04 21:26:14 +00:00
yamlSaveHelper . SaveHexUint8 ( SS_YAML_KEY_MODE , m_byMode ) ;
yamlSaveHelper . SaveHexUint8 ( SS_YAML_KEY_6821B , m_by6821B ) ;
yamlSaveHelper . SaveHexUint8 ( SS_YAML_KEY_6821A , m_by6821A ) ;
2015-12-05 16:50:27 +00:00
// New label
{
YamlSaveHelper : : Label buffer ( yamlSaveHelper , " %s: \n " , SS_YAML_KEY_BUFF ) ;
2016-02-24 22:54:53 +00:00
yamlSaveHelper . SaveMemory ( m_byBuff , sizeof ( m_byBuff ) ) ;
2015-12-05 16:50:27 +00:00
}
yamlSaveHelper . Save ( " %s: %d \n " , SS_YAML_KEY_BUFFPOS , m_nBuffPos ) ;
2016-03-04 21:26:14 +00:00
yamlSaveHelper . SaveHexUint8 ( SS_YAML_KEY_MOUSESTATE , m_byState ) ;
2016-02-24 21:51:20 +00:00
yamlSaveHelper . SaveUint ( SS_YAML_KEY_X , m_nX ) ;
yamlSaveHelper . SaveUint ( SS_YAML_KEY_Y , m_nY ) ;
yamlSaveHelper . SaveBool ( SS_YAML_KEY_BTN0 , m_bBtn0 ) ;
yamlSaveHelper . SaveBool ( SS_YAML_KEY_BTN1 , m_bBtn1 ) ;
yamlSaveHelper . SaveBool ( SS_YAML_KEY_VBL , m_bVBL ) ;
yamlSaveHelper . SaveUint ( SS_YAML_KEY_IX , m_iX ) ;
yamlSaveHelper . SaveUint ( SS_YAML_KEY_IMINX , m_iMinX ) ;
yamlSaveHelper . SaveUint ( SS_YAML_KEY_IMAXX , m_iMaxX ) ;
yamlSaveHelper . SaveUint ( SS_YAML_KEY_IY , m_iY ) ;
yamlSaveHelper . SaveUint ( SS_YAML_KEY_IMINY , m_iMinY ) ;
yamlSaveHelper . SaveUint ( SS_YAML_KEY_IMAXY , m_iMaxY ) ;
yamlSaveHelper . SaveBool ( SS_YAML_KEY_BUTTON0 , m_bButtons [ 0 ] ) ;
yamlSaveHelper . SaveBool ( SS_YAML_KEY_BUTTON1 , m_bButtons [ 1 ] ) ;
yamlSaveHelper . SaveBool ( SS_YAML_KEY_ENABLED , m_bEnabled ) ;
2015-12-05 16:50:27 +00:00
}
void CMouseInterface : : LoadSnapshotMC6821 ( YamlLoadHelper & yamlLoadHelper , std : : string key )
{
if ( ! yamlLoadHelper . GetSubMap ( key ) )
throw std : : string ( " Card: Expected key: " ) + key ;
mc6821_t mc6821 ;
2016-02-24 22:38:59 +00:00
mc6821 . pra = yamlLoadHelper . LoadUint ( SS_YAML_KEY_PRA ) ;
mc6821 . ddra = yamlLoadHelper . LoadUint ( SS_YAML_KEY_DDRA ) ;
mc6821 . cra = yamlLoadHelper . LoadUint ( SS_YAML_KEY_CRA ) ;
mc6821 . prb = yamlLoadHelper . LoadUint ( SS_YAML_KEY_PRB ) ;
mc6821 . ddrb = yamlLoadHelper . LoadUint ( SS_YAML_KEY_DDRB ) ;
mc6821 . crb = yamlLoadHelper . LoadUint ( SS_YAML_KEY_CRB ) ;
2015-12-05 16:50:27 +00:00
2016-02-24 22:38:59 +00:00
BYTE byIA = yamlLoadHelper . LoadUint ( SS_YAML_KEY_IA ) ;
BYTE byIB = yamlLoadHelper . LoadUint ( SS_YAML_KEY_IB ) ;
2015-12-05 16:50:27 +00:00
m_6821 . Set6821 ( mc6821 , byIA , byIB ) ;
yamlLoadHelper . PopMap ( ) ;
}
bool CMouseInterface : : LoadSnapshot ( class YamlLoadHelper & yamlLoadHelper , UINT slot , UINT version )
{
if ( slot ! = 4 ) // fixme
throw std : : string ( " Card: wrong slot " ) ;
if ( version ! = 1 )
throw std : : string ( " Card: wrong version " ) ;
LoadSnapshotMC6821 ( yamlLoadHelper , SS_YAML_KEY_MC6821 ) ;
2016-02-24 22:38:59 +00:00
m_nDataLen = yamlLoadHelper . LoadUint ( SS_YAML_KEY_DATALEN ) ;
m_byMode = yamlLoadHelper . LoadUint ( SS_YAML_KEY_MODE ) ;
m_by6821B = yamlLoadHelper . LoadUint ( SS_YAML_KEY_6821B ) ;
m_by6821A = yamlLoadHelper . LoadUint ( SS_YAML_KEY_6821A ) ;
2015-12-05 16:50:27 +00:00
if ( ! yamlLoadHelper . GetSubMap ( SS_YAML_KEY_BUFF ) )
2016-03-24 23:05:34 +00:00
throw std : : string ( " Card: Expected key: " SS_YAML_KEY_BUFF ) ;
2016-02-24 22:38:59 +00:00
yamlLoadHelper . LoadMemory ( m_byBuff , sizeof ( m_byBuff ) ) ;
2015-12-05 16:50:27 +00:00
yamlLoadHelper . PopMap ( ) ;
2016-02-24 22:38:59 +00:00
m_nBuffPos = yamlLoadHelper . LoadUint ( SS_YAML_KEY_BUFFPOS ) ;
m_byState = yamlLoadHelper . LoadUint ( SS_YAML_KEY_MOUSESTATE ) ;
m_nX = yamlLoadHelper . LoadInt ( SS_YAML_KEY_X ) ;
m_nY = yamlLoadHelper . LoadInt ( SS_YAML_KEY_Y ) ;
m_bBtn0 = yamlLoadHelper . LoadBool ( SS_YAML_KEY_BTN0 ) ;
m_bBtn1 = yamlLoadHelper . LoadBool ( SS_YAML_KEY_BTN1 ) ;
m_bVBL = yamlLoadHelper . LoadBool ( SS_YAML_KEY_VBL ) ;
m_iX = yamlLoadHelper . LoadInt ( SS_YAML_KEY_IX ) ;
m_iMinX = yamlLoadHelper . LoadInt ( SS_YAML_KEY_IMINX ) ;
m_iMaxX = yamlLoadHelper . LoadInt ( SS_YAML_KEY_IMAXX ) ;
m_iY = yamlLoadHelper . LoadInt ( SS_YAML_KEY_IY ) ;
m_iMinY = yamlLoadHelper . LoadInt ( SS_YAML_KEY_IMINY ) ;
m_iMaxY = yamlLoadHelper . LoadInt ( SS_YAML_KEY_IMAXY ) ;
m_bButtons [ 0 ] = yamlLoadHelper . LoadBool ( SS_YAML_KEY_BUTTON0 ) ;
m_bButtons [ 1 ] = yamlLoadHelper . LoadBool ( SS_YAML_KEY_BUTTON1 ) ;
m_bEnabled = yamlLoadHelper . LoadBool ( SS_YAML_KEY_ENABLED ) ; // MemInitializeIO() calls Initialize() which sets true
2015-12-05 16:50:27 +00:00
2019-08-26 19:10:33 +00:00
if ( m_byState & STAT_INT_ALL ) // GH#677
CpuIrqAssert ( IS_MOUSE ) ;
2015-12-05 16:50:27 +00:00
return true ;
}
2008-05-17 23:20:33 +00:00
//=============================================================================
// DirectInput interface
//=============================================================================
//#define STRICT
# define DIRECTINPUT_VERSION 0x0800
2018-02-24 15:12:40 +00:00
# include "SoundCore.h" // SAFE_RELEASE()
2008-05-17 23:20:33 +00:00
# include <dinput.h>
2013-03-23 14:14:48 +00:00
extern bool g_bDisableDirectInput ; // currently in AppleWin.h
2008-05-17 23:20:33 +00:00
namespace DIMouse
{
static LPDIRECTINPUT8 g_pDI = NULL ;
static LPDIRECTINPUTDEVICE8 g_pMouse = NULL ;
# define SAMPLE_BUFFER_SIZE 16 // arbitrary number of buffer elements
static UINT_PTR g_TimerIDEvent = 0 ;
//-----------------------------------------------------------------------------
// Name: OnCreateDevice()
// Desc: Sets up the mouse device using the flags from the dialog.
//-----------------------------------------------------------------------------
HRESULT DirectInputInit ( HWND hDlg )
{
2013-03-23 14:14:48 +00:00
LogFileOutput ( " DirectInputInit: g_bDisableDirectInput=%d \n " , g_bDisableDirectInput ) ;
if ( g_bDisableDirectInput )
return S_OK ;
2012-10-05 07:01:27 +00:00
# ifdef NO_DIRECT_X
return E_FAIL ;
# else // NO_DIRECT_X
2008-05-17 23:20:33 +00:00
HRESULT hr ;
BOOL bExclusive ;
BOOL bForeground ;
BOOL bImmediate ;
DWORD dwCoopFlags ;
DirectInputUninit ( hDlg ) ;
2013-03-23 13:34:01 +00:00
LogFileOutput ( " DirectInputInit: DirectInputUninit() \n " ) ;
2008-05-17 23:20:33 +00:00
// Determine where the buffer would like to be allocated
bExclusive = FALSE ;
bForeground = FALSE ; // Otherwise get DIERR_OTHERAPPHASPRIO (== E_ACCESSDENIED) on Acquire()
bImmediate = TRUE ;
if ( bExclusive )
dwCoopFlags = DISCL_EXCLUSIVE ;
else
dwCoopFlags = DISCL_NONEXCLUSIVE ;
if ( bForeground )
dwCoopFlags | = DISCL_FOREGROUND ;
else
dwCoopFlags | = DISCL_BACKGROUND ;
// Create a DInput object
2013-03-23 13:34:01 +00:00
hr = DirectInput8Create ( GetModuleHandle ( NULL ) , DIRECTINPUT_VERSION , IID_IDirectInput8 , ( VOID * * ) & g_pDI , NULL ) ;
2013-03-23 14:14:48 +00:00
LogFileOutput ( " DirectInputInit: DirectInput8Create(), hr=0x%08X \n " , hr ) ;
2013-03-23 13:34:01 +00:00
if ( FAILED ( hr ) )
2008-05-17 23:20:33 +00:00
return hr ;
// Obtain an interface to the system mouse device.
2013-03-23 13:34:01 +00:00
hr = g_pDI - > CreateDevice ( GUID_SysMouse , & g_pMouse , NULL ) ;
LogFileOutput ( " DirectInputInit: CreateDevice(), hr=0x%08X \n " , hr ) ;
if ( FAILED ( hr ) )
2008-05-17 23:20:33 +00:00
return hr ;
// Set the data format to "mouse format" - a predefined data format
//
// A data format specifies which controls on a device we
// are interested in, and how they should be reported.
//
// This tells DirectInput that we will be passing a
// DIMOUSESTATE2 structure to IDirectInputDevice::GetDeviceState.
2013-03-23 13:34:01 +00:00
hr = g_pMouse - > SetDataFormat ( & c_dfDIMouse2 ) ;
LogFileOutput ( " DirectInputInit: SetDataFormat(), hr=0x%08X \n " , hr ) ;
if ( FAILED ( hr ) )
2008-05-17 23:20:33 +00:00
return hr ;
// Set the cooperativity level to let DirectInput know how
// this device should interact with the system and with other
// DirectInput applications.
hr = g_pMouse - > SetCooperativeLevel ( hDlg , dwCoopFlags ) ;
2013-03-23 13:34:01 +00:00
LogFileOutput ( " DirectInputInit: SetCooperativeLevel(), hr=0x%08X \n " , hr ) ;
2008-05-17 23:20:33 +00:00
if ( hr = = DIERR_UNSUPPORTED & & ! bForeground & & bExclusive )
{
DirectInputUninit ( hDlg ) ;
2013-03-23 13:34:01 +00:00
LogFileOutput ( " DirectInputInit: DirectInputUninit()n " ) ;
2008-05-17 23:20:33 +00:00
//MessageBox( hDlg, _T("SetCooperativeLevel() returned DIERR_UNSUPPORTED.\n")
// _T("For security reasons, background exclusive mouse\n")
// _T("access is not allowed."),
// _T("Mouse"), MB_OK );
return S_OK ;
}
if ( FAILED ( hr ) )
return hr ;
if ( ! bImmediate )
{
// IMPORTANT STEP TO USE BUFFERED DEVICE DATA!
//
// DirectInput uses unbuffered I/O (buffer size = 0) by default.
// If you want to read buffered data, you need to set a nonzero
// buffer size.
//
// Set the buffer size to SAMPLE_BUFFER_SIZE (defined above) elements.
//
// The buffer size is a DWORD property associated with the device.
DIPROPDWORD dipdw ;
dipdw . diph . dwSize = sizeof ( DIPROPDWORD ) ;
dipdw . diph . dwHeaderSize = sizeof ( DIPROPHEADER ) ;
dipdw . diph . dwObj = 0 ;
dipdw . diph . dwHow = DIPH_DEVICE ;
dipdw . dwData = SAMPLE_BUFFER_SIZE ; // Arbitary buffer size
2013-03-23 13:34:01 +00:00
hr = g_pMouse - > SetProperty ( DIPROP_BUFFERSIZE , & dipdw . diph ) ;
LogFileOutput ( " DirectInputInit: SetProperty(), hr=0x%08X \n " , hr ) ;
if ( FAILED ( hr ) )
2008-05-17 23:20:33 +00:00
return hr ;
}
// Acquire the newly created device
2013-03-23 13:34:01 +00:00
hr = g_pMouse - > Acquire ( ) ;
LogFileOutput ( " DirectInputInit: Acquire(), hr=0x%08X \n " , hr ) ;
if ( FAILED ( hr ) )
2008-05-17 23:20:33 +00:00
return hr ;
// Setup timer to read mouse position
2017-10-28 20:59:48 +00:00
_ASSERT ( g_TimerIDEvent = = 0 ) ;
2013-03-23 13:34:01 +00:00
g_TimerIDEvent = SetTimer ( hDlg , IDEVENT_TIMER_MOUSE , 8 , NULL ) ; // 120Hz timer
LogFileOutput ( " DirectInputInit: SetTimer(), id=0x%08X \n " , g_TimerIDEvent ) ;
if ( g_TimerIDEvent = = 0 )
return E_FAIL ;
2008-05-17 23:20:33 +00:00
return S_OK ;
2012-10-05 07:01:27 +00:00
# endif // NO_DIRECT_X
2008-05-17 23:20:33 +00:00
}
//-----------------------------------------------------------------------------
// Name: FreeDirectInput()
// Desc: Initialize the DirectInput variables.
//-----------------------------------------------------------------------------
void DirectInputUninit ( HWND hDlg )
{
2013-03-23 13:34:01 +00:00
LogFileOutput ( " DirectInputUninit \n " ) ;
2008-05-17 23:20:33 +00:00
// Unacquire the device one last time just in case
// the app tried to exit while the device is still acquired.
if ( g_pMouse )
2013-03-23 13:34:01 +00:00
{
HRESULT hr = g_pMouse - > Unacquire ( ) ;
LogFileOutput ( " DirectInputUninit: Unacquire(), hr=0x%08X \n " , hr ) ;
}
2008-05-17 23:20:33 +00:00
// Release any DirectInput objects.
SAFE_RELEASE ( g_pMouse ) ;
SAFE_RELEASE ( g_pDI ) ;
if ( g_TimerIDEvent )
2013-03-23 13:34:01 +00:00
{
BOOL bRes = KillTimer ( hDlg , g_TimerIDEvent ) ;
LogFileOutput ( " DirectInputUninit: KillTimer(), res=%d \n " , bRes ? 1 : 0 ) ;
g_TimerIDEvent = 0 ;
}
2008-05-17 23:20:33 +00:00
}
//-----------------------------------------------------------------------------
// Name: ReadImmediateData()
// Desc: Read the input device's state when in immediate mode and display it.
//-----------------------------------------------------------------------------
HRESULT ReadImmediateData ( long * pX , long * pY )
{
HRESULT hr ;
DIMOUSESTATE2 dims2 ; // DirectInput mouse state structure
if ( pX ) * pX = 0 ;
if ( pY ) * pY = 0 ;
if ( NULL = = g_pMouse )
return S_OK ;
// Get the input's device state, and put the state in dims
ZeroMemory ( & dims2 , sizeof ( dims2 ) ) ;
hr = g_pMouse - > GetDeviceState ( sizeof ( DIMOUSESTATE2 ) , & dims2 ) ;
if ( FAILED ( hr ) )
{
// DirectInput may be telling us that the input stream has been
// interrupted. We aren't tracking any state between polls, so
// we don't have any special reset that needs to be done.
// We just re-acquire and try again.
// If input is lost then acquire and keep trying
hr = g_pMouse - > Acquire ( ) ;
while ( hr = = DIERR_INPUTLOST )
hr = g_pMouse - > Acquire ( ) ;
// Update the dialog text
if ( hr = = DIERR_OTHERAPPHASPRIO | |
hr = = DIERR_NOTACQUIRED )
{
//SetDlgItemText( hDlg, IDC_DATA, TEXT("Unacquired") );
}
// hr may be DIERR_OTHERAPPHASPRIO or other errors. This
// may occur when the app is minimized or in the process of
// switching, so just try again later
return S_OK ;
}
if ( pX ) * pX = dims2 . lX ;
if ( pY ) * pY = dims2 . lY ;
return S_OK ;
}
2015-02-13 22:40:53 +00:00
} ; // namespace DIMouse