2019-07-26 05:51:36 +00:00
//
// V i e w C o n t r o l l e r . s w i f t
// A 2 M a c
//
// C r e a t e d b y T a m a s R u d n a i o n 7 / 2 5 / 1 9 .
// C o p y r i g h t © 2 0 1 9 G a m e A l l o y . A l l r i g h t s r e s e r v e d .
//
2020-01-28 06:54:03 +00:00
2019-07-26 05:51:36 +00:00
import Cocoa
2020-02-07 08:40:31 +00:00
import AVFoundation
2019-07-26 05:51:36 +00:00
2020-01-28 06:54:03 +00:00
let K : Double = 1000.0
let M : Double = ( K * K )
let G : Double = ( M * K )
let T : Double = ( G * K )
let KB : Double = 1024.0
let MB : Double = ( KB * KB )
let GB : Double = ( MB * KB )
let TB : Double = ( GB * KB )
2020-06-21 05:14:39 +00:00
let colorWhite = NSColor . init ( red : 0.9296875 , green : 0.9296875 , blue : 0.9296875 , alpha : 1 )
let colorGreen = NSColor . init ( red : 0.16796875 , green : 0.84375 , blue : 0.2890625 , alpha : 1 )
let colorOrange = NSColor . init ( red : 1 , green : 0.38671875 , blue : 0.0078125 , alpha : 1 )
var monoColor = colorGreen ;
2020-02-07 08:40:31 +00:00
var spk_up : AVAudioPlayer ?
var spk_dn : AVAudioPlayer ?
@ _cdecl ( " ViewController_spk_up_play " )
func spk_up_play ( ) {
spk_up ? . stop ( )
spk_dn ? . stop ( )
spk_up ? . play ( )
}
@ _cdecl ( " ViewController_spk_dn_play " )
func spk_dn_play ( ) {
spk_up ? . stop ( )
spk_dn ? . stop ( )
spk_dn ? . play ( )
}
2020-06-24 22:44:15 +00:00
// # i f M E T A L _ Y E S
// i m p o r t M e t a l
// # e n d i f
2019-11-28 04:27:32 +00:00
2020-04-27 14:26:04 +00:00
class ViewController : NSViewController {
2019-07-26 05:51:36 +00:00
2019-09-19 09:27:56 +00:00
@IBOutlet weak var displayField : NSTextField !
2019-07-30 08:05:21 +00:00
@IBOutlet weak var display : NSTextFieldCell !
2019-09-17 09:12:05 +00:00
@IBOutlet weak var speedometer : NSTextFieldCell !
2020-05-29 15:50:47 +00:00
@IBOutlet weak var lores : LoRes !
2019-11-28 04:27:32 +00:00
@IBOutlet weak var hires : HiRes !
2020-06-11 02:11:27 +00:00
@IBOutlet weak var splashScreen : NSView !
2020-06-17 16:46:17 +00:00
@IBOutlet weak var scanLines : NSImageView !
2019-11-28 04:27:32 +00:00
2020-06-17 16:46:17 +00:00
var CRTMonitor = false
2020-06-21 01:46:26 +00:00
var ColorMonitor = true
2020-06-02 17:10:18 +00:00
var Keyboard2Joystick = true
var Mouse2Joystick = false
var MouseInterface = true
2019-09-17 09:12:05 +00:00
2019-09-10 07:00:00 +00:00
// s t a t i c l e t c h a r C o n v S t r : S t r i n g =
// " @ 🄰 🄱 🄲 🄳 🄴 🄵 🄶 🄷 🄸 🄹 🄺 🄻 🄼 🄽 🄾 🄿 🅀 🅁 🅂 🅃 🅄 🅅 🅆 🅇 🅈 🅉 [ \ \ ] ^ _ ! \ " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? " +
// " @ 🅰 🅱 🅲 🅳 🅴 🅵 🅶 🅷 🅸 🅹 🅺 🅻 🅼 🅽 🅾 🅿 🆀 🆁 🆂 🆃 🆄 🆅 🆆 🆇 🆈 🆉 [ \ \ ] ^ _ ⬛ ︎ ! \ " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? " + / / F L
// " @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ \ ] ^ _ ! \ " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? " +
// " @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~ ? "
2019-09-19 09:27:56 +00:00
// s t a t i c l e t c h a r C o n v S t r : S t r i n g =
// " @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ \ ] ^ _ ! \ " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? " +
// " @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ \ ] ^ _ ░ ! \ " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? " + / / F L
// " @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ \ ] ^ _ \ u { E 0 A 0 } ! \ " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? " +
// " @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~ ? "
// s t a t i c l e t c h a r C o n v S t r : S t r i n g =
// " \ u { E 1 4 0 } \ u { E 1 4 1 } \ u { E 1 4 2 } \ u { E 1 4 3 } \ u { E 1 4 4 } \ u { E 1 4 5 } \ u { E 1 4 6 } \ u { E 1 4 7 } \ u { E 1 4 8 } \ u { E 1 4 9 } \ u { E 1 4 A } \ u { E 1 4 B } \ u { E 1 4 C } \ u { E 1 4 D } \ u { E 1 4 E } \ u { E 1 4 F } \ u { E 1 5 0 } \ u { E 1 5 1 } \ u { E 1 5 2 } \ u { E 1 5 3 } \ u { E 1 5 4 } \ u { E 1 5 5 } \ u { E 1 5 6 } \ u { E 1 5 7 } \ u { E 1 5 8 } \ u { E 1 5 9 } \ u { E 1 5 A } \ u { E 1 5 B } \ u { E 1 5 C } \ u { E 1 5 D } \ u { E 1 5 E } \ u { E 1 5 F } \ u { E 1 2 0 } \ u { E 1 2 1 } \ u { E 1 2 2 } \ u { E 1 2 3 } \ u { E 1 2 4 } \ u { E 1 2 5 } \ u { E 1 2 6 } \ u { E 1 2 7 } \ u { E 1 2 8 } \ u { E 1 2 9 } \ u { E 1 2 A } \ u { E 1 2 B } \ u { E 1 2 C } \ u { E 1 2 D } \ u { E 1 2 E } \ u { E 1 2 F } \ u { E 1 3 0 } \ u { E 1 3 1 } \ u { E 1 3 2 } \ u { E 1 3 3 } \ u { E 1 3 4 } \ u { E 1 3 5 } \ u { E 1 3 6 } \ u { E 1 3 7 } \ u { E 1 3 8 } \ u { E 1 3 9 } \ u { E 1 3 A } \ u { E 1 3 B } \ u { E 1 3 C } \ u { E 1 3 D } \ u { E 1 3 E } \ u { E 1 3 F } " +
// " @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ \ ] ^ _ ░ ! \ " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? " + / / F L
// " @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ \ ] ^ _ \ u { E 0 A 0 } ! \ " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? " +
// " @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~ ? "
2019-09-09 02:55:19 +00:00
2019-09-19 09:27:56 +00:00
static let charConvStrFlashOff : String =
" \ u{E140} \ u{E141} \ u{E142} \ u{E143} \ u{E144} \ u{E145} \ u{E146} \ u{E147} \ u{E148} \ u{E149} \ u{E14A} \ u{E14B} \ u{E14C} \ u{E14D} \ u{E14E} \ u{E14F} \ u{E150} \ u{E151} \ u{E152} \ u{E153} \ u{E154} \ u{E155} \ u{E156} \ u{E157} \ u{E158} \ u{E159} \ u{E15A} \ u{E15B} \ u{E15C} \ u{E15D} \ u{E15E} \ u{E15F} \ u{E120} \ u{E121} \ u{E122} \ u{E123} \ u{E124} \ u{E125} \ u{E126} \ u{E127} \ u{E128} \ u{E129} \ u{E12A} \ u{E12B} \ u{E12C} \ u{E12D} \ u{E12E} \ u{E12F} \ u{E130} \ u{E131} \ u{E132} \ u{E133} \ u{E134} \ u{E135} \ u{E136} \ u{E137} \ u{E138} \ u{E139} \ u{E13A} \ u{E13B} \ u{E13C} \ u{E13D} \ u{E13E} \ u{E13F} " +
2020-04-26 04:28:18 +00:00
2019-09-19 09:27:56 +00:00
" @ABCDEFGHIJKLMNOPQRSTUVWXYZ[ \\ ]^_ ! \" #$%&'()*+,-./0123456789:;<=>? " + // F L
2020-04-26 04:28:18 +00:00
2019-09-22 08:31:09 +00:00
" @ABCDEFGHIJKLMNOPQRSTUVWXYZ[ \\ ]^_ ! \" #$%&'()*+,-./0123456789:;<=>? " +
2020-04-26 04:28:18 +00:00
" @ABCDEFGHIJKLMNOPQRSTUVWXYZ[ \\ ]^_`abcdefghijklmnopqrstuvwxyz{|}~ \ u{007F} "
2019-09-19 09:27:56 +00:00
static let charConvStrFlashOn : String =
" \ u{E140} \ u{E141} \ u{E142} \ u{E143} \ u{E144} \ u{E145} \ u{E146} \ u{E147} \ u{E148} \ u{E149} \ u{E14A} \ u{E14B} \ u{E14C} \ u{E14D} \ u{E14E} \ u{E14F} \ u{E150} \ u{E151} \ u{E152} \ u{E153} \ u{E154} \ u{E155} \ u{E156} \ u{E157} \ u{E158} \ u{E159} \ u{E15A} \ u{E15B} \ u{E15C} \ u{E15D} \ u{E15E} \ u{E15F} \ u{E120} \ u{E121} \ u{E122} \ u{E123} \ u{E124} \ u{E125} \ u{E126} \ u{E127} \ u{E128} \ u{E129} \ u{E12A} \ u{E12B} \ u{E12C} \ u{E12D} \ u{E12E} \ u{E12F} \ u{E130} \ u{E131} \ u{E132} \ u{E133} \ u{E134} \ u{E135} \ u{E136} \ u{E137} \ u{E138} \ u{E139} \ u{E13A} \ u{E13B} \ u{E13C} \ u{E13D} \ u{E13E} \ u{E13F} " +
" \ u{E140} \ u{E141} \ u{E142} \ u{E143} \ u{E144} \ u{E145} \ u{E146} \ u{E147} \ u{E148} \ u{E149} \ u{E14A} \ u{E14B} \ u{E14C} \ u{E14D} \ u{E14E} \ u{E14F} \ u{E150} \ u{E151} \ u{E152} \ u{E153} \ u{E154} \ u{E155} \ u{E156} \ u{E157} \ u{E158} \ u{E159} \ u{E15A} \ u{E15B} \ u{E15C} \ u{E15D} \ u{E15E} \ u{E15F} \ u{E120} \ u{E121} \ u{E122} \ u{E123} \ u{E124} \ u{E125} \ u{E126} \ u{E127} \ u{E128} \ u{E129} \ u{E12A} \ u{E12B} \ u{E12C} \ u{E12D} \ u{E12E} \ u{E12F} \ u{E130} \ u{E131} \ u{E132} \ u{E133} \ u{E134} \ u{E135} \ u{E136} \ u{E137} \ u{E138} \ u{E139} \ u{E13A} \ u{E13B} \ u{E13C} \ u{E13D} \ u{E13E} \ u{E13F} " +
2020-04-26 04:28:18 +00:00
2019-09-22 08:31:09 +00:00
" @ABCDEFGHIJKLMNOPQRSTUVWXYZ[ \\ ]^_ ! \" #$%&'()*+,-./0123456789:;<=>? " +
2020-04-26 04:28:18 +00:00
" @ABCDEFGHIJKLMNOPQRSTUVWXYZ[ \\ ]^_`abcdefghijklmnopqrstuvwxyz{|}~ \ u{007F} "
2019-09-19 09:27:56 +00:00
2019-09-22 08:31:09 +00:00
static let charConvTblFlashOn = Array ( charConvStrFlashOn )
static let charConvTblFlashOff = Array ( charConvStrFlashOff )
static var charConvTbl = charConvTblFlashOn
2020-04-26 07:23:05 +00:00
2020-06-06 20:19:29 +00:00
static var romFileName = " Apple2e_Enhanced.rom " ;
2019-09-09 02:55:19 +00:00
2020-05-29 15:50:47 +00:00
static let textLineOfs : [ Int ] = [
2019-09-09 02:55:19 +00:00
0x000 , 0x080 , 0x100 , 0x180 , 0x200 , 0x280 , 0x300 , 0x380 , 0x028 , 0x0A8 , 0x128 , 0x1A8 ,
0x228 , 0x2A8 , 0x328 , 0x3A8 , 0x050 , 0x0D0 , 0x150 , 0x1D0 , 0x250 , 0x2D0 , 0x350 , 0x3D0
]
2020-06-04 18:37:35 +00:00
func dialogOK ( title : String , text : String ) {
let alert = NSAlert ( )
alert . messageText = title
alert . informativeText = text
alert . alertStyle = . warning
alert . addButton ( withTitle : " OK " )
alert . runModal ( )
// r e t u r n a l e r t . r u n M o d a l ( ) = = . a l e r t F i r s t B u t t o n R e t u r n
}
@objc func chk_woz_load ( err : Int32 ) {
switch ( err ) {
case WOZ_ERR_OK :
break
case WOZ_ERR_FILE_NOT_FOUND :
dialogOK ( title : " Error Loading Disk Image " , text : " File Not Found! " )
break
case WOZ_ERR_NOT_WOZ_FILE :
dialogOK ( title : " Error Loading Disk Image " , text : " File is not a WOZ image! " )
break
case WOZ_ERR_BAD_CHUNK_HDR , WOZ_ERR_BAD_DATA :
dialogOK ( title : " Error Loading Disk Image " , text : " Malformed WOZ image! " )
break
default :
dialogOK ( title : " Error Loading Disk Image " , text : " Unknown Error! ( \( err ) ) " )
break
}
}
2019-09-12 01:36:30 +00:00
var workItem : DispatchWorkItem ? = nil ;
2020-06-26 03:23:08 +00:00
@IBAction func PowerOn ( _ sender : Any ) {
2020-05-09 21:40:42 +00:00
upd . suspend ( )
2020-06-17 16:46:17 +00:00
cpuState = cpuState_inited ;
2020-06-26 03:23:08 +00:00
spkr_stopAll ( )
2020-05-09 10:39:55 +00:00
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// A n i m a t e d S p l a s h S c r e e n f a d e o u t a n d ( T e x t ) M o n i t o r f a d e i n
2020-05-09 21:40:42 +00:00
hires . isHidden = true
2020-05-09 10:39:55 +00:00
displayField . alphaValue = 0
displayField . isHidden = false
splashScreen . alphaValue = 1
splashScreen . isHidden = false
2020-05-09 21:40:42 +00:00
DispatchQueue . main . asyncAfter ( deadline : . now ( ) + 0.5 ) {
2020-05-09 10:39:55 +00:00
NSAnimationContext . runAnimationGroup ( { ( context ) in
2020-05-09 21:40:42 +00:00
context . duration = 0.5
2020-05-09 10:39:55 +00:00
// U s e t h e v a l u e y o u w a n t t o a n i m a t e t o ( N O T t h e s t a r t i n g v a l u e )
self . displayField . animator ( ) . alphaValue = 1
self . splashScreen . animator ( ) . alphaValue = 0
} ,
completionHandler : { ( ) -> Void in
self . displayField . alphaValue = 1
self . splashScreen . isHidden = true
} )
2020-05-09 21:40:42 +00:00
2020-06-24 22:44:15 +00:00
m6502_ColdReset ( Bundle . main . resourcePath ! + " /rom/ " , ViewController . romFileName )
2020-05-09 21:40:42 +00:00
2020-06-17 16:46:17 +00:00
cpuState = cpuState_running ;
2020-05-09 21:40:42 +00:00
self . upd . resume ( )
2020-05-09 10:39:55 +00:00
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2020-02-07 08:40:31 +00:00
2019-09-19 09:27:56 +00:00
#if SPEEDTEST
if ( workItem != nil ) {
workItem ! . cancel ( ) ;
workItem = nil ;
}
else {
workItem = DispatchWorkItem {
DispatchQueue . global ( qos : . userInteractive ) . async {
// D i s p a t c h Q u e u e . g l o b a l ( q o s : . u s e r I n i t i a t e d ) . a s y n c {
// D i s p a t c h Q u e u e . g l o b a l ( q o s : . b a c k g r o u n d ) . a s y n c {
tst6502 ( )
}
}
DispatchQueue . global ( ) . async ( execute : workItem ! ) ;
}
#else
2020-04-30 14:26:46 +00:00
2020-05-09 21:40:42 +00:00
2019-09-19 09:27:56 +00:00
#endif
2019-09-09 07:27:31 +00:00
}
2020-06-26 03:23:08 +00:00
@IBAction func PowerOff ( _ sender : Any ) {
upd . suspend ( )
cpuState = cpuState_inited ;
spkr_stopAll ( )
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// A n i m a t e d S p l a s h S c r e e n f a d e o u t a n d ( T e x t ) M o n i t o r f a d e i n
hires . isHidden = true
displayField . alphaValue = 0
displayField . isHidden = false
splashScreen . alphaValue = 1
splashScreen . isHidden = false
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
}
@IBAction func Pause ( _ sender : Any ) {
switch ( cpuState ) {
case cpuState_halted :
upd . resume ( )
cpuState = cpuState_running
break
case cpuState_running :
upd . suspend ( )
cpuState = cpuState_halted
break
default :
// u p d . s u s p e n d ( )
// c p u S t a t e = c p u S t a t e _ h a l t e d
break
}
}
2019-09-09 07:27:31 +00:00
@IBAction func Reset ( _ sender : Any ) {
2020-05-03 05:39:54 +00:00
// m 6 5 0 2 . i n t e r r u p t = S O F T R E S E T ;
2020-05-03 05:35:59 +00:00
2020-05-03 05:39:54 +00:00
// l e t s a v e d _ f r m _ s e t = c l k _ 6 5 0 2 _ p e r _ f r m _ s e t ;
// c l k _ 6 5 0 2 _ p e r _ f r m _ s e t = 0
// c l k _ 6 5 0 2 _ p e r _ f r m _ m a x = 0
// / / w a i t f o r 1 m s t o a l l o w t h e s i m u l a t i o n t o h a l t
// u s l e e p ( 1 0 0 0 0 ) ;
2020-05-03 05:35:59 +00:00
softReset ( )
2020-05-03 05:39:54 +00:00
// c l k _ 6 5 0 2 _ p e r _ f r m _ s e t = s a v e d _ f r m _ s e t
2019-09-09 07:27:31 +00:00
}
2020-05-25 04:04:34 +00:00
static let textPage1Addr = 0x400
static let textPage2Addr = 0x800
2020-02-23 00:37:54 +00:00
static let textBufferSize = 0x400
2020-04-27 14:26:04 +00:00
// s t a t i c o n l y n e e d e d t o b e a b l e t o i n i t i a l i z e t h i n g s
static let textLines = 24
static let textCols = 40
static let lineEndChars = 1
// t h e s e a r e n e e d e d t o b e a b l e t o e a s y a c c e s s t o t h e s e c o n s t a n t s f r o m i n s t a n c e s
let textLines = ViewController . textLines
let textCols = ViewController . textCols
let lineEndChars = ViewController . lineEndChars
2020-02-23 00:37:54 +00:00
var frameCnt = 0
// l e t s p a c e C h a r : C h a r a c t e r = " \ u { E 1 7 F } "
// l e t b l o c k C h a r : C h a r a c t e r = " \ u { E 0 7 F } "
2020-04-27 14:26:04 +00:00
// s t a t i c l e t s p a c e C h a r : C h a r a c t e r = " "
// s t a t i c l e t b l o c k C h a r : C h a r a c t e r = " ░ "
// s t a t i c v a r f l a s h i n g S p a c e : C h a r a c t e r = " "
2020-02-23 00:37:54 +00:00
2020-05-01 21:43:41 +00:00
let ramBufferPointer = UnsafeRawBufferPointer ( start : MEM , count : 64 * 1024 )
2020-05-27 04:13:31 +00:00
static let textPage1Pointer = UnsafeRawBufferPointer ( start : MEM + textPage1Addr , count : textBufferSize )
static let textPage2Pointer = UnsafeRawBufferPointer ( start : MEM + textPage2Addr , count : textBufferSize )
static let textIntBufferPointer = UnsafeRawBufferPointer ( start : RAM + textPage1Addr , count : textBufferSize )
static let textAuxBufferPointer = UnsafeRawBufferPointer ( start : AUX + textPage1Addr , count : textBufferSize )
2020-05-29 15:50:47 +00:00
// TODO: R e n d e r t e x t s c r e e n i n n a t i v e C
// s t a t i c l e t t e x t S c r e e n = U n s a f e M u t a b l e R a w P o i n t e r ( m u t a t i n g : t e s t T e x t )
2020-05-25 04:04:34 +00:00
var textBufferPointer = textPage1Pointer
2020-04-27 14:26:04 +00:00
static let textArraySize = textLines * ( textCols + lineEndChars ) + textCols * 2
var txtClear = [ Character ] ( repeating : " " , count : textArraySize * 2 )
var txtArr = [ Character ] ( repeating : " " , count : textArraySize * 2 )
2020-02-23 00:37:54 +00:00
var s = String ( )
func HexDump ( ) {
var txt : String = " "
for y in 0. . . textLines - 1 {
txt += String ( format : " %04X: " , y * 16 )
for x in 0. . . 15 {
let byte = ramBufferPointer [ y * 16 + x ]
let chr = String ( format : " %02X " , byte )
txt += chr
}
txt += " \n "
}
DispatchQueue . main . async {
self . display . stringValue = txt
self . speedometer . stringValue = String ( format : " %0.3lf MHz " , mhz ) ;
}
}
2019-09-22 08:31:09 +00:00
// A p p l e S c r i p t K e y c o d e s
let leftArrowKey = 123
let rightArrowKey = 124
let upArrowKey = 126
let downArrowKey = 125
2020-02-23 00:37:54 +00:00
var ddd = 9 ;
2019-09-22 08:31:09 +00:00
2020-04-27 14:26:04 +00:00
override var acceptsFirstResponder : Bool {
return true
}
2019-09-09 07:27:31 +00:00
override func keyDown ( with event : NSEvent ) {
2020-06-17 16:46:17 +00:00
if ( cpuMode = = cpuMode_eco ) {
cpuState = cpuState_running ;
2020-06-18 22:14:54 +00:00
upd . resume ( )
2020-06-17 16:46:17 +00:00
}
2020-06-06 06:16:17 +00:00
// p r i n t ( " k e y D o w n " )
2020-02-23 00:37:54 +00:00
2020-04-23 02:18:28 +00:00
// f o r i i n 0 . . . 6 5 5 3 6 {
// d d d = I n t ( e v e n t . k e y C o d e ) + i
// }
// d d d = d d d * 2
2019-09-15 11:02:22 +00:00
// s w i t c h e v e n t . m o d i f i e r F l a g s . i n t e r s e c t i o n ( . d e v i c e I n d e p e n d e n t F l a g s M a s k ) {
// c a s e [ . c o m m a n d ] w h e r e e v e n t . c h a r a c t e r s = = " l " ,
// [ . c o m m a n d , . s h i f t ] w h e r e e v e n t . c h a r a c t e r s = = " l " :
// p r i n t ( " c o m m a n d - l o r c o m m a n d - s h i f t - l " )
// d e f a u l t :
// b r e a k
// }
// p r i n t ( " k e y = " + ( e v e n t . c h a r a c t e r s I g n o r i n g M o d i f i e r s ? ? " " ) )
// p r i n t ( " \ n c h a r a c t e r = " + ( e v e n t . c h a r a c t e r s ? ? " " ) )
2019-09-09 07:27:31 +00:00
2020-04-23 02:18:28 +00:00
if event . modifierFlags . contains ( . command ) { // . s h i f t , . o p t i o n , . c o n t r o l . . .
if let chars = event . charactersIgnoringModifiers {
switch chars {
case " v " :
print ( " CMD + V " )
let pasteBoard = NSPasteboard . general
if let str = pasteBoard . string ( forType : . string ) {
print ( " PASTED: " , str )
DispatchQueue . global ( qos : . background ) . async {
for char in str . uppercased ( ) {
if let ascii = char . asciiValue {
kbdInput ( ascii )
}
}
}
}
default :
2020-06-03 17:23:55 +00:00
super . keyDown ( with : event )
2020-04-23 02:18:28 +00:00
break
2019-09-09 07:27:31 +00:00
}
}
}
2020-04-23 02:18:28 +00:00
else {
#if FUNCTIONTEST
#else
let keyCode = Int ( event . keyCode )
switch keyCode {
case leftArrowKey :
2020-06-06 06:16:17 +00:00
// p r i n t ( " L E F T " , d d d ) ;
2020-06-02 17:10:18 +00:00
if ( Keyboard2Joystick ) {
// K e y b o a r d 2 J o y S t i c k ( G a m e C o n t r o l l e r / P a d d l e )
pdl_valarr [ 0 ] = 0
}
kbdInput ( 0x08 )
2020-05-24 19:14:09 +00:00
2020-04-23 02:18:28 +00:00
case rightArrowKey :
2020-06-06 06:16:17 +00:00
// p r i n t ( " R I G H T " )
2020-05-24 19:14:09 +00:00
// K e y b o a r d 2 J o y S t i c k ( G a m e C o n t r o l l e r / P a d d l e )
2020-06-02 17:10:18 +00:00
if ( Keyboard2Joystick ) {
pdl_valarr [ 0 ] = 1
}
kbdInput ( 0x15 )
2020-04-23 02:18:28 +00:00
case downArrowKey :
2020-06-06 06:16:17 +00:00
// p r i n t ( " D O W N " )
2020-05-24 19:14:09 +00:00
// K e y b o a r d 2 J o y S t i c k ( G a m e C o n t r o l l e r / P a d d l e )
2020-06-02 17:10:18 +00:00
if ( Keyboard2Joystick ) {
pdl_valarr [ 1 ] = 1
}
else {
kbdInput ( 0x0B )
}
2020-04-23 02:18:28 +00:00
case upArrowKey :
2020-06-06 06:16:17 +00:00
// p r i n t ( " U P " )
2020-05-24 19:14:09 +00:00
// K e y b o a r d 2 J o y S t i c k ( G a m e C o n t r o l l e r / P a d d l e )
2020-06-02 17:10:18 +00:00
if ( Keyboard2Joystick ) {
pdl_valarr [ 1 ] = 0
}
else {
kbdInput ( 0x0A )
}
2020-04-23 02:18:28 +00:00
default :
// p r i n t ( " k e y c o d e : % d " , k e y C o d e )
if let chars = event . characters {
let char = chars . uppercased ( ) [ chars . startIndex ]
if let ascii = char . asciiValue {
kbdInput ( ascii )
}
}
}
#endif
}
2020-04-27 14:26:04 +00:00
2019-09-09 07:27:31 +00:00
}
2020-05-06 06:03:36 +00:00
var savedVideoMode = videoMode_t . init ( )
2020-02-23 00:37:54 +00:00
override func keyUp ( with event : NSEvent ) {
2020-06-06 06:16:17 +00:00
// p r i n t ( " k e y U p " )
2020-02-23 00:37:54 +00:00
// s w i t c h e v e n t . m o d i f i e r F l a g s . i n t e r s e c t i o n ( . d e v i c e I n d e p e n d e n t F l a g s M a s k ) {
// c a s e [ . c o m m a n d ] w h e r e e v e n t . c h a r a c t e r s = = " l " ,
// [ . c o m m a n d , . s h i f t ] w h e r e e v e n t . c h a r a c t e r s = = " l " :
// p r i n t ( " c o m m a n d - l o r c o m m a n d - s h i f t - l " )
// d e f a u l t :
// b r e a k
// }
// p r i n t ( " k e y = " + ( e v e n t . c h a r a c t e r s I g n o r i n g M o d i f i e r s ? ? " " ) )
// p r i n t ( " \ n c h a r a c t e r = " + ( e v e n t . c h a r a c t e r s ? ? " " ) )
#if FUNCTIONTEST
#else
let keyCode = Int ( event . keyCode )
switch keyCode {
case leftArrowKey :
// k b d I n p u t ( 0 x 0 8 )
2020-05-24 19:14:09 +00:00
// s e t I O ( 0 x C 0 6 4 , 1 2 7 ) ;
2020-06-06 06:16:17 +00:00
// p r i n t ( " l e f t " )
2020-05-24 19:14:09 +00:00
// K e y b o a r d 2 J o y S t i c k ( G a m e C o n t r o l l e r / P a d d l e )
pdl_valarr [ 0 ] = 0.5
2020-02-23 00:37:54 +00:00
case rightArrowKey :
// k b d I n p u t ( 0 x 1 5 )
2020-05-24 19:14:09 +00:00
// s e t I O ( 0 x C 0 6 4 , 1 2 8 ) ;
2020-06-06 06:16:17 +00:00
// p r i n t ( " r i g h t " )
2020-05-24 19:14:09 +00:00
// K e y b o a r d 2 J o y S t i c k ( G a m e C o n t r o l l e r / P a d d l e )
pdl_valarr [ 0 ] = 0.5
2020-02-23 00:37:54 +00:00
case downArrowKey :
// k b d I n p u t ( 0 x 0 B )
2020-05-24 19:14:09 +00:00
// s e t I O ( 0 x C 0 6 5 , 1 2 7 ) ;
2020-06-06 06:16:17 +00:00
// p r i n t ( " d o w n " )
2020-05-24 19:14:09 +00:00
// K e y b o a r d 2 J o y S t i c k ( G a m e C o n t r o l l e r / P a d d l e )
pdl_valarr [ 1 ] = 0.5
2020-02-23 00:37:54 +00:00
case upArrowKey :
// k b d I n p u t ( 0 x 0 A )
2020-05-24 19:14:09 +00:00
// s e t I O ( 0 x C 0 6 5 , 1 2 8 ) ;
2020-06-06 06:16:17 +00:00
// p r i n t ( " u p " )
2020-05-24 19:14:09 +00:00
// K e y b o a r d 2 J o y S t i c k ( G a m e C o n t r o l l e r / P a d d l e )
pdl_valarr [ 1 ] = 0.5
2020-02-23 00:37:54 +00:00
default :
// p r i n t ( " k e y c o d e : % d " , k e y C o d e )
// i f l e t c h a r s = e v e n t . c h a r a c t e r s {
// l e t c h a r = c h a r s . u p p e r c a s e d ( ) [ c h a r s . s t a r t I n d e x ]
// i f l e t a s c i i = c h a r . a s c i i V a l u e {
// k b d I n p u t ( a s c i i )
// }
// }
break
}
#endif
2020-05-05 15:35:57 +00:00
kbdUp ( )
2020-02-23 00:37:54 +00:00
}
2020-05-21 05:22:44 +00:00
override func flagsChanged ( with event : NSEvent ) {
switch event . modifierFlags . intersection ( . deviceIndependentFlagsMask ) {
case [ . shift ] :
2020-06-25 04:05:55 +00:00
setIO ( 0xC061 , 0 )
setIO ( 0xC062 , 0 )
setIO ( 0xC063 , 0 ) // i n v e r t e d ( b i t 7 : n o t p r e s s e d )
2020-06-06 06:16:17 +00:00
// p r i n t ( " s h i f t k e y i s p r e s s e d " )
// c a s e [ . c o n t r o l ] :
// p r i n t ( " c o n t r o l k e y i s p r e s s e d " )
2020-05-21 05:22:44 +00:00
case [ . option ] :
2020-06-25 04:05:55 +00:00
setIO ( 0xC061 , 1 << 7 )
setIO ( 0xC062 , 0 )
setIO ( 0xC063 , 1 << 7 ) // i n v e r t e d ( b i t 7 : n o t p r e s s e d )
2020-06-06 06:16:17 +00:00
// p r i n t ( " o p t i o n k e y i s p r e s s e d " )
2020-05-21 05:22:44 +00:00
case [ . command ] :
2020-06-06 06:16:17 +00:00
// p r i n t ( " C o m m a n d k e y i s p r e s s e d " )
2020-06-25 04:05:55 +00:00
setIO ( 0xC061 , 0 )
setIO ( 0xC062 , 1 << 7 )
setIO ( 0xC063 , 1 << 7 ) // i n v e r t e d ( b i t 7 : n o t p r e s s e d )
2020-06-06 06:16:17 +00:00
// c a s e [ . c o n t r o l , . s h i f t ] :
// p r i n t ( " c o n t r o l - s h i f t k e y s a r e p r e s s e d " )
2020-05-21 05:22:44 +00:00
case [ . option , . shift ] :
2020-06-25 04:05:55 +00:00
setIO ( 0xC061 , 1 << 7 )
setIO ( 0xC062 , 0 )
setIO ( 0xC063 , 0 ) // i n v e r t e d ( b i t 7 : n o t p r e s s e d )
2020-06-06 06:16:17 +00:00
// p r i n t ( " o p t i o n - s h i f t k e y s a r e p r e s s e d " )
2020-05-21 05:22:44 +00:00
case [ . command , . shift ] :
2020-06-25 04:05:55 +00:00
setIO ( 0xC061 , 0 )
setIO ( 0xC062 , 1 << 7 )
setIO ( 0xC063 , 0 ) // i n v e r t e d ( b i t 7 : n o t p r e s s e d )
2020-06-06 06:16:17 +00:00
// p r i n t ( " c o m m a n d - s h i f t k e y s a r e p r e s s e d " )
// c a s e [ . c o n t r o l , . o p t i o n ] :
// p r i n t ( " c o n t r o l - o p t i o n k e y s a r e p r e s s e d " )
// c a s e [ . c o n t r o l , . c o m m a n d ] :
// p r i n t ( " c o n t r o l - c o m m a n d k e y s a r e p r e s s e d " )
2020-05-21 05:22:44 +00:00
case [ . option , . command ] :
2020-06-25 04:05:55 +00:00
setIO ( 0xC061 , 1 << 7 )
setIO ( 0xC062 , 1 << 7 )
setIO ( 0xC063 , 1 << 7 ) // i n v e r t e d ( b i t 7 : n o t p r e s s e d )
2020-06-06 06:16:17 +00:00
// p r i n t ( " o p t i o n - c o m m a n d k e y s a r e p r e s s e d " )
// c a s e [ . s h i f t , . c o n t r o l , . o p t i o n ] :
// p r i n t ( " s h i f t - c o n t r o l - o p t i o n k e y s a r e p r e s s e d " )
// c a s e [ . s h i f t , . c o n t r o l , . c o m m a n d ] :
// p r i n t ( " s h i f t - c o n t r o l - c o m m a n d k e y s a r e p r e s s e d " )
// c a s e [ . c o n t r o l , . o p t i o n , . c o m m a n d ] :
// p r i n t ( " c o n t r o l - o p t i o n - c o m m a n d k e y s a r e p r e s s e d " )
2020-05-21 05:22:44 +00:00
case [ . shift , . command , . option ] :
2020-06-25 04:05:55 +00:00
setIO ( 0xC061 , 1 << 7 )
setIO ( 0xC062 , 1 << 7 )
2020-05-28 16:35:17 +00:00
setIO ( 0xC063 , 0 ) ; // i n v e r t e d ( b i t 7 : n o t p r e s s e d )
2020-06-06 06:16:17 +00:00
// p r i n t ( " s h i f t - c o m m a n d - o p t i o n k e y s a r e p r e s s e d " )
// c a s e [ . s h i f t , . c o n t r o l , . o p t i o n , . c o m m a n d ] :
// p r i n t ( " s h i f t - c o n t r o l - o p t i o n - c o m m a n d k e y s a r e p r e s s e d " )
// c a s e [ . f u n c t i o n ] :
// p r i n t ( " f u n c t i o n k e y i s p r e s s e d " )
// c a s e [ . c a p s L o c k ] :
// p r i n t ( " c a p s L o c k k e y i s p r e s s e d " )
2020-05-21 05:22:44 +00:00
default :
2020-06-25 04:05:55 +00:00
setIO ( 0xC061 , 0 )
setIO ( 0xC062 , 0 )
setIO ( 0xC063 , 1 << 7 ) // i n v e r t e d ( b i t 7 : n o t p r e s s e d )
2020-06-06 06:16:17 +00:00
// p r i n t ( " n o m o d i f i e r k e y s a r e p r e s s e d " )
2020-05-21 05:22:44 +00:00
}
}
2019-09-09 07:27:31 +00:00
2020-02-23 00:37:54 +00:00
2019-09-19 09:27:56 +00:00
2019-11-28 04:27:32 +00:00
var was = 0 ;
2020-04-27 14:26:04 +00:00
var currentVideoMode = videoMode
2020-04-29 22:35:54 +00:00
var lastFrameTime = CACurrentMediaTime ( ) as Double
2020-05-06 16:56:21 +00:00
var frameCounter : UInt32 = 0
2020-04-29 22:35:54 +00:00
var clkCounter : Double = 0
2020-04-27 14:26:04 +00:00
2020-05-21 05:22:44 +00:00
var mouseLocation = NSPoint . zero
2020-05-24 19:14:09 +00:00
var shadowTxt : String = " "
2020-06-11 00:48:37 +00:00
func Render ( ) {
2019-09-17 09:12:05 +00:00
frameCnt += 1
2020-05-02 02:10:44 +00:00
2020-06-23 02:23:41 +00:00
if ( frameCnt = = fps / 2 ) {
2019-09-22 08:31:09 +00:00
ViewController . charConvTbl = ViewController . charConvTblFlashOn
2019-09-17 09:12:05 +00:00
}
2019-09-22 08:31:09 +00:00
else if ( frameCnt >= fps ) {
ViewController . charConvTbl = ViewController . charConvTblFlashOff
2019-09-17 09:12:05 +00:00
frameCnt = 0
}
2020-05-02 02:10:44 +00:00
// R e n d e r i n g i s h a p p e n i n g i n t h e m a i n t h r e a d , w h i c h h a s t w o i m p l i c a t i o n s :
// 1 . W e c a n u p d a t e U I e l e m e n t s
// 2 . i t i s i n d e p e n d e n t o f t h e s i m u l a t i o n , d e t h a t i s r u n n i n g i n t h e b a c k g r o u n d t h r e a d w h i l e w e a r e b u s y w i t h r e n d e r i n g . . .
2020-05-27 04:13:31 +00:00
DispatchQueue . main . sync {
2020-05-02 02:10:44 +00:00
var txt : String = " "
2020-06-11 00:48:37 +00:00
2020-05-02 02:10:44 +00:00
var fromLines = 0
var toLines = self . textLines
2020-06-11 00:48:37 +00:00
2020-05-02 02:10:44 +00:00
if videoMode . text = = 0 {
if videoMode . mixed = = 1 {
fromLines = toLines - 4
}
else {
toLines = 0
}
2020-02-23 00:37:54 +00:00
}
2020-06-11 00:48:37 +00:00
2020-05-02 02:10:44 +00:00
self . txtArr = self . txtClear
2020-06-11 00:48:37 +00:00
2020-05-02 02:10:44 +00:00
// r e n d e r a n e m p t y s p a c e t o e i m i n a t e d i s p l a y i n g t e x t p o r t i o n o f t h e s c r e e n c o v e r e d b y g r a p h i c s
2020-05-06 16:56:21 +00:00
let charDisposition = videoMode . col80 = = 0 ? 1 : 2
2020-05-02 02:10:44 +00:00
for y in 0 . . < fromLines {
2020-05-07 20:20:46 +00:00
self . txtArr [ y * ( self . textCols * charDisposition + self . lineEndChars ) + self . textCols * charDisposition ] = " \n "
2020-05-02 02:10:44 +00:00
}
2020-06-11 00:48:37 +00:00
2020-05-06 16:56:21 +00:00
// 4 0 c o l
if videoMode . col80 = = 0 {
2020-05-25 04:04:34 +00:00
if MEMcfg . txt_page_2 = = 0 {
self . textBufferPointer = ViewController . textPage1Pointer
}
else {
self . textBufferPointer = ViewController . textPage2Pointer
}
2020-05-06 16:56:21 +00:00
// r e n d e r t h e r e s t o f t h e t e x t s c r e e n
for y in fromLines . . < toLines {
for x in 0 . . < self . textCols {
2020-05-29 15:50:47 +00:00
let byte = self . textBufferPointer [ ViewController . textLineOfs [ y ] + x ]
2020-05-02 02:10:44 +00:00
let idx = Int ( byte ) ;
let chr = ViewController . charConvTbl [ idx ]
2020-05-06 16:56:21 +00:00
self . txtArr [ y * ( self . textCols + self . lineEndChars ) + x ] = chr
2020-05-02 02:10:44 +00:00
}
2020-05-06 16:56:21 +00:00
2020-05-02 02:10:44 +00:00
self . txtArr [ y * ( self . textCols + self . lineEndChars ) + self . textCols ] = " \n "
}
2020-05-06 16:56:21 +00:00
}
2020-06-21 05:14:39 +00:00
// 8 0 c o l
2020-05-06 16:56:21 +00:00
else {
2020-05-27 04:13:31 +00:00
let auxPage = ( MEMcfg . is_80STORE = = 1 ) && ( MEMcfg . txt_page_2 = = 1 )
let textIntBuffer = auxPage ? ViewController . textIntBufferPointer : ViewController . textPage1Pointer
let textAuxBuffer = auxPage ? ViewController . textPage1Pointer : ViewController . textAuxBufferPointer
2020-05-06 16:56:21 +00:00
// r e n d e r t h e r e s t o f t h e t e x t s c r e e n
for y in fromLines . . < toLines {
for x in 0 . . < self . textCols {
2020-05-29 15:50:47 +00:00
let byte = textIntBuffer [ ViewController . textLineOfs [ y ] + x ]
2020-05-06 16:56:21 +00:00
let idx = Int ( byte ) ;
let chr = ViewController . charConvTbl [ idx ]
self . txtArr [ y * ( self . textCols * 2 + self . lineEndChars ) + x * 2 + 1 ] = chr
2020-05-29 15:50:47 +00:00
let byte2 = textAuxBuffer [ ViewController . textLineOfs [ y ] + x ]
2020-05-06 16:56:21 +00:00
let idx2 = Int ( byte2 ) ;
let chr2 = ViewController . charConvTbl [ idx2 ]
self . txtArr [ y * ( self . textCols * 2 + self . lineEndChars ) + x * 2 ] = chr2
}
2020-05-02 02:10:44 +00:00
self . txtArr [ y * ( self . textCols * 2 + self . lineEndChars ) + self . textCols * 2 ] = " \n "
2020-04-27 14:26:04 +00:00
}
}
2020-06-11 00:48:37 +00:00
2020-05-02 02:10:44 +00:00
txt = String ( self . txtArr )
2020-06-11 00:48:37 +00:00
2020-05-29 15:50:47 +00:00
// TODO: R e n d e r t e x t S c r e e n i n n a t i v e C
2020-06-11 00:48:37 +00:00
// t x t = S t r i n g ( b y t e s N o C o p y : V i e w C o n t r o l l e r . t e x t S c r e e n ! , l e n g t h : 1 0 , e n c o d i n g : . a s c i i , f r e e W h e n D o n e : f a l s e ) ? ? " H M M "
2020-04-27 14:26:04 +00:00
if videoMode . col80 != self . currentVideoMode . col80 {
self . currentVideoMode . col80 = videoMode . col80
if let fontSize = self . display . font ? . pointSize {
if videoMode . col80 = = 1 {
self . display . font = NSFont ( name : " PRNumber3 " , size : fontSize )
}
else {
self . display . font = NSFont ( name : " PrintChar21 " , size : fontSize )
}
}
}
2020-05-24 19:14:09 +00:00
if ( self . shadowTxt != txt ) {
self . shadowTxt = txt
self . display . stringValue = txt
}
2020-06-11 00:48:37 +00:00
// s e l f . d i s p l a y . s t r i n g V a l u e = " t e s t i n g \ n i t \ n o u t "
2020-04-29 22:35:54 +00:00
if ( ( mhz < 1.5 ) && ( mhz != floor ( mhz ) ) ) {
2019-09-22 08:31:09 +00:00
self . speedometer . stringValue = String ( format : " %0.3lf MHz " , mhz ) ;
}
else {
2020-04-29 22:35:54 +00:00
self . speedometer . stringValue = String ( format : " %0.1lf MHz " , mhz ) ;
2019-09-22 08:31:09 +00:00
}
2020-06-11 00:48:37 +00:00
// e l s e {
// s e l f . s p e e d o m e t e r . s t r i n g V a l u e = S t r i n g ( f o r m a t : " % . 0 l f M H z " , m h z ) ;
// }
2019-09-22 08:31:09 +00:00
2019-11-28 04:27:32 +00:00
#if HIRES
2020-06-11 00:48:37 +00:00
2020-05-19 04:17:19 +00:00
// o n l y r e f r e s h g r a p h i c s v i e w w h e n n e e d e d ( a k a n o t i n t e x t m o d e )
if ( videoMode . text = = 0 ) {
2020-05-29 15:50:47 +00:00
if ( videoMode . hires = = 0 ) {
// w h e n w e c h a n g e v i d e o m o d e , b u f f e r n e e d s t o b e c l e a r e d t o a v o i d a r t i f a c t s
if ( self . savedVideoMode . text = = 1 )
2020-06-11 00:48:37 +00:00
|| ( self . savedVideoMode . mixed != videoMode . mixed )
|| ( self . savedVideoMode . hires != videoMode . hires )
2020-05-29 15:50:47 +00:00
{
self . lores . clearScreen ( )
self . lores . isHidden = false
self . hires . isHidden = true
}
2020-06-11 00:48:37 +00:00
2020-06-21 05:14:39 +00:00
self . lores . Render ( )
2020-05-29 15:50:47 +00:00
}
else {
// w h e n w e c h a n g e v i d e o m o d e , b u f f e r n e e d s t o b e c l e a r e d t o a v o i d a r t i f a c t s
if ( self . savedVideoMode . text = = 1 )
2020-06-11 00:48:37 +00:00
|| ( self . savedVideoMode . mixed != videoMode . mixed )
|| ( self . savedVideoMode . hires != videoMode . hires )
2020-05-29 15:50:47 +00:00
{
self . hires . clearScreen ( )
self . hires . isHidden = false
self . lores . isHidden = true
}
2020-06-21 05:14:39 +00:00
hires . Render ( )
2020-05-29 15:50:47 +00:00
}
2020-05-04 20:53:36 +00:00
}
2020-05-19 04:17:19 +00:00
else if ( self . savedVideoMode . text = = 0 ) {
// w e j u s t s w i t c h e d f r o m g r a h i c s t o t e x t
2020-05-29 15:50:47 +00:00
self . lores . isHidden = true
2020-05-19 04:17:19 +00:00
self . hires . isHidden = true
}
2020-06-11 00:48:37 +00:00
2020-05-19 04:17:19 +00:00
self . savedVideoMode = videoMode
2020-06-11 00:48:37 +00:00
2019-11-28 04:27:32 +00:00
#endif
2020-06-11 00:48:37 +00:00
2020-05-17 14:49:05 +00:00
// s t r e a m s p e a k e r f r o m a s e p a r a t e t h r e a d f r o m t h e s i m u l a t i o n
// TODO: D o w e n e e d t o d o t h i s f r o m h e r e ?
2020-06-11 00:48:37 +00:00
// s p k r _ u p d a t e ( )
2020-05-28 16:35:17 +00:00
// M o u s e 2 J o y S t i c k ( G a m e C o n t r o l l e r / P a d d l e )
mouseLocation = view . window ! . mouseLocationOutsideOfEventStream
2020-05-29 15:50:47 +00:00
2020-06-02 17:10:18 +00:00
if ( Mouse2Joystick ) {
pdl_prevarr [ 0 ] = pdl_valarr [ 0 ]
pdl_valarr [ 0 ] = Double ( mouseLocation . x / ( displayField . frame . width ) )
pdl_diffarr [ 0 ] = pdl_valarr [ 0 ] - pdl_prevarr [ 0 ]
pdl_prevarr [ 1 ] = pdl_valarr [ 1 ]
pdl_valarr [ 1 ] = 1 - Double ( mouseLocation . y / ( displayField . frame . height ) )
pdl_diffarr [ 1 ] = pdl_valarr [ 1 ] - pdl_prevarr [ 1 ]
}
2020-05-29 15:50:47 +00:00
2020-06-02 17:10:18 +00:00
if ( MouseInterface ) {
pdl_prevarr [ 2 ] = pdl_valarr [ 2 ]
pdl_valarr [ 2 ] = Double ( mouseLocation . x / ( displayField . frame . width ) )
pdl_diffarr [ 2 ] = pdl_valarr [ 2 ] - pdl_prevarr [ 2 ]
pdl_prevarr [ 3 ] = pdl_valarr [ 3 ]
pdl_valarr [ 3 ] = 1 - Double ( mouseLocation . y / ( displayField . frame . height ) )
pdl_diffarr [ 3 ] = pdl_valarr [ 3 ] - pdl_prevarr [ 3 ]
}
2020-05-29 15:50:47 +00:00
}
2020-06-11 00:48:37 +00:00
}
2020-06-25 04:05:55 +00:00
override func mouseDown ( with event : NSEvent ) {
if ( Mouse2Joystick ) {
setIO ( 0xC061 , 1 << 7 )
}
}
2020-06-11 00:48:37 +00:00
2020-06-25 04:05:55 +00:00
override func mouseUp ( with event : NSEvent ) {
if ( Mouse2Joystick ) {
setIO ( 0xC061 , 0 )
}
}
override func rightMouseDown ( with event : NSEvent ) {
if ( Mouse2Joystick ) {
setIO ( 0xC062 , 1 << 7 )
}
}
override func rightMouseUp ( with event : NSEvent ) {
if ( Mouse2Joystick ) {
setIO ( 0xC062 , 0 )
}
}
override func otherMouseDown ( with event : NSEvent ) {
if ( Mouse2Joystick ) {
setIO ( 0xC063 , 0 ) // i n v e r t e d ( b i t 7 : 0 = p r e s s e d )
}
}
override func otherMouseUp ( with event : NSEvent ) {
if ( Mouse2Joystick ) {
setIO ( 0xC063 , 1 << 7 ) // i n v e r t e d ( b i t 7 : 1 = n o t p r e s s e d )
}
}
2020-06-11 00:48:37 +00:00
2020-06-17 16:46:17 +00:00
func Input ( ) {
// M o u s e 2 J o y S t i c k ( G a m e C o n t r o l l e r / P a d d l e )
mouseLocation = view . window ! . mouseLocationOutsideOfEventStream
2020-06-11 00:48:37 +00:00
2020-06-17 16:46:17 +00:00
if ( Mouse2Joystick ) {
pdl_prevarr [ 0 ] = pdl_valarr [ 0 ]
pdl_valarr [ 0 ] = Double ( mouseLocation . x / ( displayField . frame . width ) )
pdl_diffarr [ 0 ] = pdl_valarr [ 0 ] - pdl_prevarr [ 0 ]
pdl_prevarr [ 1 ] = pdl_valarr [ 1 ]
pdl_valarr [ 1 ] = 1 - Double ( mouseLocation . y / ( displayField . frame . height ) )
pdl_diffarr [ 1 ] = pdl_valarr [ 1 ] - pdl_prevarr [ 1 ]
2020-04-30 14:26:46 +00:00
}
2020-04-29 22:35:54 +00:00
2020-06-17 16:46:17 +00:00
if ( MouseInterface ) {
pdl_prevarr [ 2 ] = pdl_valarr [ 2 ]
pdl_valarr [ 2 ] = Double ( mouseLocation . x / ( displayField . frame . width ) )
pdl_diffarr [ 2 ] = pdl_valarr [ 2 ] - pdl_prevarr [ 2 ]
pdl_prevarr [ 3 ] = pdl_valarr [ 3 ]
pdl_valarr [ 3 ] = 1 - Double ( mouseLocation . y / ( displayField . frame . height ) )
pdl_diffarr [ 3 ] = pdl_valarr [ 3 ] - pdl_prevarr [ 3 ]
}
}
func Update ( ) {
switch cpuState {
case cpuState_running :
clkCounter += Double ( clkfrm )
// w e s t a r t a n e w f r a m e f r o m h e r e , s o C P U i s r u n n i n g e v e n w h i l e r e n d e r i n g
clkfrm = 0
frameCounter += 1
if ( frameCounter % fps = = 0 ) {
let currentTime = CACurrentMediaTime ( ) as Double
let elpasedTime = currentTime - lastFrameTime
lastFrameTime = currentTime
mhz = Double ( clkCounter ) / ( elpasedTime * M ) ;
clkCounter = 0
}
#if SPEEDTEST
#else
// p o l l i n p u t d e v i c e s l i k e m o u s e a n d j o y s t i c k
Input ( )
// r u n s o m e c o d e
m6502_Run ( )
// v i d e o r e n d e r i n g
2020-06-23 02:23:41 +00:00
if ( frameCounter % video_fps_divider = = 0 ) {
2020-06-17 16:46:17 +00:00
Render ( )
2020-06-23 02:23:41 +00:00
}
2020-06-17 16:46:17 +00:00
#endif
break
case cpuState_halting :
cpuState = cpuState_halted
// c l k C o u n t e r + = D o u b l e ( c l k f r m )
// / / w e s t a r t a n e w f r a m e f r o m h e r e , s o C P U i s r u n n i n g e v e n w h i l e r e n d e r i n g
// c l k f r m = 0
//
// f r a m e C o u n t e r + = 1
//
// i f ( f r a m e C o u n t e r % f p s = = 0 ) {
// l e t c u r r e n t T i m e = C A C u r r e n t M e d i a T i m e ( ) a s D o u b l e
// l e t e l p a s e d T i m e = c u r r e n t T i m e - l a s t F r a m e T i m e
// l a s t F r a m e T i m e = c u r r e n t T i m e
// m h z = D o u b l e ( c l k C o u n t e r ) / ( e l p a s e d T i m e * M ) ;
// c l k C o u n t e r = 0
// }
//
// # i f S P E E D T E S T
// # e l s e
//
// / / p o l l i n p u t d e v i c e s l i k e m o u s e a n d j o y s t i c k
// I n p u t ( )
//
// / / r u n s o m e c o d e
// m 6 5 0 2 _ R u n ( )
//
// v i d e o r e n d e r i n g
// i f ( f r a m e C o u n t e r % 5 = = 0 ) {
Render ( )
// }
// # e n d i f
break
2020-06-18 22:14:54 +00:00
case cpuState_halted :
upd . suspend ( )
break
2020-06-17 16:46:17 +00:00
default :
break
}
2019-09-07 23:18:05 +00:00
}
2019-09-15 11:02:22 +00:00
2019-09-07 23:18:05 +00:00
// f u n c F r o m B u f ( p t r : U n s a f e M u t a b l e P o i n t e r < U I n t 8 > , l e n g t h l e n : I n t ) - > S t r i n g ? {
// / / c o n v e r t t h e b y t e s u s i n g t h e U T F 8 e n c o d i n g
// i f l e t t h e S t r i n g = N S S t r i n g ( b y t e s : p t r , l e n g t h : l e n , e n c o d i n g : N S U T F 8 S t r i n g E n c o d i n g ) {
// r e t u r n t h e S t r i n g a s S t r i n g
// } e l s e {
// r e t u r n n i l / / t h e b y t e s a r e n ' t v a l i d U T F 8
// }
// }
2019-11-28 04:27:32 +00:00
2019-09-15 11:02:22 +00:00
2020-06-23 02:23:41 +00:00
var upd = RepeatingTimer ( timeInterval : 1 )
2020-04-30 14:26:46 +00:00
2020-06-04 18:37:35 +00:00
static var current : ViewController ? = nil
2020-02-07 08:40:31 +00:00
2020-06-23 02:23:41 +00:00
func newUpdateTimer ( timeInterval : Double ) {
upd . kill ( )
upd = RepeatingTimer ( timeInterval : timeInterval )
upd . eventHandler = {
self . Update ( )
}
upd . resume ( )
}
2019-07-26 05:51:36 +00:00
override func viewDidLoad ( ) {
super . viewDidLoad ( )
2019-09-19 09:27:56 +00:00
2020-06-03 17:23:55 +00:00
ViewController . current = self
2020-05-09 10:39:55 +00:00
hires . clearScreen ( ) ;
2020-05-05 15:35:57 +00:00
2020-06-24 22:44:15 +00:00
spkr_load_sfx ( Bundle . main . resourcePath ! + " /sfx " )
2020-06-12 01:29:26 +00:00
2020-06-24 22:44:15 +00:00
let woz_err = woz_loadFile ( Bundle . main . resourcePath ! + " /dsk/Apple DOS 3.3 January 1983.woz " )
2020-06-04 18:37:35 +00:00
chk_woz_load ( err : woz_err )
2020-06-26 02:52:23 +00:00
woz_flags . image_file_readonly = 1
2020-06-04 18:37:35 +00:00
2019-11-28 04:27:32 +00:00
// v i e w . f r a m e = C G R e c t ( o r i g i n : C G P o i n t ( ) , s i z e : N S S c r e e n . m a i n ! . v i s i b l e F r a m e . s i z e )
// c r e a t e H i R e s ( )
2019-09-22 08:31:09 +00:00
self . displayField . scaleUnitSquare ( to : NSSize ( width : 1 , height : 1 ) )
// N S E v e n t . r e m o v e M o n i t o r ( N S E v e n t . E v e n t T y p e . f l a g s C h a n g e d )
// N S E v e n t . a d d L o c a l M o n i t o r F o r E v e n t s ( m a t c h i n g : . f l a g s C h a n g e d ) {
// s e l f . f l a g s C h a n g e d ( w i t h : $ 0 )
// r e t u r n $ 0
// }
2019-11-28 04:27:32 +00:00
2020-04-27 14:26:04 +00:00
// N S E v e n t . r e m o v e M o n i t o r ( N S E v e n t . E v e n t T y p e . k e y D o w n )
NSEvent . addLocalMonitorForEvents ( matching : . keyDown ) {
// p r i n t ( " k e y D o w n e v e n t " )
self . keyDown ( with : $0 )
return nil
2019-11-28 04:27:32 +00:00
// r e t u r n $ 0
2020-04-27 14:26:04 +00:00
}
NSEvent . addLocalMonitorForEvents ( matching : . keyUp ) {
// p r i n t ( " k e y U p e v e n t " )
self . keyUp ( with : $0 )
return nil
// r e t u r n $ 0
}
2019-09-19 09:27:56 +00:00
displayField . maximumNumberOfLines = textLines
displayField . preferredMaxLayoutWidth = displayField . frame . width
2019-09-07 23:18:05 +00:00
2019-09-22 08:31:09 +00:00
// D i s p a t c h Q u e u e . m a i n . a s y n c A f t e r ( d e a d l i n e : . n o w ( ) + 1 / f p s , e x e c u t e : {
2019-09-09 02:55:19 +00:00
// s e l f . u p d a t e ( )
2019-09-08 21:52:52 +00:00
// } )
2019-09-15 11:02:22 +00:00
2019-09-17 09:12:05 +00:00
// # i f F U N C T I O N T E S T
// # e l s e
2019-09-15 11:02:22 +00:00
// D i s p a t c h Q u e u e . g l o b a l ( q o s : . b a c k g r o u n d ) . a s y n c {
// s e l f . u p d a t e ( )
// }
2019-09-07 23:18:05 +00:00
2020-06-23 02:23:41 +00:00
// u p d . e v e n t H a n d l e r = {
// s e l f . U p d a t e ( )
// }
// u p d . r e s u m e ( )
newUpdateTimer ( timeInterval : 1 / Double ( fps ) )
2019-09-17 09:12:05 +00:00
// # e n d i f
2019-07-26 05:51:36 +00:00
}
2020-01-28 06:54:03 +00:00
func setCPUClockSpeed ( freq : Double ) {
2020-06-14 03:13:20 +00:00
MHz_6502 = freq
clk_6502_per_frm = UInt64 ( MHz_6502 * M / Double ( fps ) )
2020-02-17 07:09:29 +00:00
clk_6502_per_frm_set = clk_6502_per_frm
2019-07-26 05:51:36 +00:00
}
2020-01-28 06:54:03 +00:00
@IBAction func speedSelected ( _ sender : NSButton ) {
2020-04-29 22:35:54 +00:00
if ( sender . title = = " MAX " ) {
2020-05-09 02:47:19 +00:00
setCPUClockSpeed ( freq : 1600 )
2020-01-28 06:54:03 +00:00
}
else if let freq = Double ( sender . title ) {
setCPUClockSpeed ( freq : freq )
2020-05-28 02:12:28 +00:00
// TODO: P r o b a b l y t h i s i s n o t t h e b e s t w a y t o d e a l w i t h t h e p r o b l e m : T o m a k e s o u n d c o n t i n o u s i n d e p e n d e n t o f F P S a n d F r e q
2020-06-14 03:13:20 +00:00
// s p k r _ e x t r a _ b u f = I n t 3 2 ( 7 8 0 / f p s )
spkr_extra_buf = 0
2020-05-28 02:12:28 +00:00
switch freq {
case 2.0 :
2020-06-14 03:13:20 +00:00
// s p k r _ e x t r a _ b u f = I n t 3 2 ( D o u b l e ( s p k r _ e x t r a _ b u f ) * 2 . 9 6 1 5 3 8 4 6 1 5 3 8 4 6 2 ) / / n o r m a l l y i t s h o u l d c o m e u p a s 7 7 , b u t t h i s w a y i t i s c a l c u l a t e d w i t h F P S
spkr_extra_buf = 50
2020-05-28 02:12:28 +00:00
break
case 4.0 :
2020-06-14 03:13:20 +00:00
// s p k r _ e x t r a _ b u f = I n t 3 2 ( D o u b l e ( s p k r _ e x t r a _ b u f ) * 1 . 3 4 6 1 5 3 8 4 6 1 5 3 8 4 6 ) / / n o r m a l l y i t s h o u l d c o m e u p a s 3 5 , b u t t h i s w a y i t i s c a l c u l a t e d w i t h F P S
spkr_extra_buf = 8
2020-05-28 02:12:28 +00:00
break
default :
2020-06-14 03:13:20 +00:00
// s p k r _ e x t r a _ b u f = I n t 3 2 ( 7 8 0 / f p s ) / / n o r m a l l y i t s h o u l d c o m e u p a s 2 6 , b u t t h i s w a y i t i s c a l c u l a t e d w i t h F P S
spkr_extra_buf = 0
2020-05-28 02:12:28 +00:00
break
}
SoundGap . integerValue = Int ( spkr_extra_buf )
2020-01-28 06:54:03 +00:00
}
2020-05-28 02:12:28 +00:00
2020-01-28 06:54:03 +00:00
}
2020-06-23 02:23:41 +00:00
func setSimulationMode ( mode : String ) {
switch ( mode ) {
case " Eco " :
cpuMode = cpuMode_eco
2020-06-17 16:46:17 +00:00
2020-06-23 02:23:41 +00:00
fps = DEFAULT_FPS
video_fps_divider = DEF_VIDEO_DIV
break
case " Game " :
cpuMode = cpuMode_game
cpuState = cpuState_running
fps = GAME_FPS
video_fps_divider = GAME_VIDEO_DIV
break
default :
cpuMode = cpuMode_normal
cpuState = cpuState_running
fps = DEFAULT_FPS
video_fps_divider = DEF_VIDEO_DIV
break
2020-06-17 16:46:17 +00:00
}
2020-06-24 05:59:20 +00:00
spkr_fps_divider = fps / spkr_fps
spkr_play_timeout = 8 * spkr_fps_divider
// s p k r _ b u f _ s i z e = s p k r _ s a m p l e _ r a t e * 2 / s p k r _ f p s
2020-06-23 02:23:41 +00:00
newUpdateTimer ( timeInterval : 1 / Double ( fps ) )
setCPUClockSpeed ( freq : MHz_6502 )
// TODO: B e t t e r w a y t o d e a l w i t h s p e a k e r ! ! !
spkr_play_timeout = 8 * video_fps_divider
}
@IBAction func setCPUMode ( _ sender : NSButton ) {
setSimulationMode ( mode : sender . title )
2020-06-17 16:46:17 +00:00
}
2020-01-28 06:54:03 +00:00
2020-05-17 14:49:05 +00:00
@IBOutlet weak var SoundGap : NSTextFieldCell !
@IBAction func SoundGapChanged ( _ sender : NSStepper ) {
SoundGap . integerValue = sender . integerValue
2020-06-14 03:13:20 +00:00
spkr_extra_buf = Int32 ( sender . integerValue )
2020-05-17 14:49:05 +00:00
}
2020-06-17 16:46:17 +00:00
@IBAction func CRTMonitorOnOff ( _ sender : NSButton ) {
CRTMonitor = sender . state = = . on
scanLines . isHidden = ! CRTMonitor
2020-06-21 05:14:39 +00:00
hires . RenderFullScreen ( )
2020-06-21 01:46:26 +00:00
}
@IBAction func ColorMonitorOnOff ( _ sender : NSButton ) {
ColorMonitor = sender . state = = . on
2020-06-21 05:14:39 +00:00
hires . RenderFullScreen ( )
if ( ColorMonitor ) {
display . textColor = colorWhite // . w h i t e
}
else {
display . textColor = colorGreen // . g r e e n
}
}
@IBAction func MonitorChange ( _ sender : NSButton ) {
switch sender . title {
case " White Mono " :
ColorMonitor = false
monoColor = colorWhite
hires . monoColor = hires . color_white
case " Green Mono " :
ColorMonitor = false
monoColor = colorGreen
hires . monoColor = hires . color_green
case " Amber Mono " :
ColorMonitor = false
monoColor = colorOrange
hires . monoColor = hires . color_orange
default :
ColorMonitor = true
monoColor = colorWhite
}
display . textColor = monoColor
hires . RenderFullScreen ( )
2020-06-17 16:46:17 +00:00
}
2020-06-02 17:10:18 +00:00
@IBAction func Keyboard2JoystickOnOff ( _ sender : NSButton ) {
Keyboard2Joystick = sender . state = = . on
}
@IBAction func Mouse2JoystickOnOff ( _ sender : NSButton ) {
Mouse2Joystick = sender . state = = . on
}
@IBAction func MouseOnOff ( _ sender : NSButton ) {
MouseInterface = sender . state = = . on
}
2020-05-28 02:12:28 +00:00
@IBAction func QuickDisk ( _ sender : NSButton ) {
if sender . state = = . on {
2020-06-12 05:44:53 +00:00
diskAccelerator_enabled = 1 ;
2020-05-28 02:12:28 +00:00
}
else {
2020-06-12 05:44:53 +00:00
diskAccelerator_enabled = 0 ;
2020-05-28 02:12:28 +00:00
}
}
2020-06-12 06:16:26 +00:00
@IBAction func DiskSound ( _ sender : NSButton ) {
if sender . state = = . on {
disk_sfx_enabled = 1 ;
}
else {
disk_sfx_enabled = 0 ;
}
}
2020-06-03 17:23:55 +00:00
@objc func openDiskImage ( ) {
let openPanel = NSOpenPanel ( )
2020-06-26 02:52:23 +00:00
openPanel . title = " Open Disk Image "
2020-06-03 17:23:55 +00:00
openPanel . allowsMultipleSelection = false
openPanel . canChooseDirectories = false
openPanel . canCreateDirectories = false
openPanel . canChooseFiles = true
openPanel . allowedFileTypes = [ " dsk " , " do " , " po " , " nib " , " woz " ]
openPanel . begin { ( result ) -> Void in
if result = = NSApplication . ModalResponse . OK {
print ( " file: " , openPanel . url ! . path )
// D o w h a t y o u w i l l
// I f t h e r e ' s o n l y o n e U R L , s u r e l y ' o p e n P a n e l . U R L '
// b u t o t h e r w i s e a f o r l o o p w o r k s
if let filePath = openPanel . url ? . path {
2020-06-04 18:37:35 +00:00
let woz_err = woz_loadFile ( filePath )
if woz_err = = WOZ_ERR_OK {
NSDocumentController . shared . noteNewRecentDocumentURL ( URL ( fileURLWithPath : filePath ) )
}
else {
self . chk_woz_load ( err : woz_err )
}
2020-06-03 17:23:55 +00:00
}
}
}
}
2020-06-26 02:52:23 +00:00
@objc func saveDiskImage ( ) {
let openPanel = NSOpenPanel ( )
openPanel . title = " Save Disk Image "
openPanel . allowsMultipleSelection = false
openPanel . canChooseDirectories = false
openPanel . canCreateDirectories = false
openPanel . canChooseFiles = true
openPanel . allowedFileTypes = [ " dsk " , " do " , " po " , " nib " , " woz " ]
openPanel . begin { ( result ) -> Void in
if result = = NSApplication . ModalResponse . OK {
print ( " file: " , openPanel . url ! . path )
// D o w h a t y o u w i l l
// I f t h e r e ' s o n l y o n e U R L , s u r e l y ' o p e n P a n e l . U R L '
// b u t o t h e r w i s e a f o r l o o p w o r k s
if let filePath = openPanel . url ? . path {
let woz_err = woz_loadFile ( filePath )
if woz_err = = WOZ_ERR_OK {
NSDocumentController . shared . noteNewRecentDocumentURL ( URL ( fileURLWithPath : filePath ) )
}
else {
self . chk_woz_load ( err : woz_err )
}
}
}
}
}
2020-06-03 17:23:55 +00:00
@IBAction func openDocument ( _ sender : Any ? ) {
openDiskImage ( )
}
2020-06-19 22:16:27 +00:00
@IBAction func traceEnable ( _ sender : NSButton ) {
switch sender . state {
case . on :
m6502 . dbgLevel . trace = 1
openLog ( )
default :
m6502 . dbgLevel . trace = 0
closeLog ( )
}
}
2020-05-28 02:12:28 +00:00
2020-06-26 02:52:23 +00:00
func saveFile ( ) {
if ( woz_flags . image_file_readonly != 0 ) {
// i t i s r e a d o n l y , s a v e i t t o a d i f f e r e n t f i l e . . .
saveFileAs ( )
}
else {
// s a v e W O Z i m a g e f i l e o v e r w r i t i n g t h e o r i g i n a l i m a g e
woz_saveFile ( nil )
}
}
func saveFileAs ( ) {
let savePanel = NSSavePanel ( )
savePanel . title = " Save WOZ Disk Image As... "
savePanel . begin { ( result ) in
if result . rawValue = = NSApplication . ModalResponse . OK . rawValue {
woz_saveFile ( savePanel . url ? . path ) ;
}
else {
let a = NSAlert ( )
a . messageText = " Are you sure? "
a . informativeText = " Are you sure you would like to cancel and lose all modification you have made to the Disk Image? \n ALERT: You will lose all new files and modified files from this Disk Image since you loaded. Your decision if permanent and irreversible! "
a . addButton ( withTitle : " Save " )
a . addButton ( withTitle : " Cancel " )
a . alertStyle = . warning
a . beginSheetModal ( for : self . view . window ! , completionHandler : { ( modalResponse ) -> Void in
if modalResponse = = . alertFirstButtonReturn {
self . saveFileAs ( )
}
} )
}
}
}
}
@ _cdecl ( " woz_ask_to_save " )
func woz_ask_to_save ( ) {
ViewController . current ? . saveFile ( )
2019-07-26 05:51:36 +00:00
}