Cursor key mouse emulation on the Human68k platform

The Sharp X68000 sits at a strange crossroads in retrocomputing: powerful enough that its software often assumed a mouse as standard equipment, yet old enough that three decades of storage have eaten plenty of those mice. For hobbyists who have booted up a tidy CZ-600C only to discover a balky trackball or a frayed cable, the temptation is to reach for spares. In Australia, that means navigating customs paperwork, paying the goods and services tax on top of inflated postage from Osaka, and crossing fingers that the replacement is not a yellowed unit fresh out of a deceased estate in Sapporo. A software workaround, in the form of a Human68k program that emulates a mouse using the keyboard's cursor keys, sidesteps the entire logistical headache.

The technique is not new in spirit. Keyboard mouse emulation has appeared on DOS, the Amiga, and various UNIX workstations over the years. What makes the X68000 interesting is that Human68k exposes a relatively clean IOCS layer for both keyboard and mouse, with a shared buffer region that a small assembly routine can manipulate without disturbing running applications. A resident program can sit quietly in the background, translate cursor key presses into coordinate deltas, and feed those deltas back through the official mouse vector.

This article walks through one practical implementation, from reading the cursor key state through to injecting synthetic events into the system's mouse buffer. The example code is written for readability rather than absolute minimum size, and the structure should adapt to whatever monitor mode or application stack you happen to be running on machines as varied as the ACE in Brisbane or the original XVI in Perth.

Why keyboard mouse emulation still matters

The X68000 shipped with mouse hardware as a de facto expectation, and the operating system was tuned for it. Pointer-driven tools like the bundled graphics editors, and most of the MIDI sequencers that took advantage of the machine's audio capabilities, would simply refuse to be ergonomic without a working pointing device. Even some early games, particularly the simulation titles from System Sacom and Arsys, assumed the player had both hands free for cursor control and command keys.

For an Australian enthusiast in 2026, the spare-parts equation rarely favours hardware repair. A genuine Sharp mouse from a domestic seller in Sydney or Melbourne typically starts around one hundred and twenty Australian dollars once shipping is included, and untested units from Japanese Yahoo Auctions can climb higher once currency conversion, GST at the border, and the Australian Border Force's biosecurity inspection fees are tallied. A keyboard-based workaround costs nothing but an afternoon of coding.

There is also a documentation angle. Writing the emulation forces the developer to understand exactly how Human68k treats input, which is valuable knowledge when chasing more obscure bugs in older software. The same routines that fake a mouse can be repurposed to test whether a flaky genuine mouse is producing jitter from a worn encoder, or to verify that a freshly recapped power supply is not introducing electrical noise through the serial port.

Human68k's input architecture

Human68k exposes input through a family of IOCS calls. Keyboard input flows through routines such as KEYSNS (sense key state without consuming it) and KEYINP (read and consume), each of which returns status information for every key on the matrix. Mouse input is handled by parallel routines like MS_INIT, MS_CURON, and the coordinate read pair that returns current X and Y positions relative to the screen origin.

Underneath the IOCS layer sits a small block of memory in the zero page region that both subsystems share. The keyboard state is mirrored as a bitfield, and the mouse state is stored as a pair of 16-bit signed deltas plus a button mask. When an application requests the current mouse position, IOCS reads those deltas, adds them to a persistent position, and returns the result. When an application requests key state, IOCS reads the bitfield directly.

Understanding this shared layer is what makes emulation tractable. A program can read the cursor key bits, compute a delta based on how long a key has been held, and write that delta into the mouse region. As far as most software is concerned, the mouse hardware has simply produced another packet of movement. There is no need to patch the IOCS vectors or replace any system calls.

Reading cursor keys without stealing them

The X68000 keyboard matrix assigns distinct scan codes to the four cursor keys, and IOCS exposes them through the standard keyboard sense call. The challenge is that the calling program often also wants to see those keys for menu navigation or arrow-key scrolling, so a naive emulation that simply consumes the cursor keys will break the foreground application.

A practical approach is to use the sense call, which does not advance the internal pointer, and to peek at the cursor key bits only. If a cursor key is pressed, the emulation routine synthesises a mouse delta and does not touch the rest of the keyboard state. If no cursor key is active, the routine returns immediately so the foreground application sees an unmodified IOCS result.

Some titles make this difficult by polling keys directly from the zero page buffer rather than through IOCS. For those, the resident program can install a small exception handler or use the unused vector slot to filter cursor keys before they reach the application. This is more invasive but rarely necessary, since most Human68k software behaves correctly when the IOCS layer is left alone.

Translating key state into mouse movement

Once the routine knows that, for example, the right cursor key is held, it must decide how much to move the pointer per polling tick. A linear mapping of one pixel per tick feels sluggish on a 768 by 512 display, while a flat hundred-pixel step makes fine selection impossible. The standard compromise is an acceleration curve: slow movement for the first half-second, then progressively faster movement until the key is released.

