No you can't do it with the PureBasic console library yet, I wrote an incomplete include for that. I can't test it on MacOS, though. ;/
I added a little abstraction to it, so that it can be used by all OS, instead of using Inkey() and Input() there are wrappers with Console prefix i.e. ConsoleInkey() and ConsoleSpecialKey(). This allows to use the F keys, and other special keys, it returns #PB_Key_XXX constants.
I haven't fixed a few things but I imagine it could be useful already.
There's a new glitch in PB6.21 on non-windows; this causes the lib to wait for ever for a (broken) message when cursor position is queried. On Linux/Mac use PB6.20, otherwise it should work in Windows. Windows lib can't detect successfully if VT emulation is enabled (has been partially included in W10+).
Code: Select all
; =====================================================
; = UpdateConsoleMetrics.pb (c) 2025 by benubi
; =====================================================
; Author: benubi
; Version: 0.91
; OS: All
;
; Description: Additional console commands for Terminal window size query, cursor position query and 256/true color (RGB) support, and little special keys support [portable RawKey() replacement].
;
; The code uses WinAPI on Windows side and mostly VT Escape Sequneces in the other OS's, with a bit of ioctl_().
;
;
; ConsoleInkey() and ConsoleSpecialKey() are wrappers and mappers of all special keys (F1-F24 keys, Home, Cursor left/up/right/down, page etc)
;
; If ConsoleSpecialKey() = #PB_Key_F4 : Debug "User Pressed F4-Key" : EndIf
;
; This should make developping Console API's and GUI's more comfortable, because the #PB_Key_XYZ can be ported, even hitting the Return key might look different when using Inkey():
; You might prefer to use ConsoleSpecialKey() to check for #PB_Key_Return (instead of using constants Windows=Chr(13), Linux=Chr(10))
;
; +---------+
; | History |
; +---------+
; 19/Jun/2025 To-Do list
; 14/Jan/2025 Added: ConsoleBold(), ConsoleItalic(), ConsoleUnderline(), ConsoleStrikeOut(), ConsoleBlink() and ConsoleDim()
; 13/Jan/2025 ioctl_() and getyx_() implementation to get terminal metrics on non-Windows; fixes flickering, replaces original VT-escape-sequence approach where possible
; 03/Jan/2025 (description update, comments, bugfixes)
; 28/Jun/2024 (1st working version)
;
; To-do
; -----
; - Detection on Windows 10+ if VT escape sequences are enabled (reading from registry fails for now)
; - 256 color mode
; - direct buffer access
; - alternate buffer
; - MacOS testing
;
Define ConsoleBufferColumns
Define ConsoleBufferRows
Define ConsoleWidth
Define ConsoleHeight
Define ConsoleMaximumColorBits
Define ConsoleX
Define ConsoleY
Define ConsoleSizeChanged
Define ConsoleHandle
Define ConsoleVtEscapeSequences = Bool(#PB_Compiler_OS <> #PB_OS_Windows)
EnableExplicit
NewList InkeyBuffer.s()
CompilerIf Not Defined(CharLen8, #PB_Procedure)
Procedure.l xRGB(r, g, b)
r & 255
g & 255
b & 255
Protected result.l = r | (g << 8) | (b << 16)
ProcedureReturn result
EndProcedure
CompilerEndIf
; Same across different OS
CompilerIf Not Defined(CharLen8, #PB_Procedure)
Procedure CharLen8(byte.a) ; check UTF8 character byte length / check leading byte
Protected t_length
If byte < 128
ProcedureReturn 1
EndIf
While byte & $80 = $80
byte << 1
t_length + 1
Wend
ProcedureReturn t_length
EndProcedure
CompilerEndIf
Procedure ConsoleClosestColor(RGB.l)
Structure con_dist
number.i
distance.i
EndStructure
Dim dist.con_dist(16)
Protected i
Restore console_rgb
Protected r = RGB & 255
Protected g = (RGB >> 8) & 255
Protected b = (RGB >> 16) & 255
Protected r2
Protected g2
Protected b2
Protected tdist
Protected t_indx
Protected min_dist = 7000
For i = 0 To 15
Read.b r2
Read.b g2
Read.b b2
tdist = Abs(r2 - r) + Abs(g2 - g) + Abs(b2 - b)
If tdist < min_dist
min_dist = tdist
t_indx = i
EndIf
Next
ProcedureReturn t_indx
DataSection
console_rgb: ; default/cross platform "average"
Data.b 0, 0, 0
Data.b 0, 0, 127
Data.b 0, 127, 0
Data.b 0, 127, 127
Data.b 127, 0, 0
Data.b 127, 0, 127
Data.b 127, 127, 0
Data.b 127, 127, 127
Data.b 64, 64, 64
Data.b 0, 0, 255
Data.b 0, 255, 0
Data.b 0, 255, 255
Data.b 255, 0, 0
Data.b 255, 0, 255
Data.b 255, 255, 0
Data.b 128, 128, 128
EndDataSection
EndProcedure
Procedure ConsoleMaximumColorBits() ; Return the maximum color bits for console colors (4,8,24) for 16,256 or "true color"
Shared ConsoleMaximumColorBits
ProcedureReturn ConsoleMaximumColorBits
EndProcedure
Procedure ConsoleColor8(FrontColor, BackColor) ; Change console colors using 8 bit 256 colors palette
Shared ConsoleMaximumColorBits
If ConsoleMaximumColorBits >= 8
EnableGraphicalConsole(0)
Protected *A = Ascii(Chr(27) + "[38;5;" + Str(FrontColor & 255) + "m" + Chr(27) + "[48;5;" + Str(BackColor & 255) + "m")
WriteConsoleData(*A, MemorySize(*A))
FreeMemory(*A)
Else
Protected r = (FrontColor) & 255
Protected g = (FrontColor >> 8) & 255
Protected b = (FrontColor >> 16) & 255
Protected fg, bg
fg = Bool(r > 127 Or b > 127 Or g > 127) * 8
If r
fg + 4
EndIf
If g
fg + 2
EndIf
If b
fg + 1
EndIf
r = (BackColor) & 255
g = (BackColor >> 8) & 255
b = (BackColor >> 16) & 255
bg = Bool(r > 127 Or g > 127 Or b > 127) * 8
EnableGraphicalConsole(1)
ConsoleColor(fg, bg)
EndIf
EndProcedure
Procedure ConsoleColor24(FrontColor, BackColor) ; Change console colors using RGB values
Shared ConsoleMaximumColorBits
Protected r = (FrontColor) & 255
Protected g = (FrontColor >> 8) & 255
Protected b = (FrontColor >> 16) & 255
Protected r2 = (BackColor) & 255
Protected g2 = (BackColor >> 8) & 255
Protected b2 = (BackColor >> 16) & 255
If ConsoleMaximumColorBits >= 24
EnableGraphicalConsole(0)
Protected *A = Ascii(Chr(27) + "[38;2;" + Str(r) + ";" + Str(g) + ";" + Str(b) + "m" + Chr(27) + "[48;2;" + Str(r2) + ";" + Str(g2) + ";" + Str(b2) + "m")
WriteConsoleData(*A, MemorySize(*A))
FreeMemory(*A)
Else
Protected fg, bg
;
; fg = Bool(r > 127 Or b > 127 Or g > 127) * 8
; If r
; fg + 4
; EndIf
; If g
; fg + 2
; EndIf
; If b
; fg + 1
; EndIf
;
; bg = Bool(r > 127 Or g > 127 Or b > 127) * 8
; If r
; bg + 4
; EndIf
; If g
; bg + 2
; EndIf
; If b
; bg + 1
; EndIf
;
fg = ConsoleClosestColor(FrontColor)
bg = ConsoleClosestColor(BackColor)
EnableGraphicalConsole(1)
ConsoleColor(fg, bg)
EndIf
EndProcedure
Procedure ConsoleWidth() ; Returns the current console width in columns aka characters
Shared ConsoleWidth
ProcedureReturn ConsoleWidth
EndProcedure
Procedure ConsoleHeight() ; Returns the current console height in lines
Shared ConsoleHeight
ProcedureReturn ConsoleHeight
EndProcedure
Procedure ConsoleBufferColumns() ; Returns the current console buffer maximum column count (may be out of view)
Shared ConsoleBufferColumns
; ConsoleBufferColumns = ConsoleWidth()
ProcedureReturn ConsoleBufferColumns
EndProcedure
Procedure ConsoleBufferRows() ; Returns the current console buffer maximum line count (may be out of view)
Shared ConsoleBufferRows
; ConsoleBufferRows = ConsoleHeight()
ProcedureReturn ConsoleBufferRows
EndProcedure
Procedure ConsoleBold(bool) ; bold font on/off (windows=hilight foreground on/off)
Shared ConsoleVtEscapeSequences
Shared ConsoleHandle
If ConsoleVtEscapeSequences
EnableGraphicalConsole(0)
If bool
Print(Chr(27) + "[1m")
Else
Print(Chr(27) + "[22m")
EndIf
EnableGraphicalConsole(1)
Else
CompilerIf #PB_Compiler_OS = #PB_OS_Windows
Protected info.CONSOLE_SCREEN_BUFFER_INFO, wAttributes
GetConsoleScreenBufferInfo_(ConsoleHandle, @Info)
If bool
wAttributes = info\wAttributes | 8
Else
wAttributes = info\wAttributes & ~8
EndIf
SetConsoleTextAttribute_(ConsoleHandle, wAttributes)
CompilerEndIf
EndIf
EndProcedure
Procedure ConsoleItalic(bool) ; italic font on/off (non-Windows only)
Shared ConsoleVtEscapeSequences
If ConsoleVtEscapeSequences
EnableGraphicalConsole(0)
If bool
Print(Chr(27) + "[3m")
Else
Print(Chr(27) + "[23m")
EndIf
EnableGraphicalConsole(1)
EndIf
EndProcedure
Procedure ConsoleUnderline(bool) ; underline font on/off (non-Windows only)
Shared ConsoleVtEscapeSequences
If ConsoleVtEscapeSequences
EnableGraphicalConsole(0)
If bool
Print(Chr(27) + "[4m")
Else
Print(Chr(27) + "[24m")
EndIf
EnableGraphicalConsole(1)
Else
CompilerIf #PB_Compiler_OS = #PB_OS_Windows
; Protected Mode
; Shared ConsoleHandle
; GetConsoleMode_(ConsoleHandle,@Mode)
; Mode = (Mode & ~ #COMMON_LVB_UNDERSCORE) | (Bool(bool) * #COMMON_LVB_UNDERSCORE)
; SetConsoleTextAttributes_(ConsoleHandle, Mode)
CompilerEndIf
EndIf
EndProcedure
Procedure ConsoleBlink(level) ; blink 0: off 1: normal speed 2: fast (non-Windows only)
Shared ConsoleVtEscapeSequences
If ConsoleVtEscapeSequences
EnableGraphicalConsole(0)
If level = 0
Print(Chr(27) + "[25m") ; off
ElseIf level = 1
Print(Chr(27) + "[5m") ; normal speed
ElseIf level = 2
Print(Chr(27) + "[6m") ; blink fast
Else
Print(Chr(27) + "[25m") ;off
EndIf
EnableGraphicalConsole(1)
EndIf
EndProcedure
Procedure ConsoleStrikeOut(bool) ; strike-out font on/off (non-Windows only)
Shared ConsoleVtEscapeSequences
If ConsoleVtEscapeSequences
EnableGraphicalConsole(0)
If bool
Print(Chr(27) + "[9m")
Else
Print(Chr(27) + "[29m")
EndIf
EnableGraphicalConsole(1)
EndIf
EndProcedure
Procedure ConsoleDim(bool) ; dim/faint font on/off (non-Windows only)
Shared ConsoleVtEscapeSequences
If ConsoleVtEscapeSequences
EnableGraphicalConsole(0)
If bool
Print(Chr(27) + "[2m")
Else
Print(Chr(27) + "[22m")
EndIf
EnableGraphicalConsole(1)
EndIf
EndProcedure
;
; OS specific commands
CompilerIf #PB_Compiler_OS = #PB_OS_Windows
; Windows based
#DISABLE_NEWLINE_AUTO_RETURN = $0008
#ENABLE_VIRTUAL_TERMINAL_INPUT = $0200
#ENABLE_PROCESSED_OUTPUT = $0001
#ENABLE_VIRTUAL_TERMINAL_PROCESSING = $0004
#ENABLE_REGISTERY_VT_INPUT = 0
Procedure GetRegLong(hKey, strValueName$, defaultValue = 0)
Protected vres = defaultValue
Protected type = #REG_DWORD
Protected cbsize = SizeOf(INTEGER)
Protected err = RegQueryValueEx_(hKey, strValueName$, #Null, @type , @vres, @cbsize)
; Debug "Err="+err
; Debug "type="+type
; Debug "cbsize="+cbsize
; Debug "vres="+vres
If err = #ERROR_SUCCESS
Debug "success"
ProcedureReturn vres
Else
Debug "fail"
ProcedureReturn defaultValue
EndIf
EndProcedure
Procedure UpdateConsoleSize() ; Update console size values and returns 1 on resize or 0 on no changes
Shared ConsoleWidth
Shared ConsoleHeight
Shared ConsoleBufferColumns
Shared ConsoleBufferRows
Shared ConsoleHandle
Protected Changed = 0
If Not ConsoleHandle ; Get console std output handle
ConsoleHandle = GetStdHandle_( - 12)
changed = 1
EndIf
; Retrieve Windows console screen buffer info
Protected Info.CONSOLE_SCREEN_BUFFER_INFO
GetConsoleScreenBufferInfo_(ConsoleHandle, @info)
; Check for differences and update values
; - Console width:
If ConsoleWidth <> 1 + info\srWindow\right - info\srWindow\left
;Debug "changed width"
;Debug "old="+ConsoleWidth
ConsoleWidth = 1 + info\srWindow\right - info\srWindow\left
changed = 1
;Debug "new="+ConsoleWidth
EndIf
; - Console height:
If ConsoleHeight <> 1 + info\srWindow\bottom - info\srWindow\top
;Debug "changed height"
;Debug "old="+ConsoleHeight
ConsoleHeight = 1 + info\srWindow\bottom - info\srWindow\top
changed = 1
;Debug "new="+ConsoleHeight
EndIf
; - Buffer columns:
If ConsoleBufferColumns <> info\dwSize\x
;Debug "changed col"
;Debug "old="+ConsoleBufferColumns
ConsoleBufferColumns = info\dwSize\x
changed = 1
Debug "new=" + ConsoleBufferColumns
EndIf
; - Buffer rows:
If ConsoleBufferRows <> info\dwSize\y
;Debug "changed rows"
;Debug "old="+ConsoleBufferRows
ConsoleBufferRows = info\dwSize\y
changed = 1
;Debug "new="+ConsoleBufferRows
EndIf
; return update result
ProcedureReturn changed
EndProcedure
Procedure ConsoleDefaultColors() ; Reset default colors (7,0)
EnableGraphicalConsole(1)
ConsoleColor(7, 0)
EndProcedure
Procedure ConsoleX() ; Returns current cursor row (x) starting with 0
Shared ConsoleX
Shared ConsoleHandle
Protected Info.CONSOLE_SCREEN_BUFFER_INFO
GetConsoleScreenBufferInfo_(ConsoleHandle, @info)
ConsoleX = info\dwCursorPosition\x
ProcedureReturn ConsoleX
EndProcedure
Procedure ConsoleY() ; Returns current cursor line (y) starting with 0
Shared ConsoleY
Shared ConsoleHandle
Protected Info.CONSOLE_SCREEN_BUFFER_INFO
GetConsoleScreenBufferInfo_(ConsoleHandle, @info)
ConsoleY = info\dwCursorPosition\y
ProcedureReturn ConsoleY
EndProcedure
Procedure InitConsoleMetrics() ; Init console after OpenConsole()
Shared ConsoleMaximumColorBits
Shared ConsoleHandle
Shared ConsoleVtEscapeSequences
Protected mode.l, result
SetEnvironmentVariable("TERM", "TRUE")
result = UpdateConsoleSize()
If OSVersion() < #PB_OS_Windows_8_1
ConsoleMaximumColorBits = 4
Else
ConsoleMaximumColorBits = 24
GetConsoleMode_(ConsoleHandle, @mode)
; enable VT input mode for escape sequences
;Mode = Mode | #ENABLE_VIRTUAL_TERMINAL_INPUT | #DISABLE_NEWLINE_AUTO_RETURN | #ENABLE_PROCESSED_OUTPUT | #ENABLE_VIRTUAL_TERMINAL_PROCESSING ;
Mode = Mode | #ENABLE_VIRTUAL_TERMINAL_PROCESSING ;
SetConsoleMode_(ConsoleHandle, mode)
GetConsoleMode_(ConsoleHandle, @mode)
If Mode & #ENABLE_VIRTUAL_TERMINAL_INPUT = 0
;; If Mode & #ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0
; If Mode & 7 = 0
If GetRegLong(#HKEY_CURRENT_USER, "Console\UseDx")
Debug "Set VT input mode UseDx!!"
Else
ConsoleMaximumColorBits = 4
Debug "Set VT input mode for sequence: FAILED :("
EndIf
Else
ConsoleVtEscapeSequences = #True
Debug "Set VT input mode for sequence: SUCCESS"
EndIf
EndIf
EndProcedure
CompilerElse
; Linux based - untested on MacOS & AmigaOS
#STDOUT_FILENO = 0
#STDIN_FILENO = 1
#STDERR_FILENO = 2
#TIOCGWINSZ = $5413 ; Thank you ChatGPT :|
Structure _winsize
ws_row.u
ws_col.u
ws_xpixel.u
ws_ypixel.u
; struct winsize {
; unsigned short ws_row;
; unsigned short ws_col;
; unsigned short ws_xpixel; /* unused */
; unsigned short ws_ypixel; /* unused */
; };
EndStructure
DataSection
ansi_query_cursor:
Data.a Chr(27) + "[6n"
reset_console_colors:
Data.a Chr(27) + "[0m"
EndDataSection
; internal old/backward compatibility (VT escape sequences only)
Procedure$ _vt_queryCursorPos() ; VT escape sequences
Shared InkeyBuffer()
Shared ConsoleX, ConsoleY
Protected Dim buff.b(16)
Protected buff_len = 0
Protected buff_size = 16
Protected re$, ch, has_esc
EnableGraphicalConsole(0)
WriteConsoleData(?ansi_query_cursor, 4)
Repeat
If read_(#STDIN_FILENO, @ch, 1)
If buff_len + 1 > buff_size
buff_size = buff_size + 16
ReDim Buff(buff_size)
EndIf
buff(buff_len) = ch
buff_len = buff_len + 1
;Debug Chr(ch)+" "+ch
Else
Delay(0)
EndIf
Until ch = 27
Protected clen, i = 0
If buff_len > 1
While i < buff_len - 1
LastElement(InkeyBuffer())
AddElement(InkeyBuffer())
clen = CharLen8(buff(i))
InkeyBuffer() = PeekS(@buff(i), clen, #PB_ByteLength | #PB_UTF8)
i = i + clen
Wend
EndIf
re$ = Chr(27)
Repeat
If read_(#STDIN_FILENO, @ch, 1)
re$ = re$ + Chr(ch)
;Debug re$
Else
Delay(0)
EndIf
Until ch = 'R'
While CountString(re$, Chr(27)) > 1
i = FindString(re$, Chr(27), 2)
LastElement(InkeyBuffer())
AddElement(InkeyBuffer())
InkeyBuffer() = Left(re$, i - 1)
re$ = Mid(re$, i)
Wend
re$ = Mid(re$, 3)
re$ = Left(re$, Len(re$) - 1)
ConsoleY = Val(StringField(re$, 1, ";"))
ConsoleX = Val(StringField(re$, 2, ";"))
EndProcedure
Procedure _vt_queryConsoleSize() ; deprecated but potentially useful for COM port conntections/using VT sequences to query size
Shared ConsoleX, ConsoleY
Shared ConsoleWidth, ConsoleHeight
Shared ConsoleBufferColumns, ConsoleBufferRows
Shared ConsoleSizeChanged
Protected changed = ConsoleSizeChanged
_vt_queryCursorPos()
ConsoleSizeChanged = 0
Protected *A = Ascii(Chr(27) + "[" + Str(consoley) + ";" + Str(consolex) + "H")
EnableGraphicalConsole(1)
ConsoleLocate(9999, 9999)
_vt_queryCursorPos()
If ConsoleWidth <> ConsoleX
ConsoleWidth = ConsoleX
changed = 1
EndIf
If ConsoleBufferColumns <> ConsoleX
ConsoleBufferColumns = ConsoleX
changed = 1
EndIf
If ConsoleHeight <> ConsoleY
ConsoleHeight = ConsoleY
changed = 1
EndIf
If ConsoleBufferRows <> ConsoleY
; Debug "Buff rows changed"
ConsoleBufferRows = ConsoleY
changed = 1
EndIf
WriteConsoleData(*A, MemorySize(*A))
FreeMemory(*A)
ProcedureReturn changed
EndProcedure
; internal new (uses API ioctl() + getyx()) where possible
Procedure _queryCursorPos() ; more APO
Shared ConsoleX, ConsoleY
Protected Y, X
CompilerIf Defined(getyx_, #PB_Procedure) ; termios (?)
getyx_(@Y, @X)
ConsoleX = X
ConsoleY = Y
CompilerElse
_vt_queryCursorPos()
CompilerEndIf
EndProcedure
Procedure _queryConsoleSize() ; faster, robust and without flickering
Protected ws._winsize
Shared ConsoleWidth
Shared ConsoleHeight
Shared ConsoleBufferColumns
Shared ConsoleBufferRows
Protected changed
ioctl_(0, #TIOCGWINSZ, @ws);
If ws\ws_col <> ConsoleWidth
changed + 1
ConsoleWidth = ws\ws_col
ConsoleBufferColumns = ConsoleWidth
EndIf
If ws\ws_row <> ConsoleHeight
Changed + 1
ConsoleHeight = ws\ws_row
ConsoleBufferRows = ConsoleHeight
EndIf
ProcedureReturn Changed
EndProcedure
; Public:
Procedure UpdateConsoleSize() ; returns 0 if sizes haven't changed
ProcedureReturn _queryConsoleSize()
EndProcedure
Procedure ConsoleDefaultColors() ; reset to default colors
EnableGraphicalConsole(0)
WriteConsoleData(?reset_console_colors, 4)
EndProcedure
Procedure ConsoleX() ; Console cursor current column position (x)
Shared ConsoleX
_queryCursorPos()
ProcedureReturn ConsoleX
EndProcedure
Procedure ConsoleY() ; Console cursor current line position (y)
Shared ConsoleY
_queryCursorPos()
ProcedureReturn ConsoleY
EndProcedure
Procedure InitConsoleMetrics() ; Init console metrics after OpenConsole()
Shared ConsoleMaximumColorBits
Protected result = UpdateConsoleSize()
Protected colors$ = GetEnvironmentVariable("TERM") + " " + GetEnvironmentVariable("COLORTERM")
If FindString(colors$, "truecolor") Or FindString(colors$, "24bit")
ConsoleMaximumColorBits = 24
ElseIf FindString(colors$, "256")
ConsoleMaximumColorBits = 8
Else
ConsoleMaximumColorBits = 4
EndIf
ProcedureReturn result
EndProcedure
CompilerEndIf
Define ConsoleInkey_EscapeSequence$
Define ConsoleInkey_SpecialKey
Define ConsoleInkey_HasEscapeSequence
; ESCape sequence CSI
#ESC_SEQ = Chr(27) + "["
Procedure$ ConsoleInkey() ; Like Inkey() except it sets SpecialKey (#PB_Key_XYZ constant) in place of Window's RawKey
Shared ConsoleInkey_HasEscapeSequence
Shared ConsoleInkey_EscapeSequence$
Shared ConsoleInkey_SpecialKey
Shared InkeyBuffer()
Protected k$
If ListSize(InkeyBuffer())
FirstElement(InkeyBuffer())
k$ = InkeyBuffer()
DeleteElement(InkeyBuffer())
Else
EnableGraphicalConsole(0)
k$ = Inkey()
EndIf
ConsoleInkey_SpecialKey = 0
CompilerIf #PB_Compiler_OS = #PB_OS_Windows
If k$ <> #Empty$
Select Asc(k$)
Case 27
ConsoleInkey_SpecialKey = #PB_Key_Escape
Case 10, 13
ConsoleInkey_SpecialKey = #PB_Key_Return
Case 8, 127
ConsoleInkey_SpecialKey = #PB_Key_Back
Case 128
ConsoleInkey_SpecialKey = #PB_Key_Delete
Default
ConsoleInkey_SpecialKey = 0
EndSelect
If Not ConsoleInkey_SpecialKey
ProcedureReturn k$
Else
ProcedureReturn #Empty$
EndIf
Else
Protected rk = RawKey()
Select rk
Case 0
Case 33
ConsoleInkey_SpecialKey = #PB_Key_PageUp
Case 34
ConsoleInkey_SpecialKey = #PB_Key_PageDown
Case 35
ConsoleInkey_SpecialKey = #PB_Key_End
Case 36
ConsoleInkey_SpecialKey = #PB_Key_Home
Case 37
ConsoleInkey_SpecialKey = #PB_Key_Left
Case 38
ConsoleInkey_SpecialKey = #PB_Key_Up
Case 39
ConsoleInkey_SpecialKey = #PB_Key_Right
Case 40
ConsoleInkey_SpecialKey = #PB_Key_Down
Case 45
ConsoleInkey_SpecialKey = #PB_Key_Insert
Case 46
ConsoleInkey_SpecialKey = #PB_Key_Delete
Case 112 To 121
ConsoleInkey_SpecialKey = #PB_Key_F1 + (rk - 112)
Default
ProcedureReturn #Empty$
EndSelect
ProcedureReturn #Empty$
EndIf
CompilerElse
Static last_in.q
If k$ = Chr(27)
ConsoleInkey_EscapeSequence$ = ""
ConsoleInkey_HasEscapeSequence = ConsoleInkey_HasEscapeSequence + 1
last_in = ElapsedMilliseconds()
EndIf
If ConsoleInkey_HasEscapeSequence And k$ <> ""
ConsoleInkey_EscapeSequence$ + k$
; PrintN("Escape seq: "+Mid(ConsoleInkey_EscapeSequence$,2))
Select ConsoleInkey_EscapeSequence$
Case Chr(27)
If ElapsedMilliseconds() - last_in >= 150000
ConsoleInkey_SpecialKey = #PB_Key_Escape
EndIf
Case #ESC_SEQ + "A", #ESC_SEQ + "1A"
ConsoleInkey_SpecialKey = #PB_Key_Up
Case #ESC_SEQ + "B", #ESC_SEQ + "1B"
ConsoleInkey_SpecialKey = #PB_Key_Down
Case #ESC_SEQ + "C", #ESC_SEQ + "1C"
ConsoleInkey_SpecialKey = #PB_Key_Right
Case #ESC_SEQ + "D", #ESC_SEQ + "1D"
ConsoleInkey_SpecialKey = #PB_Key_Left
Case #ESC_SEQ + "1~", #ESC_SEQ + "H"
ConsoleInkey_SpecialKey = #PB_Key_Home
Case #ESC_SEQ + "2~"
ConsoleInkey_SpecialKey = #PB_Key_Insert
Case #ESC_SEQ + "3~"
ConsoleInkey_SpecialKey = #PB_Key_Delete
Case #ESC_SEQ + "4~", #ESC_SEQ + "F"
ConsoleInkey_SpecialKey = #PB_Key_End
Case #ESC_SEQ + "5~"
ConsoleInkey_SpecialKey = #PB_Key_PageUp
Case #ESC_SEQ + "6~"
ConsoleInkey_SpecialKey = #PB_Key_PageDown
Case #ESC_SEQ + "7~"
ConsoleInkey_SpecialKey = #PB_Key_Home
Case #ESC_SEQ + "8~"
ConsoleInkey_SpecialKey = #PB_Key_End
Case #ESC_SEQ + "9~"
ConsoleInkey_SpecialKey = 0
Case #ESC_SEQ + "10~"
ConsoleInkey_SpecialKey = 0
Case #ESC_SEQ + "11~"
ConsoleInkey_SpecialKey = #PB_Key_F1
Case #ESC_SEQ + "12~"
ConsoleInkey_SpecialKey = #PB_Key_F2
Case #ESC_SEQ + "13~"
ConsoleInkey_SpecialKey = #PB_Key_F3
Case #ESC_SEQ + "14~"
ConsoleInkey_SpecialKey = #PB_Key_F4
Case #ESC_SEQ + "15~"
ConsoleInkey_SpecialKey = #PB_Key_F5
Case #ESC_SEQ + "16~"
ConsoleInkey_SpecialKey = 0
Case #ESC_SEQ + "17~"
ConsoleInkey_SpecialKey = #PB_Key_F6
Case #ESC_SEQ + "18~"
ConsoleInkey_SpecialKey = #PB_Key_F7
Case #ESC_SEQ + "19~"
ConsoleInkey_SpecialKey = #PB_Key_F8
Case #ESC_SEQ + "20~"
ConsoleInkey_SpecialKey = #PB_Key_F9
Case #ESC_SEQ + "21~"
ConsoleInkey_SpecialKey = #PB_Key_F10
Case #ESC_SEQ + "22~"
ConsoleInkey_SpecialKey = 0
Case #ESC_SEQ + "23~"
ConsoleInkey_SpecialKey = #PB_Key_F11
Case #ESC_SEQ + "24~"
ConsoleInkey_SpecialKey = #PB_Key_F12
Case #ESC_SEQ + "P", #ESC_SEQ + "1P", Chr(27) + "0P", Chr(27) + "OP"
ConsoleInkey_SpecialKey = #PB_Key_F1
Case #ESC_SEQ + "Q", #ESC_SEQ + "1Q", Chr(27) + "0Q", Chr(27) + "OQ"
ConsoleInkey_SpecialKey = #PB_Key_F2
Case #ESC_SEQ + "R", #ESC_SEQ + "1R", Chr(27) + "0R", Chr(27) + "OR"
ConsoleInkey_SpecialKey = #PB_Key_F3
Case #ESC_SEQ + "S", #ESC_SEQ + "1S", Chr(27) + "0S", Chr(27) + "OS"
ConsoleInkey_SpecialKey = #PB_Key_F4
Default
Select Asc(Right(ConsoleInkey_EscapeSequence$, 1))
Case 'n'
Case '~', 'A' To 'Z', 'a' To 'z'
If Len(ConsoleInkey_EscapeSequence$) > 2
ConsoleInkey_EscapeSequence$ = #Null$
ConsoleInkey_HasEscapeSequence = 0
ConsoleInkey_SpecialKey = 0
EndIf
Case 27
If ElapsedMilliseconds() - last_in >= 25
ConsoleInkey_SpecialKey = #PB_Key_Escape
ConsoleInkey_EscapeSequence$ = #Null$
ConsoleInkey_HasEscapeSequence = 0
EndIf
Default
EndSelect
EndSelect
If ConsoleInkey_SpecialKey
ConsoleInkey_HasEscapeSequence = 0
ConsoleInkey_EscapeSequence$ = #Null$
EndIf
ProcedureReturn #Empty$
Else
Select Asc(k$)
Case 0
If ConsoleInkey_HasEscapeSequence
If ElapsedMilliseconds() - last_in >= 5 And ConsoleInkey_EscapeSequence$ = Chr(27)
ConsoleInkey_SpecialKey = #PB_Key_Escape
ConsoleInkey_EscapeSequence$ = #Null$
ConsoleInkey_HasEscapeSequence = 0
EndIf
EndIf
Case 8, 127
ConsoleInkey_SpecialKey = #PB_Key_Back
Case 128
ConsoleInkey_SpecialKey = #PB_Key_Delete
Case 10, 13
ConsoleInkey_SpecialKey = #PB_Key_Return
Default
ConsoleInkey_SpecialKey = 0
EndSelect
If ConsoleInkey_SpecialKey = 0
ProcedureReturn k$
Else
ProcedureReturn ""
EndIf
EndIf
CompilerEndIf
EndProcedure
Procedure ConsoleSpecialKey() ; Returns the #PB_Key_XYZ constant of the last pressed keyboard key
Shared ConsoleInkey_SpecialKey
ProcedureReturn ConsoleInkey_SpecialKey
EndProcedure
Procedure VTSequence_To_SpecialKey(sequence$) ; translate escape sequence to #PB_Key_XXX constant
Protected ConsoleInkey_SpecialKey
Select sequence$
Case Chr(27) + "^"
ConsoleInkey_SpecialKey = #PB_Key_Escape
Case #ESC_SEQ + "A", #ESC_SEQ + "1A"
ConsoleInkey_SpecialKey = #PB_Key_Up
Case #ESC_SEQ + "B", #ESC_SEQ + "1B"
ConsoleInkey_SpecialKey = #PB_Key_Down
Case #ESC_SEQ + "C", #ESC_SEQ + "1C"
ConsoleInkey_SpecialKey = #PB_Key_Right
Case #ESC_SEQ + "D", #ESC_SEQ + "1D"
ConsoleInkey_SpecialKey = #PB_Key_Left
Case #ESC_SEQ + "1~", #ESC_SEQ + "H"
ConsoleInkey_SpecialKey = #PB_Key_Home
Case #ESC_SEQ + "2~"
ConsoleInkey_SpecialKey = #PB_Key_Insert
Case #ESC_SEQ + "3~"
ConsoleInkey_SpecialKey = #PB_Key_Delete
Case #ESC_SEQ + "4~", #ESC_SEQ + "F"
ConsoleInkey_SpecialKey = #PB_Key_End
Case #ESC_SEQ + "5~"
ConsoleInkey_SpecialKey = #PB_Key_PageUp
Case #ESC_SEQ + "6~"
ConsoleInkey_SpecialKey = #PB_Key_PageDown
Case #ESC_SEQ + "7~"
ConsoleInkey_SpecialKey = #PB_Key_Home
Case #ESC_SEQ + "8~"
ConsoleInkey_SpecialKey = #PB_Key_End
Case #ESC_SEQ + "9~"
ConsoleInkey_SpecialKey = 0
Case #ESC_SEQ + "10~"
ConsoleInkey_SpecialKey = 0
Case #ESC_SEQ + "11~"
ConsoleInkey_SpecialKey = #PB_Key_F1
Case #ESC_SEQ + "12~"
ConsoleInkey_SpecialKey = #PB_Key_F2
Case #ESC_SEQ + "13~"
ConsoleInkey_SpecialKey = #PB_Key_F3
Case #ESC_SEQ + "14~"
ConsoleInkey_SpecialKey = #PB_Key_F4
Case #ESC_SEQ + "15~"
ConsoleInkey_SpecialKey = #PB_Key_F5
Case #ESC_SEQ + "16~"
ConsoleInkey_SpecialKey = 0
Case #ESC_SEQ + "17~"
ConsoleInkey_SpecialKey = #PB_Key_F6
Case #ESC_SEQ + "18~"
ConsoleInkey_SpecialKey = #PB_Key_F7
Case #ESC_SEQ + "19~"
ConsoleInkey_SpecialKey = #PB_Key_F8
Case #ESC_SEQ + "20~"
ConsoleInkey_SpecialKey = #PB_Key_F9
Case #ESC_SEQ + "21~"
ConsoleInkey_SpecialKey = #PB_Key_F10
Case #ESC_SEQ + "22~"
ConsoleInkey_SpecialKey = 0
Case #ESC_SEQ + "23~"
ConsoleInkey_SpecialKey = #PB_Key_F11
Case #ESC_SEQ + "24~"
ConsoleInkey_SpecialKey = #PB_Key_F12
Case #ESC_SEQ + "P", #ESC_SEQ + "1P", Chr(27) + "0P", Chr(27) + "OP"
ConsoleInkey_SpecialKey = #PB_Key_F1
Case #ESC_SEQ + "Q", #ESC_SEQ + "1Q", Chr(27) + "0Q", Chr(27) + "OQ"
ConsoleInkey_SpecialKey = #PB_Key_F2
Case #ESC_SEQ + "R", #ESC_SEQ + "1R", Chr(27) + "0R", Chr(27) + "OR"
ConsoleInkey_SpecialKey = #PB_Key_F3
Case #ESC_SEQ + "S", #ESC_SEQ + "1S", Chr(27) + "0S", Chr(27) + "OS"
ConsoleInkey_SpecialKey = #PB_Key_F4
EndSelect
ProcedureReturn ConsoleInkey_SpecialKey
EndProcedure
Procedure$ SpecialKey_To_VTSequence(SpecialKey) ; translate #PB_Key_XXX to VT sequence
Protected result$
Select SpecialKey
Case #PB_Key_Back
result$ = Chr(8)
Case #PB_Key_Return
result$ = Chr(13)
Case #PB_Key_Up
result$ = #ESC_SEQ + "A"
Case #PB_Key_Down
result$ = #ESC_SEQ + "B"
Case #PB_Key_Right
result$ = #ESC_SEQ + "C"
Case #PB_Key_Left
result$ = #ESC_SEQ + "D"
Case #PB_Key_Home
result$ = #ESC_SEQ + "1~"
Case #PB_Key_Insert
result$ = #ESC_SEQ + "2~"
Case #PB_Key_Delete
result$ = #ESC_SEQ + "3~"
Case #PB_Key_End
result$ = #ESC_SEQ + "4~"
Case #PB_Key_PageUp
result$ = #ESC_SEQ + "5~"
Case #PB_Key_PageDown
result$ = #ESC_SEQ + "6~"
Case #PB_Key_F1 To #PB_Key_F12
result$ = #ESC_SEQ + Str(11 + SpecialKey - #PB_Key_F1) + "~"
EndSelect
ProcedureReturn result$
EndProcedure
Procedure$ SpecialKey_GetName(K) ; little helper returns "F1" when given #PB_Key_F1 etc.
Protected result$
Select K
Case 0
Case #PB_Key_Return
result$ = "return"
Case #PB_Key_Home
result$ = "home"
Case #PB_Key_F1 To #PB_Key_F12
result$ = "F" + Str(1 + (K - #PB_Key_F1))
Case #PB_Key_Back
result$ = "backspace"
Case #PB_Key_End
result$ = "end"
Case #PB_Key_PageUp
result$ = "pageup"
Case #PB_Key_PageDown
result$ = "pagedown"
Case #PB_Key_Delete
result$ = "delete"
Case #PB_Key_Insert
result$ = "insert"
Case #PB_Key_Escape
result$ = "escape"
Case #PB_Key_Left
result$ = "left"
Case #PB_Key_Up
result$ = "up"
Case #PB_Key_Right
result$ = "right"
Case #PB_Key_Down
result$ = "down"
Default
result$ = "raw:" + Str(K)
EndSelect
ProcedureReturn result$
EndProcedure
; DEMO /TEST
CompilerIf #PB_Compiler_IsMainFile
Procedure$ WaitKey(Text$, FrontColor = $FFFFFF, BackColor = $0, dephased = 0) ; Wait for a key + pulsating color fader text
Protected rest
Protected last_rest
Protected inkey$
Protected f.f
Protected bf.f
Protected fr = FrontColor & 255
Protected fg = (FrontColor >> 8) & 255
Protected fb = (FrontColor >> 16) & 255
Protected br = (BackColor) & 255
Protected bg = (BackColor >> 8) & 255
Protected bb = (BackColor >> 16) & 255
Repeat
rest = ElapsedMilliseconds() & 1023
If rest > 512
rest = 1024 - rest
EndIf
rest = rest / 2
If rest <> last_rest
f = rest / 255
If dephased
bf = 1.0 - f
Else
bf = f
EndIf
;ConsoleColor24(RGB(rest,rest,rest),RGB(255-rest,255-rest,255-rest))
ConsoleDefaultColors()
EnableGraphicalConsole(0)
; Print(#CR$ + LSet("", ConsoleWidth() - 1) + #CR$)
Print(#CR$)
ConsoleColor24(xRGB(fr * f, fg * f, fb * f), xRGB(br * bf, bg * bf, bb * bf))
EnableGraphicalConsole(1)
Print(Text$)
ConsoleDefaultColors()
last_rest = rest
Else
Delay(1)
EndIf
inkey$ = ConsoleInkey()
Until inkey$ <> #Empty$ Or ConsoleSpecialKey()
ConsoleDefaultColors()
EnableGraphicalConsole(0)
Print(#CR$ + LSet("", ConsoleWidth() - 1) + #CR$)
ProcedureReturn inkey$
EndProcedure
OpenConsole()
InitConsoleMetrics()
UpdateConsoleSize()
PrintN("UpdateConsoleMetrics.pb demo/test")
PrintN("'Text decorations'")
ConsoleBold(1):PrintN("This text is bold (non-Windows OS)"):ConsoleBold(0)
ConsoleUnderline(1):PrintN("This text is underlined (non-Windows OS)"):ConsoleUnderline(0)
ConsoleItalic(1):PrintN("This text is italic (non-Windows OS)"):ConsoleItalic(0)
ConsoleStrikeOut(1):PrintN("This text is striked-out (non-Windows OS)"):ConsoleStrikeOut(0)
ConsoleBlink(1):PrintN("This text is blinking at normal speed (non-Windows OS)"):ConsoleBlink(0)
PrintN("This text doesn't blink")
ConsoleBlink(2):PrintN("This text is blinking at fast speed (non-Windows OS)"):ConsoleBlink(0)
Debug Str(ConsoleWidth()) + " x " + Str(ConsoleHeight())
PrintN("Maxium color bits: " + Str(ConsoleMaximumColorBits()))
PrintN("...")
Print("Console X: ") : PrintN(Str(ConsoleX()))
Print("Console Y: ") : PrintN(Str(ConsoleY()))
PrintN("Console Width: " + Str(ConsoleWidth()))
PrintN("Console Height: " + Str(ConsoleHeight()))
Print("Console Buffer Columns: ") : PrintN(Str(ConsoleBufferColumns()))
Print("Console Buffer Lines: ") : PrintN(Str(ConsoleBufferRows()))
PrintN("")
WaitKey("Resize your terminal window & press any key", $FFFF, $0000FF, 1)
If UpdateConsoleSize() = 0
ConsoleColor24(xRGB(127, 127, 127), 0)
PrintN("(size unchanged)")
Else
ConsoleColor24($00FF00, 0)
PrintN("size changed!")
EndIf
ConsoleDefaultColors()
Print("Console X: ") : PrintN(Str(ConsoleX()))
Print("Console Y: ") : PrintN(Str(ConsoleY()))
PrintN("Console Width: " + Str(ConsoleWidth()))
PrintN("Console Height: " + Str(ConsoleHeight()))
Print("Console Buffer Columns: ") : PrintN(Str(ConsoleBufferColumns()))
Print("Console Buffer Lines: ") : PrintN(Str(ConsoleBufferRows()))
CompilerIf #PB_Compiler_Debugger
WaitKey("Program end. Press any key to exit.")
CompilerEndIf
CloseConsole()
CompilerEndIf
CompilerIf #PB_Compiler_IsMainFile
OpenConsole()
PrintN("Hit F1-F12 keys, Home, Cursor, PageUp/Down and other special keys - #PB_Key_Escape to exit :)")
Repeat
Print(ConsoleInkey())
If ConsoleSpecialKey()
PrintN("*" + SpecialKey_GetName(ConsoleSpecialKey()) + "*")
EndIf
Until ConsoleSpecialKey() = #PB_Key_Escape
CloseConsole()
CompilerEndIf
;
;