/* * gfx_mouse_test — exercises the graphics-mode mouse cursor API: * $09 LOAD CURSOR — install a custom cursor bitmap * $81 CHANGE VIDEO MODE — let the driver re-sync after switching modes * $0B RETURN CURSOR — read the cursor back (may be a stub in MAME) * * Flow: * 1. Init the mouse driver in text mode. * 2. Switch to 320x256x256, notify the driver. * 3. Build an 8x8 cursor — solid white border + transparent middle — * and load it. Show it. Move the mouse to verify it tracks. * 4. Press a key: query the driver's view of the cursor and dump the * result so we can compare against what we loaded. * 5. Hide cursor, return to text mode, print the round-trip dump. * * The driver's bitmap format is undocumented — best guess is one byte * per pixel (palette index, with 0 meaning transparent). We load 0xFF * for opaque cells and 0 for transparent so the cursor stands out * against any background. */ #include #include #include #include #include #define CURSOR_W 12 #define CURSOR_H 12 #define CURSOR_BUF_BYTES (CURSOR_W * CURSOR_H) /* Cursor format (verified empirically 2026-05-31): * ONE BYTE per pixel — row-major, width*height bytes total. * 0xFF = transparent (background shows through) * any other byte = palette index (drawn opaque) * * Cursor bitmap lives in a dedicated video bank, not the 0x50 page used * by gfx_clear256 / gfx_putpixel256 — that's why 0xFF reads as transparent * even though in the main visible page 0xFF is a regular colour. */ static uint8_t cursor_bitmap[CURSOR_BUF_BYTES]; static uint8_t roundtrip_buf[CURSOR_BUF_BYTES]; static uint8_t palette[256 * 4]; /* Arrow shape, 1 byte per pixel. Each cell is either: * _ transparent (0xFF, lets the background through) * O black solid pixel (0x00) * W white solid pixel (0xFF would mean transparent, so use 0xFF * palette entry by hand if you want a white pixel — for the * default greyscale palette in this demo, W = bright grey 0xE0) * * Feel free to edit the 12×12 grid below to draw a nicer cursor. */ #define _ 0xFF #define O 0x00 #define W 0xE0 static const uint8_t cursor_arrow[CURSOR_BUF_BYTES] = { O,_,_,_,_,_,_,_,_,_,_,_, O,O,_,_,_,_,_,_,_,_,_,_, O,W,O,_,_,_,_,_,_,_,_,_, O,W,W,O,_,_,_,_,_,_,_,_, O,W,W,W,O,_,_,_,_,_,_,_, O,W,W,W,W,O,_,_,_,_,_,_, O,W,W,W,W,W,O,_,_,_,_,_, O,W,W,W,O,O,O,O,_,_,_,_, O,O,O,W,O,_,_,_,_,_,_,_, O,_,_,O,W,O,_,_,_,_,_,_, _,_,_,O,W,O,_,_,_,_,_,_, _,_,_,_,O,O,_,_,_,_,_,_, }; #undef _ #undef O #undef W static void make_palette(void) { for (int i = 0; i < 256; i++) { palette[i*4+0] = (uint8_t)i; palette[i*4+1] = (uint8_t)i; palette[i*4+2] = (uint8_t)i; palette[i*4+3] = 0; } } /* Copy the arrow pattern into our scratch (one place for the driver * to point IX at). */ static void build_cursor(void) { for (int i = 0; i < CURSOR_BUF_BYTES; i++) cursor_bitmap[i] = cursor_arrow[i]; } static void wait_key(void) { while (!kbhit()) { /* spin */ } (void)getch(); } int main(void) { textattr(COLOR(COLOR_LIGHTGRAY, COLOR_BLACK)); clrscr(); cputs("gfx_mouse_test\r\n"); if (mouse_init() < 0) { cputs("mouse_init failed - no driver\r\n"); return 1; } mouse_set_sensitivity(2, 2); /* --- enter graphics, load custom cursor, then show -------------- */ make_palette(); build_cursor(); uint8_t prev = gfx_init(GFX_MODE_320x256x256, 0); gfx_pal_load(0, 0, 0, palette); gfx_clear256(0x40); /* dim grey background */ /* Coordinate grid every 32 px so the cursor position reads easily. */ for (int x = 0; x < GFX_WIDTH; x += 32) gfx_vline256(x, 0, GFX_HEIGHT, 0x80); for (int y = 0; y < GFX_HEIGHT; y += 32) gfx_hline256(0, y, GFX_WIDTH, 0x80); mouse_video_mode_changed(GFX_MODE_320x256x256); mouse_bounds_x(0, GFX_WIDTH - 1); mouse_bounds_y(0, GFX_HEIGHT - 1); mouse_cursor_t custom = { .image = cursor_bitmap, .width = CURSOR_W, .height = CURSOR_H, .hot_x = 0, .hot_y = 0, }; mouse_load_cursor(&custom); mouse_show(); wait_key(); /* --- query driver to see what it has now ------------------------ */ mouse_cursor_t readback = { .image = roundtrip_buf, .width = 0, .height = 0, .hot_x = 0, .hot_y = 0, }; mouse_get_cursor(&readback); mouse_hide(); gfx_done(prev); mouse_video_mode_changed(prev); /* tell driver we're back */ /* --- back in text mode: report what the driver returned --------- */ textattr(COLOR(COLOR_LIGHTGRAY, COLOR_BLACK)); clrscr(); cprintf("loaded : %ux%u hot (%u,%u)\r\n", CURSOR_W, CURSOR_H, 0, 0); cprintf("read back: %ux%u hot (%u,%u)\r\n", readback.width, readback.height, readback.hot_x, readback.hot_y); uint16_t n = (uint16_t)readback.width * (uint16_t)readback.height; if (n > CURSOR_BUF_BYTES) n = CURSOR_BUF_BYTES; cprintf("bitmap (%u bytes):\r\n", n); for (uint16_t i = 0; i < n; i++) { cprintf("%02X ", roundtrip_buf[i]); if ((i % readback.width) == readback.width - 1) cputs("\r\n"); } cputs("\r\n"); cputs("press any key to exit"); wait_key(); return 0; }