Files
snark13 858e5755ad ChangeLog:
- big commit.
2026-06-10 10:35:48 +03:00

237 lines
9.1 KiB
C

/*
* conio.h — direct console I/O backed by ESTEX functions.
*
* Two-set output API following the Turbo-C convention:
*
* stdio (fast, no attr — system default colour):
* putchar(c) — one char + '\n' → CR LF translation
* puts(s) — string + trailing newline
* printf(...) — uses putchar internally
*
* conio (slower, applies g_text_attr — set via textcolor / textbackground /
* textattr / set_text_attr):
* putch(c) — one char, NO '\n' translation
* cputs(s) — string, NO trailing newline, NO '\n' translation
* (write "\r\n" yourself for line breaks)
* cprintf(...) — printf with attribute, via vsprintf+cputs internally
*
* The conio set short-circuits to the fast path when
* g_text_attr == KEEP_EXIST_ATTR — useful for "I usually want a
* specific colour but right now don't care".
*
* Other helpers (unchanged):
* kbhit / getch / getche — keyboard
* clrscr / clrscr_attr — clear screen
* gotoxy / wherex / wherey
* wrchar / rdchar — direct VRAM cell access
* get_videotextmode / set_videotextmode (text modes only — see gfx.h
* for graphics mode constants)
*
* Coordinates are 0-based to match ESTEX directly.
*/
#ifndef CONIO_H
#define CONIO_H
#include <stdint.h>
char kbhit (void);
char getch (void);
char getche(void);
/* Extended-key reader. Returns (scan << 8) | ascii. Plain ASCII keys
* have ascii in the low byte; extended keys (arrows / F1..F12 /
* PgUp/PgDn / Home / End / Ins / Del) carry ascii == 0 and the
* KEY_* code in the high byte. */
uint16_t getkey(void);
/* Scan codes returned in the high byte of getkey() when the low byte
* (ASCII) is 0. Empirically verified in MAME — the ProgrammerManual.txt
* "positional code" column is misleading; BIOS returns IBM-style codes
* for the F-keys and a "5N + numpad-position" pattern for the cursor /
* editing keys.
*
* Verified 2026-06-04 by reading raw getkey() output. */
#define KEY_F1 0x3B
#define KEY_F2 0x3C
#define KEY_F3 0x3D
#define KEY_F4 0x3E
#define KEY_F5 0x3F
#define KEY_F6 0x40
#define KEY_F7 0x41
#define KEY_F8 0x42
#define KEY_F9 0x43
#define KEY_F10 0x44
#define KEY_F11 0x45 /* not verified */
#define KEY_F12 0x46 /* not verified */
#define KEY_END 0x51
#define KEY_DOWN 0x52
#define KEY_PGDN 0x53
#define KEY_LEFT 0x54
#define KEY_RIGHT 0x56
#define KEY_HOME 0x57
#define KEY_UP 0x58
#define KEY_PGUP 0x59
#define KEY_INS 0x50 /* numpad 0; not verified */
#define KEY_DEL 0x55 /* numpad 5/.; not verified */
char putch (char c);
char cputs (const char *s);
int cprintf(const char *fmt, ...);
void clrscr(void);
void gotoxy(uint8_t x, uint8_t y);
/* Solid-C compatibility helpers. */
#define home() gotoxy(0, 0)
#define inp(port) z80_inp(port)
#define outp(p, v) z80_outp((p), (v))
#define enable() __asm__("ei")
#define disable() __asm__("di")
uint8_t z80_inp(uint8_t port);
void z80_outp(uint8_t port, uint8_t value);
/* Read a line from the console (no echo control — uses getche).
* `buf[0]` must be the max length; on return `buf[1]` is the actual
* length and `buf[2..]` is the NUL-terminated string. */
char *cgets(char *buf);
/* Cursor query via ESTEX $53 CURSOR. Returns 0-based row/column. */
uint8_t wherex (void);
uint8_t wherey (void);
uint16_t wherexy(void); // high byte = Y, low byte = X coords.
void scroll(uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t);
/* Direct character/attribute screen access (ESTEX $57 / $58).
* wrchar — write char + attribute at (x, y); does NOT advance the cursor
* and does NOT interpret control characters. Useful for
* coloured text and for painting the last-column-last-row cell
* without triggering ESTEX's auto-scroll on PCHARS/PUTCHAR.
* rdchar — read both character and attribute back; returned as
* (attr<<8 | ch). */
void wrchar(uint8_t x, uint8_t y, char ch, uint8_t attr);
uint16_t rdchar(uint8_t x, uint8_t y);
/* clrscr_attr — wipe the entire 80x32 screen using the given attribute
* byte (fill character = space). Companion to clrscr() which uses the
* default attr 0x0F (bright white on black). */
void clrscr_attr(uint8_t attr);
/* Text video-mode control (ESTEX $50 / $51). These constants and helpers
* cover ONLY text modes; graphics modes live in <gfx.h> as GFX_MODE_*.
* `set_videotextmode()` validates that the argument is a known text mode
* (so calling code that includes conio.h alone cannot accidentally switch
* the screen into graphics — that requires <gfx.h>). */
#define TEXT_MODE_40x32 0x02
#define TEXT_MODE_80x32 0x03
uint8_t get_videotextmode(void);
int set_videotextmode(uint8_t mode); /* 0 OK, -1 + errno on bad mode */
/* ------------------------------------------------------------------ *
* Text-output attribute (used by the conio set: putch / cputs / cprintf).
*
* textcolor(c) — set foreground (preserves background+blink)
* textbackground(c) — set background (preserves foreground+blink)
* textattr(a) — replace the whole attribute byte
* set_text_attr(a) — alias to textattr but returns the previous value
* get_text_attr() — read current attribute
*
* Range 0x00..0xFF is a real attribute byte; KEEP_EXIST_ATTR (0xFFFF)
* means "don't touch attributes — fall through to the fast no-attr path"
* (so putch becomes equivalent to putchar etc.).
*
* Default at startup = 0x0F (bright white on black).
*
* NOTE: stdio's putchar / puts / printf IGNORE this — they always use
* whatever ESTEX has cached for the cursor cell. Use the conio set
* (putch / cputs / cprintf) for coloured output.
* ------------------------------------------------------------------ */
#define KEEP_EXIST_ATTR 0xFFFF
void textcolor(uint8_t fg);
void textbackground(uint8_t bg);
void textattr(uint8_t attr);
int16_t set_text_attr(int16_t attr); /* returns the previous value */
int16_t get_text_attr(void);
/* Control how putch / cputs / cprintf (the WRCHAR path) treat
* control characters (< 0x20):
*
* mode = 0 (default) — interpret BS/TAB/LF/CR:
* 0x08 BS → pc_col-- (clamped at 0)
* 0x09 TAB → pc_col rounded up to next multiple of 8 (clamped 80)
* 0x0A LF → pc_row++ (clamped at 32; no glyph emitted)
* 0x0D CR → pc_col = 0
*
* mode = 1 — print EVERY character as a CP437 glyph (no
* interpretation; useful e.g. for drawing box-drawing
* characters that overlap the 0x00..0x1F range).
*
* Only affects the WRCHAR path (attr ≤ 0xFF). When attr is
* KEEP_EXIST_ATTR, ESTEX's own PUTCHAR/PCHARS rule the cursor and
* pc_raw_mode is irrelevant. */
void set_putch_raw_mode(uint8_t mode);
uint8_t get_putch_raw_mode(void);
/* Sprinter text-mode 03h attribute byte (verified via attr_probe):
* bits 0..3 = foreground (0..15)
* bits 4..6 = background (0..7)
* bit 7 = blink (toggles fg between fg-colour and bg-colour)
* Colour order is standard CGA / Borland-conio.h. Constants 0..7 are
* usable for both fg and bg; 8..15 are foreground-only. */
enum {
COLOR_BLACK = 0,
COLOR_BLUE,
COLOR_GREEN,
COLOR_CYAN,
COLOR_RED,
COLOR_MAGENTA,
COLOR_BROWN,
COLOR_LIGHTGRAY,
COLOR_DARKGRAY,
COLOR_LIGHTBLUE,
COLOR_LIGHTGREEN,
COLOR_LIGHTCYAN,
COLOR_LIGHTRED,
COLOR_LIGHTMAGENTA,
COLOR_YELLOW,
COLOR_WHITE
};
#define COLOR_BLINK 0x80u
#define COLOR(fg, bg) ((uint8_t)((((bg) & 0x07) << 4) | ((fg) & 0x0F)))
/* Text-mode palette. The 16 logical CGA colours seen by COLOR(fg, bg)
* actually live in four 256-entry hardware palette planes indexed by the
* full 8-bit attribute byte:
*
* TEXT_PAL_PAPER — background colour, non-blink phase
* TEXT_PAL_INK — foreground colour, non-blink phase
* TEXT_PAL_BLINK_PAPER — background colour during the blink half-cycle
* TEXT_PAL_BLINK_INK — foreground colour during the blink half-cycle
*
* For non-blinking attributes (bit 7 = 0) all four planes display the
* same colours, so writing to PAPER/INK is enough. For blinking attrs
* (bit 7 = 1) the renderer alternates between the non-blink and blink
* planes — that's how flash is implemented in hardware.
*
* These wrappers add 4 to the plane index and forward to the low-level
* <palette.h> API (pal_load / pal_set_color / pal_get / pal_get_color).
* Use text_pal_reset() to restore the system default CGA palette. */
#define TEXT_PAL_PAPER 0
#define TEXT_PAL_INK 1
#define TEXT_PAL_BLINK_PAPER 2
#define TEXT_PAL_BLINK_INK 3
void text_pal_load (uint8_t plane, uint8_t start, uint8_t count,
const uint8_t *bgr0);
void text_pal_set_color(uint8_t plane, uint8_t attr,
uint8_t r, uint8_t g, uint8_t b);
void text_pal_get (uint8_t plane, uint8_t start, uint8_t count,
uint8_t *bgr0);
void text_pal_get_color(uint8_t plane, uint8_t attr,
uint8_t *r, uint8_t *g, uint8_t *b);
void text_pal_reset (void);
#endif