Commit graph

16 commits

Author SHA1 Message Date
9a735c6adf Rename delphi/ to ansibbs/ in preparation for another module
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 17:37:00 -06:00
ec6eebb2a5 Add TrueType font support with 4-tier font selection and documentation
Replace the inherited Font property with a FontSize property that drives
a multi-tier font selection strategy for pixel-perfect OEM rendering:
Terminal raster (exact size) > Perfect DOS VGA 437 (multiples of 8px) >
Terminal raster (nearest) > stock OEM fallback.  Add DxBuf uniform
character spacing to ExtTextOut for correct TrueType monospace rendering.
Bundle the Perfect DOS VGA 437 font (cmap converted from format 6 to
format 0 for Win 3.1 compatibility).  Size the test form dynamically
from terminal dimensions.  Add component documentation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 17:15:11 -06:00
d898e73213 Move form sizing to after Show so font metrics are fully realized
Sizing the form in the constructor via HandleNeeded was unreliable --
RecalcCellSize runs again during Show with different font metrics,
shrinking FAnsi while the form keeps its stale size.  Move the
ClientWidth/ClientHeight assignment into Run after Show, when handles
are fully created and RecalcCellSize has settled.  Restore constructor
Width/Height defaults in TKPAnsi for reasonable pre-handle dimensions.
Remove CP437 box-drawing diagnostic from the terminal.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 17:36:53 -06:00
3c5b57c6b5 Size form dynamically from terminal dimensions; fix signed/unsigned mismatch
Expose CellWidth/CellHeight properties on TKPAnsi and remove hardcoded
Width/Height from both the TKPAnsi constructor and TMainForm constructor.
TESTMAIN now computes form size from FAnsi.Width/Height after handle
allocation triggers RecalcCellSize.  Fix bytesRead in reccom() from
int16_t to uint16_t to match avail/chunk types.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 17:30:34 -06:00
fd56c8003d Increase default font size from 9 to 12 for 800x600 displays
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 17:09:57 -06:00
3fc2b410ba Render characters immediately during parsing, not in deferred pass
WriteDeferredBuf now acquires a screen DC and renders each character
run via ExtTextOut as it arrives, eliminating the per-row deferred
dirty scan.  FlushPendingScrolls coalesces scroll-ups into a single
ScrollDC call.  FlipToScreen becomes a lightweight blink/fallback pass.

Removed 50ms render throttle from TESTMAIN -- no longer needed since
characters appear on screen as they are parsed.

Simplified: removed ClearLine (duplicate of AllocLine), DirtyAll,
DirtyRow, GetCursorCol/Row (dead code), FTextBlinkOn (always equal
to FBlinkOn), ParseData (inlined), ETO_CLIPPED (unused), redundant
zero-initializations in constructor.  Write and WriteDeferred now
delegate to WriteDeferredBuf.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 16:18:33 -06:00
8e3bad86e3 Bypass 255-byte string limit and batch plain text runs in parser
Add ReadInputBuf to TKPComm for direct PChar reads up to 2048 bytes,
eliminating short string allocation and 8x fewer ReadComm API calls.
Add ParseDataBuf to TKPAnsi with run batching: scans ahead for printable
text runs, computes colors once per run, fills cells in tight loop
without per-character state/wrap checks.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 17:15:35 -06:00
64b3962c59 Add render throttle to decouple parse throughput from GDI overhead
During bulk serial data flow, renders are capped at ~20fps (50ms interval)
so the ANSI parser can run at full speed without blocking on FlipToScreen.
When idle, renders immediately for interactive responsiveness.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 17:02:01 -06:00
02e01848d6 Batch serial reads before rendering to improve ANSI throughput
Drain all available serial data before calling FlipToScreen so
overlapping screen changes collapse into a single GDI render pass.
Messages are checked between chunks to keep keyboard responsive.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 15:30:51 -06:00
c8ccedf569 Change default FIFO trigger from 8 to 1, yield CPU when idle
Default RX FIFO trigger level of 8 (FCR_TRIG_8) caused exactly 8
characters to buffer in hardware before the ISR fired. Change default
to 1 (FCR_TRIG_1) for responsive single-character interrupts while
keeping the 16-byte FIFO enabled as a safety buffer. COMnRxTRIGGER
SYSTEM.INI key still allows override.

The PM_NOYIELD polling loop never yielded the CPU timeslice, starving
other Windows applications. Add Yield call when no serial data is
flowing so other apps get CPU time. During bulk data flow HasData
stays true and the loop runs at full speed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 20:44:14 -06:00
fbf4ed7c40 Fix input lag: add PM_NOYIELD, skip idle GetDC, eliminate redundant renders
PeekMessage without PM_NOYIELD surrenders the timeslice on every empty
queue check (~55ms per yield in Win16).  Adding pm_NoYield keeps the
polling loop hot so keystrokes and serial echoes are processed without
scheduler delays.

