Files
Sprinter-SDCC/libc/include/conio.h
T
snark13 484b18d10c libc+libbgi: raw-клавиатура (held-state) + column-major блит спрайтов
libc/kbd: kbd_raw_open/close/down — сырой PS/2-канал клавиатуры с
held-state (битовая карта _kbdraw_down[512], EXT-клавиши +256).  Пока
raw открыт, кадровый IRQ-трамплин перехватывает байт SIO у DSS и
декодирует make/break (0xF0/0xE0-префиксы) сам.  FIFO вычерпывается В
ЦИКЛЕ (приёмный буфер SIO 3 байта; пачка break-кодов при одновременном
отпускании иначе теряется → залипание клавиши).  Буфер W2-трамплина
поднят 224→288 Б под выросший обработчик.

libc/conio: kbd_mod_state() — live-состояние модификаторов (ESTEX
CTRLKEY $33h), Shift/Ctrl/Alt/Lock прямо сейчас, KBD_MOD_* маска.

libbgi: gfx_blit_cols(x,y,img,flip) + _bgi_blit_cols_raw — блит
column-major спрайта вертикальным accel-проходом, бесплатный
горизонтальный флип (sstride<0), клип по экрану.  Для персонажей.

libbgi/atlas_load: восстанавливать W3 ДО записи a->count (atlas_t в
--bank памяти резолвится через W3; count оставался мусором).

tests/kbdraw — тест raw-клавиатуры; size-baseline +kbdraw.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 17:48:32 +03:00

283 lines
11 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* 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 */
/* kbd_mod_state — live-состояние модификаторов ПРЯМО СЕЙЧАС (ESTEX
* CTRLKEY $33h), а не событие из буфера: держится столько, сколько
* клавиша реально зажата (в отличие от kbhit/getch/getkey). Покрывает
* ТОЛЬКО Shift/Ctrl/Alt/Rus-Lat/Lock-клавиши — обычные клавиши
* (стрелки и т.п.) у ESTEX live-state не имеют, см. <kbd_raw.h>.
*
* Возврат: (mode << 8) | shift — расшифровка через KBD_MOD_* ниже. */
uint16_t kbd_mod_state(void);
#define KBD_MOD_RUSLAT 0x8000
#define KBD_MOD_NUMLOCK 0x0800
#define KBD_MOD_SCRLOCK 0x0400
#define KBD_MOD_INSERT 0x0200
#define KBD_MOD_CAPSLOCK 0x0100
#define KBD_MOD_LSHIFT 0x0080
#define KBD_MOD_RSHIFT 0x0040
#define KBD_MOD_CTRL 0x0020
#define KBD_MOD_ALT 0x0010
#define KBD_MOD_LCTRL 0x0008
#define KBD_MOD_LALT 0x0004
#define KBD_MOD_RCTRL 0x0002
#define KBD_MOD_RALT 0x0001
typedef union {
uint16_t value;
struct {
uint8_t low;
uint8_t high;
} byte;
} two_bytes;
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 gettextmode(void);
int settextmode(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
/* Внутреннее состояние (хранилище: libc/conio/_g_text_attr.c и
* _pc_raw_mode.c) — НЕ трогать напрямую, только через функции ниже.
* Объявлено здесь, чтобы ТОНКИЕ аксессоры были inline: чистый C99
* `inline` БЕЗ static — SDCC инлайнит вызов и не эмитит standalone-
* тело (см. memory/sdcc_inline_codegen_findings). «Толстые» (RMW-
* маски textcolor/textbackground, set_text_attr с возвратом прежнего)
* НЕ inline — замерено: тело 12+ байт при 2+ сайтах вызова крупнее
* call+общее тело (conio2 +13 Б). */
extern two_bytes g_text_attr;
extern uint8_t pc_raw_mode;
void textcolor(uint8_t fg);
void textbackground(uint8_t bg);
inline void textattr(uint8_t attr) { g_text_attr.value = (uint16_t)attr; }
int16_t set_text_attr(int16_t attr); /* возвращает прежнее значение */
inline int16_t get_text_attr(void) { return g_text_attr.value; }
/* 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. */
inline void set_putch_raw_mode(uint8_t mode) { pc_raw_mode = mode; }
inline uint8_t get_putch_raw_mode(void) { return pc_raw_mode; }
/* 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