Terminal control/Positional read: Difference between revisions
m (→{{header|Phix}}: syntax coloured, marked p2js incompatible) |
m (→{{header|Wren}}: Minor tidy) |
||
(2 intermediate revisions by 2 users not shown) | |||
Line 4: | Line 4: | ||
=={{header|Action!}}== |
=={{header|Action!}}== |
||
Method 1: terminal reading |
Method 1: terminal reading |
||
< |
<syntaxhighlight lang="action!">proc Main() |
||
byte CHARS, cursorinh=$2F0 |
byte CHARS, cursorinh=$2F0 |
||
Line 16: | Line 16: | ||
position(2,4) printf("Character at column 2 row 2 was %C",CHARS) |
position(2,4) printf("Character at column 2 row 2 was %C",CHARS) |
||
return</ |
return</syntaxhighlight> |
||
=={{header|AutoHotkey}}== |
=={{header|AutoHotkey}}== |
||
{{works with|AutoHotkey_L}} |
{{works with|AutoHotkey_L}} |
||
<p>AutoHotkey is not built for the command line, so we need call the WinAPI directly.</p><p>For fun, this writes random characters to the command window so that it has something to retrieve. </p> |
<p>AutoHotkey is not built for the command line, so we need call the WinAPI directly.</p><p>For fun, this writes random characters to the command window so that it has something to retrieve. </p> |
||
< |
<syntaxhighlight lang="ahk">DllCall( "AllocConsole" ) ; create a console if not launched from one |
||
hConsole := DllCall( "GetStdHandle", int, STDOUT := -11 ) |
hConsole := DllCall( "GetStdHandle", int, STDOUT := -11 ) |
||
Loop 10 |
Loop 10 |
||
Line 57: | Line 57: | ||
return out |
return out |
||
return 0 |
return 0 |
||
}</ |
}</syntaxhighlight> |
||
=={{header|BASIC}}== |
=={{header|BASIC}}== |
||
==={{header|Applesoft BASIC}}=== |
==={{header|Applesoft BASIC}}=== |
||
< |
<syntaxhighlight lang="applesoftbasic"> 10 DEF FN C(H) = SCRN( H - 1,(V - 1) * 2) + SCRN( H - 1,(V - 1) * 2 + 1) * 16 |
||
20 LET V = 6:C$ = CHR$ ( FN C(3))</ |
20 LET V = 6:C$ = CHR$ ( FN C(3))</syntaxhighlight> |
||
==={{header| |
==={{header|BBC BASIC}}=== |
||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
The top Left corner Is at position 0,0 |
|||
⚫ | |||
<syntaxhighlight lang="freebasic">'Works on Windows. On Linux, the value returned can differ from the character shown on the console. |
|||
'For example, unprintable control codes - such as the LF character (10) that implicitly occurs |
|||
'after the end of Printed text - may be picked up instead of the untouched character in its place. |
|||
Print "T@4;4G,XIJ" |
|||
Print ">C+PE0)RM;" |
|||
Print "JEV6B/8E?H" |
|||
Print "FSC>41UIGR" |
|||
Print "V>41JMXMOW" |
|||
Print "IY0*KH6M;B"' Character at column 3, row 6 = 0 |
|||
Print "-6<UL*>DU7" |
|||
Print "MZ))<5D:B8" |
|||
Print ".@UB/P6UQ)" |
|||
Print "<9HYH)<ZJF" |
|||
Dim As Integer char_ascii_value = Screen(6,3) |
|||
Locate 6, 14 : Print "Character at column 3, row 6 = "; Chr(char_ascii_value) |
|||
Sleep</syntaxhighlight> |
|||
==={{header|Locomotive Basic}}=== |
|||
⚫ | |||
⚫ | |||
Amstrad CPC screen memory only stores pixels but no character information (as opposed to e.g. the C64), so the firmware routine (TXT_UNWRITE) called by BASIC works by trying to find a match between screen pixels and the shape of a currently defined character. If the character table or screen pixels in the area of the character are changed between writing and reading, COPYCHR$ will therefore fail. |
Amstrad CPC screen memory only stores pixels but no character information (as opposed to e.g. the C64), so the firmware routine (TXT_UNWRITE) called by BASIC works by trying to find a match between screen pixels and the shape of a currently defined character. If the character table or screen pixels in the area of the character are changed between writing and reading, COPYCHR$ will therefore fail. |
||
===[[QuickBASIC#QBasic|QBasic]]=== |
===[[QuickBASIC#QBasic|QBasic]]=== |
||
The top left corner is (1, 1). |
The top left corner is (1, 1). |
||
< |
<syntaxhighlight lang="qbasic">c$ = CHR$(SCREEN(6, 3))</syntaxhighlight> |
||
==={{header|ZX Spectrum Basic}}=== |
==={{header|ZX Spectrum Basic}}=== |
||
< |
<syntaxhighlight lang="basic"> 10 REM The top left corner is at position 0,0 |
||
20 REM So we subtract one from the coordinates |
20 REM So we subtract one from the coordinates |
||
30 LET c$ = SCREEN$(5,2)</ |
30 LET c$ = SCREEN$(5,2)</syntaxhighlight> |
||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
=={{header|C}}== |
=={{header|C}}== |
||
Line 98: | Line 118: | ||
{{libheader|Win32}} |
{{libheader|Win32}} |
||
< |
<syntaxhighlight lang="c">#include <windows.h> |
||
#include <wchar.h> |
#include <wchar.h> |
||
Line 130: | Line 150: | ||
wprintf(L"Character at (3, 6) had been '%lc'\n", c); |
wprintf(L"Character at (3, 6) had been '%lc'\n", c); |
||
return 0; |
return 0; |
||
}</ |
}</syntaxhighlight> |
||
=={{header|Common Lisp}}== |
=={{header|Common Lisp}}== |
||
==={{header|ncurses}}=== |
==={{header|ncurses}}=== |
||
To interface the ncurses C library from Lisp, the ''croatoan'' library is used. |
To interface the ncurses C library from Lisp, the ''croatoan'' library is used. |
||
< |
<syntaxhighlight lang="lisp">(defun positional-read () |
||
(with-screen (scr :input-blocking t :input-echoing nil :cursor-visible nil) |
(with-screen (scr :input-blocking t :input-echoing nil :cursor-visible nil) |
||
;; print random characters in a 10x20 grid |
;; print random characters in a 10x20 grid |
||
Line 152: | Line 172: | ||
(format scr "extracted char: ~A" char)) |
(format scr "extracted char: ~A" char)) |
||
(refresh scr) |
(refresh scr) |
||
(get-char scr)))</ |
(get-char scr)))</syntaxhighlight> |
||
=={{header|Go}}== |
=={{header|Go}}== |
||
{{trans|Kotlin}} |
{{trans|Kotlin}} |
||
< |
<syntaxhighlight lang="go">package main |
||
/* |
/* |
||
Line 183: | Line 203: | ||
} |
} |
||
fmt.Printf("The character at column 3, row 6 is '%c'\n", c) |
fmt.Printf("The character at column 3, row 6 is '%c'\n", c) |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 192: | Line 212: | ||
=={{header|Julia}}== |
=={{header|Julia}}== |
||
{{trans|Raku}} |
{{trans|Raku}} |
||
< |
<syntaxhighlight lang="julia">using LibNCurses |
||
randtxt(n) = foldl(*, rand(split("1234567890abcdefghijklmnopqrstuvwxyz", ""), n)) |
randtxt(n) = foldl(*, rand(split("1234567890abcdefghijklmnopqrstuvwxyz", ""), n)) |
||
Line 206: | Line 226: | ||
ch = LibNCurses.winch(row, col) |
ch = LibNCurses.winch(row, col) |
||
LibNCurses.mvwaddstr(col, 52, "The character at ($row, $col) is $ch.") ) |
LibNCurses.mvwaddstr(col, 52, "The character at ($row, $col) is $ch.") ) |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Kotlin}}== |
=={{header|Kotlin}}== |
||
This is based on the C entry and works on Windows 10: |
This is based on the C entry and works on Windows 10: |
||
< |
<syntaxhighlight lang="scala">// Kotlin Native version 0.3 |
||
import kotlinx.cinterop.* |
import kotlinx.cinterop.* |
||
Line 234: | Line 254: | ||
else println("Something went wrong!") |
else println("Something went wrong!") |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 242: | Line 262: | ||
=={{header|Ksh}}== |
=={{header|Ksh}}== |
||
< |
<syntaxhighlight lang="ksh"> |
||
#!/bin/ksh |
#!/bin/ksh |
||
Line 296: | Line 316: | ||
move 14 1 |
move 14 1 |
||
refresh |
refresh |
||
endwin</ |
endwin</syntaxhighlight> |
||
{{out}}<pre> |
{{out}}<pre> |
||
Line 317: | Line 337: | ||
{{libheader|nim-ncurses}} |
{{libheader|nim-ncurses}} |
||
This Nim version is inspired by Raku and Julia versions. |
This Nim version is inspired by Raku and Julia versions. |
||
< |
<syntaxhighlight lang="nim">import random, sequtils, strutils |
||
import ncurses |
import ncurses |
||
Line 337: | Line 357: | ||
discard getch() |
discard getch() |
||
endwin()</ |
endwin()</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 355: | Line 375: | ||
=={{header|Perl}}== |
=={{header|Perl}}== |
||
{{trans|Raku}} |
{{trans|Raku}} |
||
< |
<syntaxhighlight lang="perl"># 20200917 added Perl programming solution |
||
use strict; |
use strict; |
||
Line 381: | Line 401: | ||
$win->getch; |
$win->getch; |
||
endwin;</ |
endwin;</syntaxhighlight> |
||
=={{header|Phix}}== |
=={{header|Phix}}== |
||
<!--< |
<!--<syntaxhighlight lang="phix">(notonline)--> |
||
<span style="color: #000080;font-style:italic;">-- |
<span style="color: #000080;font-style:italic;">-- |
||
-- demo\rosetta\Positional_read.exw |
-- demo\rosetta\Positional_read.exw |
||
Line 395: | Line 415: | ||
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"\n\n=>%c"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">ch</span><span style="color: #0000FF;">)</span> |
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"\n\n=>%c"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">ch</span><span style="color: #0000FF;">)</span> |
||
<span style="color: #0000FF;">{}</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">wait_key</span><span style="color: #0000FF;">()</span> |
<span style="color: #0000FF;">{}</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">wait_key</span><span style="color: #0000FF;">()</span> |
||
<!--</ |
<!--</syntaxhighlight>--> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 410: | Line 430: | ||
=={{header|PowerShell}}== |
=={{header|PowerShell}}== |
||
This gets the character at position (3, 6) of the ''buffer'', not necessarily of the screen. |
This gets the character at position (3, 6) of the ''buffer'', not necessarily of the screen. |
||
< |
<syntaxhighlight lang="powershell"> |
||
$coord = [System.Management.Automation.Host.Coordinates]::new(3, 6) |
$coord = [System.Management.Automation.Host.Coordinates]::new(3, 6) |
||
$rect = [System.Management.Automation.Host.Rectangle]::new($coord, $coord) |
$rect = [System.Management.Automation.Host.Rectangle]::new($coord, $coord) |
||
$char = $Host.UI.RawUI.GetBufferContents($rect).Character |
$char = $Host.UI.RawUI.GetBufferContents($rect).Character |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Python}}== |
=={{header|Python}}== |
||
< |
<syntaxhighlight lang="python">import curses |
||
from random import randint |
from random import randint |
||
Line 438: | Line 458: | ||
curses.endwin() |
curses.endwin() |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
Line 455: | Line 475: | ||
=={{header|Racket}}== |
=={{header|Racket}}== |
||
Works in a CMD box on Windows: |
Works in a CMD box on Windows: |
||
< |
<syntaxhighlight lang="racket"> |
||
#lang racket |
#lang racket |
||
(require ffi/unsafe ffi/unsafe/define) |
(require ffi/unsafe ffi/unsafe/define) |
||
Line 466: | Line 486: | ||
(and (ReadConsoleOutputCharacterA (GetStdHandle -11) b 1 #x50002) |
(and (ReadConsoleOutputCharacterA (GetStdHandle -11) b 1 #x50002) |
||
(printf "The character at 3x6 is <~a>\n" b)) |
(printf "The character at 3x6 is <~a>\n" b)) |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Raku}}== |
=={{header|Raku}}== |
||
(formerly Perl 6) |
(formerly Perl 6) |
||
{{trans|Python}} |
{{trans|Python}} |
||
<lang |
<syntaxhighlight lang="raku" line>use NCurses; |
||
# Reference: |
# Reference: |
||
Line 506: | Line 526: | ||
delwin($win) if $win; |
delwin($win) if $win; |
||
endwin; |
endwin; |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 539: | Line 559: | ||
{{works with|PC/REXX}} |
{{works with|PC/REXX}} |
||
{{works with|Personal REXX}} |
{{works with|Personal REXX}} |
||
< |
<syntaxhighlight lang="rexx">/*REXX program demonstrates reading a character from (at) at specific screen location. */ |
||
row = 6 /*point to a particular row on screen*/ |
row = 6 /*point to a particular row on screen*/ |
||
col = 3 /* " " " " column " " */ |
col = 3 /* " " " " column " " */ |
||
Line 547: | Line 567: | ||
other = scrRead(40, 3, 1) /*same thing, but for row forty. */ |
other = scrRead(40, 3, 1) /*same thing, but for row forty. */ |
||
/*stick a fork in it, we're all done. */</ |
/*stick a fork in it, we're all done. */</syntaxhighlight><br><br> |
||
=={{header|TXR}}== |
=={{header|TXR}}== |
||
< |
<syntaxhighlight lang="txrlisp">;;; Type definitions and constants |
||
(typedef BOOL (enum BOOL FALSE TRUE)) |
(typedef BOOL (enum BOOL FALSE TRUE)) |
||
Line 621: | Line 641: | ||
(unless (plusp [nread 0]) |
(unless (plusp [nread 0]) |
||
(error "ReadConsoleOutputCharacter read zero characters")) |
(error "ReadConsoleOutputCharacter read zero characters")) |
||
(format t "character is ~s\n" [chars 0])))</ |
(format t "character is ~s\n" [chars 0])))</syntaxhighlight> |
||
Notes: |
Notes: |
||
Line 631: | Line 651: | ||
{{libheader|ncurses}} |
{{libheader|ncurses}} |
||
An embedded program so we can ask the C host to communicate with ncurses for us. |
An embedded program so we can ask the C host to communicate with ncurses for us. |
||
<syntaxhighlight lang="wren">/* Terminal_control_Positional_read.wren */ |
|||
<lang ecmascript>/* terminal_control_positional_read.wren */ |
|||
import "random" for Random |
import "random" for Random |
||
Line 688: | Line 708: | ||
// clean-up |
// clean-up |
||
win.delwin() |
win.delwin() |
||
Ncurses.endwin()</ |
Ncurses.endwin()</syntaxhighlight> |
||
<br> |
<br> |
||
We now embed this in the following C program, compile and run it. |
We now embed this in the following C program, compile and run it. |
||
<syntaxhighlight lang="c">/* gcc Terminal_control_Positional_read.c -o Terminal_control_Positional_read -lncurses -lwren -lm */ |
|||
⚫ | |||
⚫ | |||
#include <stdlib.h> |
#include <stdlib.h> |
||
#include <string.h> |
#include <string.h> |
||
Line 818: | Line 840: | ||
WrenVM* vm = wrenNewVM(&config); |
WrenVM* vm = wrenNewVM(&config); |
||
const char* module = "main"; |
const char* module = "main"; |
||
const char* fileName = " |
const char* fileName = "Terminal_control_Positional_read.wren"; |
||
char *script = readFile(fileName); |
char *script = readFile(fileName); |
||
WrenInterpretResult result = wrenInterpret(vm, module, script); |
WrenInterpretResult result = wrenInterpret(vm, module, script); |
||
Line 834: | Line 856: | ||
free(script); |
free(script); |
||
return 0; |
return 0; |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 854: | Line 876: | ||
=={{header|XPL0}}== |
=={{header|XPL0}}== |
||
< |
<syntaxhighlight lang="xpl0">include c:\cxpl\stdlib; |
||
int C; |
int C; |
||
[Cursor(3, 6); \move cursor to column 3, row 6 (top left = 0,0) |
[Cursor(3, 6); \move cursor to column 3, row 6 (top left = 0,0) |
||
\Call BIOS interrupt routine to read character (& attribute) at cursor position |
\Call BIOS interrupt routine to read character (& attribute) at cursor position |
||
C:= CallInt($10, $0800, 0) & $00FF; \mask off attribute, leaving the character |
C:= CallInt($10, $0800, 0) & $00FF; \mask off attribute, leaving the character |
||
]</ |
]</syntaxhighlight> |
||
{{omit from|ACL2}} |
{{omit from|ACL2}} |
Latest revision as of 12:09, 13 February 2024
You are encouraged to solve this task according to the task description, using any language you may know.
Determine the character displayed on the screen at column 3, row 6 and store that character in a variable. Note that it is permissible to utilize system or language provided methods or system provided facilities, system maintained records or available buffers or system maintained display records to achieve this task, rather than query the terminal directly, if those methods are more usual for the system type or language.
Action!
Method 1: terminal reading
proc Main()
byte CHARS, cursorinh=$2F0
graphics(0) cursorinh=1
position(2,2) printe("Action!")
CHARS=Locate(2,2) position(2,2) put(CHARS)
cursorinh=0
position(2,4) printf("Character at column 2 row 2 was %C",CHARS)
return
AutoHotkey
AutoHotkey is not built for the command line, so we need call the WinAPI directly.
For fun, this writes random characters to the command window so that it has something to retrieve.
DllCall( "AllocConsole" ) ; create a console if not launched from one
hConsole := DllCall( "GetStdHandle", int, STDOUT := -11 )
Loop 10
{
Loop 10
{
Random, asc, % asc("A"), % Asc("Z")
WriteConsole(hConsole, Chr(asc))
}
WriteConsole(hConsole, "`n")
}
MsgBox % ReadConsoleOutputCharacter(hConsole, 1, 3, 6)
; === The below simply wraps part of the WinAPI ===
WriteConsole(hConsole, text){
VarSetCapacity(out, 16)
If DllCall( "WriteConsole", UPtr, hConsole, Str, text, UInt, StrLen(text)
, UPtrP, out, uint, 0 )
return out
return 0
}
ReadConsoleOutputCharacter(hConsole, length, x, y){
VarSetCapacity(out, length * (1 << !!A_IsUnicode))
VarSetCapacity(n, 16)
if DllCall( "ReadConsoleOutputCharacter"
, UPtr, hConsole
, Str, out
, UInt, length
, UInt, x | (y << 16)
, UPtrP, n )
&& VarSetCapacity(out, -1)
return out
return 0
}
BASIC
Applesoft BASIC
10 DEF FN C(H) = SCRN( H - 1,(V - 1) * 2) + SCRN( H - 1,(V - 1) * 2 + 1) * 16
20 LET V = 6:C$ = CHR$ ( FN C(3))
BBC BASIC
PRINT TAB(2,5) "Here"
char$ = GET$(2,5)
PRINT ''"Character at column 3 row 6 was " char$
that support calling OSBYTE
PRINT TAB(2,5) "Here"
PRINT TAB(2,5); : REM Position cursor over character to read
A%=&87:char%=((USR&FFF4)AND&FF00)DIV256 : REM Ask operating system to read character
PRINT ''"Character at column 3 row 6 was CHR$(";char%;")"
FreeBASIC
The top Left corner Is at position 0,0
'Works on Windows. On Linux, the value returned can differ from the character shown on the console.
'For example, unprintable control codes - such as the LF character (10) that implicitly occurs
'after the end of Printed text - may be picked up instead of the untouched character in its place.
Print "T@4;4G,XIJ"
Print ">C+PE0)RM;"
Print "JEV6B/8E?H"
Print "FSC>41UIGR"
Print "V>41JMXMOW"
Print "IY0*KH6M;B"' Character at column 3, row 6 = 0
Print "-6<UL*>DU7"
Print "MZ))<5D:B8"
Print ".@UB/P6UQ)"
Print "<9HYH)<ZJF"
Dim As Integer char_ascii_value = Screen(6,3)
Locate 6, 14 : Print "Character at column 3, row 6 = "; Chr(char_ascii_value)
Sleep
Locomotive Basic
10 LOCATE 3,6
20 a$=COPYCHR$(#0)
Amstrad CPC screen memory only stores pixels but no character information (as opposed to e.g. the C64), so the firmware routine (TXT_UNWRITE) called by BASIC works by trying to find a match between screen pixels and the shape of a currently defined character. If the character table or screen pixels in the area of the character are changed between writing and reading, COPYCHR$ will therefore fail.
QBasic
The top left corner is (1, 1).
c$ = CHR$(SCREEN(6, 3))
ZX Spectrum Basic
10 REM The top left corner is at position 0,0
20 REM So we subtract one from the coordinates
30 LET c$ = SCREEN$(5,2)
C
With the Windows console, call GetConsoleScreenBufferInfo()
to find the top-left corner of the display screen. Then add (3, 6) to the top-left corner and call ReadConsoleOutputCharacterW()
to read character. This program reckons that the top-left corner is (0, 0).
#include <windows.h>
#include <wchar.h>
int
main()
{
CONSOLE_SCREEN_BUFFER_INFO info;
COORD pos;
HANDLE conout;
long len;
wchar_t c;
/* Create a handle to the console screen. */
conout = CreateFileW(L"CONOUT$", GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
0, NULL);
if (conout == INVALID_HANDLE_VALUE)
return 1;
/* Where is the display window? */
if (GetConsoleScreenBufferInfo(conout, &info) == 0)
return 1;
/* c = character at position. */
pos.X = info.srWindow.Left + 3; /* Column */
pos.Y = info.srWindow.Top + 6; /* Row */
if (ReadConsoleOutputCharacterW(conout, &c, 1, pos, &len) == 0 ||
len <= 0)
return 1;
wprintf(L"Character at (3, 6) had been '%lc'\n", c);
return 0;
}
Common Lisp
ncurses
To interface the ncurses C library from Lisp, the croatoan library is used.
(defun positional-read ()
(with-screen (scr :input-blocking t :input-echoing nil :cursor-visible nil)
;; print random characters in a 10x20 grid
(loop for i from 0 to 9 do
(loop for j from 0 to 19 do
(add-char scr (+ 33 (random 94)) :y i :x j)))
;; highlight char to extract at row 6 column 3
(change-attributes scr 1 (list :reverse) :y 5 :x 2)
(refresh scr)
;; wait for keypress
(get-char scr)
;; extract char from row 6 column 3
(let ((char (extract-char scr :y 5 :x 2)))
;; then print it out again
(move scr 11 0)
(format scr "extracted char: ~A" char))
(refresh scr)
(get-char scr)))
Go
package main
/*
#include <windows.h>
*/
import "C"
import "fmt"
func main() {
for i := 0; i < 80*25; i++ {
fmt.Print("A") // fill 80 x 25 console with 'A's
}
fmt.Println()
conOut := C.GetStdHandle(C.STD_OUTPUT_HANDLE)
info := C.CONSOLE_SCREEN_BUFFER_INFO{}
pos := C.COORD{}
C.GetConsoleScreenBufferInfo(conOut, &info)
pos.X = info.srWindow.Left + 3 // column number 3 of display window
pos.Y = info.srWindow.Top + 6 // row number 6 of display window
var c C.wchar_t
var le C.ulong
ret := C.ReadConsoleOutputCharacterW(conOut, &c, 1, pos, &le)
if ret == 0 || le <= 0 {
fmt.Println("Something went wrong!")
return
}
fmt.Printf("The character at column 3, row 6 is '%c'\n", c)
}
- Output:
The character at column 3, row 6 is 'A'
Julia
using LibNCurses
randtxt(n) = foldl(*, rand(split("1234567890abcdefghijklmnopqrstuvwxyz", ""), n))
initscr()
for i in 1:20
LibNCurses.mvwaddstr(i, 1, randtxt(50))
end
row = rand(1:20)
col = rand(1:50)
ch = LibNCurses.winch(row, col)
LibNCurses.mvwaddstr(col, 52, "The character at ($row, $col) is $ch.") )
Kotlin
This is based on the C entry and works on Windows 10:
// Kotlin Native version 0.3
import kotlinx.cinterop.*
import win32.*
fun main(args: Array<String>) {
for (i in 0 until (80 * 25)) print("A") // fill 80 x 25 console with 'A's
println()
memScoped {
val conOut = GetStdHandle(-11)
val info = alloc<CONSOLE_SCREEN_BUFFER_INFO>()
val pos = alloc<COORD>()
GetConsoleScreenBufferInfo(conOut, info.ptr)
pos.X = (info.srWindow.Left + 3).toShort() // column number 3 of display window
pos.Y = (info.srWindow.Top + 6).toShort() // row number 6 of display window
val c = alloc<wchar_tVar>()
val len = alloc<IntVar>()
ReadConsoleOutputCharacterW(conOut, c.ptr, 1, pos.readValue(), len.ptr)
if (len.value == 1) {
val ch = c.value.toChar()
println("The character at column 3, row 6 is '$ch'")
}
else println("Something went wrong!")
}
}
- Output:
The character at column 3, row 6 is 'A'
Ksh
#!/bin/ksh
# Determine the character displayed on the screen at column 3, row 6 and
# store that character in a variable.
#
# Use a group of functions "shellcurses"
# # Variables:
#
FPATH="/usr/local/functions/shellcurses/"
rst="�[0m"
red="�[31m"
whi="�[37m"
integer row=${1:-6} col=${2:-3} # Allow command line row col input
# # 10x10 grid of random digits
#
typeset -A grid
for ((i=0; i<10; i++)); do
for ((j=0; j<10; j++)); do
(( grid[${i}][${j}] = (RANDOM % 9) + 1 ))
done
done
# # Functions:
#
######
# main #
######
# # Initialize the curses screen
#
initscr ; export MAX_LINES MAX_COLS
# # Display the random number grid with target in red
#
clear
for ((i=1; i<=10; i++)); do
for ((j=1; j<=10; j++)); do
colr=${whi}
(( i == row )) && (( j == col )) && colr=${red}
mvaddstr ${i} ${j} "${colr}${grid[$((i-1))][$((j-1))]}${rst}"
done
done
str=$(rtnch ${row} ${col}) # return char at (row, col) location
mvaddstr 12 1 "Digit at (${row},${col}) = ${str}" # Display result
move 14 1
refresh
endwin
- Output:
2466511215 6743931696 7546513188 7233775996 4748942123 8893655153 8341639139 8772676987 3772947552 8454526539
Digit at (6,3) = 9
Nim
This Nim version is inspired by Raku and Julia versions.
import random, sequtils, strutils
import ncurses
randomize()
let win = initscr()
assert not win.isNil, "Unable to initialize."
for y in 0..9:
mvaddstr(y.cint, 0, newSeqWith(10, sample({'0'..'9', 'a'..'z'})).join())
let row = rand(9).cint
let col = rand(9).cint
let ch = win.mvwinch(row, col)
mvaddstr(row, col + 11, "The character at ($1, $2) is $3.".format(row, col, chr(ch)))
mvaddstr(11, 0, "Press any key to quit.")
refresh()
discard getch()
endwin()
- Output:
tw5bl8mhvl 37t0nvwjhr 055co0b3hm 409stl3jgv The character at (3, 8) is g. a9j5354rci o5ymlrtgt2 9yjag11u7n 2nv32g6s7x 3l1zujlpl2 opkl6us0mf Press any key to quit.
Perl
# 20200917 added Perl programming solution
use strict;
use warnings;
use Curses;
initscr or die;
my $win = Curses->new;
foreach my $row (0..9) {
$win->addstr( $row , 0, join('', map { chr(int(rand(50)) + 41) } (0..9)))
};
my $icol = 3 - 1;
my $irow = 6 - 1;
my $ch = $win->inch($irow,$icol);
$win->addstr( $irow, $icol+10, 'Character at column 3, row 6 = '.$ch );
$win->addstr( LINES() - 2, 2, "Press any key to exit..." );
$win->getch;
endwin;
Phix
-- -- demo\rosetta\Positional_read.exw -- ================================ -- without js -- (position, get_screen_char) position(6,1) -- line 6 column 1 (1-based) puts(1,"abcdef") integer {ch,attr} = get_screen_char(6,3) printf(1,"\n\n=>%c",ch) {} = wait_key()
- Output:
abcdef =>c
PowerShell
This gets the character at position (3, 6) of the buffer, not necessarily of the screen.
$coord = [System.Management.Automation.Host.Coordinates]::new(3, 6)
$rect = [System.Management.Automation.Host.Rectangle]::new($coord, $coord)
$char = $Host.UI.RawUI.GetBufferContents($rect).Character
Python
import curses
from random import randint
# Print random text in a 10x10 grid
stdscr = curses.initscr()
for rows in range(10):
line = ''.join([chr(randint(41, 90)) for i in range(10)])
stdscr.addstr(line + '\n')
# Read
icol = 3 - 1
irow = 6 - 1
ch = stdscr.instr(irow, icol, 1).decode(encoding="utf-8")
# Show result
stdscr.move(irow, icol + 10)
stdscr.addstr('Character at column 3, row 6 = ' + ch + '\n')
stdscr.getch()
curses.endwin()
- Output:
T@4;4G,XIJ >C+PE0)RM; JEV6B/8E?H FSC>41UIGR V>41JMXMOW IY0*KH6M;B Character at column 3, row 6 = 0 -6<UL*>DU7 MZ))<5D:B8 .@UB/P6UQ) <9HYH)<ZJF
Racket
Works in a CMD box on Windows:
#lang racket
(require ffi/unsafe ffi/unsafe/define)
(define-ffi-definer defwin #f)
(defwin GetStdHandle (_fun _int -> _pointer))
(defwin ReadConsoleOutputCharacterA
(_fun _pointer _pointer _uint _uint [len : (_ptr o _uint)] -> _bool))
(define b (make-bytes 1 32))
(and (ReadConsoleOutputCharacterA (GetStdHandle -11) b 1 #x50002)
(printf "The character at 3x6 is <~a>\n" b))
Raku
(formerly Perl 6)
use NCurses;
# Reference:
# https://github.com/azawawi/perl6-ncurses
# Initialize curses window
my $win = initscr() or die "Failed to initialize ncurses\n";
# Print random text in a 10x10 grid
for ^10 { mvaddstr($_ , 0, (for ^10 {(41 .. 90).roll.chr}).join )};
# Read
my $icol = 3 - 1;
my $irow = 6 - 1;
my $ch = mvinch($irow,$icol);
# Show result
mvaddstr($irow, $icol+10, 'Character at column 3, row 6 = ' ~ $ch.chr);
mvaddstr( LINES() - 2, 2, "Press any key to exit..." );
# Refresh (this is needed)
nc_refresh;
# Wait for a keypress
getch;
# Cleanup
LEAVE {
delwin($win) if $win;
endwin;
}
- Output:
+W18:5I<1N N-I.HG45SK BFJY8:AK)8 J+4U<H1++: RP>BX-/19Y URDESVX;HX Character at column 3, row 6 = D J7+X3@E<BG M;?2U<8+FI )@BG,:D)O1 )>A-=LDY-. Press any key to exit...
REXX
The REXX doesn't have any cursor or screen management tools, but some REXX interpreters have added the functionality via different methods.
/*REXX program demonstrates reading a character from (at) at specific screen location. */
row = 6 /*point to a particular row on screen*/
col = 3 /* " " " " column " " */
howMany = 1 /*read this many characters from screen*/
stuff = scrRead(row, col, howMany) /*this'll do it. */
other = scrRead(40, 3, 1) /*same thing, but for row forty. */
/*stick a fork in it, we're all done. */
TXR
;;; Type definitions and constants
(typedef BOOL (enum BOOL FALSE TRUE))
(typedef HANDLE cptr)
(typedef WCHAR wchar)
(typedef DWORD uint32)
(typedef WORD uint16)
(typedef SHORT short)
(typedef COORD
(struct COORD
(X SHORT)
(Y SHORT)))
(typedef SMALL_RECT
(struct SMALL_RECT
(Left SHORT)
(Top SHORT)
(Right SHORT)
(Bottom SHORT)))
(typedef CONSOLE_SCREEN_BUFFER_INFO
(struct CONSOLE_SCREEN_BUFFER_INFO
(dwSize COORD)
(dwCursorPosition COORD)
(wAttributes WORD)
(srWindow SMALL_RECT)
(dwMaximumWindowSize COORD)))
;;; Various constants
(defvarl STD_INPUT_HANDLE (- #x100000000 10))
(defvarl STD_OUTPUT_HANDLE (- #x100000000 11))
(defvarl STD_ERROR_HANDLE (- #x100000000 12))
(defvarl NULL cptr-null)
(defvarl INVALID_HANDLE_VALUE (cptr-int -1))
;;; Foreign Function Bindings
(with-dyn-lib "kernel32.dll"
(deffi GetStdHandle "GetStdHandle" HANDLE (DWORD))
(deffi GetConsoleScreenBufferInfo "GetConsoleScreenBufferInfo"
BOOL (HANDLE (ptr-out CONSOLE_SCREEN_BUFFER_INFO)))
(deffi ReadConsoleOutputCharacter "ReadConsoleOutputCharacterW"
BOOL (HANDLE (ptr-out (array 1 WCHAR))
DWORD COORD (ptr-out (array 1 DWORD)))))
;;; Now the character at <2, 5> -- column 3, row 6.
(let ((console-handle (GetStdHandle STD_OUTPUT_HANDLE)))
(when (equal console-handle INVALID_HANDLE_VALUE)
(error "couldn't get console handle"))
(let* ((cinfo (new CONSOLE_SCREEN_BUFFER_INFO))
(getinfo-ok (GetConsoleScreenBufferInfo console-handle cinfo))
(coord (if getinfo-ok
^#S(COORD X ,(+ 2 cinfo.srWindow.Left)
Y ,(+ 5 cinfo.srWindow.Top))
#S(COORD X 0 Y 0)))
(chars (vector 1))
(nread (vector 1))
(read-ok (ReadConsoleOutputCharacter console-handle chars
1 coord nread)))
(when (eq getinfo-ok 'FALSE)
(error "GetConsoleScreenBufferInfo failed"))
(prinl cinfo)
(when (eq read-ok 'FALSE)
(error "ReadConsoleOutputCharacter failed"))
(unless (plusp [nread 0])
(error "ReadConsoleOutputCharacter read zero characters"))
(format t "character is ~s\n" [chars 0])))
Notes:
- An
ptr-out
to anarray
of 1DWORD
is used for the number of characters out parameter. The FFI type(ptr-out DWORD)
cannot work as a function argument, because integer objects are not mutable, and there isn't any concept of taking the address of a variable. A vector of 1 integer is mutable, and by making such a vector correspond with the FFI type(array 1 DWORD)
, the necessary semantics is achieved. - The quasiquote expression
^#S(COORD X ,(+ 2 cinfo.srWindow.Left) Y ,(+ 5 cinfo.srWindow.Top))
is equivalent to(new COORD X (+ 2 cinfo.srWindow.Left) Y (+ 5 cinfo.srWindow.Top))
. It is done this way to demonstrate support for structure quasiquoting.
Wren
An embedded program so we can ask the C host to communicate with ncurses for us.
/* Terminal_control_Positional_read.wren */
import "random" for Random
foreign class Window {
construct initscr() {}
foreign addstr(str)
foreign inch(y, x)
foreign move(y, x)
foreign refresh()
foreign getch()
foreign delwin()
}
class Ncurses {
foreign static endwin()
}
// initialize curses window
var win = Window.initscr()
if (win == 0) {
System.print("Failed to initialize ncurses.")
return
}
// print random text in a 10x10 grid
var rand = Random.new()
for (row in 0..9) {
var line = (0..9).map{ |d| String.fromByte(rand.int(41, 91)) }.join()
win.addstr(line + "\n")
}
// read
var col = 3 - 1
var row = 6 - 1
var ch = win.inch(row, col)
// show result
win.move(row, col + 10)
win.addstr("Character at column 3, row 6 = %(ch)")
win.move(11, 0)
win.addstr("Press any key to exit...")
// refresh
win.refresh()
// wait for a keypress
win.getch()
// clean-up
win.delwin()
Ncurses.endwin()
We now embed this in the following C program, compile and run it.
/* gcc Terminal_control_Positional_read.c -o Terminal_control_Positional_read -lncurses -lwren -lm */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ncurses.h>
#include "wren.h"
/* C <=> Wren interface functions */
void C_windowAllocate(WrenVM* vm) {
WINDOW** pwin = (WINDOW**)wrenSetSlotNewForeign(vm, 0, 0, sizeof(WINDOW*));
*pwin = initscr();
}
void C_addstr(WrenVM* vm) {
WINDOW* win = *(WINDOW**)wrenGetSlotForeign(vm, 0);
const char *str = wrenGetSlotString(vm, 1);
waddstr(win, str);
}
void C_inch(WrenVM* vm) {
WINDOW* win = *(WINDOW**)wrenGetSlotForeign(vm, 0);
int y = (int)wrenGetSlotDouble(vm, 1);
int x = (int)wrenGetSlotDouble(vm, 2);
char c = (char)mvwinch(win, y, x);
char s[2] = "\0";
sprintf(s, "%c", c);
wrenSetSlotString(vm, 0, s);
}
void C_move(WrenVM* vm) {
WINDOW* win = *(WINDOW**)wrenGetSlotForeign(vm, 0);
int y = (int)wrenGetSlotDouble(vm, 1);
int x = (int)wrenGetSlotDouble(vm, 2);
wmove(win, y, x);
}
void C_refresh(WrenVM* vm) {
WINDOW* win = *(WINDOW**)wrenGetSlotForeign(vm, 0);
wrefresh(win);
}
void C_getch(WrenVM* vm) {
WINDOW* win = *(WINDOW**)wrenGetSlotForeign(vm, 0);
wgetch(win);
}
void C_delwin(WrenVM* vm) {
WINDOW* win = *(WINDOW**)wrenGetSlotForeign(vm, 0);
delwin(win);
}
void C_endwin(WrenVM* vm) {
endwin();
}
WrenForeignClassMethods bindForeignClass(WrenVM* vm, const char* module, const char* className) {
WrenForeignClassMethods methods;
methods.allocate = NULL;
methods.finalize = NULL;
if (strcmp(module, "main") == 0) {
if (strcmp(className, "Window") == 0) {
methods.allocate = C_windowAllocate;
}
}
return methods;
}
WrenForeignMethodFn bindForeignMethod(
WrenVM* vm,
const char* module,
const char* className,
bool isStatic,
const char* signature) {
if (strcmp(module, "main") == 0) {
if (strcmp(className, "Window") == 0) {
if (!isStatic && strcmp(signature, "addstr(_)") == 0) return C_addstr;
if (!isStatic && strcmp(signature, "inch(_,_)") == 0) return C_inch;
if (!isStatic && strcmp(signature, "move(_,_)") == 0) return C_move;
if (!isStatic && strcmp(signature, "refresh()") == 0) return C_refresh;
if (!isStatic && strcmp(signature, "getch()") == 0) return C_getch;
if (!isStatic && strcmp(signature, "delwin()") == 0) return C_delwin;
} else if (strcmp(className, "Ncurses") == 0) {
if ( isStatic && strcmp(signature, "endwin()") == 0) return C_endwin;
}
}
return NULL;
}
static void writeFn(WrenVM* vm, const char* text) {
printf("%s", text);
}
void errorFn(WrenVM* vm, WrenErrorType errorType, const char* module, const int line, const char* msg) {
switch (errorType) {
case WREN_ERROR_COMPILE:
printf("[%s line %d] [Error] %s\n", module, line, msg);
break;
case WREN_ERROR_STACK_TRACE:
printf("[%s line %d] in %s\n", module, line, msg);
break;
case WREN_ERROR_RUNTIME:
printf("[Runtime Error] %s\n", msg);
break;
}
}
char *readFile(const char *fileName) {
FILE *f = fopen(fileName, "r");
fseek(f, 0, SEEK_END);
long fsize = ftell(f);
rewind(f);
char *script = malloc(fsize + 1);
fread(script, 1, fsize, f);
fclose(f);
script[fsize] = 0;
return script;
}
int main(int argc, char **argv) {
WrenConfiguration config;
wrenInitConfiguration(&config);
config.writeFn = &writeFn;
config.errorFn = &errorFn;
config.bindForeignClassFn = &bindForeignClass;
config.bindForeignMethodFn = &bindForeignMethod;
WrenVM* vm = wrenNewVM(&config);
const char* module = "main";
const char* fileName = "Terminal_control_Positional_read.wren";
char *script = readFile(fileName);
WrenInterpretResult result = wrenInterpret(vm, module, script);
switch (result) {
case WREN_RESULT_COMPILE_ERROR:
printf("Compile Error!\n");
break;
case WREN_RESULT_RUNTIME_ERROR:
printf("Runtime Error!\n");
break;
case WREN_RESULT_SUCCESS:
break;
}
wrenFreeVM(vm);
free(script);
return 0;
}
- Output:
Sample output:
86.Z=B>)0I R/X,HX=6RE >*12?I-G0+ D*8S-2A.)3 9)+=89UNXW YQN4L8NC4W Character at column 3, row 6 = N 6EQC@=))B/ XWOSZ4/CR@ LU->=2@RW1 ZKFRC9EOT0 Press any key to exit...
XPL0
include c:\cxpl\stdlib;
int C;
[Cursor(3, 6); \move cursor to column 3, row 6 (top left = 0,0)
\Call BIOS interrupt routine to read character (& attribute) at cursor position
C:= CallInt($10, $0800, 0) & $00FF; \mask off attribute, leaving the character
]
- Programming Tasks
- Terminal control
- Action!
- AutoHotkey
- BASIC
- Applesoft BASIC
- BBC BASIC
- FreeBASIC
- Locomotive Basic
- ZX Spectrum Basic
- C
- Win32
- Common Lisp
- Ncurses
- Go
- Julia
- Kotlin
- Ksh
- Nim
- Nim-ncurses
- Perl
- Phix
- PowerShell
- Python
- Racket
- Raku
- REXX
- TXR
- Wren
- XPL0
- ACL2/Omit
- Brlcad/Omit
- GUISS/Omit
- Lilypond/Omit
- Mathematica/Omit
- Openscad/Omit
- Tcl/Omit