Capturing Escape state

Discussions related to network, internet and socket programming; also to serial, parallel, Bluetooth, USB etc.
jgharston
Posts: 37
Joined: Thu 05 Apr 2018, 14:08

Capturing Escape state

Post by jgharston »

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).

Code: Select all

   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
How would I do the same with SDL versions?
Hated Moron

Re: Capturing Escape state

Post by Hated Moron »

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:

Code: Select all

      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:

Code: Select all

      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

Re: Capturing Escape state

Post by Hated Moron »

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:

Code: Select all

      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!
Hated Moron

Re: Capturing Escape state

Post by Hated Moron »

jgharston wrote: Wed 04 Oct 2023, 20:39 How would I do the same with SDL versions?
Once again, no reaction from the OP to my replies so I have no way of knowing whether they were helpful, or indeed whether he has even seen them.

Here's a self-contained program that can be run (in either BB4W or BBCSDL); press the Escape key to see what happens:

Code: Select all

      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.
jgharston
Posts: 37
Joined: Thu 05 Apr 2018, 14:08

Re: Capturing Escape state

Post by jgharston »

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
Posts: 37
Joined: Thu 05 Apr 2018, 14:08

Re: Capturing Escape state

Post by jgharston »

Ah ha! That's got it working:

Image

I can now do some testing on my tablet thingy. :)
Hated Moron

Re: Capturing Escape state

Post by Hated Moron »

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:

Code: Select all

      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
Posts: 37
Joined: Thu 05 Apr 2018, 14:08

Re: Capturing Escape state

Post by jgharston »

Hated Moron wrote: Tue 31 Oct 2023, 14:31
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. ;)