FlipToScreen was calling GetDC/ReleaseDC on every loop iteration even
with zero dirty rows.  Added early-exit scan before acquiring a DC.

TickBlink was calling FlipToScreen redundantly (main loop also calls it).
Removed the FlipToScreen from TickBlink and reordered the main loop to
TickBlink (dirty only) then FlipToScreen (single render pass).

Also: removed FBlinkOn := True reset from ParseData (was dirtying the
cursor row on every incoming chunk), added WriteDeferred for parse-only
without render, moved FlipToScreen from private to public, added Show
call before entering the polling loop.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 19:28:56 -06:00
ec0ec8f074 Replace event-driven WM_COMMNOTIFY architecture with polling main loop
The ISR still fills the ring buffer (mandatory for 115200 baud), but the
app now polls ReadComm directly via a PeekMessage loop instead of waiting
for WM_COMMNOTIFY.  Blink uses GetTickCount instead of WM_TIMER.  This
eliminates all Windows message overhead from the data path while keeping
the message loop alive for keyboard, paint, and scrollbar.

Removed from KPCOMM.PAS: NotifyWndProc, hidden notification window,
RegisterClass/CreateWindow, EnableCommNotification, SetCommEventMask,
DoCommEvent, Process*Notify methods, OnComm/CommEvent/RThreshold/
SThreshold properties, modem shadow state (CTS/DSR/CD).

Removed from KPANSI.PAS: WM_TIMER handler, SetTimer/KillTimer, replaced
with public TickBlink method using GetTickCount at 500ms intervals.

Removed from drv/isr.c: checkNotify function and its call from
isrDispatch.  Removed from drv/commdrv.c: pfnPostMessage, all
rxNotifySent/txNotifySent edge-trigger bookkeeping, gutted
enableNotification to a no-op API-compat stub.  Removed from
drv/commdrv.h: rxNotifySent/txNotifySent fields (shifts struct layout),
PostMessageProcT typedef, pfnPostMessage extern.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 19:01:40 -06:00
acf1a6b691 Remove BeginUpdate/EndUpdate, fix rendering starvation, add variable docs
Remove BeginUpdate/EndUpdate batching from TKPAnsi entirely -- Write now
renders immediately via FlipToScreen after every ParseData call.  Remove
FPendingScroll (caused rendering deadlock: EndUpdate refused to call
FlipToScreen while FPendingScroll > 0, but only FlipToScreen cleared it).
DoScrollUp simplified to set FAllDirty directly.

CommEvent drain loop retained (required by edge-triggered CN_RECEIVE) but
each chunk renders immediately -- no deferred batching.  Edge-triggered
notifications verified starvation-free at all levels: ISR, driver, KPCOMM
dispatch, terminal rendering, and keyboard output path.

Add comprehensive variable comments to all project files: TKPAnsi (44
fields), TKPComm (23 fields), TMainForm (9 fields), PortStateT, and
driver globals.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 18:34:19 -06:00
ca99d1d21b Optimize TKPAnsi rendering with batched TextOut and dirty row tracking
Separate parsing from rendering to eliminate per-character GDI calls.
ProcessChar now only updates cell data in memory; rendering is deferred
to FlipToScreen which batches consecutive same-color cells into single
TextOut calls (~5-10 per row instead of 80). Partial BitBlt transfers
only the dirty row band to the screen. Non-blinking rows render to one
buffer and BitBlt to the second, halving GDI work for typical content.

Also removes redundant GetCommError from KPComm receive path and adds
BeginUpdate/EndUpdate batching in the test app's CommEvent handler.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 21:15:51 -06:00
c3ae983a73 Add TKPAnsi ANSI BBS terminal emulation component for Delphi 1.0
TKPAnsi is a TCustomControl descendant providing a visual ANSI terminal
with 16-color palette, scrollback buffer, blinking cursor, and ANSI music.
Supports CSI sequences (cursor movement, erase, SGR colors/attributes,
insert/delete lines/chars, scroll), DEC private modes (wrap, cursor
visibility), and keyboard translation (arrows, function keys, etc.).

Test app (TESTMAIN.PAS) updated to wire TKPAnsi to TKPComm as a
full terminal: received data feeds the terminal display, keystrokes
are sent out the serial port.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 23:12:23 -06:00
dd8326d16a Add native Delphi 1.0 TKPComm serial communications component
VBX registration is non-functional in VB4 16-bit (VBRegisterModel is a
no-op, VBGetModelInfo never called). Native Delphi component avoids all
DLL/export/registration issues — compiles directly into the IDE.

TKPComm is a TComponent descendant calling the Windows 3.1 comm API
directly. Uses RegisterClass/CreateWindow for WM_COMMNOTIFY dispatch
with the component instance pointer stored in cbWndExtra. Includes a
test application (KPTEST) with send/receive UI built entirely in code.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 22:04:54 -06:00