Empirically, a curve that starts at two pixels per tick and ramps to sixteen pixels per tick after about thirty ticks feels natural across most X68000 software. Adding a Shift modifier to halve the speed gives precise control for pixel-level work in graphics editors, while a faster ramp triggered by holding a second key benefits large monitors used in hobby setups from Canberra through to Hobart.

Edge wrapping is a small but important detail. If the synthetic delta pushes the pointer past the screen boundary, the position must be clamped rather than allowed to overflow, otherwise some applications will silently scroll their internal canvas by an unexpected amount. Clamping at zero and at the screen maximum, then returning early when the position would not actually change, prevents wasted ticks.

Injecting events through the mouse buffer

With a delta in hand, the emulation routine must make Human68k believe the mouse hardware produced it. The mouse region in zero page holds two 16-bit values for horizontal and vertical motion since the last read, plus a byte of button state. Writing the computed delta into those locations, followed by an update to a sequence counter, is enough for most IOCS-level consumers.

A few applications poll the mouse hardware port directly through the MFP chip, bypassing IOCS entirely. Those will not see synthetic events no matter how cleanly the buffer is updated. For such software, the only options are a real mouse, a hardware intercept using something like a Pico-based adaptor, or accepting that the program will not work under emulation. The vast majority of Human68k productivity and entertainment software, fortunately, uses IOCS.

The resident program itself is small. A few hundred bytes of M68k assembly is enough to handle reading, translating, and writing. Linking the routine against the standard Human68k startup stubs and using the KEEP directive leaves it resident after exit, ready to be loaded from CONFIG.SYS or invoked manually at the command prompt.

Tuning, testing, and Australian practicalities

A finished emulator is only useful if it behaves well across the software you actually run. Testing on a variety of titles, from the bundled benchmarks through to commercial games, reveals edge cases that pure code review will not. Worth checking: applications that swap into high-resolution modes where the mouse coordinate space changes, programs that disable cursor keys for their own shortcut schemes, and the occasional title that reads the mouse buffer between every scanline and notices the synthetic delta arriving one tick late.

For Australian hobbyists, the practical environment matters. Summer heat in Adelaide can push workshop temperatures past forty degrees, and vintage 68000 silicon does not enjoy that. Running the machine with adequate ventilation, ideally in a shed or garage with a ceiling fan rather than in direct sun through a north-facing window, keeps both the original hardware and the developer's concentration intact. Power quality is generally reliable in urban centres, but rural properties in Queensland or Western Australia may need a small UPS to ride out the brief dropouts that can corrupt the mouse buffer mid-write.

Distribution is straightforward. The compiled binary, a short text manual, and a CONFIG.SYS snippet fit comfortably on a single 1.2MB floppy. Hosting the package on a community site such as the X68K links page makes it accessible to other enthusiasts who may be wrestling with the same flaky mouse hardware.

Approach Memory footprint Compatibility Skill required Hardware cost
Pure IOCS TSR Under 1 KB High for IOCS apps, low for direct MFP readers Intermediate assembly None
Interrupt-driven resident Around 2 KB High, lower latency Advanced assembly None
Application wrapper script Varies Only the wrapped app Basic scripting None
Hardware intercept (Pico) External Near universal Electronics and firmware Around forty AUD
Replacement mouse purchase None Universal None One hundred plus AUD plus shipping

Try building the routine from scratch on your own machine, then experiment with the acceleration curve until the feel matches what you remember from a genuine pointing device. Share your finished binary and any patches back through the community, and consider documenting any unusual applications that needed extra handling. A working keyboard mouse emulator, even a rough one, makes the X68000 more accessible to the next wave of Australian hobbyists who are still discovering what the platform can do.

Nereid-X Expansion Board

A personally-produced LAN+USB+Memory expansion board for Sharp X68000 series computers. Multiple production runs were offered, including a final batch and a later revival reproduction run.

Power Supply Repair

X68 power supply repair and modification services were offered by the site owner, with documentation shared through diary entries spanning 2001–2006.

Server & Networking

Notes on FreeBSD administration, ISP changes, server migration, and networking topics. The site itself ran on FreeBSD with the hns diary system and Namazu search integration.

A two-ink risograph print in muted slate-blue and charcoal on off-white paper, showing a stylized desktop computer monitor beside a circuit board with soft geometric trace lines, conveying a calm retro-computing workshop atmosphere. A two-ink risograph print in deep purple and dark grey on cream stock, depicting a compact expansion card with connector ports and subtle Japanese technical annotations, evoking a hobbyist electronics bench. A two-ink risograph print in teal and charcoal on warm white paper, showing a server rack silhouette with soft network-line motifs and a small weather icon, suggesting a personal server room corner.

Get in touch

X68K.NET connects Sharp X68000 enthusiasts through community links and shared projects. Reach out with questions about the Nereid project or X68 resources.