0326-Chip8-实现键盘按键

环境

  • Time 2023-07-27
  • Zig 0.11.0-dev.4191+1bf16b172
  • SLD2 2.28.1

前言

说明

参考资料:

  1. https://en.wikipedia.org/wiki/CHIP-8
  2. https://austinmorlan.com/posts/chip8_emulator/
  3. https://rsj217.github.io/chip8-py/
  4. https://github.com/Timendus/chip8-test-suite

其中最后一个提供了测试的套件,实现的过程中,可以检测哪些指令有问题,帮助很大。

目标

实现按键功能,其中涉及到指令 EX9E、EXA1、FX0A。

keypad.zig

Chip8 只支持 16 个按键,分别是 0x0 到 0xF,可以根据自己的喜好设置映射。

const c = @cImport(@cInclude("SDL.h"));
const std = @import("std");

pub const Keypad = struct {
    buffer: [16]bool = std.mem.zeroes([16]bool),
    event: c.SDL_Event = undefined,

    pub fn poll(self: *Keypad) bool {
        while (c.SDL_PollEvent(&self.event) > 0) {
            if (self.event.type == c.SDL_QUIT) return false;

            const flag = if (self.event.type == c.SDL_KEYDOWN) true //
            else if (self.event.type == c.SDL_KEYUP) false //
            else continue;
            self.setBuffer(self.event.key.keysym.sym, flag);
        }
        return true;
    }

    fn setBuffer(self: *Keypad, code: i32, value: bool) void {
        switch (code) {
            c.SDLK_x => self.buffer[0] = value,
            c.SDLK_1 => self.buffer[1] = value,
            c.SDLK_2 => self.buffer[2] = value,
            c.SDLK_3 => self.buffer[3] = value,
            c.SDLK_q => self.buffer[4] = value,
            c.SDLK_w => self.buffer[5] = value,
            c.SDLK_e => self.buffer[6] = value,
            c.SDLK_a => self.buffer[7] = value,
            c.SDLK_s => self.buffer[8] = value,
            c.SDLK_d => self.buffer[9] = value,
            c.SDLK_z => self.buffer[10] = value,
            c.SDLK_c => self.buffer[11] = value,
            c.SDLK_4 => self.buffer[12] = value,
            c.SDLK_r => self.buffer[13] = value,
            c.SDLK_f => self.buffer[14] = value,
            c.SDLK_v => self.buffer[15] = value,
            else => return,
        }
    }
};

memory.zig

其它无关代码已省略,新增检查某个按键是否按下和哪个键被按下的方法。

pub fn isPress(self: *Memory, index: usize) bool {
    return self.keypad.buffer[index];
}

pub fn getPress(self: *Memory) ?u8 {
    for (self.keypad.buffer, 0..) |code, index| {
        if (code) return @truncate(index);
    }
    return null;
}

0xE

    0xE => {
        const isPress = memory.isPress(reg[ins.x]);
        if (ins.nn == 0x9E and isPress) self.next();
        if (ins.nn == 0xA1 and !isPress) self.next();
    },

0x0A

codef中的新增检查 0x0A的分支。

        0x0A => if (memory.getPress()) |index| {
            self.register[ins.x] = index;
        } else self.back(),

    fn back(self: *CPU) void {
        self.pc -= 2;
    }

main.zig

const std = @import("std");
const chip8 = @import("chip8.zig");

pub fn main() !void {
    // const rom = @embedFile("roms/1-chip8-logo.ch8");
    // const rom = @embedFile("roms/2-ibm-logo.ch8");
    // const rom = @embedFile("roms/3-corax+.ch8");
    // const rom = @embedFile("roms/4-flags.ch8");
    // const rom = @embedFile("roms/5-quirks.ch8");
    const rom = @embedFile("roms/6-keypad.ch8");
    var emulator = chip8.Emulator.new(rom);
    emulator.run();
}

启动

zig build run

效果

窗口

总结

实现了键盘按键的功能,测试时,需要将输入法调整成英文,不然只有数字生效,字母不生效。

附录

posted @ 2025-12-04 10:06  jiangbo4444  阅读(4)  评论(0)    收藏  举报