C C BBC Microcomputer emulation package C BBCMOS_SCREEN - Screen and keyboard handling subsystem using SMG C C Copyright Peter Coghlan 1996 C C The following routines are provided: C C BBC_Screen_Init - Initialize the SMG environment C BBC_Oswrch - Write a character to the screen C BBC_Osrdch - Read a character from the keyboard C BBC_Osword_0 - Read a line from the keyboard C BBC_Osbyte_129 - Read a character from the keyboard with timeout C BBC_Osbyte_135 - Get character at cursor and current screen mode C BBC_Spawn - Execute a host command handling screen output C C C Set up the SMG environment C Subroutine BBC_Screen_Init Implicit None Integer Status, Smg$Create_Pasteboard, Smg$Create_Virtual_Display Integer Smg$Paste_Virtual_Display, Smg$Create_Virtual_Keyboard Integer Smg$Set_Out_Of_Band_Asts, Smg$Control_Mode Integer Smg_Pasteboard, Smg_Display, Smg_Keyboard, Smg_Flags Integer Smg_MaxRows /24/, Smg_MaxColumns /80/, Smg_BbcMode /0/ Character Smg_Devicename*255 /'SYS$OUTPUT '/ Character Smg_InputDevicename*255 External BBC_Smg_OutOfBand_Ast Include '($SmgDef)' Common /BBC_Smg_Stuff/ Smg_Pasteboard, Smg_Display, Smg_Keyboard, + Smg_MaxRows, Smg_MaxColumns, Smg_BbcMode Status = Smg$Create_Pasteboard(Smg_Pasteboard, Smg_Devicename, , , , ) If (.Not. Status) Call Lib$Signal(%Val(Status)) If (Smg_Devicename(1:11) .Eq. 'SYS$OUTPUT ') Then Smg_InputDevicename = 'SYS$INPUT' Else Smg_InputDevicename = Smg_Devicename Endif C Write (*, *) 'Using input device : ', Smg_InputDevicename(1:20) C Write (*, *) 'Using output device : ', Smg_Devicename(1:20) Status = Smg$Create_Virtual_Display(Smg_MaxRows, + Smg_MaxColumns, + Smg_Display, , ,) If (.Not. Status) Call Lib$Signal(%Val(Status)) Status = Smg$Paste_Virtual_Display(Smg_Display, Smg_Pasteboard, , , ) If (.Not. Status) Call Lib$Signal(%Val(Status)) Status = Smg$Create_Virtual_Keyboard(Smg_Keyboard, + Smg_InputDevicename, , , ) If (.Not. Status) Call Lib$Signal(%Val(Status)) C Enable out-of-band-asts for ctrl-C (8) and ctrl-D (16) Status = Smg$Set_Out_Of_Band_Asts(Smg_Pasteboard, + 8 + 16, + BBC_Smg_OutOfBand_Ast, ) If (.Not. Status) Call Lib$Signal(%Val(Status)) Smg_Flags = Smg$M_Buf_Enabled + Smg$M_Clear_Screen + Smg$M_MinUpd + + Smg$M_Notabs + Smg$M_Protect Status = Smg$Control_Mode(Smg_Pasteboard, Smg_Flags) If (.Not. Status) Call Lib$Signal(%Val(Status)) Return End C C Oswrch - write the character in A to the screen C Subroutine BBC_Oswrch(A) Implicit None Integer Status, Smg$Put_Chars, Smg$Erase_Chars, Smg$Cursor_Row Integer Smg$Cursor_Column, Smg$Ring_Bell, Smg$Set_Cursor_Rel Integer Smg$Scroll_Display_Area, Smg$Set_Cursor_Abs Integer Smg$Return_Cursor_Pos, Smg$Erase_Display, Smg$Flush_Buffer Integer Smg$Home_Cursor, Smg$Set_Cursor_Mode Integer Smg$Change_Virtual_Display Integer Smg_Pasteboard, Smg_Display, Smg_Keyboard Integer Smg_MaxRows, Smg_MaxColumns, Smg_BbcMode Integer Smg_Row, Smg_Column Integer A, Vdu_Queue_Count /0/, Vdu_Queue(10) Logical Vdu_Disabled /.False./ Include '($SmgDef)' Common /BBC_Smg_Stuff/ Smg_Pasteboard, Smg_Display, Smg_Keyboard, + Smg_MaxRows, Smg_MaxColumns, Smg_BbcMode External Smg$_InvRow, Smg$_InvCol C If the vdu has been disabled using vdu 21, only allow vdu 6 If (Vdu_Disabled) Then If (A .Ne. 6) Return Endif C Check if we are already processing a multi-byte vdu command C If we are, then queue the next byte. When the last byte is queued, C process the queue. If (Vdu_Queue_Count .Ne. 0) Then Vdu_Queue(Vdu_Queue_Count + 1) = A Vdu_Queue_Count = Vdu_Queue_Count - 1 If (Vdu_Queue_Count .Eq. 0) + Goto ( 2000, 2001, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2017, 2018, 2019, 2000, 2000, 2022, 2023, + 2024, 2025, 2000, 2000, 2028, 2029, 2000, 2031) + Vdu_Queue(1) + 1 Return Endif C Printable characters should be most frequent - check them first If (A .Gt. 31 .And. A .Lt. 127) Then Smg_Column = Smg$Cursor_Column(Smg_Display) Status = Smg$Put_Chars(Smg_Display, Char(A), , , , , , ) If (.Not. Status) Call Lib$Signal(%Val(Status)) C If we are at maximum column, cursor column will not have changed If (Smg_Column .Eq. Smg$Cursor_Column(Smg_Display)) Then C If we are at maximum row, then we need to scroll. Otherwise, LF CR If (Smg$Cursor_Row(Smg_Display) .Eq. Smg_MaxRows) Then Status = Smg$Scroll_Display_Area(Smg_Display, , , , , Smg$M_Up, ) If (.Not. Status) Call Lib$Signal(%Val(Status)) Status = Smg$Set_Cursor_Abs(Smg_Display, Smg_MaxRows, 1) If (.Not. Status) Call Lib$Signal(%Val(Status)) Else Status = Smg$Set_Cursor_Rel(Smg_Display, 1, ) If (.Not. Status) Call Lib$Signal(%Val(Status)) Status = Smg$Set_Cursor_Abs(Smg_Display, , 1) If (.Not. Status) Call Lib$Signal(%Val(Status)) Endif Endif C Next most popular would be control codes Else If (A. Lt. 32) Then Goto (1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, + 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015, + 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023, + 1024, 1025, 1026, 1027, 1028, 1029, 1030, 1031) A + 1 C Check for delete character Else If (A .Eq. 127) Then Status = Smg$Return_Cursor_Pos(Smg_Display, Smg_Row, Smg_Column) If (.Not. Status) Call Lib$Signal(%Val(Status)) If (Smg_Column .Eq. 1) Then Smg_Column = Smg_MaxColumns If (Smg_Row .Eq. 1) Then Status = Smg$Scroll_Display_Area(Smg_Display, , , , , + Smg$M_Down, ) If (.Not. Status) Call Lib$Signal(%Val(Status)) Else Smg_Row = Smg_Row - 1 Endif Else Smg_Column = Smg_Column - 1 Endif Status = Smg$Erase_Chars(Smg_Display, 1, Smg_Row, Smg_Column) If (.Not. Status) Call Lib$Signal(%Val(Status)) C For characters greater than 127, just display a space for now Else If (A .Ge. 128) Then Smg_Column = Smg$Cursor_Column(Smg_Display) Status = Smg$Put_Chars(Smg_Display, ' ', , , , , , ) If (.Not. Status) Call Lib$Signal(%Val(Status)) C If we are at maximum column, cursor column will not have changed If (Smg_Column .Eq. Smg$Cursor_Column(Smg_Display)) Then C If we are at maximum row, then we need to scroll. Otherwise, LF CR If (Smg$Cursor_Row(Smg_Display) .Eq. Smg_MaxRows) Then Status = Smg$Scroll_Display_Area(Smg_Display, , , , , Smg$M_Up, ) If (.Not. Status) Call Lib$Signal(%Val(Status)) Status = Smg$Set_Cursor_Abs(Smg_Display, Smg_MaxRows, 1) If (.Not. Status) Call Lib$Signal(%Val(Status)) Else Status = Smg$Set_Cursor_Rel(Smg_Display, 1, ) If (.Not. Status) Call Lib$Signal(%Val(Status)) Status = Smg$Set_Cursor_Abs(Smg_Display, , 1) If (.Not. Status) Call Lib$Signal(%Val(Status)) Endif Endif Endif Return C Process control codes C Null 1000 Continue Return C Send one character to printer 1001 Continue Vdu_Queue(1) = A Vdu_Queue_Count = 1 Return C Enable printer 1002 Continue Return C Disable printer 1003 Continue Return C Write text at text cursor 1004 Continue Return C Write text at graphics cursor 1005 Continue Return C Enable display 1006 Continue Vdu_Disabled = .False. Return C Keyboard bell 1007 Continue Status = Smg$Ring_Bell(Smg_Display, ) If (.Not. Status) Call Lib$Signal(%Val(Status)) Return C Cursor left (backspace) 1008 Continue Status = Smg$Set_Cursor_Rel(Smg_Display, , -1) If (Status .Eq. %Loc(Smg$_InvCol)) Then Status = Smg$Set_Cursor_Abs(Smg_Display, , Smg_MaxColumns) If (.Not. Status) Call Lib$Signal(%Val(Status)) Status = Smg$Set_Cursor_Rel(Smg_Display, -1, ) If (Status .Eq. %Loc(Smg$_InvRow)) Then Status = Smg$Scroll_Display_Area(Smg_Display, , , , , Smg$M_Down, ) If (.Not. Status) Call Lib$Signal(%Val(Status)) Status = Smg$Set_Cursor_Abs(Smg_Display, 1, Smg_MaxColumns) If (.Not. Status) Call Lib$Signal(%Val(Status)) Else If (.Not. Status) Then Call Lib$Signal(%Val(Status)) Endif Else If (.Not. Status) Then Call Lib$Signal(%Val(Status)) Endif Return C Cursor right (Tab) 1009 Continue Status = Smg$Set_Cursor_Rel(Smg_Display, , 1) If (Status .Eq. %Loc(Smg$_InvCol)) Then Status = Smg$Set_Cursor_Abs(Smg_Display, , 1) If (.Not. Status) Call Lib$Signal(%Val(Status)) Status = Smg$Set_Cursor_Rel(Smg_Display, 1, ) If (Status .Eq. %Loc(Smg$_InvRow)) Then Status = Smg$Scroll_Display_Area(Smg_Display, , , , , Smg$M_Up, ) If (.Not. Status) Call Lib$Signal(%Val(Status)) Status = Smg$Set_Cursor_Abs(Smg_Display, Smg_MaxRows, 1) If (.Not. Status) Call Lib$Signal(%Val(Status)) Else If (.Not. Status) Then Call Lib$Signal(%Val(Status)) Endif Else If (.Not. Status) Then Call Lib$Signal(%Val(Status)) Endif Return C Cursor down (line feed) 1010 Continue Status = Smg$Set_Cursor_Rel(Smg_Display, 1, ) If (Status .Eq. %Loc(Smg$_InvRow)) Then Smg_Column = Smg$Cursor_Column(Smg_Display) Status = Smg$Scroll_Display_Area(Smg_Display, , , , , Smg$M_Up, ) If (.Not. Status) Call Lib$Signal(%Val(Status)) Status = Smg$Set_Cursor_Abs(Smg_Display, Smg_MaxRows, Smg_Column) If (.Not. Status) Call Lib$Signal(%Val(Status)) Else If (.Not. Status) Then Call Lib$Signal(%Val(Status)) Endif Return C Cursor up 1011 Continue Status = Smg$Set_Cursor_Rel(Smg_Display, -1, ) If (Status .Eq. %Loc(Smg$_InvRow)) Then Smg_Column = Smg$Cursor_Column(Smg_Display) Status = Smg$Scroll_Display_Area(Smg_Display, , , , , Smg$M_Down, ) If (.Not. Status) Call Lib$Signal(%Val(Status)) Status = Smg$Set_Cursor_Abs(Smg_Display, 1, Smg_Column) If (.Not. Status) Call Lib$Signal(%Val(Status)) Else If (.Not. Status) Then Call Lib$Signal(%Val(Status)) Endif Return C Clear screen (form feed) 1012 Continue Status = Smg$Erase_Display(Smg_Display, , , , ) If (.Not. Status) Call Lib$Signal(%Val(Status)) Return C Carriage return 1013 Continue Status = Smg$Set_Cursor_Abs(Smg_Display, , 1) If (.Not. Status) Call Lib$Signal(%Val(Status)) Status = Smg$Flush_Buffer(Smg_Pasteboard) If (.Not. Status) Call Lib$Signal(%Val(Status)) Return C Page mode on 1014 Continue Return C Page mode off 1015 Continue Return C Clear graphics window 1016 Continue Return C Text colour 1017 Continue Vdu_Queue(1) = A Vdu_Queue_Count = 1 Return C Graphics colour 1018 Continue Vdu_Queue(1) = A Vdu_Queue_Count = 2 Return C Define logical colour 1019 Continue Vdu_Queue(1) = A Vdu_Queue_Count = 5 Return C Restore default colours 1020 Continue Return C Disable display 1021 Continue Vdu_Disabled = .True. Return C Change screen mode 1022 Continue Vdu_Queue(1) = A Vdu_Queue_Count = 1 Return C Define character / program 6845 1023 Continue Vdu_Queue(1) = A Vdu_Queue_Count = 9 Return C Define graphics window 1024 Continue Vdu_Queue(1) = A Vdu_Queue_Count = 8 Return C Plot 1025 Continue Vdu_Queue(1) = A Vdu_Queue_Count = 5 Return C Restore default windows 1026 Continue Return C Escape (ignore) 1027 Continue Return C Define text window 1028 Continue Vdu_Queue(1) = A Vdu_Queue_Count = 4 Return C Define graphics origin 1029 Continue Vdu_Queue(1) = A Vdu_Queue_Count = 4 Return C Cursor home 1030 Continue Status = Smg$Home_Cursor(Smg_Display, ) If (.Not. Status) Call Lib$Signal(%Val(Status)) Return C Position cursor 1031 Continue Vdu_Queue(1) = A Vdu_Queue_Count = 2 Return C Process multi-byte control functions 2000 Continue Return C Send a single character to the printer 2001 Continue Return C Text colour 2017 Continue Return C Graphics colour 2018 Continue Return C Define logical colour 2019 Continue Return C Change screen mode 2022 Continue Status = Smg$Erase_Display(Smg_Display, , , , ) If (.Not. Status) Call Lib$Signal(%Val(Status)) Status = Smg$Set_Cursor_Mode(Smg_Pasteboard, Smg$M_Cursor_On) If (.Not. Status) Call Lib$Signal(%Val(Status)) If (Vdu_Queue(2) .Eq. 0 .Or. Vdu_Queue(2) .Eq. 3) Smg_MaxColumns = 80 If (Vdu_Queue(2) .Eq. 1 .Or. Vdu_Queue(2) .Eq. 4) Smg_MaxColumns = 40 If (Vdu_Queue(2) .Eq. 2 .Or. Vdu_Queue(2) .Eq. 5) Smg_MaxColumns = 20 If (Vdu_Queue(2) .Eq. 6 .Or. Vdu_Queue(2) .Eq. 7) Smg_MaxColumns = 40 Smg_BbcMode = Vdu_Queue(2) Status = Smg$Change_Virtual_Display(Smg_Display, + Smg_MaxRows, + Smg_MaxColumns, , , ) If (.Not. Status) Call Lib$Signal(%Val(Status)) Return C Define character / program 6845 2023 Continue If (Vdu_Queue(10) .Eq. 0 .And. Vdu_Queue(9) .Eq. 10) Then If (Iand(Vdu_Queue(8), 96) .Eq. 32) Then Status = Smg$Set_Cursor_Mode(Smg_Pasteboard, Smg$M_Cursor_Off) Else Status = Smg$Set_Cursor_Mode(Smg_Pasteboard, Smg$M_Cursor_On) Endif If (.Not. Status) Call Lib$Signal(%Val(Status)) Endif Return C Define graphics window 2024 Continue Return C Plot 2025 Continue Return C Define text window 2028 Continue Return C Define graphics origin 2029 Continue Return C Position cursor 2031 Continue If (Vdu_Queue(2) + 1 .Gt. Smg_MaxRows .Or. + Vdu_Queue(3) + 1 .Gt. Smg_MaxColumns) Return Status = Smg$Set_Cursor_Abs(Smg_Display, + Vdu_Queue(2) + 1, Vdu_Queue(3) + 1) If (.Not. Status) Call Lib$Signal(%Val(Status)) Return End C C Osrdch - Read a character from the keyboard - return it in A. C Function returns Smg$_Eof if Ctrl-Z is pressed, Ss$_Normal otherwise. C Function BBC_Osrdch(A, P) Implicit None Integer BBC_Osrdch, Status, Smg$Flush_Buffer, Smg$Read_Keystroke Integer A, P, Y6502_Read_Memory Integer Smg_Pasteboard, Smg_Display, Smg_Keyboard Integer Smg_MaxRows, Smg_MaxColumns, Smg_BbcMode Integer*2 KeyCode Include '($SmgDef)' Common /BBC_Smg_Stuff/ Smg_Pasteboard, Smg_Display, Smg_Keyboard, + Smg_MaxRows, Smg_MaxColumns, Smg_BbcMode External Ss$_Normal, Ss$_Abort, Ss$_Cancel, Smg$_Eof C Set a successful return code and clear the carry flag in anticipation C of things going well. BBC_Osrdch = %Loc(Ss$_Normal) P = Iand(P, -2) C Flush the output buffer in case there are prompts etc Status = Smg$Flush_Buffer(Smg_Pasteboard) If (.Not. Status) Call Lib$Signal(%Val(Status)) C Check for escape pressed already If (Iand(Y6502_Read_Memory(255), 128) .Eq. 128) Then A = 27 P = Ior(P, 1) Return Endif C Do the actual read Status = Smg$Read_Keystroke(Smg_Keyboard, KeyCode) C Check for Ctrl Z. Avoid signalling Ss$_Abort or Ss$_Cancel as these C would be as result of the Smg$Cancel_Input when escape is pressed. If (Status .Eq. %Loc(Smg$_Eof)) Then BBC_Osrdch = %Loc(Smg$_Eof) Return Else If (.Not. Status .And. Status .Ne. %Loc(Ss$_Abort) .And. + Status .Ne. %Loc(Ss$_Cancel)) Then Call Lib$Signal(%Val(Status)) Endif If (KeyCode .Gt. 255) Then A = 255 Else A = KeyCode Endif C Check the escape flag to see if escape was pressed during the read. If (Iand(Y6502_Read_Memory(255), 128) .Eq. 128) Then A = 27 P = Ior(P, 1) Endif Return End C C Osword 0 - Read a line from the keyboard C Function returns Smg$_Eof if Ctrl-Z is pressed, Ss$_Normal otherwise. C Function BBC_Osword_0(X, Y, P) Implicit None Integer BBC_Osword_0, Status, Smg$Cursor_Row, Smg$Read_Composed_Line Integer Smg$Scroll_Display_Area, Smg$Set_Cursor_Abs, Smg$Set_Cursor_Rel Integer X, Y, P, Y6502_Read_Memory Integer Block, Address, Max_Length, Min_Value, Max_Value, Byte, i Integer Smg_Pasteboard, Smg_Display, Smg_Keyboard Integer Smg_MaxRows, Smg_MaxColumns, Smg_BbcMode Integer*2 TermCode, Length Character String*256 Logical Scroll_Required Include '($SmgDef)' Common /BBC_Smg_Stuff/ Smg_Pasteboard, Smg_Display, Smg_Keyboard, + Smg_MaxRows, Smg_MaxColumns, Smg_BbcMode External Ss$_Normal, Ss$_Abort, Ss$_Cancel, Smg$_Eof BBC_Osword_0 = %Loc(Ss$_Normal) P = Iand(P, -2) Block = X + Y * 256 Address = Y6502_Read_Memory(Block) + Y6502_Read_Memory(Block + 1) * 256 Max_Length = Y6502_Read_Memory(Block + 2) Min_Value = Y6502_Read_Memory(Block + 3) Max_Value = Y6502_Read_Memory(Block + 4) Y = 0 C Note whether we are on the last line of the display. If we are, C Smg$Read_Composed_Line only issues a CR rather than CR LF. Scroll_Required = Smg$Cursor_Row(Smg_Display) .Eq. Smg_MaxRows C Check if escape has been pressed. Otherwise we will go into the C read without knowing. It is ok if it is pressed after we start C reading as Smg$Cancel_Input will sort that one out If (Iand(Y6502_Read_Memory(255), 128) .Eq. 128) Then P = Ior(P, 1) Return Endif C If someone is quick enough to press escape in this gap, they better C press it again if they want anything to happen. Status = Smg$Read_Composed_Line(Smg_Keyboard, , + String, , + Length, + Smg_Display, , , , , , + TermCode) If (Status .Eq. %Loc(Smg$_Eof)) Then BBC_Osword_0 = %Loc(Smg$_Eof) Return Else If (.Not. Status .And. Status .Ne. %Loc(Ss$_Abort) .And. + Status .Ne. %Loc(Ss$_Cancel)) Then Call Lib$Signal(%Val(Status)) Endif C Check if escape was pressed while we were waiting for input If (Iand(Y6502_Read_Memory(255), 128) .Eq. 128) Then P = Ior(P, 1) Return Endif C Make sure we have scrolled if we were on the last line of the display. If (Scroll_Required) Then Status = Smg$Scroll_Display_Area(Smg_Display, , , , , Smg$M_Up, ) If (.Not. Status) Call Lib$Signal(%Val(Status)) Status = Smg$Set_Cursor_Abs(Smg_Display, Smg_MaxRows, 1) If (.Not. Status) Call Lib$Signal(%Val(Status)) C Secondly, Smg$Read_Composed_Line for some inexplicable reason does not C LFCR if nothing was read. If we have not already done it, we better now Else If (Length .Eq. 0) Then Status = Smg$Set_Cursor_Rel(Smg_Display, 1, ) If (.Not. Status) Call Lib$Signal(%Val(Status)) Status = Smg$Set_Cursor_Abs(Smg_Display, , 1) If (.Not. Status) Call Lib$Signal(%Val(Status)) Endif Do i = 1, Min(Length, Max_Length) Byte = Ichar(String(i:i)) If (Byte .Ge. Min_Value .And. Byte .Le. Max_Value) Then Call Y6502_Write_Memory(Address + Y, Byte) Y = Y + 1 Endif End Do Call Y6502_Write_Memory(Address + Y, 13) Return End C C Osbyte 129 - Read a character from the keyboard with timeout C Function returns Smg$_Eof if Ctrl-Z is pressed, Ss$_Normal otherwise. C Function BBC_Osbyte_129(X, Y, P) Implicit None Integer BBC_Osbyte_129, Status, Smg$Flush_Buffer, Smg$Read_Keystroke Integer X, Y, P, Y6502_Read_Memory, Timeout Integer Smg_Pasteboard, Smg_Display, Smg_Keyboard Integer Smg_MaxRows, Smg_MaxColumns, Smg_BbcMode Integer*2 KeyCode Include '($SmgDef)' Common /BBC_Smg_Stuff/ Smg_Pasteboard, Smg_Display, Smg_Keyboard, + Smg_MaxRows, Smg_MaxColumns, Smg_BbcMode External Ss$_Normal, Ss$_Abort, Ss$_Cancel, Ss$_Timeout, Smg$_Eof BBC_Osbyte_129 = %Loc(Ss$_Normal) C First check for keyboard scan case - we can't do this at present If (Y .Gt. 127) Then X = 0 Y = 0 Return Endif C We are definately in the read key with timeout ballpark. Check the C timeout. If it is zero, leave it. Otherwise convert it to seconds, C rounding up. Timeout = Y * 256 + X If (Timeout .Ne. 0) Timeout = (Timeout - 1) / 100 + 1 C Clear the carry flag and Y in anticipation of things going well. P = Iand(P, -2) Y = 0 C Flush the output buffer in case there are prompts etc Status = Smg$Flush_Buffer(Smg_Pasteboard) If (.Not. Status) Call Lib$Signal(%Val(Status)) C Check for escape pressed already If (Iand(Y6502_Read_Memory(255), 128) .Eq. 128) Then Y = 27 P = Ior(P, 1) Return Endif C Do the actual read Status = Smg$Read_Keystroke(Smg_Keyboard, KeyCode, , Timeout) C Check for Ctrl Z. Avoid signalling Ss$_Abort or Ss$_Cancel as these C would be as result of the Smg$Cancel_Input when escape is pressed. C Also, check for timeout. If (Status .Eq. %Loc(Smg$_Eof)) Then BBC_Osbyte_129 = %Loc(Smg$_Eof) Return Else If (Status .Eq. %Loc(Ss$_Timeout)) Then Y = 255 P = Ior(P, 1) Return Else If (.Not. Status .And. Status .Ne. %Loc(Ss$_Abort) .And. + Status .Ne. %Loc(Ss$_Cancel)) Then Call Lib$Signal(%Val(Status)) Endif C Check the escape flag to see if escape was pressed during the read. If (Iand(Y6502_Read_Memory(255), 128) .Eq. 128) Then Y = 27 P = Ior(P, 1) Return Endif If (KeyCode .Gt. 255) Then X = 255 Else X = KeyCode Endif Return End C C Osbyte 135 - Get character at cursor and current screen mode. C Returns status from SMG$GET_CHAR_AT_PHYSICAL_CURSOR. C Function BBC_Osbyte_135(X, Y) Implicit None Integer BBC_Osbyte_135, Smg$Get_Char_At_Physical_Cursor Integer X, Y Integer Smg_Pasteboard, Smg_Display, Smg_Keyboard Integer Smg_MaxRows, Smg_MaxColumns, Smg_BbcMode Integer *1 Character Common /BBC_Smg_Stuff/ Smg_Pasteboard, Smg_Display, Smg_Keyboard, + Smg_MaxRows, Smg_MaxColumns, Smg_BbcMode External Ss$_Normal BBC_Osbyte_135 = + Smg$Get_Char_At_Physical_Cursor(Smg_Pasteboard, Character) X = Character Y = Smg_BbcMode Return End C C Spawn a subprocess either to execute a single DCL command or if none C is specified leave the user at the DCL command prompt. If a command is C specified, use the SMG facilities to execute it in a subprocess and C write the output to our virtual display. If not, save the display C before calling Lib$Spawn so that it can be restored afterwards. C Subroutine BBC_Spawn(Command) Implicit None Integer Status, Smg$Save_Physical_Screen, Lib$Spawn Integer Smg$Restore_Physical_Screen, Smg$Create_Subprocess Integer Smg$Execute_Command, Smg$Delete_Subprocess Integer Saved_Display Integer Smg_Pasteboard, Smg_Display, Smg_Keyboard Integer Smg_MaxRows, Smg_MaxColumns, Smg_BbcMode Character *(*) Command Common /BBC_Smg_Stuff/ Smg_Pasteboard, Smg_Display, Smg_Keyboard, + Smg_MaxRows, Smg_MaxColumns, Smg_BbcMode If (Command .Eq. ' ') Then Status = Smg$Save_Physical_Screen(Smg_Pasteboard, Saved_Display, , ) If (.Not. Status) Call Lib$Signal(%Val(Status)) Status = Lib$Spawn(, , , , , , , , , , , , ) If (.Not. Status) Call Lib$Signal(%Val(Status)) Status = Smg$Restore_Physical_Screen(Smg_Pasteboard, Saved_Display) If (.Not. Status) Call Lib$Signal(%Val(Status)) Else Status = Smg$Create_Subprocess(Smg_Display, , ) If (.Not. Status) Call Lib$Signal(%Val(Status)) Status = Smg$Execute_Command(Smg_Display, Command, , ) If (.Not. Status) Call Lib$Signal(%Val(Status)) Status = Smg$Delete_Subprocess(Smg_Display) If (.Not. Status) Call Lib$Signal(%Val(Status)) Endif Return End C C Ast routine to process control C (Escape) and control D (Toggle Debug) C These keys set the escape flag and toggle trace mode respectively. C If we receive Ctrl C, cancel any keyboard read in operation so that C we know about it immediately. C Subroutine BBC_Smg_OutOfBand_Ast(Smg_Ast_Info_Table) Implicit None Integer Smg_Pasteboard, Smg_Display, Smg_Keyboard Integer Smg_MaxRows, Smg_MaxColumns, Smg_BbcMode Integer PC, A, X, Y, P, SP, Flags Include '($SmgDef)' Common /BBC_Smg_Stuff/ Smg_Pasteboard, Smg_Display, Smg_Keyboard, + Smg_MaxRows, Smg_MaxColumns, Smg_BbcMode Common /Y6502_Registers/ PC, A, X, Y, P, SP, Flags Volatile Flags Record /Smg$R_Out_Of_Band_Table/ Smg_Ast_Info_Table If (Smg_Ast_Info_Table.Smg$B_Char .Eq. Smg$K_Trm_CtrlC) Then Call Y6502_Write_Memory(255, 128) Call Smg$Cancel_Input(Smg_Keyboard) Else If (Smg_Ast_Info_Table.Smg$B_Char .Eq. Smg$K_Trm_CtrlD) Then Flags = Ieor(Flags, 128) Endif Return End