2020-11-23 19:21:20 +00:00
/*
AppleWin : An Apple //e emulator for Windows
Copyright ( C ) 1994 - 1996 , Michael O ' Brien
Copyright ( C ) 1999 - 2001 , Oliver Schmidt
Copyright ( C ) 2002 - 2005 , Tom Charlesworth
Copyright ( C ) 2006 - 2014 , Tom Charlesworth , Michael Pohoreski
AppleWin is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
AppleWin is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with AppleWin ; if not , write to the Free Software
Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
/* Description: Frame
*
* Author : Various
*/
# include "StdAfx.h"
2020-12-24 15:08:50 +00:00
# include "Windows/Win32Frame.h"
2020-11-26 21:50:06 +00:00
# include "Windows/AppleWin.h"
2020-12-20 15:32:51 +00:00
# include "Interface.h"
2020-11-23 19:21:20 +00:00
# include "Keyboard.h"
# include "Log.h"
# include "Memory.h"
# include "Mockingboard.h"
# include "MouseInterface.h"
# include "Windows/DirectInput.h"
# include "NTSC.h"
# include "ParallelPrinter.h"
2021-01-17 10:48:06 +00:00
# include "Pravets.h"
2020-11-23 19:21:20 +00:00
# include "Registry.h"
# include "SaveState.h"
# include "SerialComms.h"
# include "SoundCore.h"
2022-02-27 17:26:48 +00:00
# include "Uthernet1.h"
# include "Uthernet2.h"
2020-11-23 19:21:20 +00:00
# include "Speaker.h"
2020-11-28 15:49:19 +00:00
# include "Utilities.h"
2022-05-08 15:26:01 +00:00
# include "CardManager.h"
2020-11-23 19:21:20 +00:00
# include "../resource/resource.h"
# include "Configuration/PropertySheet.h"
# include "Debugger/Debug.h"
2020-11-28 22:55:45 +00:00
# if _MSC_VER < 1900 // VS2013 or before (cl.exe v18.x or before)
2020-11-23 19:21:20 +00:00
# include <sys/stat.h>
# endif
//#define ENABLE_MENU 0
# define DEBUG_KEY_MESSAGES 0
2021-01-16 21:57:28 +00:00
static bool FileExists ( std : : string strFilename ) ;
2020-11-23 19:21:20 +00:00
// Must keep in sync with Disk_Status_e g_aDiskFullScreenColors
2021-01-16 21:57:28 +00:00
static const DWORD g_aDiskFullScreenColorsLED [ NUM_DISK_STATUS ] =
2020-11-23 19:21:20 +00:00
{
RGB ( 0 , 0 , 0 ) , // DISK_STATUS_OFF BLACK
RGB ( 0 , 255 , 0 ) , // DISK_STATUS_READ GREEN
RGB ( 255 , 0 , 0 ) , // DISK_STATUS_WRITE RED
RGB ( 255 , 128 , 0 ) // DISK_STATUS_PROT ORANGE
// RGB( 0, 0,255) // DISK_STATUS_PROT -blue-
} ;
2020-12-24 15:08:50 +00:00
void Win32Frame : : SetAltEnterToggleFullScreen ( bool mode )
2020-11-23 19:21:20 +00:00
{
g_bAltEnter_ToggleFullScreen = mode ;
}
// ==========================================================================
// Display construction:
// . Apple II video gets rendered to the framebuffer (maybe with some preliminary/final NTSC data in the border areas)
// . The *borderless* framebuffer is stretchblt() copied to the frame DC, in VideoRefreshScreen()
// . Draw cross-hairs (if using mouse as either a mouse or joystick) to frame DC
// . In Windowed mode:
// - Draw 3D border, 8x buttons, status area (disk LEDs, caps) to frame DC
// . In Fullscreen mode:
// - Optional: Draw status area to frame DC
//
2021-01-10 16:33:06 +00:00
UINT Win32Frame : : Get3DBorderWidth ( void )
2020-11-23 19:21:20 +00:00
{
return IsFullScreen ( ) ? 0 : VIEWPORTX ;
}
2021-01-10 16:33:06 +00:00
UINT Win32Frame : : Get3DBorderHeight ( void )
2020-11-23 19:21:20 +00:00
{
return IsFullScreen ( ) ? 0 : VIEWPORTY ;
}
//===========================================================================
2021-01-10 16:33:06 +00:00
void Win32Frame : : FrameShowCursor ( BOOL bShow )
2020-11-23 19:21:20 +00:00
{
int nCount ;
if ( bShow )
{
do
{
nCount = ShowCursor ( bShow ) ;
}
while ( nCount < 0 ) ;
g_bShowingCursor = true ;
}
else
{
do
{
nCount = ShowCursor ( bShow ) ;
}
while ( nCount > = 0 ) ;
g_bShowingCursor = false ;
}
}
// Called when:
// . Ctrl-Left mouse button
// . PAUSE pressed (when MODE_RUNNING)
// . AppleWin's main window is activated/deactivated
2021-01-10 16:33:06 +00:00
void Win32Frame : : RevealCursor ( )
2020-11-23 19:21:20 +00:00
{
CMouseInterface * pMouseCard = GetCardMgr ( ) . GetMouseCard ( ) ;
if ( ! pMouseCard | | ! pMouseCard - > IsActiveAndEnabled ( ) )
return ;
pMouseCard - > SetEnabled ( false ) ;
FrameShowCursor ( TRUE ) ;
2020-12-20 15:32:51 +00:00
if ( GetPropertySheet ( ) . GetMouseShowCrosshair ( ) ) // Erase crosshairs if they are being drawn
2020-11-23 19:21:20 +00:00
DrawCrosshairs ( 0 , 0 ) ;
2020-12-20 15:32:51 +00:00
if ( GetPropertySheet ( ) . GetMouseRestrictToWindow ( ) )
2020-11-23 19:21:20 +00:00
SetUsingCursor ( FALSE ) ;
g_bLastCursorInAppleViewport = false ;
}
// Called when:
// . WM_MOUSEMOVE event
// . Switch from full-screen to normal (windowed) mode
// . AppleWin's main window is activated/deactivated
2021-01-10 16:33:06 +00:00
void Win32Frame : : FullScreenRevealCursor ( void )
2020-11-23 19:21:20 +00:00
{
if ( ! g_bIsFullScreen )
return ;
if ( GetCardMgr ( ) . IsMouseCardInstalled ( ) )
return ;
if ( ! g_bUsingCursor & & ! g_bShowingCursor )
{
FrameShowCursor ( TRUE ) ;
g_uCount100msec = 0 ;
}
}
//===========================================================================
2021-01-10 16:33:06 +00:00
# define LOADBUTTONBITMAP(bitmapname) LoadImage(g_hInstance,bitmapname, \
2020-11-23 19:21:20 +00:00
IMAGE_BITMAP , 0 , 0 , \
LR_CREATEDIBSECTION | \
LR_LOADMAP3DCOLORS | \
LR_LOADTRANSPARENT ) ;
2021-01-10 16:33:06 +00:00
void Win32Frame : : CreateGdiObjects ( void )
2020-11-23 19:21:20 +00:00
{
2020-12-10 21:08:15 +00:00
memset ( buttonbitmap , 0 , BUTTONS * sizeof ( HBITMAP ) ) ;
2020-11-23 19:21:20 +00:00
buttonbitmap [ BTN_HELP ] = ( HBITMAP ) LOADBUTTONBITMAP ( TEXT ( " HELP_BUTTON " ) ) ;
switch ( g_Apple2Type )
{
case A2TYPE_PRAVETS82 :
case A2TYPE_PRAVETS8M :
case A2TYPE_PRAVETS8A :
buttonbitmap [ BTN_RUN ] = ( HBITMAP ) LOADBUTTONBITMAP ( TEXT ( " RUNP_BUTTON " ) ) ;
break ;
case A2TYPE_TK30002E :
buttonbitmap [ BTN_RUN ] = ( HBITMAP ) LOADBUTTONBITMAP ( TEXT ( " RUN3000E_BUTTON " ) ) ;
break ;
case A2TYPE_BASE64A :
buttonbitmap [ BTN_RUN ] = ( HBITMAP ) LOADBUTTONBITMAP ( TEXT ( " RUNBASE64A_BUTTON " ) ) ;
break ;
default :
buttonbitmap [ BTN_RUN ] = ( HBITMAP ) LOADBUTTONBITMAP ( TEXT ( " RUN_BUTTON " ) ) ;
break ;
}
buttonbitmap [ BTN_DRIVE1 ] = ( HBITMAP ) LOADBUTTONBITMAP ( TEXT ( " DRIVE1_BUTTON " ) ) ;
buttonbitmap [ BTN_DRIVE2 ] = ( HBITMAP ) LOADBUTTONBITMAP ( TEXT ( " DRIVE2_BUTTON " ) ) ;
buttonbitmap [ BTN_DRIVESWAP ] = ( HBITMAP ) LOADBUTTONBITMAP ( TEXT ( " DRIVESWAP_BUTTON " ) ) ;
buttonbitmap [ BTN_FULLSCR ] = ( HBITMAP ) LOADBUTTONBITMAP ( TEXT ( " FULLSCR_BUTTON " ) ) ;
buttonbitmap [ BTN_DEBUG ] = ( HBITMAP ) LOADBUTTONBITMAP ( TEXT ( " DEBUG_BUTTON " ) ) ;
buttonbitmap [ BTN_SETUP ] = ( HBITMAP ) LOADBUTTONBITMAP ( TEXT ( " SETUP_BUTTON " ) ) ;
//
g_hCapsLockBitmap [ 0 ] = ( HBITMAP ) LOADBUTTONBITMAP ( TEXT ( " LED_CAPSOFF_BITMAP " ) ) ;
g_hCapsLockBitmap [ 1 ] = ( HBITMAP ) LOADBUTTONBITMAP ( TEXT ( " LED_CAPSON_BITMAP " ) ) ;
//Pravets8 only
g_hCapsBitmapP8 [ 0 ] = ( HBITMAP ) LOADBUTTONBITMAP ( TEXT ( " LED_CAPSOFF_P8_BITMAP " ) ) ;
g_hCapsBitmapP8 [ 1 ] = ( HBITMAP ) LOADBUTTONBITMAP ( TEXT ( " LED_CAPSON_P8_BITMAP " ) ) ;
g_hCapsBitmapLat [ 0 ] = ( HBITMAP ) LOADBUTTONBITMAP ( TEXT ( " LED_LATOFF_BITMAP " ) ) ;
g_hCapsBitmapLat [ 1 ] = ( HBITMAP ) LOADBUTTONBITMAP ( TEXT ( " LED_LATON_BITMAP " ) ) ;
/*charsetbitmap[0] = (HBITMAP)LOADBUTTONBITMAP(TEXT("CHARSET_APPLE_BITMAP"));
charsetbitmap [ 1 ] = ( HBITMAP ) LOADBUTTONBITMAP ( TEXT ( " CHARSET_82_BITMAP " ) ) ;
charsetbitmap [ 2 ] = ( HBITMAP ) LOADBUTTONBITMAP ( TEXT ( " CHARSET_8A_BITMAP " ) ) ;
charsetbitmap [ 3 ] = ( HBITMAP ) LOADBUTTONBITMAP ( TEXT ( " CHARSET_8M_BITMAP " ) ) ;
*/
//===========================
g_hDiskWindowedLED [ DISK_STATUS_OFF ] = ( HBITMAP ) LOADBUTTONBITMAP ( TEXT ( " DISKOFF_BITMAP " ) ) ;
g_hDiskWindowedLED [ DISK_STATUS_READ ] = ( HBITMAP ) LOADBUTTONBITMAP ( TEXT ( " DISKREAD_BITMAP " ) ) ;
g_hDiskWindowedLED [ DISK_STATUS_WRITE ] = ( HBITMAP ) LOADBUTTONBITMAP ( TEXT ( " DISKWRITE_BITMAP " ) ) ;
g_hDiskWindowedLED [ DISK_STATUS_PROT ] = ( HBITMAP ) LOADBUTTONBITMAP ( TEXT ( " DISKPROT_BITMAP " ) ) ;
btnfacebrush = CreateSolidBrush ( GetSysColor ( COLOR_BTNFACE ) ) ;
btnfacepen = CreatePen ( PS_SOLID , 1 , GetSysColor ( COLOR_BTNFACE ) ) ;
btnhighlightpen = CreatePen ( PS_SOLID , 1 , GetSysColor ( COLOR_BTNHIGHLIGHT ) ) ;
btnshadowpen = CreatePen ( PS_SOLID , 1 , GetSysColor ( COLOR_BTNSHADOW ) ) ;
smallfont = CreateFont ( 11 , 6 , 0 , 0 , FW_NORMAL , 0 , 0 , 0 , ANSI_CHARSET ,
OUT_DEFAULT_PRECIS , CLIP_DEFAULT_PRECIS ,
DEFAULT_QUALITY , VARIABLE_PITCH | FF_SWISS ,
TEXT ( " Small Fonts " ) ) ;
}
//===========================================================================
2021-01-16 21:57:28 +00:00
void Win32Frame : : DeleteGdiObjects ( void )
2020-11-23 19:21:20 +00:00
{
for ( int loop = 0 ; loop < BUTTONS ; loop + + )
_ASSERT ( DeleteObject ( buttonbitmap [ loop ] ) ) ;
for ( int loop = 0 ; loop < 2 ; loop + + )
{
_ASSERT ( DeleteObject ( g_hCapsLockBitmap [ loop ] ) ) ;
_ASSERT ( DeleteObject ( g_hCapsBitmapP8 [ loop ] ) ) ;
_ASSERT ( DeleteObject ( g_hCapsBitmapLat [ loop ] ) ) ;
}
for ( int loop = 0 ; loop < NUM_DISK_STATUS ; loop + + )
{
_ASSERT ( DeleteObject ( g_hDiskWindowedLED [ loop ] ) ) ;
}
_ASSERT ( DeleteObject ( btnfacebrush ) ) ;
_ASSERT ( DeleteObject ( btnfacepen ) ) ;
_ASSERT ( DeleteObject ( btnhighlightpen ) ) ;
_ASSERT ( DeleteObject ( btnshadowpen ) ) ;
_ASSERT ( DeleteObject ( smallfont ) ) ;
}
// Draws an 3D box around the main apple screen
//===========================================================================
2021-01-16 21:57:28 +00:00
void Win32Frame : : Draw3dRect ( HDC dc , int x1 , int y1 , int x2 , int y2 , BOOL out )
2020-11-23 19:21:20 +00:00
{
SelectObject ( dc , GetStockObject ( NULL_BRUSH ) ) ;
SelectObject ( dc , out ? btnshadowpen : btnhighlightpen ) ;
POINT pt [ 3 ] ;
pt [ 0 ] . x = x1 ; pt [ 0 ] . y = y2 - 1 ;
pt [ 1 ] . x = x2 - 1 ; pt [ 1 ] . y = y2 - 1 ;
pt [ 2 ] . x = x2 - 1 ; pt [ 2 ] . y = y1 ;
Polyline ( dc , ( LPPOINT ) & pt , 3 ) ;
SelectObject ( dc , ( out = = 1 ) ? btnhighlightpen : btnshadowpen ) ;
pt [ 1 ] . x = x1 ; pt [ 1 ] . y = y1 ;
pt [ 2 ] . x = x2 ; pt [ 2 ] . y = y1 ;
Polyline ( dc , ( LPPOINT ) & pt , 3 ) ;
}
//===========================================================================
2021-01-16 21:57:28 +00:00
void Win32Frame : : DrawBitmapRect ( HDC dc , int x , int y , LPRECT rect , HBITMAP bitmap ) {
2020-11-23 19:21:20 +00:00
HDC memdc = CreateCompatibleDC ( dc ) ;
SelectObject ( memdc , bitmap ) ;
BitBlt ( dc , x , y ,
rect - > right + 1 - rect - > left ,
rect - > bottom + 1 - rect - > top ,
memdc ,
rect - > left ,
rect - > top ,
SRCCOPY ) ;
DeleteDC ( memdc ) ;
}
//===========================================================================
2021-01-10 16:33:06 +00:00
void Win32Frame : : DrawButton ( HDC passdc , int number ) {
2020-11-23 19:21:20 +00:00
FrameReleaseDC ( ) ;
2021-01-10 16:33:06 +00:00
HDC dc = ( passdc ? passdc : GetDC ( g_hFrameWindow ) ) ;
2020-11-23 19:21:20 +00:00
int x = buttonx ;
int y = buttony + number * BUTTONCY ;
if ( number = = buttondown ) {
int loop = 0 ;
while ( loop + + < 3 )
Draw3dRect ( dc , x + loop , y + loop , x + BUTTONCX , y + BUTTONCY , 0 ) ;
RECT rect = { 0 , 0 , 39 , 39 } ;
DrawBitmapRect ( dc , x + 4 , y + 4 , & rect , buttonbitmap [ number ] ) ;
}
else {
Draw3dRect ( dc , x + 1 , y + 1 , x + BUTTONCX , y + BUTTONCY , 1 ) ;
Draw3dRect ( dc , x + 2 , y + 2 , x + BUTTONCX - 1 , y + BUTTONCY - 1 , 1 ) ;
RECT rect = { 1 , 1 , 40 , 40 } ;
DrawBitmapRect ( dc , x + 3 , y + 3 , & rect , buttonbitmap [ number ] ) ;
}
if ( ( number = = BTN_DRIVE1 ) | | ( number = = BTN_DRIVE2 ) ) {
int offset = ( number = = buttondown ) < < 1 ;
RECT rect = { x + offset + 3 ,
y + offset + 31 ,
x + offset + 42 ,
y + offset + 42 } ;
SelectObject ( dc , smallfont ) ;
SetTextColor ( dc , RGB ( 0 , 0 , 0 ) ) ;
SetTextAlign ( dc , TA_CENTER | TA_TOP ) ;
SetBkMode ( dc , TRANSPARENT ) ;
LPCTSTR pszBaseName = ( GetCardMgr ( ) . QuerySlot ( SLOT6 ) = = CT_Disk2 )
? dynamic_cast < Disk2InterfaceCard & > ( GetCardMgr ( ) . GetRef ( SLOT6 ) ) . GetBaseName ( number - BTN_DRIVE1 ) . c_str ( )
: " " ;
ExtTextOut ( dc , x + offset + 22 , rect . top , ETO_CLIPPED , & rect ,
pszBaseName ,
MIN ( 8 , _tcslen ( pszBaseName ) ) ,
NULL ) ;
}
if ( ! passdc )
2021-01-10 16:33:06 +00:00
ReleaseDC ( g_hFrameWindow , dc ) ;
2020-11-23 19:21:20 +00:00
}
//===========================================================================
// NB. x=y=0 means erase only
2021-01-10 16:33:06 +00:00
void Win32Frame : : DrawCrosshairs ( int x , int y ) {
2020-11-23 19:21:20 +00:00
static int lastx = 0 ;
static int lasty = 0 ;
FrameReleaseDC ( ) ;
2021-01-10 16:33:06 +00:00
HDC dc = GetDC ( g_hFrameWindow ) ;
2020-11-23 19:21:20 +00:00
# define LINE(x1,y1,x2,y2) MoveToEx(dc,x1,y1,NULL); LineTo(dc,x2,y2);
// ERASE THE OLD CROSSHAIRS
if ( lastx & & lasty )
if ( g_bIsFullScreen )
{
int loop = 4 ;
while ( loop - - ) {
RECT rect = { 0 , 0 , 5 , 5 } ;
switch ( loop ) {
case 0 : OffsetRect ( & rect , GetFullScreenOffsetX ( ) + lastx - 2 , GetFullScreenOffsetY ( ) + viewporty - 5 ) ; break ;
case 1 : OffsetRect ( & rect , GetFullScreenOffsetX ( ) + lastx - 2 , GetFullScreenOffsetY ( ) + viewporty + g_nViewportCY ) ; break ;
case 2 : OffsetRect ( & rect , GetFullScreenOffsetX ( ) + viewportx - 5 , GetFullScreenOffsetY ( ) + lasty - 2 ) ; break ;
case 3 : OffsetRect ( & rect , GetFullScreenOffsetX ( ) + viewportx + g_nViewportCX , GetFullScreenOffsetY ( ) + lasty - 2 ) ; break ;
}
FillRect ( dc , & rect , ( HBRUSH ) GetStockObject ( BLACK_BRUSH ) ) ;
}
}
else
{
int loop = 5 ;
while ( loop - - ) {
switch ( loop ) {
case 0 : SelectObject ( dc , GetStockObject ( BLACK_PEN ) ) ; break ;
case 1 : // fall through
case 2 : SelectObject ( dc , btnshadowpen ) ; break ;
case 3 : // fall through
case 4 : SelectObject ( dc , btnfacepen ) ; break ;
}
LINE ( lastx - 2 , VIEWPORTY - loop - 1 ,
lastx + 3 , VIEWPORTY - loop - 1 ) ;
LINE ( VIEWPORTX - loop - 1 , lasty - 2 ,
VIEWPORTX - loop - 1 , lasty + 3 ) ;
if ( ( loop = = 1 ) | | ( loop = = 2 ) )
SelectObject ( dc , btnhighlightpen ) ;
LINE ( lastx - 2 , VIEWPORTY + g_nViewportCY + loop ,
lastx + 3 , VIEWPORTY + g_nViewportCY + loop ) ;
LINE ( VIEWPORTX + g_nViewportCX + loop , lasty - 2 ,
VIEWPORTX + g_nViewportCX + loop , lasty + 3 ) ;
}
}
// DRAW THE NEW CROSSHAIRS
if ( x & & y ) {
if ( g_bIsFullScreen )
{
int loop = 4 ;
while ( loop - - ) {
if ( ( loop = = 1 ) | | ( loop = = 2 ) )
SelectObject ( dc , GetStockObject ( WHITE_PEN ) ) ;
else
SelectObject ( dc , GetStockObject ( BLACK_PEN ) ) ;
LINE ( GetFullScreenOffsetX ( ) + x + loop - 2 , GetFullScreenOffsetY ( ) + viewporty - 5 ,
GetFullScreenOffsetX ( ) + x + loop - 2 , GetFullScreenOffsetY ( ) + viewporty ) ;
LINE ( GetFullScreenOffsetX ( ) + x + loop - 2 , GetFullScreenOffsetY ( ) + viewporty + g_nViewportCY + 4 ,
GetFullScreenOffsetX ( ) + x + loop - 2 , GetFullScreenOffsetY ( ) + viewporty + g_nViewportCY - 1 ) ;
LINE ( GetFullScreenOffsetX ( ) + viewportx - 5 , GetFullScreenOffsetY ( ) + y + loop - 2 ,
GetFullScreenOffsetX ( ) + viewportx , GetFullScreenOffsetY ( ) + y + loop - 2 ) ;
LINE ( GetFullScreenOffsetX ( ) + viewportx + g_nViewportCX + 4 , GetFullScreenOffsetY ( ) + y + loop - 2 ,
GetFullScreenOffsetX ( ) + viewportx + g_nViewportCX - 1 , GetFullScreenOffsetY ( ) + y + loop - 2 ) ;
}
}
else
{
int loop = 4 ;
while ( loop - - ) {
if ( ( loop = = 1 ) | | ( loop = = 2 ) )
SelectObject ( dc , GetStockObject ( WHITE_PEN ) ) ;
else
SelectObject ( dc , GetStockObject ( BLACK_PEN ) ) ;
LINE ( x + loop - 2 , viewporty - 5 ,
x + loop - 2 , viewporty ) ;
LINE ( x + loop - 2 , viewporty + g_nViewportCY + 4 ,
x + loop - 2 , viewporty + g_nViewportCY - 1 ) ;
LINE ( viewportx - 5 , y + loop - 2 ,
viewportx , y + loop - 2 ) ;
LINE ( viewportx + g_nViewportCX + 4 , y + loop - 2 ,
viewportx + g_nViewportCX - 1 , y + loop - 2 ) ;
}
}
}
# undef LINE
lastx = x ;
lasty = y ;
2021-01-10 16:33:06 +00:00
ReleaseDC ( g_hFrameWindow , dc ) ;
2020-11-23 19:21:20 +00:00
}
//===========================================================================
2021-01-10 16:33:06 +00:00
void Win32Frame : : DrawFrameWindow ( bool bPaintingWindow /*=false*/ )
2020-11-23 19:21:20 +00:00
{
FrameReleaseDC ( ) ;
PAINTSTRUCT ps ;
HDC dc = bPaintingWindow
2021-01-10 16:33:06 +00:00
? BeginPaint ( g_hFrameWindow , & ps )
: GetDC ( g_hFrameWindow ) ;
2020-11-23 19:21:20 +00:00
if ( ! g_bIsFullScreen )
{
// DRAW THE 3D BORDER AROUND THE EMULATED SCREEN
Draw3dRect ( dc ,
VIEWPORTX - 2 , VIEWPORTY - 2 ,
VIEWPORTX + g_nViewportCX + 2 , VIEWPORTY + g_nViewportCY + 2 ,
0 ) ;
Draw3dRect ( dc ,
VIEWPORTX - 3 , VIEWPORTY - 3 ,
VIEWPORTX + g_nViewportCX + 3 , VIEWPORTY + g_nViewportCY + 3 ,
0 ) ;
SelectObject ( dc , btnfacepen ) ;
Rectangle ( dc ,
VIEWPORTX - 4 , VIEWPORTY - 4 ,
VIEWPORTX + g_nViewportCX + 4 , VIEWPORTY + g_nViewportCY + 4 ) ;
Rectangle ( dc ,
VIEWPORTX - 5 , VIEWPORTY - 5 ,
VIEWPORTX + g_nViewportCX + 5 , VIEWPORTY + g_nViewportCY + 5 ) ;
// DRAW THE TOOLBAR BUTTONS
int iButton = BUTTONS ;
while ( iButton - - )
{
DrawButton ( dc , iButton ) ;
}
2021-11-30 21:41:02 +00:00
if ( g_nViewportScale = = 2 | | GetVideo ( ) . HasVidHD ( ) )
2020-11-23 19:21:20 +00:00
{
2021-11-30 21:41:02 +00:00
const int x = buttonx + 1 ;
const int y = buttony + BUTTONS * BUTTONCY + 36 ; // 36 = height of StatusArea
RECT rect = { x , y , x + BUTTONCX , y + BUTTONS * BUTTONCY + 22 } ;
if ( GetVideo ( ) . HasVidHD ( ) )
{
if ( g_nViewportScale = = 1 )
rect . bottom + = 14 ;
else
rect . bottom + = 32 ;
}
2020-11-23 19:21:20 +00:00
int res = FillRect ( dc , & rect , btnfacebrush ) ;
}
}
// DRAW THE STATUS AREA
DrawStatusArea ( dc , DRAW_BACKGROUND | DRAW_LEDS | DRAW_DISK_STATUS ) ;
// DRAW THE CONTENTS OF THE EMULATED SCREEN
if ( g_nAppMode = = MODE_LOGO )
2021-01-10 16:33:06 +00:00
DisplayLogo ( ) ;
2020-11-23 19:21:20 +00:00
else if ( g_nAppMode = = MODE_DEBUG )
DebugDisplay ( ) ;
else
2021-01-10 16:33:06 +00:00
VideoRedrawScreen ( ) ;
2020-11-23 19:21:20 +00:00
if ( bPaintingWindow )
2021-01-10 16:33:06 +00:00
EndPaint ( g_hFrameWindow , & ps ) ;
2020-11-23 19:21:20 +00:00
else
2021-01-10 16:33:06 +00:00
ReleaseDC ( g_hFrameWindow , dc ) ;
2020-11-23 19:21:20 +00:00
}
//===========================================================================
2021-01-10 16:33:06 +00:00
bool Win32Frame : : IsFullScreen ( void )
2020-11-23 19:21:20 +00:00
{
return g_bIsFullScreen ;
}
2021-01-10 16:33:06 +00:00
bool Win32Frame : : GetFullScreenShowSubunitStatus ( void )
2020-11-23 19:21:20 +00:00
{
return g_bFullScreen_ShowSubunitStatus ;
}
2020-12-24 15:08:50 +00:00
void Win32Frame : : SetFullScreenShowSubunitStatus ( bool bShow )
2020-11-23 19:21:20 +00:00
{
g_bFullScreen_ShowSubunitStatus = bShow ;
}
2021-01-10 16:33:06 +00:00
void Win32Frame : : FrameDrawDiskLEDS ( )
{
FrameDrawDiskLEDS ( ( HDC ) 0 ) ;
}
2020-11-23 19:21:20 +00:00
//===========================================================================
2020-12-24 15:08:50 +00:00
void Win32Frame : : FrameDrawDiskLEDS ( HDC passdc )
2020-11-23 19:21:20 +00:00
{
g_eStatusDrive1 = DISK_STATUS_OFF ;
g_eStatusDrive2 = DISK_STATUS_OFF ;
// Slot6 drive takes priority unless it's off:
if ( GetCardMgr ( ) . QuerySlot ( SLOT6 ) = = CT_Disk2 )
dynamic_cast < Disk2InterfaceCard & > ( GetCardMgr ( ) . GetRef ( SLOT6 ) ) . GetLightStatus ( & g_eStatusDrive1 , & g_eStatusDrive2 ) ;
// Slot5:
{
Disk_Status_e eDrive1StatusSlot5 = DISK_STATUS_OFF ;
Disk_Status_e eDrive2StatusSlot5 = DISK_STATUS_OFF ;
if ( GetCardMgr ( ) . QuerySlot ( SLOT5 ) = = CT_Disk2 )
dynamic_cast < Disk2InterfaceCard & > ( GetCardMgr ( ) . GetRef ( SLOT5 ) ) . GetLightStatus ( & eDrive1StatusSlot5 , & eDrive2StatusSlot5 ) ;
if ( g_eStatusDrive1 = = DISK_STATUS_OFF ) g_eStatusDrive1 = eDrive1StatusSlot5 ;
if ( g_eStatusDrive2 = = DISK_STATUS_OFF ) g_eStatusDrive2 = eDrive2StatusSlot5 ;
}
// Draw Track/Sector
FrameReleaseDC ( ) ;
2021-01-10 16:33:06 +00:00
HDC dc = ( passdc ? passdc : GetDC ( g_hFrameWindow ) ) ;
2020-11-23 19:21:20 +00:00
int x = buttonx ;
int y = buttony + BUTTONS * BUTTONCY + 1 ;
if ( g_bIsFullScreen )
{
if ( ! g_bFullScreen_ShowSubunitStatus )
return ;
SelectObject ( dc , smallfont ) ;
SetBkMode ( dc , OPAQUE ) ;
SetBkColor ( dc , RGB ( 0 , 0 , 0 ) ) ;
SetTextAlign ( dc , TA_LEFT | TA_TOP ) ;
SetTextColor ( dc , g_aDiskFullScreenColorsLED [ g_eStatusDrive1 ] ) ;
TextOut ( dc , x + 3 , y + 2 , TEXT ( " 1 " ) , 1 ) ;
SetTextColor ( dc , g_aDiskFullScreenColorsLED [ g_eStatusDrive2 ] ) ;
TextOut ( dc , x + 13 , y + 2 , TEXT ( " 2 " ) , 1 ) ;
}
else
{
RECT rDiskLed = { 0 , 0 , 8 , 8 } ;
DrawBitmapRect ( dc , x + 12 , y + 6 , & rDiskLed , g_hDiskWindowedLED [ g_eStatusDrive1 ] ) ;
DrawBitmapRect ( dc , x + 31 , y + 6 , & rDiskLed , g_hDiskWindowedLED [ g_eStatusDrive2 ] ) ;
}
}
2021-01-10 16:33:06 +00:00
void Win32Frame : : FrameDrawDiskStatus ( )
{
FrameDrawDiskStatus ( ( HDC ) 0 ) ;
}
2020-11-23 19:21:20 +00:00
// Feature Request #201 Show track status
// https://github.com/AppleWin/AppleWin/issues/201
//===========================================================================
2020-12-24 15:08:50 +00:00
void Win32Frame : : FrameDrawDiskStatus ( HDC passdc )
2020-11-23 19:21:20 +00:00
{
if ( mem = = NULL )
return ;
if ( g_nAppMode = = MODE_LOGO )
return ;
if ( g_windowMinimized ) // Prevent DC leaks when app window is minimised (GH#820)
return ;
// We use the actual drive since probing from memory doesn't tell us anything we don't already know.
// DOS3.3 ProDOS
// Drive $B7EA $BE3D
// Track $B7EC LC1 $D356
// Sector $B7ED LC1 $D357
// RWTS LC1 $D300
if ( GetCardMgr ( ) . QuerySlot ( SLOT6 ) ! = CT_Disk2 )
return ;
Disk2InterfaceCard & disk2Card = dynamic_cast < Disk2InterfaceCard & > ( GetCardMgr ( ) . GetRef ( SLOT6 ) ) ;
int nActiveFloppy = disk2Card . GetCurrentDrive ( ) ;
int nDisk1Track = disk2Card . GetTrack ( DRIVE_1 ) ;
int nDisk2Track = disk2Card . GetTrack ( DRIVE_2 ) ;
// Probe known OS's for Track/Sector
int isProDOS = mem [ 0xBF00 ] = = 0x4C ;
bool isValid = true ;
// Try DOS3.3 Sector
if ( ! isProDOS )
{
int nDOS33track = mem [ 0xB7EC ] ;
int nDOS33sector = mem [ 0xB7ED ] ;
if ( ( nDOS33track > = 0 & & nDOS33track < 40 )
& & ( nDOS33sector > = 0 & & nDOS33sector < 16 ) )
{
# if _DEBUG && 0
if ( nDOS33track ! = nDisk1Track )
{
2022-02-13 21:37:05 +00:00
LogOutput ( " \n \n \n WARNING: DOS33Track: %d (%02X) != nDisk1Track: %d (%02X) \n \n \n " , nDOS33track , nDOS33track , nDisk1Track , nDisk1Track ) ;
2020-11-23 19:21:20 +00:00
}
# endif // _DEBUG
/**/ if ( nActiveFloppy = = 0 ) g_nSectorDrive1 = nDOS33sector ;
else if ( nActiveFloppy = = 1 ) g_nSectorDrive2 = nDOS33sector ;
}
else
isValid = false ;
}
else // isProDOS
{
// we can't just read from mem[ 0xD357 ] since it might be bank-switched from ROM
// and we need the Language Card RAM
// memrom[ 0xD350 ] = " ERROR\x07\x00" Applesoft error message
// T S
int nProDOStrack = * MemGetMainPtr ( 0xC356 ) ; // LC1 $D356
int nProDOSsector = * MemGetMainPtr ( 0xC357 ) ; // LC1 $D357
if ( ( nProDOStrack > = 0 & & nProDOStrack < 40 )
& & ( nProDOSsector > = 0 & & nProDOSsector < 16 ) )
{
/**/ if ( nActiveFloppy = = 0 ) g_nSectorDrive1 = nProDOSsector ;
else if ( nActiveFloppy = = 1 ) g_nSectorDrive2 = nProDOSsector ;
}
else
isValid = false ;
}
g_nTrackDrive1 = nDisk1Track ;
g_nTrackDrive2 = nDisk2Track ;
if ( ! isValid )
{
if ( nActiveFloppy = = 0 ) g_nSectorDrive1 = - 1 ;
else g_nSectorDrive2 = - 1 ;
}
2022-02-26 17:54:06 +00:00
g_strTrackDrive1 = StrFormat ( " %2d " , g_nTrackDrive1 ) ;
g_strSectorDrive1 = ( g_nSectorDrive1 < 0 ) ? " ?? " : StrFormat ( " %2d " , g_nSectorDrive1 ) ;
2020-11-23 19:21:20 +00:00
2022-02-26 17:54:06 +00:00
g_strTrackDrive2 = StrFormat ( " %2d " , g_nTrackDrive2 ) ;
g_strSectorDrive2 = ( g_nSectorDrive2 < 0 ) ? " ?? " : StrFormat ( " %2d " , g_nSectorDrive2 ) ;
2020-11-23 19:21:20 +00:00
// Draw Track/Sector
FrameReleaseDC ( ) ;
2021-01-10 16:33:06 +00:00
HDC dc = ( passdc ? passdc : GetDC ( g_hFrameWindow ) ) ;
2020-11-23 19:21:20 +00:00
int x = buttonx ;
int y = buttony + BUTTONS * BUTTONCY + 4 ;
SelectObject ( dc , smallfont ) ;
SetBkMode ( dc , OPAQUE ) ;
SetBkColor ( dc , RGB ( 0 , 0 , 0 ) ) ;
SetTextAlign ( dc , TA_LEFT | TA_TOP ) ;
if ( g_bIsFullScreen )
{
// GH#57 - drive lights in full screen mode
if ( ! g_bFullScreen_ShowSubunitStatus )
return ;
2022-02-26 17:54:06 +00:00
SetTextColor ( dc , g_aDiskFullScreenColorsLED [ g_eStatusDrive1 ] ) ;
TextOut ( dc , x + 3 , y + 2 , TEXT ( " 1 " ) , 1 ) ;
2020-11-23 19:21:20 +00:00
2022-02-26 17:54:06 +00:00
SetTextColor ( dc , g_aDiskFullScreenColorsLED [ g_eStatusDrive2 ] ) ;
TextOut ( dc , x + 13 , y + 2 , TEXT ( " 2 " ) , 1 ) ;
2020-11-23 19:21:20 +00:00
int dx = 0 ;
2022-02-26 17:54:06 +00:00
std : : string text = ( nActiveFloppy = = 0 )
? StrFormat ( " %s/%s " , g_strTrackDrive1 . c_str ( ) , g_strSectorDrive1 . c_str ( ) )
: StrFormat ( " %s/%s " , g_strTrackDrive2 . c_str ( ) , g_strSectorDrive2 . c_str ( ) ) ;
2020-11-23 19:21:20 +00:00
SetTextColor ( dc , g_aDiskFullScreenColorsLED [ DISK_STATUS_READ ] ) ;
2022-02-26 17:54:06 +00:00
TextOut ( dc , x + dx , y - 12 , text . c_str ( ) , text . length ( ) ) ; // original: y+2; y-12 puts status in the Configuration Button Icon
2020-11-23 19:21:20 +00:00
}
else
{
// NB. Only draw Track/Sector if 2x windowed
if ( g_nViewportScale = = 1 )
return ;
// Erase background
2022-02-26 17:54:06 +00:00
SelectObject ( dc , GetStockObject ( NULL_PEN ) ) ;
SelectObject ( dc , btnfacebrush ) ;
Rectangle ( dc , x + 4 , y + 32 , x + BUTTONCX + 1 , y + 56 ) ; // y+35 -> 44 -> 56
SetTextColor ( dc , RGB ( 0 , 0 , 0 ) ) ;
SetBkMode ( dc , TRANSPARENT ) ;
std : : string text ;
text = " T " + g_strTrackDrive1 ;
TextOut ( dc , x + 6 , y + 32 , text . c_str ( ) , text . length ( ) ) ;
text = " S " + g_strSectorDrive1 ;
TextOut ( dc , x + 6 , y + 42 , text . c_str ( ) , text . length ( ) ) ;
text = " T " + g_strTrackDrive2 ;
TextOut ( dc , x + 26 , y + 32 , text . c_str ( ) , text . length ( ) ) ;
text = " S " + g_strSectorDrive2 ;
TextOut ( dc , x + 26 , y + 42 , text . c_str ( ) , text . length ( ) ) ;
2020-11-23 19:21:20 +00:00
}
}
//===========================================================================
2021-01-10 16:33:06 +00:00
void Win32Frame : : DrawStatusArea ( HDC passdc , int drawflags )
2020-11-23 19:21:20 +00:00
{
2021-01-10 16:33:06 +00:00
if ( g_hFrameWindow = = NULL )
2020-11-23 19:21:20 +00:00
{
// TC: Fix drawing of drive buttons before frame created:
// . Main init loop: LoadConfiguration() called before FrameCreateWindow(), eg:
2020-12-24 15:08:50 +00:00
// LoadConfiguration() -> Disk_LoadLastDiskImage() -> DiskInsert() -> GetFrame().FrameRefreshStatus()
2020-11-23 19:21:20 +00:00
return ;
}
FrameReleaseDC ( ) ;
2021-01-10 16:33:06 +00:00
HDC dc = ( passdc ? passdc : GetDC ( g_hFrameWindow ) ) ;
2020-11-23 19:21:20 +00:00
int x = buttonx ;
int y = buttony + BUTTONS * BUTTONCY + 1 ;
const bool bCaps = KeybGetCapsStatus ( ) ;
Disk_Status_e eHardDriveStatus = DISK_STATUS_OFF ;
2021-11-01 20:12:42 +00:00
if ( GetCardMgr ( ) . QuerySlot ( SLOT7 ) = = CT_GenericHDD )
dynamic_cast < HarddiskInterfaceCard & > ( GetCardMgr ( ) . GetRef ( SLOT7 ) ) . GetLightStatus ( & eHardDriveStatus ) ;
2020-11-23 19:21:20 +00:00
if ( g_bIsFullScreen )
{
if ( ! g_bFullScreen_ShowSubunitStatus )
{
// Erase Config button icon too, as trk/sec is written here - see FrameDrawDiskStatus()
RECT rect = { x - 2 , y - BUTTONCY , x + BUTTONCX + 2 , y + BUTTONCY } ; // Extend rect's width by +/-2 as the TITLE_PAUSED text is wider than an icon button
FillRect ( dc , & rect , ( HBRUSH ) GetStockObject ( BLACK_BRUSH ) ) ;
}
else
{
SelectObject ( dc , smallfont ) ;
if ( drawflags & DRAW_DISK_STATUS )
2021-01-10 16:33:06 +00:00
{
FrameDrawDiskStatus ( dc ) ;
}
2020-11-23 19:21:20 +00:00
SetTextAlign ( dc , TA_RIGHT | TA_TOP ) ;
SetTextColor ( dc , g_aDiskFullScreenColorsLED [ eHardDriveStatus ] ) ;
TextOut ( dc , x + 23 , y + 2 , TEXT ( " H " ) , 1 ) ;
if ( ! IS_APPLE2 )
{
SetTextAlign ( dc , TA_RIGHT | TA_TOP ) ;
SetTextColor ( dc , ( bCaps
? RGB ( 128 , 128 , 128 )
: RGB ( 0 , 0 , 0 ) ) ) ;
TextOut ( dc , x + BUTTONCX , y + 2 , TEXT ( " A " ) , 1 ) ; // NB. Caps Lock indicator is already flush right!
}
//
static const char * pCurrentAppModeText = NULL ;
const char * const pNewAppModeText = ( g_nAppMode = = MODE_PAUSED )
? TITLE_PAUSED
: ( g_nAppMode = = MODE_STEPPING )
? TITLE_STEPPING
: NULL ;
SetTextAlign ( dc , TA_CENTER | TA_TOP ) ;
if ( pCurrentAppModeText & & pNewAppModeText ! = pCurrentAppModeText )
{
SetTextColor ( dc , RGB ( 0 , 0 , 0 ) ) ;
TextOut ( dc , x + BUTTONCX / 2 , y + 13 , pCurrentAppModeText , strlen ( pCurrentAppModeText ) ) ;
pCurrentAppModeText = NULL ;
}
if ( pNewAppModeText )
{
SetTextColor ( dc , RGB ( 255 , 255 , 255 ) ) ;
TextOut ( dc , x + BUTTONCX / 2 , y + 13 , pNewAppModeText , strlen ( pNewAppModeText ) ) ;
pCurrentAppModeText = pNewAppModeText ;
}
}
}
else // !g_bIsFullScreen
{
if ( drawflags & DRAW_BACKGROUND )
{
SelectObject ( dc , GetStockObject ( NULL_PEN ) ) ;
SelectObject ( dc , btnfacebrush ) ;
Rectangle ( dc , x , y , x + BUTTONCX + 2 , y + 34 ) ;
Draw3dRect ( dc , x + 1 , y + 3 , x + BUTTONCX , y + 30 , 0 ) ;
SelectObject ( dc , smallfont ) ;
SetTextAlign ( dc , TA_CENTER | TA_TOP ) ;
SetTextColor ( dc , RGB ( 0 , 0 , 0 ) ) ;
SetBkMode ( dc , TRANSPARENT ) ;
TextOut ( dc , x + 7 , y + 5 , TEXT ( " 1 " ) , 1 ) ;
TextOut ( dc , x + 27 , y + 5 , TEXT ( " 2 " ) , 1 ) ;
// 1.19.0.0 Hard Disk Status/Indicator Light
TextOut ( dc , x + 7 , y + 17 , TEXT ( " H " ) , 1 ) ;
}
if ( drawflags & DRAW_LEDS )
{
2021-01-10 16:33:06 +00:00
FrameDrawDiskLEDS ( dc ) ;
2020-11-23 19:21:20 +00:00
if ( drawflags & DRAW_DISK_STATUS )
2021-01-10 16:33:06 +00:00
FrameDrawDiskStatus ( dc ) ;
2020-11-23 19:21:20 +00:00
if ( ! IS_APPLE2 )
{
RECT rCapsLed = { 0 , 0 , 10 , 12 } ; // HACK: HARD-CODED bitmaps size
switch ( g_Apple2Type )
{
case A2TYPE_APPLE2 :
case A2TYPE_APPLE2PLUS :
case A2TYPE_APPLE2E :
case A2TYPE_APPLE2EENHANCED :
default : DrawBitmapRect ( dc , x + 31 , y + 17 , & rCapsLed , g_hCapsLockBitmap [ bCaps ! = 0 ] ) ; break ;
case A2TYPE_PRAVETS82 :
case A2TYPE_PRAVETS8M : DrawBitmapRect ( dc , x + 31 , y + 17 , & rCapsLed , g_hCapsBitmapP8 [ bCaps ! = 0 ] ) ; break ; // TODO: FIXME: Shouldn't one of these use g_hCapsBitmapLat ??
case A2TYPE_PRAVETS8A : DrawBitmapRect ( dc , x + 31 , y + 17 , & rCapsLed , g_hCapsBitmapP8 [ bCaps ! = 0 ] ) ; break ;
}
RECT rDiskLed = { 0 , 0 , 8 , 8 } ;
DrawBitmapRect ( dc , x + 12 , y + 18 , & rDiskLed , g_hDiskWindowedLED [ eHardDriveStatus ] ) ;
}
}
if ( drawflags & DRAW_TITLE )
{
GetAppleWindowTitle ( ) ; // SetWindowText() // WindowTitle
2021-01-10 16:33:06 +00:00
SendMessage ( g_hFrameWindow , WM_SETTEXT , 0 , ( LPARAM ) g_pAppTitle . c_str ( ) ) ;
2020-11-23 19:21:20 +00:00
}
if ( drawflags & DRAW_BUTTON_DRIVES )
{
DrawButton ( dc , BTN_DRIVE1 ) ;
DrawButton ( dc , BTN_DRIVE2 ) ;
}
}
if ( ! passdc )
2021-01-10 16:33:06 +00:00
ReleaseDC ( g_hFrameWindow , dc ) ;
2020-11-23 19:21:20 +00:00
}
//===========================================================================
2021-01-10 16:33:06 +00:00
void Win32Frame : : EraseButton ( int number ) {
2020-11-23 19:21:20 +00:00
RECT rect ;
rect . left = buttonx ;
rect . right = rect . left + BUTTONCX ;
rect . top = buttony + number * BUTTONCY ;
rect . bottom = rect . top + BUTTONCY ;
2021-01-10 16:33:06 +00:00
InvalidateRect ( g_hFrameWindow , & rect , 1 ) ;
2020-11-23 19:21:20 +00:00
}
//===========================================================================
2021-01-16 21:57:28 +00:00
LRESULT CALLBACK Win32Frame : : FrameWndProc (
2021-01-10 16:33:06 +00:00
HWND window ,
UINT message ,
WPARAM wparam ,
LPARAM lparam )
{
Win32Frame & win32Frame = Win32Frame : : GetWin32Frame ( ) ;
return win32Frame . WndProc ( window , message , wparam , lparam ) ;
}
LRESULT Win32Frame : : WndProc (
2020-11-23 19:21:20 +00:00
HWND window ,
UINT message ,
WPARAM wparam ,
LPARAM lparam )
{
switch ( message )
{
case WM_ACTIVATE : // Sent when window is activated/deactivated. wParam indicates WA_ACTIVE, WA_INACTIVE, etc
// Eg. Deactivate when Config dialog is active, AppleWin app loses focus, etc
JoyReset ( ) ;
SetUsingCursor ( FALSE ) ;
RevealCursor ( ) ;
FullScreenRevealCursor ( ) ;
g_bFrameActive = ( wparam ! = WA_INACTIVE ) ;
break ;
case WM_ACTIVATEAPP : // Sent when different app's window is activated/deactivated.
// Eg. Deactivate when AppleWin app loses focus
g_bAppActive = ( wparam ? TRUE : FALSE ) ;
break ;
case WM_SIZE :
switch ( wparam )
{
case SIZE_RESTORED :
case SIZE_MAXIMIZED :
g_windowMinimized = false ;
break ;
case SIZE_MINIMIZED :
g_windowMinimized = true ;
break ;
default : // SIZE_MAXSHOW, SIZE_MAXHIDE
break ;
}
break ;
case WM_CLOSE :
LogFileOutput ( " WM_CLOSE \n " ) ;
if ( g_bIsFullScreen & & g_bRestart )
g_bRestartFullScreen = true ;
if ( g_bIsFullScreen )
SetNormalMode ( ) ;
if ( ! IsIconic ( window ) )
GetWindowRect ( window , & framerect ) ;
RegSaveValue ( TEXT ( REG_PREFS ) , TEXT ( REGVALUE_PREF_WINDOW_X_POS ) , 1 , framerect . left ) ;
RegSaveValue ( TEXT ( REG_PREFS ) , TEXT ( REGVALUE_PREF_WINDOW_Y_POS ) , 1 , framerect . top ) ;
FrameReleaseDC ( ) ;
SetUsingCursor ( FALSE ) ;
if ( helpquit ) {
helpquit = 0 ;
HtmlHelp ( NULL , NULL , HH_CLOSE_ALL , 0 ) ;
}
if ( g_TimerIDEvent_100msec )
{
2021-01-10 16:33:06 +00:00
BOOL bRes = KillTimer ( g_hFrameWindow , g_TimerIDEvent_100msec ) ;
2020-11-23 19:21:20 +00:00
LogFileOutput ( " KillTimer(g_TimerIDEvent_100msec), res=%d \n " , bRes ? 1 : 0 ) ;
g_TimerIDEvent_100msec = 0 ;
}
LogFileOutput ( " WM_CLOSE (done) \n " ) ;
// Exit via DefWindowProc(), which does the default action for WM_CLOSE, which is to call DestroyWindow(), posting WM_DESTROY
break ;
case WM_DESTROY :
LogFileOutput ( " WM_DESTROY \n " ) ;
DragAcceptFiles ( window , 0 ) ;
if ( ! g_bRestart ) // GH#564: Only save-state on shutdown (not on a restart)
Snapshot_Shutdown ( ) ;
DebugDestroy ( ) ;
if ( ! g_bRestart ) {
2022-03-11 22:17:03 +00:00
GetCardMgr ( ) . Destroy ( ) ;
2020-11-23 19:21:20 +00:00
}
CpuDestroy ( ) ;
MemDestroy ( ) ;
SpkrDestroy ( ) ;
2021-01-10 16:33:06 +00:00
Destroy ( ) ;
2020-11-23 19:21:20 +00:00
MB_Destroy ( ) ;
DeleteGdiObjects ( ) ;
DIMouse : : DirectInputUninit ( window ) ; // NB. do before window is destroyed
PostQuitMessage ( 0 ) ; // Post WM_QUIT message to the thread's message queue
2021-01-19 20:37:43 +00:00
g_hFrameWindow = ( HWND ) 0 ;
2020-11-23 19:21:20 +00:00
LogFileOutput ( " WM_DESTROY (done) \n " ) ;
break ;
case WM_CREATE :
LogFileOutput ( " WM_CREATE \n " ) ;
2021-01-10 16:33:06 +00:00
g_hFrameWindow = window ; // NB. g_hFrameWindow by CreateWindow()
2020-11-23 19:21:20 +00:00
CreateGdiObjects ( ) ;
LogFileOutput ( " WM_CREATE: CreateGdiObjects() \n " ) ;
DSInit ( ) ;
LogFileOutput ( " WM_CREATE: DSInit() \n " ) ;
DIMouse : : DirectInputInit ( window ) ;
LogFileOutput ( " WM_CREATE: DIMouse::DirectInputInit() \n " ) ;
MB_Initialize ( ) ;
LogFileOutput ( " WM_CREATE: MB_Initialize() \n " ) ;
SpkrInitialize ( ) ;
LogFileOutput ( " WM_CREATE: SpkrInitialize() \n " ) ;
DragAcceptFiles ( window , 1 ) ;
LogFileOutput ( " WM_CREATE: DragAcceptFiles() \n " ) ;
LogFileOutput ( " WM_CREATE (done) \n " ) ;
break ;
case WM_DDE_INITIATE : {
LogFileOutput ( " WM_DDE_INITIATE \n " ) ;
ATOM application = GlobalAddAtom ( TEXT ( " applewin " ) ) ;
ATOM topic = GlobalAddAtom ( TEXT ( " system " ) ) ;
if ( LOWORD ( lparam ) = = application & & HIWORD ( lparam ) = = topic )
SendMessage ( ( HWND ) wparam , WM_DDE_ACK , ( WPARAM ) window , MAKELPARAM ( application , topic ) ) ;
GlobalDeleteAtom ( application ) ;
GlobalDeleteAtom ( topic ) ;
LogFileOutput ( " WM_DDE_INITIATE (done) \n " ) ;
break ;
}
case WM_DDE_EXECUTE :
{
LogFileOutput ( " WM_DDE_EXECUTE \n " ) ;
if ( GetCardMgr ( ) . QuerySlot ( SLOT6 ) = = CT_Disk2 )
{
Disk2InterfaceCard & disk2Card = dynamic_cast < Disk2InterfaceCard & > ( GetCardMgr ( ) . GetRef ( SLOT6 ) ) ;
LPTSTR filename = ( LPTSTR ) GlobalLock ( ( HGLOBAL ) lparam ) ;
ImageError_e Error = disk2Card . InsertDisk ( DRIVE_1 , filename , IMAGE_USE_FILES_WRITE_PROTECT_STATUS , IMAGE_DONT_CREATE ) ;
if ( Error = = eIMAGE_ERROR_NONE )
{
if ( ! g_bIsFullScreen )
DrawButton ( ( HDC ) 0 , BTN_DRIVE1 ) ;
PostMessage ( window , WM_USER_BOOT , 0 , 0 ) ;
}
else
{
disk2Card . NotifyInvalidImage ( DRIVE_1 , filename , Error ) ;
}
}
GlobalUnlock ( ( HGLOBAL ) lparam ) ;
LogFileOutput ( " WM_DDE_EXECUTE (done) \n " ) ;
break ;
}
case WM_DISPLAYCHANGE :
2021-01-13 22:02:48 +00:00
GetVideo ( ) . VideoReinitialize ( false ) ;
2020-11-23 19:21:20 +00:00
break ;
case WM_DROPFILES :
{
if ( GetCardMgr ( ) . QuerySlot ( SLOT6 ) = = CT_Disk2 )
{
Disk2InterfaceCard & disk2Card = dynamic_cast < Disk2InterfaceCard & > ( GetCardMgr ( ) . GetRef ( SLOT6 ) ) ;
TCHAR filename [ MAX_PATH ] ;
DragQueryFile ( ( HDROP ) wparam , 0 , filename , sizeof ( filename ) ) ;
POINT point ;
DragQueryPoint ( ( HDROP ) wparam , & point ) ;
RECT rect ;
rect . left = buttonx ;
rect . right = rect . left + BUTTONCX + 1 ;
rect . top = buttony + BTN_DRIVE2 * BUTTONCY + 1 ;
rect . bottom = rect . top + BUTTONCY ;
const int iDrive = PtInRect ( & rect , point ) ? DRIVE_2 : DRIVE_1 ;
ImageError_e Error = disk2Card . InsertDisk ( iDrive , filename , IMAGE_USE_FILES_WRITE_PROTECT_STATUS , IMAGE_DONT_CREATE ) ;
if ( Error = = eIMAGE_ERROR_NONE )
{
if ( ! g_bIsFullScreen )
DrawButton ( ( HDC ) 0 , PtInRect ( & rect , point ) ? BTN_DRIVE2 : BTN_DRIVE1 ) ;
rect . top = buttony + BTN_DRIVE1 * BUTTONCY + 1 ;
if ( ! PtInRect ( & rect , point ) )
{
SetForegroundWindow ( window ) ;
ProcessButtonClick ( BTN_RUN ) ;
}
}
else
{
disk2Card . NotifyInvalidImage ( iDrive , filename , Error ) ;
}
}
DragFinish ( ( HDROP ) wparam ) ;
break ;
}
// @see: http://answers.google.com/answers/threadview?id=133059
// Win32 doesn't pass the PrintScreen key via WM_CHAR
// else if (wparam == VK_SNAPSHOT)
// Solution: 2 choices:
// 1) register hotkey, or
// 2) Use low level Keyboard hooks
// We use the 1st one since it is compatible with Win95
case WM_HOTKEY :
// wparam = user id
// lparam = modifiers: shift, ctrl, alt, win
if ( wparam = = VK_SNAPSHOT_560 )
{
2021-01-10 16:33:06 +00:00
Video_TakeScreenShot ( Video : : SCREENSHOT_560x384 ) ;
2020-11-23 19:21:20 +00:00
}
else
if ( wparam = = VK_SNAPSHOT_280 ) // ( lparam & MOD_SHIFT )
{
2021-01-10 16:33:06 +00:00
Video_TakeScreenShot ( Video : : SCREENSHOT_280x192 ) ;
2020-11-23 19:21:20 +00:00
}
else
if ( wparam = = VK_SNAPSHOT_TEXT ) // ( lparam & MOD_CONTROL )
{
char * pText ;
size_t nSize = 0 ;
// if viewing the debugger, get the last virtual debugger screen
if ( ( g_nAppMode = = MODE_DEBUG ) & & ! DebugGetVideoMode ( NULL ) )
nSize = Util_GetDebuggerText ( pText ) ;
else
nSize = Util_GetTextScreen ( pText ) ;
Util_CopyTextToClipboard ( nSize , pText ) ;
}
break ;
case WM_KEYDOWN :
KeybUpdateCtrlShiftStatus ( ) ;
// Processing is done in WM_KEYUP for: VK_F1 VK_F2 VK_F3 VK_F4 VK_F5 VK_F6 VK_F7 VK_F8
if ( ( wparam > = VK_F1 ) & & ( wparam < = VK_F8 ) & & ( buttondown = = - 1 ) )
{
SetUsingCursor ( FALSE ) ;
buttondown = wparam - VK_F1 ;
if ( g_bIsFullScreen & & ( buttonover ! = - 1 ) ) {
if ( buttonover ! = buttondown )
EraseButton ( buttonover ) ;
buttonover = - 1 ;
}
DrawButton ( ( HDC ) 0 , buttondown ) ;
}
else if ( wparam = = VK_F9 )
{
// F9 Next Video Mode
// SHIFT+F9 Prev Video Mode
// CTRL+SHIFT+F9 Toggle 50% Scan Lines
// ALT+F9 Can't use Alt-F9 as Alt is Open-Apple = Joystick Button #1
if ( ! KeybGetCtrlStatus ( ) & & ! KeybGetShiftStatus ( ) ) // F9
{
2020-12-28 16:25:29 +00:00
GetVideo ( ) . IncVideoType ( ) ;
2020-11-23 19:21:20 +00:00
}
else if ( ! KeybGetCtrlStatus ( ) & & KeybGetShiftStatus ( ) ) // SHIFT+F9
{
2020-12-28 16:25:29 +00:00
GetVideo ( ) . DecVideoType ( ) ;
2020-11-23 19:21:20 +00:00
}
else if ( KeybGetCtrlStatus ( ) & & KeybGetShiftStatus ( ) ) // CTRL+SHIFT+F9
{
2020-12-28 16:25:29 +00:00
GetVideo ( ) . SetVideoStyle ( ( VideoStyle_e ) ( GetVideo ( ) . GetVideoStyle ( ) ^ VS_HALF_SCANLINES ) ) ;
2020-11-23 19:21:20 +00:00
}
// TODO: Clean up code:FrameRefreshStatus(DRAW_TITLE) DrawStatusArea((HDC)0,DRAW_TITLE)
DrawStatusArea ( ( HDC ) 0 , DRAW_TITLE ) ;
2021-01-13 22:02:48 +00:00
ApplyVideoModeChange ( ) ;
2020-11-23 19:21:20 +00:00
}
else if ( wparam = = VK_F10 )
{
if ( g_Apple2Type = = A2TYPE_APPLE2E | | g_Apple2Type = = A2TYPE_APPLE2EENHANCED | | g_Apple2Type = = A2TYPE_BASE64A )
{
2020-12-28 16:25:29 +00:00
GetVideo ( ) . SetVideoRomRockerSwitch ( ! GetVideo ( ) . GetVideoRomRockerSwitch ( ) ) ; // F10: toggle rocker switch
2020-11-23 19:21:20 +00:00
NTSC_VideoInitAppleType ( ) ;
}
else if ( g_Apple2Type = = A2TYPE_PRAVETS8A )
{
2021-01-17 10:48:06 +00:00
GetPravets ( ) . ToggleP8ACapsLock ( ) ; // F10: Toggles Pravets8A Capslock
2020-11-23 19:21:20 +00:00
}
}
else if ( wparam = = VK_F11 & & ! KeybGetCtrlStatus ( ) ) // Save state (F11)
{
SoundCore_SetFade ( FADE_OUT ) ;
2020-12-20 15:32:51 +00:00
if ( GetPropertySheet ( ) . SaveStateSelectImage ( window , true ) )
2020-11-23 19:21:20 +00:00
{
Snapshot_SaveState ( ) ;
}
SoundCore_SetFade ( FADE_IN ) ;
}
else if ( wparam = = VK_F12 ) // Load state (F12 or Ctrl+F12)
{
SoundCore_SetFade ( FADE_OUT ) ;
2020-12-20 15:32:51 +00:00
if ( GetPropertySheet ( ) . SaveStateSelectImage ( window , false ) )
2020-11-23 19:21:20 +00:00
{
Snapshot_LoadState ( ) ;
}
SoundCore_SetFade ( FADE_IN ) ;
}
else if ( wparam = = VK_CAPITAL )
{
KeybToggleCapsLock ( ) ;
}
else if ( wparam = = VK_PAUSE )
{
SetUsingCursor ( FALSE ) ;
switch ( g_nAppMode )
{
case MODE_RUNNING :
g_nAppMode = MODE_PAUSED ;
SoundCore_SetFade ( FADE_OUT ) ;
RevealCursor ( ) ;
break ;
case MODE_PAUSED :
g_nAppMode = MODE_RUNNING ;
SoundCore_SetFade ( FADE_IN ) ;
// Don't call FrameShowCursor(FALSE) else ClipCursor() won't be called
break ;
case MODE_STEPPING :
SoundCore_SetFade ( FADE_OUT ) ;
DebugStopStepping ( ) ;
break ;
}
DrawStatusArea ( ( HDC ) 0 , DRAW_TITLE ) ;
if ( ( g_nAppMode ! = MODE_LOGO ) & & ( g_nAppMode ! = MODE_DEBUG ) )
2021-01-10 16:33:06 +00:00
VideoRedrawScreen ( ) ;
2020-11-23 19:21:20 +00:00
}
2020-12-20 15:32:51 +00:00
else if ( ( wparam = = VK_SCROLL ) & & GetPropertySheet ( ) . GetScrollLockToggle ( ) )
2020-11-23 19:21:20 +00:00
{
g_bScrollLock_FullSpeed = ! g_bScrollLock_FullSpeed ;
}
else if ( ( g_nAppMode = = MODE_RUNNING ) | | ( g_nAppMode = = MODE_LOGO ) | | ( g_nAppMode = = MODE_STEPPING ) )
{
// NB. Alt Gr (Right-Alt): this normally send 2 WM_KEYDOWN messages for: VK_LCONTROL, then VK_RMENU
// . NB. The keyboard hook filter will suppress VK_LCONTROL (if -hook-altgr-control is passed on the cmd-line)
bool extended = ( HIWORD ( lparam ) & KF_EXTENDED ) ! = 0 ;
bool down = true ;
bool autorep = ( HIWORD ( lparam ) & KF_REPEAT ) ! = 0 ;
BOOL IsJoyKey = JoyProcessKey ( ( int ) wparam , extended , down , autorep ) ;
# if DEBUG_KEY_MESSAGES
LogOutput ( " WM_KEYDOWN: %08X (scanCode=%04X) \n " , wparam , ( lparam > > 16 ) & 0xfff ) ;
# endif
if ( ! IsJoyKey & &
( g_nAppMode ! = MODE_LOGO ) ) // !MODE_LOGO - not emulating so don't pass to the VM's keyboard
{
// GH#678 Alternate key(s) to toggle max speed
// . Ctrl-0: Toggle speed: custom speed / Full-Speed
// . Ctrl-1: Speed = 1 MHz
// . Ctrl-3: Speed = Full-Speed
bool keyHandled = false ;
if ( KeybGetCtrlStatus ( ) & &
! KeybGetAltStatus ( ) & & // GH#749 - AltGr also fakes CTRL being pressed!
wparam > = ' 0 ' & & wparam < = ' 9 ' )
{
switch ( wparam )
{
case ' 0 ' : // Toggle speed: custom speed / Full-Speed
if ( g_dwSpeed = = SPEED_MAX )
REGLOAD_DEFAULT ( TEXT ( REGVALUE_EMULATION_SPEED ) , & g_dwSpeed , SPEED_NORMAL ) ;
else
g_dwSpeed = SPEED_MAX ;
keyHandled = true ; break ;
case ' 1 ' : // Speed = 1 MHz
g_dwSpeed = SPEED_NORMAL ;
REGSAVE ( TEXT ( REGVALUE_EMULATION_SPEED ) , g_dwSpeed ) ;
keyHandled = true ; break ;
case ' 3 ' : // Speed = Full-Speed
g_dwSpeed = SPEED_MAX ;
keyHandled = true ; break ;
default :
break ;
}
if ( keyHandled )
SetCurrentCLK6502 ( ) ;
}
if ( ! keyHandled )
KeybQueueKeypress ( wparam , NOT_ASCII ) ;
if ( ! autorep )
KeybAnyKeyDown ( WM_KEYDOWN , wparam , extended ) ;
}
}
else if ( g_nAppMode = = MODE_DEBUG )
{
DebuggerProcessKey ( wparam ) ; // Debugger already active, re-direct key to debugger
}
break ;
case WM_CHAR :
if ( ( g_nAppMode = = MODE_RUNNING ) | | ( g_nAppMode = = MODE_STEPPING ) | | ( g_nAppMode = = MODE_LOGO ) )
{
if ( ! g_bDebuggerEatKey )
{
# if DEBUG_KEY_MESSAGES
LogOutput ( " WM_CHAR: %08X \n " , wparam ) ;
# endif
if ( g_nAppMode ! = MODE_LOGO ) // !MODE_LOGO - not emulating so don't pass to the VM's keyboard
KeybQueueKeypress ( wparam , ASCII ) ;
}
g_bDebuggerEatKey = false ;
}
else if ( g_nAppMode = = MODE_DEBUG )
{
DebuggerInputConsoleChar ( ( TCHAR ) wparam ) ;
}
break ;
case WM_KEYUP :
if ( ( wparam > = VK_F1 ) & & ( wparam < = VK_F8 ) & & ( buttondown = = ( int ) wparam - VK_F1 ) )
{
buttondown = - 1 ;
if ( g_bIsFullScreen )
EraseButton ( wparam - VK_F1 ) ;
else
DrawButton ( ( HDC ) 0 , wparam - VK_F1 ) ;
const int iButton = wparam - VK_F1 ;
if ( KeybGetCtrlStatus ( ) & & ( wparam = = VK_F3 | | wparam = = VK_F4 ) ) // Ctrl+F3/F4 for drive pop-up menu (GH#817)
{
POINT pt ; // location of mouse click
pt . x = buttonx + BUTTONCX / 2 ;
pt . y = buttony + BUTTONCY / 2 + iButton * BUTTONCY ;
const int iDrive = wparam - VK_F3 ;
ProcessDiskPopupMenu ( window , pt , iDrive ) ;
2021-01-10 16:33:06 +00:00
FrameRefreshStatus ( DRAW_LEDS | DRAW_BUTTON_DRIVES | DRAW_DISK_STATUS ) ;
2020-11-23 19:21:20 +00:00
DrawButton ( ( HDC ) 0 , iButton ) ;
}
else
{
ProcessButtonClick ( iButton , true ) ;
}
}
else
{
bool extended = ( HIWORD ( lparam ) & KF_EXTENDED ) ! = 0 ;
bool down = false ;
bool autorep = false ;
BOOL bIsJoyKey = JoyProcessKey ( ( int ) wparam , extended , down , autorep ) ;
# if DEBUG_KEY_MESSAGES
LogOutput ( " WM_KEYUP: %08X \n " , wparam ) ;
# endif
if ( ! bIsJoyKey )
KeybAnyKeyDown ( WM_KEYUP , wparam , extended ) ;
}
break ;
case WM_LBUTTONDOWN :
KeybUpdateCtrlShiftStatus ( ) ;
if ( buttondown = = - 1 )
{
int x = LOWORD ( lparam ) ;
int y = HIWORD ( lparam ) ;
if ( ( x > = buttonx ) & &
( y > = buttony ) & &
( y < = buttony + BUTTONS * BUTTONCY ) )
{
buttonactive = buttondown = ( y - buttony - 1 ) / BUTTONCY ;
DrawButton ( ( HDC ) 0 , buttonactive ) ;
SetCapture ( window ) ;
}
else if ( g_bUsingCursor & & ! GetCardMgr ( ) . IsMouseCardInstalled ( ) )
{
if ( wparam & ( MK_CONTROL | MK_SHIFT ) )
{
SetUsingCursor ( FALSE ) ;
}
else
{
JoySetButton ( BUTTON0 , BUTTON_DOWN ) ;
}
}
else if ( ( ( x < buttonx ) & & JoyUsingMouse ( ) & & ( ( g_nAppMode = = MODE_RUNNING ) | | ( g_nAppMode = = MODE_STEPPING ) ) ) )
{
SetUsingCursor ( TRUE ) ;
}
else if ( GetCardMgr ( ) . IsMouseCardInstalled ( ) )
{
if ( wparam & ( MK_CONTROL | MK_SHIFT ) )
{
RevealCursor ( ) ;
}
else if ( g_nAppMode = = MODE_RUNNING | | g_nAppMode = = MODE_STEPPING )
{
CMouseInterface * pMouseCard = GetCardMgr ( ) . GetMouseCard ( ) ;
if ( pMouseCard )
{
if ( ! pMouseCard - > IsEnabled ( ) )
{
pMouseCard - > SetEnabled ( true ) ;
POINT Point ;
GetCursorPos ( & Point ) ;
2021-01-10 16:33:06 +00:00
ScreenToClient ( g_hFrameWindow , & Point ) ;
2020-11-23 19:21:20 +00:00
const int iOutOfBoundsX = 0 , iOutOfBoundsY = 0 ;
UpdateMouseInAppleViewport ( iOutOfBoundsX , iOutOfBoundsY , Point . x , Point . y ) ;
// Don't call SetButton() when 1st enabled (else get the confusing action of both enabling & an Apple mouse click)
}
else
{
pMouseCard - > SetButton ( BUTTON0 , BUTTON_DOWN ) ;
}
}
}
}
DebuggerMouseClick ( x , y ) ;
}
RelayEvent ( WM_LBUTTONDOWN , wparam , lparam ) ;
break ;
case WM_LBUTTONUP :
if ( buttonactive ! = - 1 ) {
ReleaseCapture ( ) ;
if ( buttondown = = buttonactive ) {
buttondown = - 1 ;
if ( g_bIsFullScreen )
EraseButton ( buttonactive ) ;
else
DrawButton ( ( HDC ) 0 , buttonactive ) ;
ProcessButtonClick ( buttonactive , true ) ;
}
buttonactive = - 1 ;
}
else if ( g_bUsingCursor & & ! GetCardMgr ( ) . IsMouseCardInstalled ( ) )
{
JoySetButton ( BUTTON0 , BUTTON_UP ) ;
}
else if ( GetCardMgr ( ) . IsMouseCardInstalled ( ) )
{
GetCardMgr ( ) . GetMouseCard ( ) - > SetButton ( BUTTON0 , BUTTON_UP ) ;
}
RelayEvent ( WM_LBUTTONUP , wparam , lparam ) ;
break ;
case WM_MOUSEMOVE : {
// MSDN: "WM_MOUSEMOVE message" : Do not use the LOWORD or HIWORD macros to extract the x- and y- coordinates...
int x = GET_X_LPARAM ( lparam ) ;
int y = GET_Y_LPARAM ( lparam ) ;
int newover = ( ( ( x > = buttonx ) & &
( x < = buttonx + BUTTONCX ) & &
( y > = buttony ) & &
( y < = buttony + BUTTONS * BUTTONCY ) )
? ( y - buttony - 1 ) / BUTTONCY : - 1 ) ;
if ( buttonactive ! = - 1 ) {
int newdown = ( newover = = buttonactive ) ? buttonactive : - 1 ;
if ( newdown ! = buttondown ) {
buttondown = newdown ;
DrawButton ( ( HDC ) 0 , buttonactive ) ;
}
}
else if ( g_bIsFullScreen & & ( newover ! = buttonover ) & & ( buttondown = = - 1 ) ) {
if ( buttonover ! = - 1 )
EraseButton ( buttonover ) ;
buttonover = newover ;
if ( buttonover ! = - 1 )
DrawButton ( ( HDC ) 0 , buttonover ) ;
}
else if ( g_bUsingCursor & & ! GetCardMgr ( ) . IsMouseCardInstalled ( ) )
{
DrawCrosshairs ( x , y ) ;
JoySetPosition ( x - viewportx - 2 , g_nViewportCX - 4 , y - viewporty - 2 , g_nViewportCY - 4 ) ;
}
else if ( GetCardMgr ( ) . IsMouseCardInstalled ( ) & & GetCardMgr ( ) . GetMouseCard ( ) - > IsActiveAndEnabled ( ) & & ( g_nAppMode = = MODE_RUNNING | | g_nAppMode = = MODE_STEPPING ) )
{
if ( g_bLastCursorInAppleViewport )
break ;
// Outside Apple viewport
const int iAppleScreenMaxX = g_nViewportCX - 1 ;
const int iAppleScreenMaxY = g_nViewportCY - 1 ;
const int iBoundMinX = viewportx ;
const int iBoundMaxX = iAppleScreenMaxX ;
const int iBoundMinY = viewporty ;
const int iBoundMaxY = iAppleScreenMaxY ;
int iOutOfBoundsX = 0 , iOutOfBoundsY = 0 ;
if ( x < iBoundMinX ) iOutOfBoundsX = - 1 ;
if ( x > iBoundMaxX ) iOutOfBoundsX = 1 ;
if ( y < iBoundMinY ) iOutOfBoundsY = - 1 ;
if ( y > iBoundMaxY ) iOutOfBoundsY = 1 ;
UpdateMouseInAppleViewport ( iOutOfBoundsX , iOutOfBoundsY , x , y ) ;
}
FullScreenRevealCursor ( ) ;
RelayEvent ( WM_MOUSEMOVE , wparam , lparam ) ;
break ;
}
case WM_TIMER :
if ( wparam = = IDEVENT_TIMER_MOUSE )
{
// NB. Need to check /g_bAppActive/ since WM_TIMER events still occur after AppleWin app has lost focus
if ( g_bAppActive & & GetCardMgr ( ) . IsMouseCardInstalled ( ) & & GetCardMgr ( ) . GetMouseCard ( ) - > IsActiveAndEnabled ( ) & & ( g_nAppMode = = MODE_RUNNING | | g_nAppMode = = MODE_STEPPING ) )
{
if ( ! g_bLastCursorInAppleViewport )
break ;
// Inside Apple viewport
int iOutOfBoundsX = 0 , iOutOfBoundsY = 0 ;
long dX , dY ;
if ( DIMouse : : ReadImmediateData ( & dX , & dY ) = = S_OK )
GetCardMgr ( ) . GetMouseCard ( ) - > SetPositionRel ( dX , dY , & iOutOfBoundsX , & iOutOfBoundsY ) ;
UpdateMouseInAppleViewport ( iOutOfBoundsX , iOutOfBoundsY ) ;
}
}
else if ( wparam = = IDEVENT_TIMER_100MSEC ) // GH#504
{
if ( g_bIsFullScreen
& & ! GetCardMgr ( ) . IsMouseCardInstalled ( ) // Don't interfere if there's a mousecard present!
& & ! g_bUsingCursor // Using mouse for joystick emulation (or mousecard restricted to window)
& & g_bShowingCursor
& & g_bFrameActive ) // Frame inactive when eg. Config or 'Select Disk Image' dialogs are opened
{
g_uCount100msec + + ;
if ( g_uCount100msec > 20 ) // Hide every 2sec of mouse inactivity
{
FrameShowCursor ( FALSE ) ;
}
}
}
break ;
// VSCROLL
// SB_LINEUP // Line Scrolling
// SB_PAGEUP // Page Scrolling
case WM_MOUSEWHEEL :
if ( g_nAppMode = = MODE_DEBUG )
{
KeybUpdateCtrlShiftStatus ( ) ;
int zDelta = ( short ) HIWORD ( wparam ) ;
if ( zDelta > 0 )
{
DebuggerProcessKey ( VK_UP ) ;
}
else
{
DebuggerProcessKey ( VK_DOWN ) ;
}
}
break ;
case WM_NOTIFY : // Tooltips for Drive buttons
if ( ( ( LPNMTTDISPINFO ) lparam ) - > hdr . hwndFrom = = tooltipwindow & & ( ( LPNMTTDISPINFO ) lparam ) - > hdr . code = = TTN_GETDISPINFO )
{
LPNMTTDISPINFO pInfo = ( LPNMTTDISPINFO ) lparam ;
SendMessage ( pInfo - > hdr . hwndFrom , TTM_SETMAXTIPWIDTH , 0 , 150 ) ;
Disk2InterfaceCard * pDisk2Slot5 = NULL , * pDisk2Slot6 = NULL ;
if ( GetCardMgr ( ) . QuerySlot ( SLOT5 ) = = CT_Disk2 )
pDisk2Slot5 = dynamic_cast < Disk2InterfaceCard * > ( GetCardMgr ( ) . GetObj ( SLOT5 ) ) ;
if ( GetCardMgr ( ) . QuerySlot ( SLOT6 ) = = CT_Disk2 )
pDisk2Slot6 = dynamic_cast < Disk2InterfaceCard * > ( GetCardMgr ( ) . GetObj ( SLOT6 ) ) ;
std : : string slot5 = pDisk2Slot5 ? pDisk2Slot5 - > GetFullDiskFilename ( ( ( LPNMTTDISPINFO ) lparam ) - > hdr . idFrom ) : " " ;
std : : string slot6 = pDisk2Slot6 ? pDisk2Slot6 - > GetFullDiskFilename ( ( ( LPNMTTDISPINFO ) lparam ) - > hdr . idFrom ) : " " ;
if ( pDisk2Slot5 )
{
if ( slot6 . empty ( ) ) slot6 = " <empty> " ;
if ( slot5 . empty ( ) ) slot5 = " <empty> " ;
slot6 = std : : string ( " Slot6: " ) + slot6 ;
slot5 = std : : string ( " Slot5: " ) + slot5 ;
}
std : : string join = ( ! slot6 . empty ( ) & & ! slot5 . empty ( ) ) ? " \r \n " : " " ;
driveTooltip = slot6 + join + slot5 ;
( ( LPNMTTDISPINFO ) lparam ) - > lpszText = ( LPTSTR ) driveTooltip . c_str ( ) ;
}
break ;
case WM_PAINT :
if ( GetUpdateRect ( window , NULL , 0 ) ) {
DrawFrameWindow ( true ) ;
}
break ;
case WM_PALETTECHANGED :
// To avoid creating an infinite loop, a window that receives this
// message must not realize its palette, unless it determines that
// wParam does not contain its own window handle.
if ( ( HWND ) wparam = = window )
break ;
// else fall through
case WM_QUERYNEWPALETTE :
DrawFrameWindow ( ) ;
break ;
case WM_RBUTTONDOWN :
case WM_RBUTTONUP :
if ( ( buttonover = = - 1 ) & & ( message = = WM_RBUTTONUP ) ) // HACK: BUTTON_NONE
{
int x = LOWORD ( lparam ) ;
int y = HIWORD ( lparam ) ;
if ( ( x > = buttonx ) & &
( y > = buttony ) & &
( y < = buttony + BUTTONS * BUTTONCY ) )
{
const int iButton = ( y - buttony - 1 ) / BUTTONCY ;
const int iDrive = iButton - BTN_DRIVE1 ;
if ( ( iButton = = BTN_DRIVE1 ) | | ( iButton = = BTN_DRIVE2 ) )
{
{
RECT rect ; // client area
POINT pt ; // location of mouse click
// Get the bounding rectangle of the client area.
GetClientRect ( window , ( LPRECT ) & rect ) ;
// Get the client coordinates for the mouse click.
pt . x = GET_X_LPARAM ( lparam ) ;
pt . y = GET_Y_LPARAM ( lparam ) ;
// If the mouse click took place inside the client
// area, execute the application-defined function
// that displays the shortcut menu.
if ( PtInRect ( ( LPRECT ) & rect , pt ) )
ProcessDiskPopupMenu ( window , pt , iDrive ) ;
}
2021-01-10 16:33:06 +00:00
FrameRefreshStatus ( DRAW_LEDS | DRAW_BUTTON_DRIVES | DRAW_DISK_STATUS ) ;
2020-11-23 19:21:20 +00:00
DrawButton ( ( HDC ) 0 , iButton ) ;
}
}
}
if ( g_bUsingCursor & & ! GetCardMgr ( ) . IsMouseCardInstalled ( ) )
JoySetButton ( BUTTON1 , ( message = = WM_RBUTTONDOWN ) ? BUTTON_DOWN : BUTTON_UP ) ;
else if ( GetCardMgr ( ) . IsMouseCardInstalled ( ) )
GetCardMgr ( ) . GetMouseCard ( ) - > SetButton ( BUTTON1 , ( message = = WM_RBUTTONDOWN ) ? BUTTON_DOWN : BUTTON_UP ) ;
RelayEvent ( message , wparam , lparam ) ;
break ;
case WM_SYSCOLORCHANGE :
# if DEBUG_DD_PALETTE
if ( g_bIsFullScreen )
2022-02-14 20:37:18 +00:00
OutputDebugString ( " WM_SYSCOLORCHANGE: Full Screen \n " ) ;
2020-11-23 19:21:20 +00:00
else
2022-02-14 20:37:18 +00:00
OutputDebugString ( " WM_SYSCOLORCHANGE: Windowed \n " ) ;
2020-11-23 19:21:20 +00:00
# endif
DeleteGdiObjects ( ) ;
CreateGdiObjects ( ) ;
break ;
case WM_SYSCOMMAND :
switch ( wparam & 0xFFF0 ) {
case SC_KEYMENU :
if ( g_bIsFullScreen & & g_bAppActive )
return 0 ;
break ;
case SC_MINIMIZE :
GetWindowRect ( window , & framerect ) ;
break ;
}
break ;
case WM_SYSKEYDOWN : // ALT + any key; or F10
KeybUpdateCtrlShiftStatus ( ) ;
// http://msdn.microsoft.com/en-us/library/windows/desktop/gg153546(v=vs.85).aspx
if ( g_bAltEnter_ToggleFullScreen & & KeybGetAltStatus ( ) & & ( wparam = = VK_RETURN ) ) // NB. VK_RETURN = 0x0D; Normally WM_CHAR will be 0x0A but ALT key triggers as WM_SYSKEYDOWN and VK_MENU
return 0 ; // NOP -- eat key
PostMessage ( window , WM_KEYDOWN , wparam , lparam ) ;
if ( ( wparam = = VK_F10 ) | | ( wparam = = VK_MENU ) ) // VK_MENU == ALT Key
return 0 ;
break ;
case WM_SYSKEYUP :
KeybUpdateCtrlShiftStatus ( ) ;
// F10: no WM_KEYUP handler for VK_F10. Don't allow WM_KEYUP to pass to default handler which will show the app window's "menu" (and lose focus)
if ( wparam = = VK_F10 )
return 0 ;
if ( g_bAltEnter_ToggleFullScreen & & KeybGetAltStatus ( ) & & ( wparam = = VK_RETURN ) ) // NB. VK_RETURN = 0x0D; Normally WM_CHAR will be 0x0A but ALT key triggers as WM_SYSKEYDOWN and VK_MENU
ScreenWindowResize ( false ) ;
else
PostMessage ( window , WM_KEYUP , wparam , lparam ) ;
break ;
case WM_MENUCHAR : // GH#556 - Suppress the Windows Default Beep (ie. Ding) whenever ALT+<key> is pressed
return ( MNC_CLOSE < < 16 ) | ( wparam & 0xffff ) ;
case WM_USER_BENCHMARK : {
UpdateWindow ( window ) ;
ResetMachineState ( ) ;
DrawStatusArea ( ( HDC ) 0 , DRAW_TITLE ) ;
HCURSOR oldcursor = SetCursor ( LoadCursor ( 0 , IDC_WAIT ) ) ;
g_nAppMode = MODE_BENCHMARK ;
2021-01-10 16:33:06 +00:00
Win32Frame : : GetWin32Frame ( ) . Benchmark ( ) ;
2020-11-23 19:21:20 +00:00
g_nAppMode = MODE_LOGO ;
ResetMachineState ( ) ;
SetCursor ( oldcursor ) ;
break ;
}
case WM_USER_SAVESTATE : // Save state
Snapshot_SaveState ( ) ;
break ;
case WM_USER_LOADSTATE : // Load state
Snapshot_LoadState ( ) ;
break ;
case WM_USER_TCP_SERIAL : // TCP serial events
{
WORD error = WSAGETSELECTERROR ( lparam ) ;
if ( error ! = 0 )
{
LogOutput ( " TCP Serial Winsock error 0x%X (%d) \r " , error , error ) ;
switch ( error )
{
case WSAENETRESET :
case WSAECONNABORTED :
case WSAECONNRESET :
case WSAENOTCONN :
case WSAETIMEDOUT :
if ( GetCardMgr ( ) . IsSSCInstalled ( ) )
GetCardMgr ( ) . GetSSC ( ) - > CommTcpSerialClose ( ) ;
break ;
default :
if ( GetCardMgr ( ) . IsSSCInstalled ( ) )
GetCardMgr ( ) . GetSSC ( ) - > CommTcpSerialCleanup ( ) ;
break ;
}
}
else
{
WORD wSelectEvent = WSAGETSELECTEVENT ( lparam ) ;
switch ( wSelectEvent )
{
case FD_ACCEPT :
if ( GetCardMgr ( ) . IsSSCInstalled ( ) )
GetCardMgr ( ) . GetSSC ( ) - > CommTcpSerialAccept ( ) ;
break ;
case FD_CLOSE :
if ( GetCardMgr ( ) . IsSSCInstalled ( ) )
GetCardMgr ( ) . GetSSC ( ) - > CommTcpSerialClose ( ) ;
break ;
case FD_READ :
if ( GetCardMgr ( ) . IsSSCInstalled ( ) )
GetCardMgr ( ) . GetSSC ( ) - > CommTcpSerialReceive ( ) ;
break ;
}
}
break ;
}
// Message posted by: WM_DDE_EXECUTE & Cmd-line boot
case WM_USER_BOOT :
{
SetForegroundWindow ( window ) ;
Sleep ( 500 ) ; // Wait for SetForegroundWindow() to take affect (400ms seems OK, so use 500ms to be sure)
SoundCore_TweakVolumes ( ) ;
ProcessButtonClick ( BTN_RUN ) ;
break ;
}
// Message posted by: Cmd-line boot
case WM_USER_FULLSCREEN :
{
ScreenWindowResize ( false ) ;
break ;
}
} // switch(message)
return DefWindowProc ( window , message , wparam , lparam ) ;
}
//===========================================================================
// Process: VK_F6
2021-01-10 16:33:06 +00:00
void Win32Frame : : ScreenWindowResize ( const bool bCtrlKey )
2020-11-23 19:21:20 +00:00
{
static int nOldViewportScale = kDEFAULT_VIEWPORT_SCALE ;
if ( g_bIsFullScreen ) // if full screen: then switch back to normal
{
SetNormalMode ( ) ;
FrameResizeWindow ( nOldViewportScale ) ;
}
else if ( bCtrlKey ) // if normal screen && CTRL: then toggle scaling
{
FrameResizeWindow ( ( g_nViewportScale = = 1 ) ? 2 : 1 ) ; // Toggle between 1x and 2x
REGSAVE ( TEXT ( REGVALUE_WINDOW_SCALE ) , g_nViewportScale ) ;
}
else
{
nOldViewportScale = g_nViewportScale ;
FrameResizeWindow ( 1 ) ; // reset to 1x
SetFullScreenMode ( ) ;
}
}
2021-01-10 16:33:06 +00:00
bool Win32Frame : : ConfirmReboot ( bool bFromButtonUI )
2020-11-23 19:21:20 +00:00
{
2021-01-10 16:33:06 +00:00
if ( ! bFromButtonUI | | ! g_bConfirmReboot )
2020-11-23 19:21:20 +00:00
return true ;
2021-01-19 20:37:43 +00:00
int res = FrameMessageBox (
2020-11-23 19:21:20 +00:00
" Are you sure you want to reboot? \n "
" (All data will be lost!) \n "
" \n "
" You can skip this dialog from displaying \n "
" in the future by unchecking: \n "
" \n "
" [ ] Confirm reboot \n "
" \n "
" in the Configuration dialog. \n "
, " Reboot " , MB_ICONWARNING | MB_YESNO ) ;
return res = = IDYES ;
}
2021-01-10 16:33:06 +00:00
void Win32Frame : : ProcessButtonClick ( int button , bool bFromButtonUI /*=false*/ )
2020-11-23 19:21:20 +00:00
{
SoundCore_SetFade ( FADE_OUT ) ;
bool bAllowFadeIn = true ;
# if DEBUG_DD_PALETTE
2022-02-13 21:37:05 +00:00
LogOutput ( " Button: F%d Full Screen: %d \n " , button + 1 , g_bIsFullScreen ) ;
2020-11-23 19:21:20 +00:00
# endif
switch ( button ) {
case BTN_HELP :
{
const std : : string filename = g_sProgramDir + TEXT ( " APPLEWIN.CHM " ) ;
// (GH#437) For any internet downloaded AppleWin.chm files (stored on an NTFS drive) there may be an Alt Data Stream containing a Zone Identifier
// - try to delete it, otherwise the content won't be displayed unless it's unblock (via File Properties)
{
const std : : string filename_with_zone_identifier = filename + TEXT ( " :Zone.Identifier " ) ;
DeleteFile ( filename_with_zone_identifier . c_str ( ) ) ;
}
2021-01-10 16:33:06 +00:00
HtmlHelp ( g_hFrameWindow , filename . c_str ( ) , HH_DISPLAY_TOC , 0 ) ;
2020-11-23 19:21:20 +00:00
helpquit = 1 ;
}
break ;
case BTN_RUN :
KeybUpdateCtrlShiftStatus ( ) ;
if ( KeybGetCtrlStatus ( ) )
{
CtrlReset ( ) ;
if ( g_nAppMode = = MODE_DEBUG )
DebugDisplay ( TRUE ) ;
return ;
}
if ( g_nAppMode = = MODE_LOGO )
{
if ( GetCardMgr ( ) . QuerySlot ( SLOT6 ) = = CT_Disk2 )
dynamic_cast < Disk2InterfaceCard & > ( GetCardMgr ( ) . GetRef ( SLOT6 ) ) . Boot ( ) ;
LogFileTimeUntilFirstKeyReadReset ( ) ;
g_nAppMode = MODE_RUNNING ;
}
else if ( ( g_nAppMode = = MODE_RUNNING ) | | ( g_nAppMode = = MODE_DEBUG ) | | ( g_nAppMode = = MODE_STEPPING ) | | ( g_nAppMode = = MODE_PAUSED ) )
{
if ( ConfirmReboot ( bFromButtonUI ) )
{
ResetMachineState ( ) ;
// NB. Don't exit debugger or stepping
if ( g_nAppMode = = MODE_DEBUG )
DebugDisplay ( TRUE ) ;
}
}
DrawStatusArea ( ( HDC ) 0 , DRAW_TITLE ) ;
2021-01-10 16:33:06 +00:00
VideoRedrawScreen ( ) ;
2020-11-23 19:21:20 +00:00
break ;
case BTN_DRIVE1 :
case BTN_DRIVE2 :
if ( GetCardMgr ( ) . QuerySlot ( SLOT6 ) = = CT_Disk2 )
{
dynamic_cast < Disk2InterfaceCard & > ( GetCardMgr ( ) . GetRef ( SLOT6 ) ) . UserSelectNewDiskImage ( button - BTN_DRIVE1 ) ;
if ( ! g_bIsFullScreen )
DrawButton ( ( HDC ) 0 , button ) ;
}
break ;
case BTN_DRIVESWAP :
if ( GetCardMgr ( ) . QuerySlot ( SLOT6 ) = = CT_Disk2 )
{
dynamic_cast < Disk2InterfaceCard & > ( GetCardMgr ( ) . GetRef ( SLOT6 ) ) . DriveSwap ( ) ;
}
break ;
case BTN_FULLSCR :
KeybUpdateCtrlShiftStatus ( ) ;
ScreenWindowResize ( KeybGetCtrlStatus ( ) ) ;
break ;
case BTN_DEBUG :
if ( g_nAppMode = = MODE_LOGO & & ! GetLoadedSaveStateFlag ( ) )
{
// FIXME: Why is this needed? Surely when state is MODE_LOGO, then AppleII system will have been reset!
// - Transition to MODE_LOGO when: (a) AppleWin starts, (b) there's a Config change to the AppleII h/w
ResetMachineState ( ) ;
}
if ( g_nAppMode = = MODE_STEPPING )
{
// Allow F7 to enter debugger even when not MODE_RUNNING
DebugStopStepping ( ) ;
bAllowFadeIn = false ;
}
else if ( g_nAppMode = = MODE_DEBUG )
{
DebugExitDebugger ( ) ; // Exit debugger, switch to MODE_RUNNING or MODE_STEPPING
g_bDebuggerEatKey = false ; // Don't "eat" the next keypress when leaving the debugger via F7 (or clicking the Debugger button)
}
else // MODE_RUNNING, MODE_LOGO, MODE_PAUSED
{
2021-11-30 21:41:02 +00:00
GetVideo ( ) . ClearSHRResidue ( ) ; // Clear the framebuffer to remove any SHR residue in the borders
2020-11-23 19:21:20 +00:00
DebugBegin ( ) ;
}
break ;
case BTN_SETUP :
{
2020-12-20 15:32:51 +00:00
GetPropertySheet ( ) . Init ( ) ;
2020-11-23 19:21:20 +00:00
}
break ;
}
if ( ( g_nAppMode ! = MODE_DEBUG ) & & ( g_nAppMode ! = MODE_PAUSED ) & & bAllowFadeIn )
{
SoundCore_SetFade ( FADE_IN ) ;
}
}
//===========================================================================
// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/resources/menus/usingmenus.asp
// http://www.codeproject.com/menu/MenusForBeginners.asp?df=100&forumid=67645&exp=0&select=903061
2021-01-10 16:33:06 +00:00
void Win32Frame : : ProcessDiskPopupMenu ( HWND hwnd , POINT pt , const int iDrive )
2020-11-23 19:21:20 +00:00
{
if ( GetCardMgr ( ) . QuerySlot ( SLOT6 ) ! = CT_Disk2 )
return ;
Disk2InterfaceCard & disk2Card = dynamic_cast < Disk2InterfaceCard & > ( GetCardMgr ( ) . GetRef ( SLOT6 ) ) ;
// This is the default installation path of CiderPress.
// It shall not be left blank, otherwise an explorer window will be open.
TCHAR PathToCiderPress [ MAX_PATH ] ;
RegLoadString (
TEXT ( " Configuration " ) ,
REGVALUE_CIDERPRESSLOC ,
1 ,
PathToCiderPress ,
MAX_PATH ,
TEXT ( " C: \\ Program Files \\ faddenSoft \\ CiderPress \\ CiderPress.exe " ) ) ;
//TODO: A directory is open if an empty path to CiderPress is set. This has to be fixed.
std : : string filename1 = " \" " ;
filename1 . append ( disk2Card . GetFullName ( iDrive ) ) ;
filename1 . append ( " \" " ) ;
std : : string sFileNameEmpty = " \" " ;
sFileNameEmpty . append ( " \" " ) ;
// Load the menu template containing the shortcut menu from the
// application's resources.
2021-01-10 16:33:06 +00:00
HMENU hmenu = LoadMenu ( g_hInstance , MAKEINTRESOURCE ( IDR_MENU_DISK_POPUP ) ) ; // menu template
2020-11-23 19:21:20 +00:00
if ( hmenu = = NULL )
return ;
// Get the first shortcut menu in the menu template.
// This is the menu that TrackPopupMenu displays.
HMENU hmenuTrackPopup = GetSubMenu ( hmenu , 0 ) ; // shortcut menu
// TrackPopup uses screen coordinates, so convert the
// coordinates of the mouse click to screen coordinates.
ClientToScreen ( hwnd , ( LPPOINT ) & pt ) ;
// Check menu depending on current floppy protection
{
int iMenuItem = ID_DISKMENU_WRITEPROTECTION_OFF ;
2021-10-18 20:13:37 +00:00
if ( disk2Card . GetProtect ( iDrive ) )
2020-11-23 19:21:20 +00:00
iMenuItem = ID_DISKMENU_WRITEPROTECTION_ON ;
CheckMenuItem ( hmenu , iMenuItem , MF_CHECKED ) ;
}
if ( disk2Card . IsDriveEmpty ( iDrive ) )
EnableMenuItem ( hmenu , ID_DISKMENU_EJECT , MF_GRAYED ) ;
2021-10-18 20:13:37 +00:00
if ( disk2Card . GetProtect ( iDrive ) )
2020-11-23 19:21:20 +00:00
{
// If image-file is read-only (or a gzip) then disable these menu items
EnableMenuItem ( hmenu , ID_DISKMENU_WRITEPROTECTION_ON , MF_GRAYED ) ;
EnableMenuItem ( hmenu , ID_DISKMENU_WRITEPROTECTION_OFF , MF_GRAYED ) ;
}
// Draw and track the shortcut menu.
int iCommand = TrackPopupMenu (
hmenuTrackPopup
, TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_RETURNCMD
, pt . x , pt . y
, 0
, hwnd , NULL ) ;
if ( iCommand = = ID_DISKMENU_EJECT )
disk2Card . EjectDisk ( iDrive ) ;
else
if ( iCommand = = ID_DISKMENU_WRITEPROTECTION_ON )
disk2Card . SetProtect ( iDrive , true ) ;
else
if ( iCommand = = ID_DISKMENU_WRITEPROTECTION_OFF )
disk2Card . SetProtect ( iDrive , false ) ;
else
if ( iCommand = = ID_DISKMENU_SENDTO_CIDERPRESS )
{
static char szCiderpressNotFoundCaption [ ] = " CiderPress not found " ;
static char szCiderpressNotFoundText [ ] = " CiderPress not found! \n "
" Please install CiderPress. \n "
" Otherwise set the path to CiderPress from Configuration->Disk. " ;
disk2Card . FlushCurrentTrack ( iDrive ) ;
//if(!filename1.compare("\"\"") == false) //Do not use this, for some reason it does not work!!!
if ( ! filename1 . compare ( sFileNameEmpty ) )
{
2021-01-19 20:37:43 +00:00
int MB_Result = FrameMessageBox ( " No disk image loaded. Do you want to run CiderPress anyway? " , " No disk image. " , MB_ICONINFORMATION | MB_YESNO ) ;
2020-11-23 19:21:20 +00:00
if ( MB_Result = = IDYES )
{
if ( FileExists ( PathToCiderPress ) )
{
HINSTANCE nResult = ShellExecute ( NULL , " open " , PathToCiderPress , " " , NULL , SW_SHOWNORMAL ) ;
}
else
{
2021-01-19 20:37:43 +00:00
FrameMessageBox ( szCiderpressNotFoundText , szCiderpressNotFoundCaption , MB_ICONINFORMATION | MB_OK ) ;
2020-11-23 19:21:20 +00:00
}
}
}
else
{
if ( FileExists ( PathToCiderPress ) )
{
HINSTANCE nResult = ShellExecute ( NULL , " open " , PathToCiderPress , filename1 . c_str ( ) , NULL , SW_SHOWNORMAL ) ;
}
else
{
2021-01-19 20:37:43 +00:00
FrameMessageBox ( szCiderpressNotFoundText , szCiderpressNotFoundCaption , MB_ICONINFORMATION | MB_OK ) ;
2020-11-23 19:21:20 +00:00
}
}
}
// Destroy the menu.
BOOL bRes = DestroyMenu ( hmenu ) ;
_ASSERT ( bRes ) ;
}
//===========================================================================
2021-01-10 16:33:06 +00:00
void Win32Frame : : RelayEvent ( UINT message , WPARAM wparam , LPARAM lparam ) {
2020-11-23 19:21:20 +00:00
if ( g_bIsFullScreen )
return ;
MSG msg ;
2021-01-10 16:33:06 +00:00
msg . hwnd = g_hFrameWindow ;
2020-11-23 19:21:20 +00:00
msg . message = message ;
msg . wParam = wparam ;
msg . lParam = lparam ;
SendMessage ( tooltipwindow , TTM_RELAYEVENT , 0 , ( LPARAM ) & msg ) ;
}
//===========================================================================
2021-01-10 16:33:06 +00:00
int Win32Frame : : GetFullScreenOffsetX ( void )
2020-11-23 19:21:20 +00:00
{
return g_win_fullscreen_offsetx ;
}
2021-01-10 16:33:06 +00:00
int Win32Frame : : GetFullScreenOffsetY ( void )
2020-11-23 19:21:20 +00:00
{
return g_win_fullscreen_offsety ;
}
2021-05-31 15:09:39 +00:00
void Win32Frame : : SetFullScreenMode ( void )
2020-11-23 19:21:20 +00:00
{
# ifdef NO_DIRECT_X
return ;
# else // NO_DIRECT_X
2021-05-31 15:09:39 +00:00
if ( m_bestWidthForFullScreen & & m_bestHeightForFullScreen )
{
DEVMODE devMode ;
memset ( & devMode , 0 , sizeof ( devMode ) ) ;
devMode . dmSize = sizeof ( devMode ) ;
devMode . dmPelsWidth = m_bestWidthForFullScreen ;
devMode . dmPelsHeight = m_bestHeightForFullScreen ;
devMode . dmFields = DM_PELSWIDTH | DM_PELSHEIGHT ;
DWORD dwFlags = 0 ;
LONG res = ChangeDisplaySettings ( & devMode , dwFlags ) ;
2021-06-19 14:06:04 +00:00
m_changedDisplaySettings = true ;
2021-05-31 15:09:39 +00:00
}
//
2020-11-23 19:21:20 +00:00
MONITORINFO monitor_info ;
FULLSCREEN_SCALE_TYPE width , height , scalex , scaley ;
int top , left ;
buttonover = - 1 ;
2021-01-10 16:33:06 +00:00
g_main_window_saved_style = GetWindowLong ( g_hFrameWindow , GWL_STYLE ) ;
g_main_window_saved_exstyle = GetWindowLong ( g_hFrameWindow , GWL_EXSTYLE ) ;
GetWindowRect ( g_hFrameWindow , & g_main_window_saved_rect ) ;
SetWindowLong ( g_hFrameWindow , GWL_STYLE , g_main_window_saved_style & ~ ( WS_CAPTION | WS_THICKFRAME ) ) ;
SetWindowLong ( g_hFrameWindow , GWL_EXSTYLE , g_main_window_saved_exstyle & ~ ( WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE ) ) ;
2020-11-23 19:21:20 +00:00
monitor_info . cbSize = sizeof ( monitor_info ) ;
2021-01-10 16:33:06 +00:00
GetMonitorInfo ( MonitorFromWindow ( g_hFrameWindow , MONITOR_DEFAULTTONEAREST ) , & monitor_info ) ;
2020-11-23 19:21:20 +00:00
left = monitor_info . rcMonitor . left ;
top = monitor_info . rcMonitor . top ;
width = ( FULLSCREEN_SCALE_TYPE ) ( monitor_info . rcMonitor . right - monitor_info . rcMonitor . left ) ;
height = ( FULLSCREEN_SCALE_TYPE ) ( monitor_info . rcMonitor . bottom - monitor_info . rcMonitor . top ) ;
2020-12-28 16:25:29 +00:00
scalex = width / GetVideo ( ) . GetFrameBufferBorderlessWidth ( ) ;
scaley = height / GetVideo ( ) . GetFrameBufferBorderlessHeight ( ) ;
2020-11-23 19:21:20 +00:00
2021-11-30 21:41:02 +00:00
// NB. Separate x,y scaling is OK in full-screen mode
// . eg. SHR 640x400 (scalex=2, scaley=3) => 1280x1200, which roughly gives a 4:3 aspect ratio for a resolution of 1600x1200
g_win_fullscreen_offsetx = ( ( int ) width - ( int ) ( scalex * GetVideo ( ) . GetFrameBufferBorderlessWidth ( ) ) ) / 2 ;
g_win_fullscreen_offsety = ( ( int ) height - ( int ) ( scaley * GetVideo ( ) . GetFrameBufferBorderlessHeight ( ) ) ) / 2 ;
2021-01-10 16:33:06 +00:00
SetWindowPos ( g_hFrameWindow , NULL , left , top , ( int ) width , ( int ) height , SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED ) ;
2020-11-23 19:21:20 +00:00
g_bIsFullScreen = true ;
2021-11-30 21:41:02 +00:00
SetFullScreenViewportScale ( scalex , scaley ) ;
2020-11-23 19:21:20 +00:00
buttonx = GetFullScreenOffsetX ( ) + g_nViewportCX + VIEWPORTX * 2 ;
buttony = GetFullScreenOffsetY ( ) ;
viewportx = VIEWPORTX ; // TC-TODO: Should be zero too? (Since there's no 3D border in full-screen)
viewporty = 0 ; // GH#464
2021-01-10 16:33:06 +00:00
InvalidateRect ( g_hFrameWindow , NULL , 1 ) ;
2020-11-23 19:21:20 +00:00
# endif // NO_DIRECT_X
}
//===========================================================================
2021-05-31 15:09:39 +00:00
void Win32Frame : : SetNormalMode ( void )
2020-11-23 19:21:20 +00:00
{
2021-06-19 14:06:04 +00:00
if ( m_changedDisplaySettings )
{
// Only call ChangeDisplaySettings() if resolution has changed, otherwise there'll be a display flicker (GH#965)
ChangeDisplaySettings ( NULL , 0 ) ; // restore default resolution
m_changedDisplaySettings = false ;
}
2021-05-31 15:09:39 +00:00
2020-11-23 19:21:20 +00:00
FullScreenRevealCursor ( ) ; // Do before clearing g_bIsFullScreen flag
buttonover = - 1 ;
buttonx = BUTTONX ;
buttony = BUTTONY ;
viewportx = VIEWPORTX ;
viewporty = VIEWPORTY ;
g_win_fullscreen_offsetx = 0 ;
g_win_fullscreen_offsety = 0 ;
2021-01-10 16:33:06 +00:00
SetWindowLong ( g_hFrameWindow , GWL_STYLE , g_main_window_saved_style ) ;
SetWindowLong ( g_hFrameWindow , GWL_EXSTYLE , g_main_window_saved_exstyle ) ;
SetWindowPos ( g_hFrameWindow , NULL ,
2020-11-23 19:21:20 +00:00
g_main_window_saved_rect . left ,
g_main_window_saved_rect . top ,
g_main_window_saved_rect . right - g_main_window_saved_rect . left ,
g_main_window_saved_rect . bottom - g_main_window_saved_rect . top ,
SWP_SHOWWINDOW ) ;
g_bIsFullScreen = false ;
}
//===========================================================================
2021-01-10 16:33:06 +00:00
void Win32Frame : : SetUsingCursor ( BOOL bNewValue )
2020-11-23 19:21:20 +00:00
{
if ( bNewValue = = g_bUsingCursor )
return ;
g_bUsingCursor = bNewValue ;
if ( g_bUsingCursor )
{
// Set TRUE when:
// . Using mouse for joystick emulation
// . Using mousecard and mouse is restricted to window
2021-01-10 16:33:06 +00:00
SetCapture ( g_hFrameWindow ) ;
2020-11-23 19:21:20 +00:00
RECT rect = { viewportx + 2 , // left
viewporty + 2 , // top
viewportx + g_nViewportCX - 1 , // right
viewporty + g_nViewportCY - 1 } ; // bottom
2021-01-10 16:33:06 +00:00
ClientToScreen ( g_hFrameWindow , ( LPPOINT ) & rect . left ) ;
ClientToScreen ( g_hFrameWindow , ( LPPOINT ) & rect . right ) ;
2020-11-23 19:21:20 +00:00
ClipCursor ( & rect ) ;
FrameShowCursor ( FALSE ) ;
POINT pt ;
GetCursorPos ( & pt ) ;
2021-01-10 16:33:06 +00:00
ScreenToClient ( g_hFrameWindow , & pt ) ;
2020-11-23 19:21:20 +00:00
DrawCrosshairs ( pt . x , pt . y ) ;
}
else
{
DrawCrosshairs ( 0 , 0 ) ;
FrameShowCursor ( TRUE ) ;
ClipCursor ( NULL ) ;
ReleaseCapture ( ) ;
}
}
2021-01-16 21:57:28 +00:00
int Win32Frame : : GetViewportScale ( void )
2020-11-23 19:21:20 +00:00
{
return g_nViewportScale ;
}
2020-12-24 15:08:50 +00:00
int Win32Frame : : SetViewportScale ( int nNewScale , bool bForce /*=false*/ )
2020-11-23 19:21:20 +00:00
{
if ( ! bForce & & nNewScale > g_nMaxViewportScale )
nNewScale = g_nMaxViewportScale ;
g_nViewportScale = nNewScale ;
2020-12-28 16:25:29 +00:00
g_nViewportCX = g_nViewportScale * GetVideo ( ) . GetFrameBufferBorderlessWidth ( ) ;
g_nViewportCY = g_nViewportScale * GetVideo ( ) . GetFrameBufferBorderlessHeight ( ) ;
2020-11-23 19:21:20 +00:00
2021-11-30 21:41:02 +00:00
buttonx = BUTTONX ; // NB. macro uses g_nViewportCX
buttony = BUTTONY ;
2020-11-23 19:21:20 +00:00
return nNewScale ;
}
2021-11-30 21:41:02 +00:00
void Win32Frame : : SetFullScreenViewportScale ( int nNewXScale , int nNewYScale )
{
g_nViewportScale = MIN ( nNewXScale , nNewYScale ) ; // Not needed in FS mode
g_nViewportCX = nNewXScale * GetVideo ( ) . GetFrameBufferBorderlessWidth ( ) ;
g_nViewportCY = nNewYScale * GetVideo ( ) . GetFrameBufferBorderlessHeight ( ) ;
buttonx = BUTTONX ; // NB. macro uses g_nViewportCX
buttony = BUTTONY ;
}
2021-01-10 16:33:06 +00:00
void Win32Frame : : SetupTooltipControls ( void )
2020-11-23 19:21:20 +00:00
{
TOOLINFO toolinfo ;
toolinfo . cbSize = sizeof ( toolinfo ) ;
toolinfo . uFlags = TTF_CENTERTIP ;
2021-01-10 16:33:06 +00:00
toolinfo . hwnd = g_hFrameWindow ;
toolinfo . hinst = g_hInstance ;
2020-11-23 19:21:20 +00:00
toolinfo . lpszText = LPSTR_TEXTCALLBACK ;
toolinfo . rect . left = BUTTONX ;
toolinfo . rect . right = toolinfo . rect . left + BUTTONCX + 1 ;
toolinfo . uId = 0 ;
toolinfo . rect . top = BUTTONY + BTN_DRIVE1 * BUTTONCY + 1 ;
toolinfo . rect . bottom = toolinfo . rect . top + BUTTONCY ;
SendMessage ( tooltipwindow , TTM_ADDTOOL , 0 , ( LPARAM ) & toolinfo ) ;
toolinfo . uId = 1 ;
toolinfo . rect . top = BUTTONY + BTN_DRIVE2 * BUTTONCY + 1 ;
toolinfo . rect . bottom = toolinfo . rect . top + BUTTONCY ;
SendMessage ( tooltipwindow , TTM_ADDTOOL , 0 , ( LPARAM ) & toolinfo ) ;
}
// SM_CXPADDEDBORDER is not supported on 2000 & XP, but GetSystemMetrics() returns 0 for unknown values, so this use of SM_CXPADDEDBORDER works on 2000 & XP too:
// http://msdn.microsoft.com/en-nz/library/windows/desktop/ms724385(v=vs.85).aspx
// NB. GetSystemMetrics(SM_CXPADDEDBORDER) returns 0 for Win7, when built with VS2008 (see GH#571)
2021-01-16 21:57:28 +00:00
void Win32Frame : : GetWidthHeight ( int & nWidth , int & nHeight )
2020-11-23 19:21:20 +00:00
{
nWidth = g_nViewportCX + VIEWPORTX * 2
+ BUTTONCX
+ ( GetSystemMetrics ( SM_CXFIXEDFRAME ) + GetSystemMetrics ( SM_CXPADDEDBORDER ) ) * 2 ;
nHeight = g_nViewportCY + VIEWPORTY * 2
+ ( GetSystemMetrics ( SM_CYFIXEDFRAME ) + GetSystemMetrics ( SM_CXPADDEDBORDER ) ) * 2 // NB. No SM_CYPADDEDBORDER
+ GetSystemMetrics ( SM_CYCAPTION ) ;
#if 0 // GH#571
LogOutput ( " g_nViewportCX = %d \n " , g_nViewportCX ) ;
LogOutput ( " VIEWPORTX = %d (const) \n " , VIEWPORTX ) ;
LogOutput ( " BUTTONCX = %d (const) \n " , BUTTONCX ) ;
LogOutput ( " GetSystemMetrics(SM_CXFRAME) = %d (unused) \n " , GetSystemMetrics ( SM_CXFRAME ) ) ;
LogOutput ( " GetSystemMetrics(SM_CXFIXEDFRAME) = %d \n " , GetSystemMetrics ( SM_CXFIXEDFRAME ) ) ;
LogOutput ( " GetSystemMetrics(SM_CXBORDER) = %d (unused) \n " , GetSystemMetrics ( SM_CXBORDER ) ) ;
LogOutput ( " GetSystemMetrics(SM_CXPADDEDBORDER) = %d \n " , GetSystemMetrics ( SM_CXPADDEDBORDER ) ) ;
LogOutput ( " nWidth = %d \n " , nWidth ) ;
LogOutput ( " g_nViewportCY = %d \n " , g_nViewportCY ) ;
LogOutput ( " VIEWPORTY = %d (const) \n " , VIEWPORTY ) ;
LogOutput ( " GetSystemMetrics(SM_CYFRAME) = %d (unused) \n " , GetSystemMetrics ( SM_CYFRAME ) ) ;
LogOutput ( " GetSystemMetrics(SM_CYFIXEDFRAME) = %d \n " , GetSystemMetrics ( SM_CYFIXEDFRAME ) ) ;
LogOutput ( " GetSystemMetrics(SM_CYBORDER) = %d (unused) \n " , GetSystemMetrics ( SM_CYBORDER ) ) ;
LogOutput ( " GetSystemMetrics(SM_CYCAPTION) = %d \n " , GetSystemMetrics ( SM_CYCAPTION ) ) ;
LogOutput ( " nHeight = %d \n \n " , nHeight ) ;
# endif
}
2021-11-30 21:41:02 +00:00
// Window frame's border size has changed (eg. VidHD added/removed)
void Win32Frame : : ResizeWindow ( void )
{
FrameResizeWindow ( GetViewportScale ( ) ) ;
}
2021-01-10 16:33:06 +00:00
void Win32Frame : : FrameResizeWindow ( int nNewScale )
2020-11-23 19:21:20 +00:00
{
int nOldWidth , nOldHeight ;
GetWidthHeight ( nOldWidth , nOldHeight ) ;
2021-01-10 16:33:06 +00:00
nNewScale = SetViewportScale ( nNewScale ) ;
2020-11-23 19:21:20 +00:00
2021-01-10 16:33:06 +00:00
GetWindowRect ( g_hFrameWindow , & framerect ) ;
2020-11-23 19:21:20 +00:00
int nXPos = framerect . left ;
int nYPos = framerect . top ;
// Invalidate old rect region
{
RECT irect ;
irect . left = irect . top = 0 ;
irect . right = nOldWidth ;
irect . bottom = nOldHeight ;
2021-01-10 16:33:06 +00:00
InvalidateRect ( g_hFrameWindow , & irect , TRUE ) ;
2020-11-23 19:21:20 +00:00
}
// Resize the window
int nNewWidth , nNewHeight ;
GetWidthHeight ( nNewWidth , nNewHeight ) ;
2021-01-10 16:33:06 +00:00
MoveWindow ( g_hFrameWindow , nXPos , nYPos , nNewWidth , nNewHeight , TRUE ) ;
UpdateWindow ( g_hFrameWindow ) ;
2020-11-23 19:21:20 +00:00
// Remove the tooltips for the old window size
TOOLINFO toolinfo = { 0 } ;
toolinfo . cbSize = sizeof ( toolinfo ) ;
2021-01-10 16:33:06 +00:00
toolinfo . hwnd = g_hFrameWindow ;
2020-11-23 19:21:20 +00:00
toolinfo . uId = 0 ;
SendMessage ( tooltipwindow , TTM_DELTOOL , 0 , ( LPARAM ) & toolinfo ) ;
toolinfo . uId = 1 ;
SendMessage ( tooltipwindow , TTM_DELTOOL , 0 , ( LPARAM ) & toolinfo ) ;
// Setup the tooltips for the new window size
SetupTooltipControls ( ) ;
}
//
// ----- ALL GLOBALLY ACCESSIBLE FUNCTIONS ARE BELOW THIS LINE -----
//
//===========================================================================
2021-01-10 16:33:06 +00:00
void Win32Frame : : FrameCreateWindow ( void )
2020-11-23 19:21:20 +00:00
{
int nWidth , nHeight ;
// Set g_nMaxViewportScale
{
int nOldViewportCX = g_nViewportCX ;
int nOldViewportCY = g_nViewportCY ;
2020-12-28 16:25:29 +00:00
g_nViewportCX = GetVideo ( ) . GetFrameBufferBorderlessWidth ( ) * 2 ;
g_nViewportCY = GetVideo ( ) . GetFrameBufferBorderlessHeight ( ) * 2 ;
2020-11-23 19:21:20 +00:00
GetWidthHeight ( nWidth , nHeight ) ; // Probe with 2x dimensions
g_nViewportCX = nOldViewportCX ;
g_nViewportCY = nOldViewportCY ;
if ( nWidth > GetSystemMetrics ( SM_CXSCREEN ) | | nHeight > GetSystemMetrics ( SM_CYSCREEN ) )
g_nMaxViewportScale = 1 ;
}
GetWidthHeight ( nWidth , nHeight ) ;
// If screen is too small for 2x, then revert to 1x
if ( g_nViewportScale = = 2 & & ( nWidth > GetSystemMetrics ( SM_CXSCREEN ) | | nHeight > GetSystemMetrics ( SM_CYSCREEN ) ) )
{
g_nMaxViewportScale = 1 ;
2021-01-10 16:33:06 +00:00
SetViewportScale ( 1 ) ;
2020-11-23 19:21:20 +00:00
GetWidthHeight ( nWidth , nHeight ) ;
}
// Restore Window X Position
int nXPos = - 1 ;
{
const int nXScreen = GetSystemMetrics ( SM_CXSCREEN ) - nWidth ;
if ( RegLoadValue ( TEXT ( REG_PREFS ) , TEXT ( REGVALUE_PREF_WINDOW_X_POS ) , 1 , ( DWORD * ) & nXPos ) )
{
2021-01-10 16:33:06 +00:00
if ( ( nXPos > nXScreen ) & & ! g_bMultiMon )
2020-11-23 19:21:20 +00:00
nXPos = - 1 ; // Not fully visible, so default to centre position
}
2021-01-10 16:33:06 +00:00
if ( ( nXPos = = - 1 ) & & ! g_bMultiMon )
2020-11-23 19:21:20 +00:00
nXPos = nXScreen / 2 ;
}
// Restore Window Y Position
int nYPos = - 1 ;
{
const int nYScreen = GetSystemMetrics ( SM_CYSCREEN ) - nHeight ;
if ( RegLoadValue ( TEXT ( REG_PREFS ) , TEXT ( REGVALUE_PREF_WINDOW_Y_POS ) , 1 , ( DWORD * ) & nYPos ) )
{
2021-01-10 16:33:06 +00:00
if ( ( nYPos > nYScreen ) & & ! g_bMultiMon )
2020-11-23 19:21:20 +00:00
nYPos = - 1 ; // Not fully visible, so default to centre position
}
2021-01-10 16:33:06 +00:00
if ( ( nYPos = = - 1 ) & & ! g_bMultiMon )
2020-11-23 19:21:20 +00:00
nYPos = nYScreen / 2 ;
}
//
buttonx = ( g_nViewportCX + VIEWPORTX * 2 ) ;
buttony = 0 ;
GetAppleWindowTitle ( ) ;
// NB. g_hFrameWindow also set by WM_CREATE - NB. CreateWindow() must synchronously send WM_CREATE
2021-01-10 16:33:06 +00:00
g_hFrameWindow = CreateWindow (
2020-11-23 19:21:20 +00:00
TEXT ( " APPLE2FRAME " ) ,
g_pAppTitle . c_str ( ) ,
WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU |
WS_MINIMIZEBOX | WS_VISIBLE ,
nXPos , nYPos , nWidth , nHeight ,
HWND_DESKTOP ,
( HMENU ) 0 ,
2021-01-10 16:33:06 +00:00
g_hInstance , NULL ) ;
2020-11-23 19:21:20 +00:00
InitCommonControls ( ) ;
tooltipwindow = CreateWindow (
TOOLTIPS_CLASS , NULL , TTS_ALWAYSTIP ,
CW_USEDEFAULT , CW_USEDEFAULT , CW_USEDEFAULT , CW_USEDEFAULT ,
2021-01-10 16:33:06 +00:00
g_hFrameWindow ,
2020-11-23 19:21:20 +00:00
( HMENU ) 0 ,
2021-01-10 16:33:06 +00:00
g_hInstance , NULL ) ;
2020-11-23 19:21:20 +00:00
SetupTooltipControls ( ) ;
_ASSERT ( g_TimerIDEvent_100msec = = 0 ) ;
2021-01-10 16:33:06 +00:00
g_TimerIDEvent_100msec = SetTimer ( g_hFrameWindow , IDEVENT_TIMER_100MSEC , 100 , NULL ) ;
2020-11-23 19:21:20 +00:00
LogFileOutput ( " FrameCreateWindow: SetTimer(), id=0x%08X \n " , g_TimerIDEvent_100msec ) ;
}
//===========================================================================
2021-01-16 21:57:28 +00:00
HDC Win32Frame : : FrameGetDC ( ) {
2020-11-23 19:21:20 +00:00
if ( ! g_hFrameDC ) {
2021-01-16 21:57:28 +00:00
g_hFrameDC = GetDC ( g_hFrameWindow ) ;
2020-11-23 19:21:20 +00:00
SetViewportOrgEx ( g_hFrameDC , viewportx , viewporty , NULL ) ;
}
return g_hFrameDC ;
}
//===========================================================================
2021-01-16 21:57:28 +00:00
void Win32Frame : : FrameReleaseDC ( ) {
2020-11-23 19:21:20 +00:00
if ( g_hFrameDC ) {
SetViewportOrgEx ( g_hFrameDC , 0 , 0 , NULL ) ;
2021-01-16 21:57:28 +00:00
ReleaseDC ( g_hFrameWindow , g_hFrameDC ) ;
2020-11-23 19:21:20 +00:00
g_hFrameDC = ( HDC ) 0 ;
}
}
//===========================================================================
2021-01-10 16:33:06 +00:00
void Win32Frame : : FrameRefreshStatus ( int drawflags ) {
2020-11-23 19:21:20 +00:00
DrawStatusArea ( ( HDC ) 0 , drawflags ) ;
}
//===========================================================================
2021-01-10 16:33:06 +00:00
void Win32Frame : : FrameRegisterClass ( ) {
2020-11-23 19:21:20 +00:00
WNDCLASSEX wndclass ;
2020-12-10 21:08:15 +00:00
memset ( & wndclass , 0 , sizeof ( WNDCLASSEX ) ) ;
2020-11-23 19:21:20 +00:00
wndclass . cbSize = sizeof ( WNDCLASSEX ) ;
wndclass . style = CS_OWNDC | CS_BYTEALIGNCLIENT ;
wndclass . lpfnWndProc = FrameWndProc ;
2021-01-10 16:33:06 +00:00
wndclass . hInstance = g_hInstance ;
wndclass . hIcon = LoadIcon ( g_hInstance , TEXT ( " APPLEWIN_ICON " ) ) ;
2020-11-23 19:21:20 +00:00
wndclass . hCursor = LoadCursor ( 0 , IDC_ARROW ) ;
wndclass . hbrBackground = ( HBRUSH ) GetStockObject ( BLACK_BRUSH ) ;
# if ENABLE_MENU
wndclass . lpszMenuName = ( LPCSTR ) IDR_MENU1 ;
# endif
wndclass . lpszClassName = TEXT ( " APPLE2FRAME " ) ;
2021-01-10 16:33:06 +00:00
wndclass . hIconSm = ( HICON ) LoadImage ( g_hInstance , TEXT ( " APPLEWIN_ICON " ) ,
2020-11-23 19:21:20 +00:00
IMAGE_ICON , 16 , 16 , LR_DEFAULTCOLOR ) ;
RegisterClassEx ( & wndclass ) ;
}
//===========================================================================
// TODO: FIXME: Util_TestFileExists()
static bool FileExists ( std : : string strFilename )
2020-11-28 22:55:45 +00:00
{
struct _stat64 stFileInfo ;
int intStat = _stat64 ( strFilename . c_str ( ) , & stFileInfo ) ;
return ( intStat = = 0 ) ;
2020-11-23 19:21:20 +00:00
}
//===========================================================================
// Called when:
// . Mouse f/w sets abs position
// . UpdateMouseInAppleViewport() is called and inside Apple screen
2020-12-24 15:08:50 +00:00
void Win32Frame : : FrameSetCursorPosByMousePos ( )
2020-11-23 19:21:20 +00:00
{
// _ASSERT(GetCardMgr().IsMouseCardInstalled()); // CMouseInterface::ctor calls this function, ie. before GetCardMgr()::m_pMouseCard is setup
if ( ! GetCardMgr ( ) . IsMouseCardInstalled ( ) )
return ;
2021-01-10 16:33:06 +00:00
if ( ! g_hFrameWindow | | g_bShowingCursor )
2020-11-23 19:21:20 +00:00
return ;
int iX , iMinX , iMaxX ;
int iY , iMinY , iMaxY ;
GetCardMgr ( ) . GetMouseCard ( ) - > GetXY ( iX , iMinX , iMaxX , iY , iMinY , iMaxY ) ;
float fScaleX = ( float ) ( iX - iMinX ) / ( ( float ) ( iMaxX - iMinX ) ) ;
float fScaleY = ( float ) ( iY - iMinY ) / ( ( float ) ( iMaxY - iMinY ) ) ;
int iWindowX = ( int ) ( fScaleX * ( float ) g_nViewportCX ) ;
int iWindowY = ( int ) ( fScaleY * ( float ) g_nViewportCY ) ;
POINT Point = { viewportx + 2 , viewporty + 2 } ; // top-left
2021-01-10 16:33:06 +00:00
ClientToScreen ( g_hFrameWindow , & Point ) ;
2020-11-23 19:21:20 +00:00
SetCursorPos ( Point . x + iWindowX - VIEWPORTX , Point . y + iWindowY - VIEWPORTY ) ;
# if defined(_DEBUG) && 0 // OutputDebugString() when cursor position changes since last time
2022-02-13 21:37:05 +00:00
static int OldX = 0 , OldY = 0 ;
int X = Point . x + iWindowX - VIEWPORTX ;
int Y = Point . y + iWindowY - VIEWPORTY ;
2020-11-23 19:21:20 +00:00
if ( X ! = OldX | | Y ! = OldY )
{
2022-02-13 21:37:05 +00:00
LogOutput ( " [FrameSetCursorPosByMousePos] x,y=%d,%d (MaxX,Y=%d,%d) \n " , X , Y , iMaxX , iMaxY ) ;
OldX = X ; OldY = Y ;
2020-11-23 19:21:20 +00:00
}
# endif
}
// Called when:
// . UpdateMouseInAppleViewport() is called and mouse leaving/entering Apple screen area
// . NB. Not called when leaving & mouse clipped to Apple screen area
2021-01-10 16:33:06 +00:00
void Win32Frame : : FrameSetCursorPosByMousePos ( int x , int y , int dx , int dy , bool bLeavingAppleScreen )
2020-11-23 19:21:20 +00:00
{
_ASSERT ( GetCardMgr ( ) . IsMouseCardInstalled ( ) ) ;
if ( ! GetCardMgr ( ) . IsMouseCardInstalled ( ) )
return ;
2021-01-10 16:33:06 +00:00
if ( ! g_hFrameWindow | | ( g_bShowingCursor & & bLeavingAppleScreen ) | | ( ! g_bShowingCursor & & ! bLeavingAppleScreen ) )
2020-11-23 19:21:20 +00:00
return ;
int iX , iMinX , iMaxX ;
int iY , iMinY , iMaxY ;
GetCardMgr ( ) . GetMouseCard ( ) - > GetXY ( iX , iMinX , iMaxX , iY , iMinY , iMaxY ) ;
if ( bLeavingAppleScreen )
{
// Set mouse x/y pos to edge of mouse's window
if ( dx < 0 ) iX = iMinX ;
if ( dx > 0 ) iX = iMaxX ;
if ( dy < 0 ) iY = iMinY ;
if ( dy > 0 ) iY = iMaxY ;
float fScaleX = ( float ) ( iX - iMinX ) / ( ( float ) ( iMaxX - iMinX ) ) ;
float fScaleY = ( float ) ( iY - iMinY ) / ( ( float ) ( iMaxY - iMinY ) ) ;
int iWindowX = ( int ) ( fScaleX * ( float ) g_nViewportCX ) + dx ;
int iWindowY = ( int ) ( fScaleY * ( float ) g_nViewportCY ) + dy ;
POINT Point = { viewportx + 2 , viewporty + 2 } ; // top-left
2021-01-10 16:33:06 +00:00
ClientToScreen ( g_hFrameWindow , & Point ) ;
2020-11-23 19:21:20 +00:00
SetCursorPos ( Point . x + iWindowX - VIEWPORTX , Point . y + iWindowY - VIEWPORTY ) ;
2022-02-13 21:37:05 +00:00
//LogOutput("[MOUSE_LEAVING ] x=%d, y=%d (Scale: x,y=%f,%f; iX,iY=%d,%d)\n", iWindowX, iWindowY, fScaleX, fScaleY, iX, iY);
2020-11-23 19:21:20 +00:00
}
else // Mouse entering Apple screen area
{
2022-02-13 21:37:05 +00:00
//LogOutput("[MOUSE_ENTERING] x=%d, y=%d\n", x, y);
2020-11-23 19:21:20 +00:00
if ( ! g_bIsFullScreen ) // GH#464
{
x - = ( viewportx + 2 - VIEWPORTX ) ; if ( x < 0 ) x = 0 ;
y - = ( viewporty + 2 - VIEWPORTY ) ; if ( y < 0 ) y = 0 ;
}
_ASSERT ( x < = g_nViewportCX ) ;
_ASSERT ( y < = g_nViewportCY ) ;
float fScaleX = ( float ) x / ( float ) g_nViewportCX ;
float fScaleY = ( float ) y / ( float ) g_nViewportCY ;
int iAppleX = iMinX + ( int ) ( fScaleX * ( float ) ( iMaxX - iMinX ) ) ;
int iAppleY = iMinY + ( int ) ( fScaleY * ( float ) ( iMaxY - iMinY ) ) ;
GetCardMgr ( ) . GetMouseCard ( ) - > SetCursorPos ( iAppleX , iAppleY ) ; // Set new entry position
// Dump initial deltas (otherwise can get big deltas since last read when entering Apple screen area)
DIMouse : : ReadImmediateData ( ) ;
}
}
2021-01-10 16:33:06 +00:00
void Win32Frame : : DrawCrosshairsMouse ( )
2020-11-23 19:21:20 +00:00
{
_ASSERT ( GetCardMgr ( ) . IsMouseCardInstalled ( ) ) ;
if ( ! GetCardMgr ( ) . IsMouseCardInstalled ( ) )
return ;
2020-12-20 15:32:51 +00:00
if ( ! GetPropertySheet ( ) . GetMouseShowCrosshair ( ) )
2020-11-23 19:21:20 +00:00
return ;
int iX , iMinX , iMaxX ;
int iY , iMinY , iMaxY ;
GetCardMgr ( ) . GetMouseCard ( ) - > GetXY ( iX , iMinX , iMaxX , iY , iMinY , iMaxY ) ;
_ASSERT ( iMinX = = 0 & & iMinY = = 0 ) ;
float fScaleX = ( float ) ( iX - iMinX ) / ( ( float ) ( iMaxX - iMinX ) ) ;
float fScaleY = ( float ) ( iY - iMinY ) / ( ( float ) ( iMaxY - iMinY ) ) ;
int iWindowX = ( int ) ( fScaleX * ( float ) g_nViewportCX ) ;
int iWindowY = ( int ) ( fScaleY * ( float ) g_nViewportCY ) ;
DrawCrosshairs ( iWindowX , iWindowY ) ;
}
# ifdef _DEBUG
//#define _DEBUG_SHOW_CURSOR // NB. Get an ASSERT on LMB (after Ctrl+LMB)
# endif
2021-01-10 16:33:06 +00:00
void Win32Frame : : UpdateMouseInAppleViewport ( int iOutOfBoundsX , int iOutOfBoundsY , int x , int y )
2020-11-23 19:21:20 +00:00
{
const bool bOutsideAppleViewport = iOutOfBoundsX | | iOutOfBoundsY ;
if ( bOutsideAppleViewport )
{
2020-12-20 15:32:51 +00:00
if ( GetPropertySheet ( ) . GetMouseRestrictToWindow ( ) )
2020-11-23 19:21:20 +00:00
return ;
g_bLastCursorInAppleViewport = false ;
if ( ! g_bShowingCursor )
{
// Mouse leaving Apple screen area
FrameSetCursorPosByMousePos ( 0 , 0 , iOutOfBoundsX , iOutOfBoundsY , true ) ;
# ifdef _DEBUG_SHOW_CURSOR
g_bShowingCursor = true ;
# else
FrameShowCursor ( TRUE ) ;
# endif
}
}
else
{
g_bLastCursorInAppleViewport = true ;
if ( g_bShowingCursor )
{
// Mouse entering Apple screen area
FrameSetCursorPosByMousePos ( x , y , 0 , 0 , false ) ;
# ifdef _DEBUG_SHOW_CURSOR
g_bShowingCursor = false ;
# else
FrameShowCursor ( FALSE ) ;
# endif
//
2020-12-20 15:32:51 +00:00
if ( GetPropertySheet ( ) . GetMouseRestrictToWindow ( ) )
2020-11-23 19:21:20 +00:00
SetUsingCursor ( TRUE ) ;
}
else
{
2021-01-10 16:33:06 +00:00
FrameSetCursorPosByMousePos ( ) ; // Set cursor to Apple position each time
2020-11-23 19:21:20 +00:00
}
DrawCrosshairsMouse ( ) ;
}
}
2021-01-16 21:57:28 +00:00
void Win32Frame : : GetViewportCXCY ( int & nViewportCX , int & nViewportCY )
2020-11-23 19:21:20 +00:00
{
nViewportCX = g_nViewportCX ;
nViewportCY = g_nViewportCY ;
}
// Call all funcs with dependency on g_Apple2Type
2020-12-24 15:08:50 +00:00
void Win32Frame : : FrameUpdateApple2Type ( void )
2020-11-23 19:21:20 +00:00
{
DeleteGdiObjects ( ) ;
CreateGdiObjects ( ) ;
// DRAW_TITLE : calls GetAppleWindowTitle()
// DRAW_LEDS : update LEDs (eg. CapsLock varies on Apple2 type)
DrawStatusArea ( ( HDC ) 0 , DRAW_TITLE | DRAW_LEDS ) ;
// Draw buttons & call DrawStatusArea(DRAW_BACKGROUND | DRAW_LEDS | DRAW_DISK_STATUS)
DrawFrameWindow ( ) ;
}
2021-11-30 21:41:02 +00:00
bool Win32Frame : : GetBestDisplayResolutionForFullScreen ( UINT & bestWidth , UINT & bestHeight , UINT userSpecifiedWidth /*=0*/ , UINT userSpecifiedHeight /*=0*/ )
2020-11-23 19:21:20 +00:00
{
2021-05-31 15:09:39 +00:00
m_bestWidthForFullScreen = 0 ;
m_bestHeightForFullScreen = 0 ;
2020-11-23 19:21:20 +00:00
typedef std : : vector < std : : pair < UINT , UINT > > VEC_PAIR ;
VEC_PAIR vecDisplayResolutions ;
for ( UINT iModeNum = 0 ; ; iModeNum + + )
{
DEVMODE devMode ;
devMode . dmSize = sizeof ( DEVMODE ) ;
devMode . dmDriverExtra = 0 ;
BOOL bValid = EnumDisplaySettings ( NULL , iModeNum , & devMode ) ;
if ( ! bValid )
break ;
if ( iModeNum = = 0 ) // 0 is the initial "cache info about display device" operation
continue ;
if ( devMode . dmBitsPerPel ! = 32 )
continue ;
if ( userSpecifiedHeight = = 0 | | userSpecifiedHeight = = devMode . dmPelsHeight )
{
if ( vecDisplayResolutions . size ( ) = = 0 | | vecDisplayResolutions . back ( ) ! = std : : pair < UINT , UINT > ( devMode . dmPelsWidth , devMode . dmPelsHeight ) ) // Skip duplicate resolutions
{
vecDisplayResolutions . push_back ( std : : pair < UINT , UINT > ( devMode . dmPelsWidth , devMode . dmPelsHeight ) ) ;
LogFileOutput ( " EnumDisplaySettings(%d) - %d x %d \n " , iModeNum , devMode . dmPelsWidth , devMode . dmPelsHeight ) ;
}
}
}
if ( userSpecifiedHeight )
{
if ( vecDisplayResolutions . size ( ) = = 0 )
return false ;
2021-11-30 21:41:02 +00:00
// Pick user-specific width if it exists
// Else pick least width (such that it's wide enough to scale)
2020-11-23 19:21:20 +00:00
UINT width = ( UINT ) - 1 ;
for ( VEC_PAIR : : iterator it = vecDisplayResolutions . begin ( ) ; it ! = vecDisplayResolutions . end ( ) ; + + it )
{
2021-11-30 21:41:02 +00:00
if ( it - > first = = userSpecifiedWidth )
{
width = userSpecifiedWidth ;
break ;
}
2020-11-23 19:21:20 +00:00
if ( width > it - > first )
{
2020-12-28 16:25:29 +00:00
UINT scaleFactor = it - > second / GetVideo ( ) . GetFrameBufferBorderlessHeight ( ) ;
if ( it - > first > = ( GetVideo ( ) . GetFrameBufferBorderlessWidth ( ) * scaleFactor ) )
2020-11-23 19:21:20 +00:00
{
width = it - > first ;
}
}
}
if ( width = = ( UINT ) - 1 )
return false ;
bestWidth = width ;
bestHeight = userSpecifiedHeight ;
2021-05-31 15:09:39 +00:00
m_bestWidthForFullScreen = bestWidth ;
m_bestHeightForFullScreen = bestHeight ;
2020-11-23 19:21:20 +00:00
return true ;
}
// Pick max height that's an exact multiple of GetFrameBufferBorderlessHeight()
UINT tmpBestWidth = 0 ;
UINT tmpBestHeight = 0 ;
for ( VEC_PAIR : : iterator it = vecDisplayResolutions . begin ( ) ; it ! = vecDisplayResolutions . end ( ) ; + + it )
{
2020-12-28 16:25:29 +00:00
if ( ( it - > second % GetVideo ( ) . GetFrameBufferBorderlessHeight ( ) ) = = 0 )
2020-11-23 19:21:20 +00:00
{
if ( it - > second > tmpBestHeight )
{
2020-12-28 16:25:29 +00:00
UINT scaleFactor = it - > second / GetVideo ( ) . GetFrameBufferBorderlessHeight ( ) ;
if ( it - > first > = ( GetVideo ( ) . GetFrameBufferBorderlessWidth ( ) * scaleFactor ) )
2020-11-23 19:21:20 +00:00
{
tmpBestWidth = it - > first ;
tmpBestHeight = it - > second ;
}
}
}
}
if ( tmpBestWidth = = 0 )
return false ;
bestWidth = tmpBestWidth ;
bestHeight = tmpBestHeight ;
2021-05-31 15:09:39 +00:00
m_bestWidthForFullScreen = bestWidth ;
m_bestHeightForFullScreen = bestHeight ;
2020-11-23 19:21:20 +00:00
return true ;
}