In my emulators I use the following code to capture Escape transitions, so that my program knows about them instead of them either being ignored (*ESC OFF) or interupting the BASIC program itself (*ESC ON).
10 REM > EscCatch
20 :
30 REM Background Escape sets user flag escflg% instead of either being ignored
40 REM or being tested by BASIC and generating an error. After PROCEscOff an
50 REM Escape sets escflg%. After PROCEscOff an Escape is processed by the MOS
60 REM and BASIC and is ignored/acted on.
70 :
80 :
90 DEFPROCEscInit:esch%=esch%:IFesch%:ENDPROC:REM Already set up
100 IF Windows% THEN
110 DIM P% 36, L% -1:[OPT 8:.escyes:mov byte [edi-1],0:mov eax,-1:ret
120 .esch%:mov ecx,256:mov edi,[@vdu%-148]:mov al,27:cld
130 repnz scasb:jz escyes:xor eax,eax:ret:.escb%:dw 0:dw 0:]:ENDPROC
140 ENDIF
150 IF RISCOS% THEN
160 DIM esch% 31:FOR P=0 TO 1:P%=esch%:[OPT P*2:MOV R11,R11,LSL #1
170 LDR R12,escb%:STRB R11,[R12]:MOV PC,R14:.escb%:EQUD escflg%:]:NEXT:escho%=0:ENDPROC
180 ENDIF
190 ENDPROC
200 :
210 DEFPROCEscOff:escho%=escho%:IFescho%:ENDPROC
220 IF RISCOS% THEN SYS "OS_ChangeEnvironment",9,esch%,0,0 TO ,escho%,escRo%,escbo%:ENDPROC
230 IF Windows% THEN
240 OSCLI"ESC OFF":escho%=TRUE:ON TIME IF USResch%:?escflg%=&FF:RETURN ELSE RETURN
250 ENDIF
260 ENDPROC
270 :
280 DEFPROCEscOn
290 IF Windows% THEN ON TIME OFF:escho%=0:OSCLI"ESC ON":ENDPROC
300 IF RISCOS% THEN SYS "OS_ChangeEnvironment",9,escho%,escRo%,escbo%:escho%=0:ENDPROC
310 ENDPROC
jgharston wrote: ↑Wed 04 Oct 2023, 20:39
In my emulators I use the following code to capture Escape transitions, so that my program knows about them instead of them either being ignored (*ESC OFF) or interupting the BASIC program itself (*ESC ON).
How would I do the same with SDL versions?
Exactly the same as in BBC BASIC for Windows, i.e. scan the keyboard buffer for the relevant keycode (&1B), except of course that if you want it to be cross-platform you will need to avoid the use of assembly language code and do it entirely in BASIC:
DEF FN_was_escape_pressed
LOCAL I%, kbdq%%
IF @platform% AND &40 kbdq%% = ]428 ELSE kbdq%% = !428
FOR I%=0 TO 255 : IF kbdq%%?I% = &1B THEN = TRUE ELSE NEXT
= FALSE
If you want it to be compatible with BB4W as well:
DEF FN_was_escape_pressed
LOCAL I%, kbdq%%
IF INKEY$(-256) = "S" OR INKEY$(-256) = "s" IF @platform% AND &40 kbdq%% = ]428 ELSE kbdq%% = !428
FOR I%=0 TO 255 : IF kbdq%%?I% = &1B THEN = TRUE ELSE NEXT
= FALSE
Hated Moron wrote: ↑Wed 04 Oct 2023, 21:29
except of course that if you want it to be cross-platform you will need to avoid the use of assembly language code and do it entirely in BASIC
If you're exceptionally concerned about the speed implications of doing it in BASIC, you could fudge a global string variable pointing at the keyboard buffer and scan it with INSTR:
DIM escflg%% 0
!(^KbdQ$ + 4) = 256
IF @platform% AND &40 THEN PTR(KbdQ$) = ]428 ELSE PTR(KbdQ$) = !428
ON TIME IF INSTR(KbdQ$,CHR$&1B) ?escflg%%=&FF:RETURN ELSE RETURN
But be careful not to write to KbdQ$ otherwise nasty things could happen!
DIM escflg%% 0
!(^KbdQ$ + 4) = 256
IF INKEY(-256) <> &57 IF @platform% AND &40 THEN PTR(KbdQ$) = ]428 ELSE PTR(KbdQ$) = !428
ON TIME IF INSTR(KbdQ$,CHR$&1B) ?escflg%%=&FF:RETURN ELSE RETURN
*ESC OFF
REPEAT
WAIT 20
PRINT ?escflg%% ADVAL(-1)
UNTIL FALSE
It's worth noting that if there have been so many keypresses (without being read) that the keyboard buffer has filled, the escape detection will fail.
That looks great, thanks. I've been deep in tracking down a very deep bug interacting between my BASIC interpreter and Assembler*. I can now work on integrating this into my emulator.
*(aside: if a function with a localised error handler called another function with a localised error handler, but only if the call was in the RHS of an expression, the popped error handler was popped from the wrong place. Took a lot of test code, single-stepping and break-pointing to track down what was happening and where it was happening. Errors in error handlers are one of the hardest problems to diagnose!)
jgharston wrote: ↑Mon 23 Oct 2023, 23:58
if a function with a localised error handler called another function with a localised error handler, but only if the call was in the RHS of an expression, the popped error handler was popped from the wrong place.
Was this a fault in your own code, or are you reporting a bug in BBC BASIC that I need to know about?
I have a little test program which was designed to tease out bugs resulting from calling a function with LOCAL error handling:
ON ERROR PRINT "Error handled in main: " REPORT$ : END
PRINT FN0
END
DEF FN0
LOCAL dummy
ON ERROR LOCAL RESTORE LOCAL : PRINT "Error handled in FN0" : ERROR ERR,REPORT$
test$ = FN1(PI)
= test$
DEF FN1(parameter)
ON ERROR LOCAL RESTORE LOCAL : PRINT "Error handled in FN1" : ERROR ERR,REPORT$
= STR$(FN2)
DEF FN2
ON ERROR LOCAL RESTORE LOCAL : PRINT "Error handled in FN2" : ERROR ERR,REPORT$
A = 1/0
= 0
jgharston wrote: ↑Mon 23 Oct 2023, 23:58
if a function with a localised error handler called another function with a localised error handler, but only if the call was in the RHS of an expression, the popped error handler was popped from the wrong place.
Was this a fault in your own code, or are you reporting a bug in BBC BASIC that I need to know about?
It was a bug in my PDP11 code in the implementation of "commandEquals", ie exiting a DEFFN via =returnvalue unwinding the stack to restore the caller's environment. A bit annoying as the language itself is essentially "complete", and all the work I do on it nowadays is on porting the I/O interface to new platforms. I don't like fiddling with the interpreter code itself as that's more likely to break it than improve it.