@@ -218,6 +218,8 @@ static bool g_forceConsole = false;
218
218
static bool g_forceLowercase = false ;
219
219
static bool g_backspaceToDel = false ;
220
220
static bool g_kayproToCP437 = false ;
221
+ static size_t g_fileInputOffset = 0 ;
222
+ static vector<char > g_fileInputText;
221
223
222
224
enum terminal_escape { termVT100, termVT52, termKayproII };
223
225
static terminal_escape g_termEscape = termVT100;
@@ -1523,13 +1525,26 @@ uint8_t map_input( uint8_t input )
1523
1525
return output;
1524
1526
} // map_input
1525
1527
1528
+ char get_next_kbd_char ()
1529
+ {
1530
+ if ( g_fileInputOffset < g_fileInputText.size () )
1531
+ return g_fileInputText[ g_fileInputOffset++ ];
1532
+
1533
+ return (char ) ConsoleConfiguration::portable_getch ();
1534
+ } // get_next_kbd_char
1535
+
1536
+ bool is_kbd_char_available ()
1537
+ {
1538
+ return ( ( g_fileInputOffset < g_fileInputText.size () ) || g_consoleConfig.throttled_kbhit () );
1539
+ } // is_kbd_char_available
1540
+
1526
1541
bool cpm_read_console ( char * buf, size_t bufsize, uint8_t & out_len )
1527
1542
{
1528
1543
char ch = 0 ;
1529
1544
out_len = 0 ;
1530
1545
while ( out_len < (uint8_t ) bufsize )
1531
1546
{
1532
- ch = ( char ) ConsoleConfiguration::portable_getch ();
1547
+ ch = get_next_kbd_char ();
1533
1548
tracer.Trace ( " cpm_read_console read character %02x -- '%c'\n " , ch, printable ( ch ) );
1534
1549
1535
1550
// CP/M read console buffer treats these control characters as special: c, e, h, j, m, r, u, x
@@ -1669,15 +1684,15 @@ uint8_t x80_invoke_hook()
1669
1684
}
1670
1685
case 2 : // const console status. A=0 if nothing available, A=0xff if a keystroke is available
1671
1686
{
1672
- if ( g_consoleConfig. throttled_kbhit () )
1687
+ if ( is_kbd_char_available () )
1673
1688
reg.a = 0xff ;
1674
1689
else
1675
1690
reg.a = 0 ;
1676
1691
break ;
1677
1692
}
1678
1693
case 3 : // conin. wait until the keyboard has a character and return it in a.
1679
1694
{
1680
- uint8_t input = (uint8_t ) g_consoleConfig. portable_getch ();
1695
+ uint8_t input = (uint8_t ) get_next_kbd_char ();
1681
1696
tracer.Trace ( " conin got %02xh from getch()\n " , input );
1682
1697
reg.a = map_input ( input );
1683
1698
tracer.Trace ( " conin is returning %02xh = '%c'\n " , reg.a , printable ( reg.a ) );
@@ -1741,7 +1756,7 @@ uint8_t x80_invoke_hook()
1741
1756
{
1742
1757
// console input. echo input to console
1743
1758
1744
- uint8_t ch = (uint8_t ) g_consoleConfig. portable_getch ();
1759
+ uint8_t ch = (uint8_t ) get_next_kbd_char ();
1745
1760
reg.a = map_input ( ch );
1746
1761
set_bdos_status ();
1747
1762
tracer.Trace ( " bdos console in: %02x == '%c'\n " , ch, printable ( ch ) );
@@ -1769,7 +1784,7 @@ uint8_t x80_invoke_hook()
1769
1784
{
1770
1785
// reader input. aka raw console input. I haven't found an app that uses this yet.
1771
1786
1772
- uint8_t ch = (uint8_t ) g_consoleConfig. portable_getch ();
1787
+ uint8_t ch = (uint8_t ) get_next_kbd_char ();
1773
1788
reg.a = map_input ( ch );
1774
1789
set_bdos_status ();
1775
1790
tracer.Trace ( " bdos reader input / raw console in: %02x == '%c'\n " , ch, printable ( ch ) );
@@ -1793,10 +1808,10 @@ uint8_t x80_invoke_hook()
1793
1808
1794
1809
if ( 0xff == reg.e )
1795
1810
{
1796
- if ( g_consoleConfig. throttled_kbhit () )
1811
+ if ( is_kbd_char_available () )
1797
1812
{
1798
1813
kbd_poll_busyloops = 0 ;
1799
- uint8_t input = (uint8_t ) g_consoleConfig. portable_getch ();
1814
+ uint8_t input = (uint8_t ) get_next_kbd_char ();
1800
1815
tracer.Trace ( " read character %u == %02x == '%c'\n " , input, input, printable ( input ) );
1801
1816
reg.a = map_input ( input );
1802
1817
}
@@ -1890,7 +1905,7 @@ uint8_t x80_invoke_hook()
1890
1905
{
1891
1906
// get console status. return A=0 if no characters are waiting or non-zero if a character is waiting
1892
1907
1893
- if ( g_consoleConfig. throttled_kbhit () )
1908
+ if ( is_kbd_char_available () )
1894
1909
reg.a = 0xff ;
1895
1910
else
1896
1911
reg.a = 0 ;
@@ -2762,8 +2777,9 @@ void usage( char const * perr = 0 )
2762
2777
printf ( " -c never auto-detect ESC characters and change to to 80x24 mode\n " );
2763
2778
printf ( " -C always switch to 80x24 mode (Windows only)\n " );
2764
2779
printf ( " -d don't clear the display on app exit when in 80x24 mode\n " );
2780
+ printf ( " -f:<file> plain text file of characters fed to the app as keystrokes.\n " );
2765
2781
printf ( " -i trace 8080/Z80 instructions when tracing with -t\n " );
2766
- printf ( " -k translate Kaypro II extended characters to Windows code page 437 or Linux ascii art \n " );
2782
+ printf ( " -k translate Kaypro II extended characters to approximate native characters \n " );
2767
2783
printf ( " -l force CP/M filenames to be lowercase (can be useful on Linux)\n " );
2768
2784
printf ( " -p show performance information at app exit\n " );
2769
2785
printf ( " -s:X speed in Hz. Default is 0, which is as fast as possible.\n " );
@@ -2787,6 +2803,40 @@ void usage( char const * perr = 0 )
2787
2803
exit ( -1 );
2788
2804
} // usage
2789
2805
2806
+ static void load_input_file_text ( const char * file_path )
2807
+ {
2808
+ FILE * fp = fopen ( file_path, " rb" );
2809
+ if ( !fp )
2810
+ usage ( " -f file not found" );
2811
+ CFile thefile ( fp );
2812
+
2813
+ size_t file_size = portable_filelen ( fp );
2814
+ vector<char > original;
2815
+ original.resize ( file_size );
2816
+ bool ok = ( 1 == fread ( original.data (), file_size, 1 , fp ) );
2817
+ if ( !ok )
2818
+ {
2819
+ printf ( " can't read from text input file '%s', error %d = %s\n " , file_path, errno, strerror ( errno ) );
2820
+ usage ( " can't read from -f file" );
2821
+ }
2822
+
2823
+ // remove any line feeds. stop at ^z. pass through CR and TAB. fail on other non-alpha characters.
2824
+
2825
+ for ( size_t cur = 0 ; cur < file_size; cur++ )
2826
+ {
2827
+ char c = original[ cur ];
2828
+ if ( ( c >= 0x20 && c <= 0x7e ) || ( 13 == c || 9 == c ) ) // normal, CR, TAB
2829
+ g_fileInputText.push_back ( c );
2830
+ else if ( 0x1a == c ) // ^z
2831
+ break ;
2832
+ else if ( 10 != c ) // line feed
2833
+ {
2834
+ tracer.Trace ( " input file has byte %02x at offset %zd\n " , c, cur );
2835
+ usage ( " -f input file can't contain binary data" );
2836
+ }
2837
+ }
2838
+ } // load_input_file_text
2839
+
2790
2840
bool write_fcb_arg ( FCB * arg, char * pc )
2791
2841
{
2792
2842
if ( ' :' == pc[ 1 ] )
@@ -2846,6 +2896,7 @@ int main( int argc, char * argv[] )
2846
2896
char * pcCOM = 0 ;
2847
2897
char * pcArg1 = 0 ;
2848
2898
char * pcArg2 = 0 ;
2899
+ char * pfileInputText = 0 ;
2849
2900
bool trace = false ;
2850
2901
bool traceInstructions = false ;
2851
2902
uint64_t clockrate = 0 ;
@@ -2898,6 +2949,13 @@ int main( int argc, char * argv[] )
2898
2949
clearDisplayOnExit = false ;
2899
2950
else if ( ' 8' == ca )
2900
2951
reg.fZ80Mode = false ;
2952
+ else if ( ' f' == ca )
2953
+ {
2954
+ if ( ( ' :' != parg[2 ] ) || !strlen ( parg + 3 ) )
2955
+ usage ( " :<filename> expected with -f" );
2956
+
2957
+ pfileInputText = parg + 3 ;
2958
+ }
2901
2959
else if ( ' i' == ca )
2902
2960
traceInstructions = true ;
2903
2961
else if ( ' l' == ca )
@@ -2951,7 +3009,13 @@ int main( int argc, char * argv[] )
2951
3009
tracer.SetQuiet ( true );
2952
3010
tracer.SetFlushEachTrace ( true );
2953
3011
x80_trace_instructions ( traceInstructions );
2954
-
3012
+
3013
+ if ( pfileInputText )
3014
+ {
3015
+ load_input_file_text ( pfileInputText );
3016
+ tracer.Trace ( " -f input file has %ld characters\n " , g_fileInputText.size () );
3017
+ }
3018
+
2955
3019
if ( 0 != processAffinityMask )
2956
3020
set_process_affinity ( processAffinityMask );
2957
3021
0 commit comments