jsbeeb 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.editorconfig +15 -0
- package/.git-blame-ignore-revs +3 -0
- package/.github/copilot-instructions.md +94 -0
- package/.github/workflows/claude-issue-triage.yml +105 -0
- package/.github/workflows/claude.yml +63 -0
- package/.github/workflows/release-please.yml +75 -0
- package/.github/workflows/test-and-deploy.yml +86 -0
- package/.gitmodules +6 -0
- package/.husky/pre-commit +1 -0
- package/.idea/codeStyleSettings.xml +9 -0
- package/.idea/codeStyles/Project.xml +62 -0
- package/.idea/codeStyles/codeStyleConfig.xml +5 -0
- package/.idea/compiler.xml +22 -0
- package/.idea/copyright/profiles_settings.xml +3 -0
- package/.idea/encodings.xml +6 -0
- package/.idea/inspectionProfiles/Project_Default.xml +7 -0
- package/.idea/jsLibraryMappings.xml +6 -0
- package/.idea/jsLinters/jshint.xml +85 -0
- package/.idea/jsLinters/jslint.xml +15 -0
- package/.idea/jsbeeb.iml +11 -0
- package/.idea/misc.xml +6 -0
- package/.idea/modules.xml +8 -0
- package/.idea/prettier.xml +7 -0
- package/.idea/runConfigurations/Debug.xml +5 -0
- package/.idea/scopes/scope_settings.xml +5 -0
- package/.idea/vcs.xml +8 -0
- package/.prettierignore +4 -0
- package/.prettierrc.json +1 -0
- package/.release-please-manifest.json +3 -0
- package/.vscode/launch.json +14 -0
- package/.vscode/settings.json +6 -0
- package/CHANGELOG.md +32 -0
- package/CLAUDE.md +136 -0
- package/COPYING +674 -0
- package/Dockerfile +22 -0
- package/Makefile +30 -0
- package/README.md +259 -0
- package/docker/nginx-default.conf +10 -0
- package/docs/pal-comb-filter-research.md +129 -0
- package/docs/pal-simulation-design.md +368 -0
- package/eslint.config.js +35 -0
- package/index.html +954 -0
- package/jsconfig.json +10 -0
- package/package.json +102 -0
- package/public/discs/README.Irq-Timing +3 -0
- package/public/discs/README.bcdtest +5 -0
- package/public/discs/README.elite +6 -0
- package/public/discs/README.eng_test +3 -0
- package/public/discs/README.protection +7 -0
- package/public/favicon.ico +0 -0
- package/public/images/botbar.png +0 -0
- package/public/images/cub-monitor.png +0 -0
- package/public/images/jsbeeb-example.png +0 -0
- package/public/images/placeholder.png +0 -0
- package/public/images/red-off-16.png +0 -0
- package/public/images/red-on-16.png +0 -0
- package/public/images/sb/CD-left.jpg +0 -0
- package/public/images/sb/CD-right.jpg +0 -0
- package/public/images/sidebar.png +0 -0
- package/public/images/tv.png +0 -0
- package/public/images/yellow-off-16.png +0 -0
- package/public/images/yellow-on-16.png +0 -0
- package/public/jsbeeb-icon.png +0 -0
- package/public/robots.txt +3 -0
- package/public/roms/ADFS1-53.rom +0 -0
- package/public/roms/BASIC.ROM +0 -0
- package/public/roms/README +4 -0
- package/public/roms/a01/BASIC1.rom +0 -0
- package/public/roms/ample.rom +0 -0
- package/public/roms/ats-3.0.rom +0 -0
- package/public/roms/b/DFS-0.9.rom +0 -0
- package/public/roms/b/DFS-1.2.rom +0 -0
- package/public/roms/b1770/dfs1770.rom +0 -0
- package/public/roms/b1770/zADFS.ROM +0 -0
- package/public/roms/bp/dfs.rom +0 -0
- package/public/roms/bp/zADFS.ROM +0 -0
- package/public/roms/bpos.rom +0 -0
- package/public/roms/compact/adfs210.rom +0 -0
- package/public/roms/compact/basic48.rom +0 -0
- package/public/roms/compact/basic486.rom +0 -0
- package/public/roms/compact/os51.rom +0 -0
- package/public/roms/compact/utils.rom +0 -0
- package/public/roms/deos.rom +0 -0
- package/public/roms/master/anfs-4.25.rom +0 -0
- package/public/roms/master/mos.txt +68819 -0
- package/public/roms/master/mos3.20 +0 -0
- package/public/roms/os.rom +0 -0
- package/public/roms/os01.rom +0 -0
- package/public/roms/tube/6502Tube.rom +0 -0
- package/public/roms/tube/ARMeval_100.rom +0 -0
- package/public/roms/tube/BIOS.ROM +0 -0
- package/public/roms/tube/ReCo6502ROM_816 +0 -0
- package/public/roms/tube/Z80_120.rom +0 -0
- package/public/roms/us/USBASIC.rom +0 -0
- package/public/roms/us/USDNFS.rom +0 -0
- package/public/roms/usmos.rom +0 -0
- package/public/sounds/disc525/motor.wav +0 -0
- package/public/sounds/disc525/motoroff.wav +0 -0
- package/public/sounds/disc525/motoron.wav +0 -0
- package/public/sounds/disc525/seek.wav +0 -0
- package/public/sounds/disc525/seek2.wav +0 -0
- package/public/sounds/disc525/seek3.wav +0 -0
- package/public/sounds/disc525/step.wav +0 -0
- package/public/teletext/txt0.dat +0 -0
- package/public/teletext/txt1.dat +0 -0
- package/public/teletext/txt2.dat +0 -0
- package/public/teletext/txt3.dat +0 -0
- package/release-please-config.json +13 -0
- package/run-container.sh +92 -0
- package/src/6502.js +1347 -0
- package/src/6502.opcodes.js +1411 -0
- package/src/acia.js +261 -0
- package/src/adc.js +149 -0
- package/src/analogue-source.js +21 -0
- package/src/app/app.js +175 -0
- package/src/app/electron.js +20 -0
- package/src/app/preload.js +8 -0
- package/src/app-bench.js +33 -0
- package/src/basic/multiline-tetris +9 -0
- package/src/basic-tokenise.js +104 -0
- package/src/canvas.js +177 -0
- package/src/cmos.js +141 -0
- package/src/config.js +165 -0
- package/src/ddnoise.js +138 -0
- package/src/disc-drive.js +371 -0
- package/src/disc-hfe.js +396 -0
- package/src/disc.js +997 -0
- package/src/econet/L3FS.dat +0 -0
- package/src/econet/scsi.dat +0 -0
- package/src/econet.js +714 -0
- package/src/fake6502.js +32 -0
- package/src/fdc.js +248 -0
- package/src/filestore.js +666 -0
- package/src/gamepad-source.js +59 -0
- package/src/gamepads.js +268 -0
- package/src/google-drive.js +160 -0
- package/src/intel-fdc.js +1717 -0
- package/src/jsbeeb.css +363 -0
- package/src/keyboard.js +411 -0
- package/src/lib/README +1 -0
- package/src/lib/webgl-debug.js +911 -0
- package/src/main.js +1759 -0
- package/src/microphone-input.js +149 -0
- package/src/models.js +200 -0
- package/src/mouse-joystick-source.js +107 -0
- package/src/music5000-worklet.js +43 -0
- package/src/music5000.js +207 -0
- package/src/scheduler.js +148 -0
- package/src/serial.js +31 -0
- package/src/soundchip.js +314 -0
- package/src/sth.js +59 -0
- package/src/tapes.js +265 -0
- package/src/teletext.js +348 -0
- package/src/teletext_adaptor.js +172 -0
- package/src/teletext_data.js +1064 -0
- package/src/touchscreen.js +86 -0
- package/src/tube.js +349 -0
- package/src/url-params.js +256 -0
- package/src/utils.js +1090 -0
- package/src/via.js +702 -0
- package/src/video-filters/pal-composite.js +94 -0
- package/src/video-filters/passthrough-filter.js +70 -0
- package/src/video-filters/shaders/pal-composite.frag.glsl +147 -0
- package/src/video-filters/shaders/pal-composite.vert.glsl +8 -0
- package/src/video-filters/shaders/passthrough.frag.glsl +6 -0
- package/src/video-filters/shaders/passthrough.vert.glsl +7 -0
- package/src/video.js +794 -0
- package/src/wd-fdc.js +1344 -0
- package/src/web/audio-handler.js +146 -0
- package/src/web/audio-renderer.js +115 -0
- package/src/web/debug.js +529 -0
- package/tests/integration/RmwX.asm +47 -0
- package/tests/integration/TestInstructionsSource +27 -0
- package/tests/integration/TestTimingsResults +27 -0
- package/tests/integration/TestTimingsSource +61 -0
- package/tests/integration/bcd.js +23 -0
- package/tests/integration/dormann.js +101 -0
- package/tests/integration/dp111timing.js +42 -0
- package/tests/integration/ensure-submodules.js +25 -0
- package/tests/integration/nops.bas +119 -0
- package/tests/integration/nops.js +24 -0
- package/tests/integration/protection.js +26 -0
- package/tests/integration/rmw.js +69 -0
- package/tests/integration/teletext/expected_bug_469.png +0 -0
- package/tests/integration/teletext/expected_flash_0.png +0 -0
- package/tests/integration/teletext/expected_flash_1.png +0 -0
- package/tests/integration/teletext/expected_hoglet_held_char.png +0 -0
- package/tests/integration/teletext/expected_reveal_flash_0.png +0 -0
- package/tests/integration/teletext/expected_reveal_flash_1.png +0 -0
- package/tests/integration/teletext.js +126 -0
- package/tests/integration/timings.js +56 -0
- package/tests/integration/via.js +1125 -0
- package/tests/suite/README.md +7 -0
- package/tests/suite/Test Suite 2.15.txt +373 -0
- package/tests/suite/bin/ start +0 -0
- package/tests/suite/bin/adca +0 -0
- package/tests/suite/bin/adcax +0 -0
- package/tests/suite/bin/adcay +0 -0
- package/tests/suite/bin/adcb +0 -0
- package/tests/suite/bin/adcix +0 -0
- package/tests/suite/bin/adciy +0 -0
- package/tests/suite/bin/adcz +0 -0
- package/tests/suite/bin/adczx +0 -0
- package/tests/suite/bin/alrb +0 -0
- package/tests/suite/bin/ancb +0 -0
- package/tests/suite/bin/anda +0 -0
- package/tests/suite/bin/andax +0 -0
- package/tests/suite/bin/anday +0 -0
- package/tests/suite/bin/andb +0 -0
- package/tests/suite/bin/andix +0 -0
- package/tests/suite/bin/andiy +0 -0
- package/tests/suite/bin/andz +0 -0
- package/tests/suite/bin/andzx +0 -0
- package/tests/suite/bin/aneb +0 -0
- package/tests/suite/bin/arrb +0 -0
- package/tests/suite/bin/asla +0 -0
- package/tests/suite/bin/aslax +0 -0
- package/tests/suite/bin/asln +0 -0
- package/tests/suite/bin/aslz +0 -0
- package/tests/suite/bin/aslzx +0 -0
- package/tests/suite/bin/asoa +0 -0
- package/tests/suite/bin/asoax +0 -0
- package/tests/suite/bin/asoay +0 -0
- package/tests/suite/bin/asoix +0 -0
- package/tests/suite/bin/asoiy +0 -0
- package/tests/suite/bin/asoz +0 -0
- package/tests/suite/bin/asozx +0 -0
- package/tests/suite/bin/axsa +0 -0
- package/tests/suite/bin/axsix +0 -0
- package/tests/suite/bin/axsz +0 -0
- package/tests/suite/bin/axszy +0 -0
- package/tests/suite/bin/bccr +0 -0
- package/tests/suite/bin/bcsr +0 -0
- package/tests/suite/bin/beqr +0 -0
- package/tests/suite/bin/bita +0 -0
- package/tests/suite/bin/bitz +0 -0
- package/tests/suite/bin/bmir +0 -0
- package/tests/suite/bin/bner +0 -0
- package/tests/suite/bin/bplr +0 -0
- package/tests/suite/bin/branchwrap +0 -0
- package/tests/suite/bin/brkn +0 -0
- package/tests/suite/bin/bvcr +0 -0
- package/tests/suite/bin/bvsr +0 -0
- package/tests/suite/bin/cia1pb6 +0 -0
- package/tests/suite/bin/cia1pb7 +0 -0
- package/tests/suite/bin/cia1ta +0 -0
- package/tests/suite/bin/cia1tab +0 -0
- package/tests/suite/bin/cia1tb +0 -0
- package/tests/suite/bin/cia1tb123 +0 -0
- package/tests/suite/bin/cia2pb6 +0 -0
- package/tests/suite/bin/cia2pb7 +0 -0
- package/tests/suite/bin/cia2ta +0 -0
- package/tests/suite/bin/cia2tb +0 -0
- package/tests/suite/bin/cia2tb123 +0 -0
- package/tests/suite/bin/clcn +0 -0
- package/tests/suite/bin/cldn +0 -0
- package/tests/suite/bin/clin +0 -0
- package/tests/suite/bin/clvn +0 -0
- package/tests/suite/bin/cmpa +0 -0
- package/tests/suite/bin/cmpax +0 -0
- package/tests/suite/bin/cmpay +0 -0
- package/tests/suite/bin/cmpb +0 -0
- package/tests/suite/bin/cmpix +0 -0
- package/tests/suite/bin/cmpiy +0 -0
- package/tests/suite/bin/cmpz +0 -0
- package/tests/suite/bin/cmpzx +0 -0
- package/tests/suite/bin/cntdef +0 -0
- package/tests/suite/bin/cnto2 +0 -0
- package/tests/suite/bin/cpuport +0 -0
- package/tests/suite/bin/cputiming +0 -0
- package/tests/suite/bin/cpxa +0 -0
- package/tests/suite/bin/cpxb +0 -0
- package/tests/suite/bin/cpxz +0 -0
- package/tests/suite/bin/cpya +0 -0
- package/tests/suite/bin/cpyb +0 -0
- package/tests/suite/bin/cpyz +0 -0
- package/tests/suite/bin/dcma +0 -0
- package/tests/suite/bin/dcmax +0 -0
- package/tests/suite/bin/dcmay +0 -0
- package/tests/suite/bin/dcmix +0 -0
- package/tests/suite/bin/dcmiy +0 -0
- package/tests/suite/bin/dcmz +0 -0
- package/tests/suite/bin/dcmzx +0 -0
- package/tests/suite/bin/deca +0 -0
- package/tests/suite/bin/decax +0 -0
- package/tests/suite/bin/decz +0 -0
- package/tests/suite/bin/deczx +0 -0
- package/tests/suite/bin/dexn +0 -0
- package/tests/suite/bin/deyn +0 -0
- package/tests/suite/bin/eora +0 -0
- package/tests/suite/bin/eorax +0 -0
- package/tests/suite/bin/eoray +0 -0
- package/tests/suite/bin/eorb +0 -0
- package/tests/suite/bin/eorix +0 -0
- package/tests/suite/bin/eoriy +0 -0
- package/tests/suite/bin/eorz +0 -0
- package/tests/suite/bin/eorzx +0 -0
- package/tests/suite/bin/finish +0 -0
- package/tests/suite/bin/flipos +0 -0
- package/tests/suite/bin/icr01 +0 -0
- package/tests/suite/bin/imr +0 -0
- package/tests/suite/bin/inca +0 -0
- package/tests/suite/bin/incax +0 -0
- package/tests/suite/bin/incz +0 -0
- package/tests/suite/bin/inczx +0 -0
- package/tests/suite/bin/insa +0 -0
- package/tests/suite/bin/insax +0 -0
- package/tests/suite/bin/insay +0 -0
- package/tests/suite/bin/insix +0 -0
- package/tests/suite/bin/insiy +0 -0
- package/tests/suite/bin/insz +0 -0
- package/tests/suite/bin/inszx +0 -0
- package/tests/suite/bin/inxn +0 -0
- package/tests/suite/bin/inyn +0 -0
- package/tests/suite/bin/irq +0 -0
- package/tests/suite/bin/jmpi +0 -0
- package/tests/suite/bin/jmpw +0 -0
- package/tests/suite/bin/jsrw +0 -0
- package/tests/suite/bin/lasay +0 -0
- package/tests/suite/bin/laxa +0 -0
- package/tests/suite/bin/laxay +0 -0
- package/tests/suite/bin/laxix +0 -0
- package/tests/suite/bin/laxiy +0 -0
- package/tests/suite/bin/laxz +0 -0
- package/tests/suite/bin/laxzy +0 -0
- package/tests/suite/bin/ldaa +0 -0
- package/tests/suite/bin/ldaax +0 -0
- package/tests/suite/bin/ldaay +0 -0
- package/tests/suite/bin/ldab +0 -0
- package/tests/suite/bin/ldaix +0 -0
- package/tests/suite/bin/ldaiy +0 -0
- package/tests/suite/bin/ldaz +0 -0
- package/tests/suite/bin/ldazx +0 -0
- package/tests/suite/bin/ldxa +0 -0
- package/tests/suite/bin/ldxay +0 -0
- package/tests/suite/bin/ldxb +0 -0
- package/tests/suite/bin/ldxz +0 -0
- package/tests/suite/bin/ldxzy +0 -0
- package/tests/suite/bin/ldya +0 -0
- package/tests/suite/bin/ldyax +0 -0
- package/tests/suite/bin/ldyb +0 -0
- package/tests/suite/bin/ldyz +0 -0
- package/tests/suite/bin/ldyzx +0 -0
- package/tests/suite/bin/loadth +0 -0
- package/tests/suite/bin/lsea +0 -0
- package/tests/suite/bin/lseax +0 -0
- package/tests/suite/bin/lseay +0 -0
- package/tests/suite/bin/lseix +0 -0
- package/tests/suite/bin/lseiy +0 -0
- package/tests/suite/bin/lsez +0 -0
- package/tests/suite/bin/lsezx +0 -0
- package/tests/suite/bin/lsra +0 -0
- package/tests/suite/bin/lsrax +0 -0
- package/tests/suite/bin/lsrn +0 -0
- package/tests/suite/bin/lsrz +0 -0
- package/tests/suite/bin/lsrzx +0 -0
- package/tests/suite/bin/lxab +0 -0
- package/tests/suite/bin/mmu +0 -0
- package/tests/suite/bin/mmufetch +0 -0
- package/tests/suite/bin/nmi +0 -0
- package/tests/suite/bin/nopa +0 -0
- package/tests/suite/bin/nopax +0 -0
- package/tests/suite/bin/nopb +0 -0
- package/tests/suite/bin/nopn +0 -0
- package/tests/suite/bin/nopz +0 -0
- package/tests/suite/bin/nopzx +0 -0
- package/tests/suite/bin/oneshot +0 -0
- package/tests/suite/bin/oraa +0 -0
- package/tests/suite/bin/oraax +0 -0
- package/tests/suite/bin/oraay +0 -0
- package/tests/suite/bin/orab +0 -0
- package/tests/suite/bin/oraix +0 -0
- package/tests/suite/bin/oraiy +0 -0
- package/tests/suite/bin/oraz +0 -0
- package/tests/suite/bin/orazx +0 -0
- package/tests/suite/bin/phan +0 -0
- package/tests/suite/bin/phpn +0 -0
- package/tests/suite/bin/plan +0 -0
- package/tests/suite/bin/plpn +0 -0
- package/tests/suite/bin/rlaa +0 -0
- package/tests/suite/bin/rlaax +0 -0
- package/tests/suite/bin/rlaay +0 -0
- package/tests/suite/bin/rlaix +0 -0
- package/tests/suite/bin/rlaiy +0 -0
- package/tests/suite/bin/rlaz +0 -0
- package/tests/suite/bin/rlazx +0 -0
- package/tests/suite/bin/rola +0 -0
- package/tests/suite/bin/rolax +0 -0
- package/tests/suite/bin/roln +0 -0
- package/tests/suite/bin/rolz +0 -0
- package/tests/suite/bin/rolzx +0 -0
- package/tests/suite/bin/rora +0 -0
- package/tests/suite/bin/rorax +0 -0
- package/tests/suite/bin/rorn +0 -0
- package/tests/suite/bin/rorz +0 -0
- package/tests/suite/bin/rorzx +0 -0
- package/tests/suite/bin/rraa +0 -0
- package/tests/suite/bin/rraax +0 -0
- package/tests/suite/bin/rraay +0 -0
- package/tests/suite/bin/rraix +0 -0
- package/tests/suite/bin/rraiy +0 -0
- package/tests/suite/bin/rraz +0 -0
- package/tests/suite/bin/rrazx +0 -0
- package/tests/suite/bin/rtin +0 -0
- package/tests/suite/bin/rtsn +0 -0
- package/tests/suite/bin/sbca +0 -0
- package/tests/suite/bin/sbcax +0 -0
- package/tests/suite/bin/sbcay +0 -0
- package/tests/suite/bin/sbcb +0 -0
- package/tests/suite/bin/sbcb(eb) +0 -0
- package/tests/suite/bin/sbcix +0 -0
- package/tests/suite/bin/sbciy +0 -0
- package/tests/suite/bin/sbcz +0 -0
- package/tests/suite/bin/sbczx +0 -0
- package/tests/suite/bin/sbxb +0 -0
- package/tests/suite/bin/secn +0 -0
- package/tests/suite/bin/sedn +0 -0
- package/tests/suite/bin/sein +0 -0
- package/tests/suite/bin/shaay +0 -0
- package/tests/suite/bin/shaiy +0 -0
- package/tests/suite/bin/shsay +0 -0
- package/tests/suite/bin/shxay +0 -0
- package/tests/suite/bin/shyax +0 -0
- package/tests/suite/bin/staa +0 -0
- package/tests/suite/bin/staax +0 -0
- package/tests/suite/bin/staay +0 -0
- package/tests/suite/bin/staix +0 -0
- package/tests/suite/bin/staiy +0 -0
- package/tests/suite/bin/staz +0 -0
- package/tests/suite/bin/stazx +0 -0
- package/tests/suite/bin/stxa +0 -0
- package/tests/suite/bin/stxz +0 -0
- package/tests/suite/bin/stxzy +0 -0
- package/tests/suite/bin/stya +0 -0
- package/tests/suite/bin/styz +0 -0
- package/tests/suite/bin/styzx +0 -0
- package/tests/suite/bin/taxn +0 -0
- package/tests/suite/bin/tayn +0 -0
- package/tests/suite/bin/trap1 +0 -0
- package/tests/suite/bin/trap10 +0 -0
- package/tests/suite/bin/trap11 +0 -0
- package/tests/suite/bin/trap12 +0 -0
- package/tests/suite/bin/trap13 +0 -0
- package/tests/suite/bin/trap14 +0 -0
- package/tests/suite/bin/trap15 +0 -0
- package/tests/suite/bin/trap16 +0 -0
- package/tests/suite/bin/trap17 +0 -0
- package/tests/suite/bin/trap2 +0 -0
- package/tests/suite/bin/trap3 +0 -0
- package/tests/suite/bin/trap4 +0 -0
- package/tests/suite/bin/trap5 +0 -0
- package/tests/suite/bin/trap6 +0 -0
- package/tests/suite/bin/trap7 +0 -0
- package/tests/suite/bin/trap8 +0 -0
- package/tests/suite/bin/trap9 +0 -0
- package/tests/suite/bin/tsxn +0 -0
- package/tests/suite/bin/txan +0 -0
- package/tests/suite/bin/txsn +0 -0
- package/tests/suite/bin/tyan +0 -0
- package/tests/suite/cbm-hackers-post.html +178 -0
- package/tests/suite/cbm-hackers-post.md +78 -0
- package/tests/test-machine.js +288 -0
- package/tests/test-suite.js +147 -0
- package/tests/test.css +7 -0
- package/tests/unit/gzip/test-1 +0 -0
- package/tests/unit/gzip/test-1.gz +0 -0
- package/tests/unit/gzip/test-2 +0 -0
- package/tests/unit/gzip/test-2.gz +0 -0
- package/tests/unit/gzip/test-3 +0 -0
- package/tests/unit/gzip/test-3.gz +0 -0
- package/tests/unit/gzip/test-4 +0 -0
- package/tests/unit/gzip/test-4.gz +0 -0
- package/tests/unit/test-adc.js +307 -0
- package/tests/unit/test-bcd.js +30 -0
- package/tests/unit/test-cmos.js +266 -0
- package/tests/unit/test-disc-drive.js +85 -0
- package/tests/unit/test-disc-hfe.js +347 -0
- package/tests/unit/test-disc.js +232 -0
- package/tests/unit/test-fifo.js +35 -0
- package/tests/unit/test-gamepad-source.js +67 -0
- package/tests/unit/test-gzip.js +22 -0
- package/tests/unit/test-intel-fdc.js +93 -0
- package/tests/unit/test-keyboard.js +410 -0
- package/tests/unit/test-mouse-joystick-source.js +128 -0
- package/tests/unit/test-scheduler.js +190 -0
- package/tests/unit/test-serial.js +154 -0
- package/tests/unit/test-teletext-adaptor.js +359 -0
- package/tests/unit/test-tokenise.js +65 -0
- package/tests/unit/test-url-params.js +398 -0
- package/tests/unit/test-utils.js +276 -0
- package/tests/unit/test-video.js +498 -0
- package/tests/unit/test-zip.js +56 -0
- package/tests/unit/zip/test-mixed.zip +0 -0
- package/tests/unit/zip/test-rom.zip +0 -0
- package/tests/unit/zip/test-ssd.zip +0 -0
- package/tools/fir-generator.js +80 -0
- package/tools/vite-plugin-fir-shader.js +131 -0
- package/vite.config.js +34 -0
package/src/keyboard.js
ADDED
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
import * as utils from "./utils.js";
|
|
3
|
+
import EventEmitter from "event-emitter-es6";
|
|
4
|
+
|
|
5
|
+
const isMac = typeof window !== "undefined" && /^Mac/i.test(window.navigator?.platform || "");
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @typedef {Object} KeyboardConfig
|
|
9
|
+
* @property {Object} processor - The processor instance
|
|
10
|
+
* @property {Function} inputEnabledFunction - A function to check if input is enabled
|
|
11
|
+
* @property {string} [keyLayout="physical"] - The keyboard layout
|
|
12
|
+
* @property {Debugger} dbgr - The debugger instance
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Keyboard class that handles all keyboard related functionality
|
|
17
|
+
*/
|
|
18
|
+
export class Keyboard extends EventEmitter {
|
|
19
|
+
/**
|
|
20
|
+
* Create a new Keyboard instance with specified configuration
|
|
21
|
+
* @param {KeyboardConfig} config - The configuration object
|
|
22
|
+
*/
|
|
23
|
+
constructor(config) {
|
|
24
|
+
super();
|
|
25
|
+
const { processor, inputEnabledFunction, keyLayout = "physical", dbgr } = config;
|
|
26
|
+
|
|
27
|
+
// Core components
|
|
28
|
+
this.processor = processor;
|
|
29
|
+
this.inputEnabledFunction = inputEnabledFunction;
|
|
30
|
+
this.dbgr = dbgr;
|
|
31
|
+
|
|
32
|
+
// State
|
|
33
|
+
this.emuKeyHandlers = {};
|
|
34
|
+
this.running = false;
|
|
35
|
+
this.pauseEmu = false;
|
|
36
|
+
this.stepEmuWhenPaused = false;
|
|
37
|
+
this.keyLayout = keyLayout;
|
|
38
|
+
|
|
39
|
+
// Modifier key states
|
|
40
|
+
this.lastShiftLocation = 1;
|
|
41
|
+
this.lastCtrlLocation = 1;
|
|
42
|
+
this.lastAltLocation = 1;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Translates a keyboard event to a BBC key code
|
|
47
|
+
* @param {KeyboardEvent} evt - The keyboard event
|
|
48
|
+
* @returns {number} - The BBC key code
|
|
49
|
+
*/
|
|
50
|
+
keyCode(evt) {
|
|
51
|
+
const ret = evt.which || evt.charCode || evt.keyCode;
|
|
52
|
+
const keyCodes = utils.keyCodes;
|
|
53
|
+
|
|
54
|
+
switch (evt.location) {
|
|
55
|
+
default:
|
|
56
|
+
// keyUp events seem to pass location = 0 (Chrome)
|
|
57
|
+
switch (ret) {
|
|
58
|
+
case keyCodes.SHIFT:
|
|
59
|
+
return this.lastShiftLocation === 1 ? keyCodes.SHIFT_LEFT : keyCodes.SHIFT_RIGHT;
|
|
60
|
+
case keyCodes.ALT:
|
|
61
|
+
return this.lastAltLocation === 1 ? keyCodes.ALT_LEFT : keyCodes.ALT_RIGHT;
|
|
62
|
+
case keyCodes.CTRL:
|
|
63
|
+
return this.lastCtrlLocation === 1 ? keyCodes.CTRL_LEFT : keyCodes.CTRL_RIGHT;
|
|
64
|
+
}
|
|
65
|
+
break;
|
|
66
|
+
case 1:
|
|
67
|
+
switch (ret) {
|
|
68
|
+
case keyCodes.SHIFT:
|
|
69
|
+
this.lastShiftLocation = 1;
|
|
70
|
+
return keyCodes.SHIFT_LEFT;
|
|
71
|
+
case keyCodes.ALT:
|
|
72
|
+
this.lastAltLocation = 1;
|
|
73
|
+
return keyCodes.ALT_LEFT;
|
|
74
|
+
case keyCodes.CTRL:
|
|
75
|
+
this.lastCtrlLocation = 1;
|
|
76
|
+
return keyCodes.CTRL_LEFT;
|
|
77
|
+
}
|
|
78
|
+
break;
|
|
79
|
+
case 2:
|
|
80
|
+
switch (ret) {
|
|
81
|
+
case keyCodes.SHIFT:
|
|
82
|
+
this.lastShiftLocation = 2;
|
|
83
|
+
return keyCodes.SHIFT_RIGHT;
|
|
84
|
+
case keyCodes.ALT:
|
|
85
|
+
this.lastAltLocation = 2;
|
|
86
|
+
return keyCodes.ALT_RIGHT;
|
|
87
|
+
case keyCodes.CTRL:
|
|
88
|
+
this.lastCtrlLocation = 2;
|
|
89
|
+
return keyCodes.CTRL_RIGHT;
|
|
90
|
+
}
|
|
91
|
+
break;
|
|
92
|
+
case 3: // numpad
|
|
93
|
+
switch (ret) {
|
|
94
|
+
case keyCodes.ENTER:
|
|
95
|
+
return utils.keyCodes.NUMPADENTER;
|
|
96
|
+
case keyCodes.DELETE:
|
|
97
|
+
return utils.keyCodes.NUMPAD_DECIMAL_POINT;
|
|
98
|
+
}
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return ret;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Registers a handler for a specific key with optional modifiers
|
|
107
|
+
* @param {number} keyCode - The key code to handle
|
|
108
|
+
* @param {Function} handler - The handler function
|
|
109
|
+
* @param {Object} [options] - Options for this handler
|
|
110
|
+
* @param {boolean} [options.alt=true] - Whether this handler requires the Alt key
|
|
111
|
+
* @param {boolean} [options.ctrl=false] - Whether this handler requires the Ctrl key
|
|
112
|
+
*/
|
|
113
|
+
registerKeyHandler(keyCode, handler, options = { alt: true, ctrl: false }) {
|
|
114
|
+
// Generate a unique key that includes modifiers
|
|
115
|
+
const handlerKey = `${options.alt ? "alt:" : ""}${options.ctrl ? "ctrl:" : ""}${keyCode}`;
|
|
116
|
+
this.emuKeyHandlers[handlerKey] = {
|
|
117
|
+
handler,
|
|
118
|
+
alt: !!options.alt,
|
|
119
|
+
ctrl: !!options.ctrl,
|
|
120
|
+
keyCode,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Updates the current key layout
|
|
126
|
+
* @param {string} layout - The keyboard layout to use
|
|
127
|
+
*/
|
|
128
|
+
setKeyLayout(layout) {
|
|
129
|
+
this.keyLayout = layout;
|
|
130
|
+
this.processor.sysvia.setKeyLayout(layout);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Sets the running state of the emulator
|
|
135
|
+
* @param {boolean} isRunning - Whether the emulator is running
|
|
136
|
+
*/
|
|
137
|
+
setRunning(isRunning) {
|
|
138
|
+
this.running = isRunning;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Find a matching key handler for the given key event
|
|
143
|
+
* @param {number} keyCode - The key code
|
|
144
|
+
* @param {boolean} altKey - Whether Alt is pressed
|
|
145
|
+
* @param {boolean} ctrlKey - Whether Ctrl is pressed
|
|
146
|
+
* @returns {Object|null} The handler object or null if none found
|
|
147
|
+
* @private
|
|
148
|
+
*/
|
|
149
|
+
_findKeyHandler(keyCode, altKey, ctrlKey) {
|
|
150
|
+
// Try to find a handler with exact modifier match first
|
|
151
|
+
const exactModKey = `${altKey ? "alt:" : ""}${ctrlKey ? "ctrl:" : ""}${keyCode}`;
|
|
152
|
+
if (this.emuKeyHandlers[exactModKey]) {
|
|
153
|
+
return this.emuKeyHandlers[exactModKey];
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Handles a key press event
|
|
161
|
+
* @param {KeyboardEvent} evt - The keyboard event
|
|
162
|
+
*/
|
|
163
|
+
keyPress(evt) {
|
|
164
|
+
// Common key constants
|
|
165
|
+
const LOWERCASE_G = 103;
|
|
166
|
+
const LOWERCASE_N = 110;
|
|
167
|
+
|
|
168
|
+
// Early returns for common scenarios
|
|
169
|
+
// Check if input is enabled. If inputEnabledFunction returns true, keyboard events should not be processed.
|
|
170
|
+
if (this.inputEnabledFunction()) return;
|
|
171
|
+
if (this.running || (!this.dbgr.enabled() && !this.pauseEmu)) return;
|
|
172
|
+
|
|
173
|
+
const code = this.keyCode(evt);
|
|
174
|
+
|
|
175
|
+
// Handle debugger 'g' key press
|
|
176
|
+
if (this.dbgr.enabled() && code === LOWERCASE_G) {
|
|
177
|
+
this.dbgr.hide();
|
|
178
|
+
this.emit("resume");
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Handle pause/step control keys
|
|
183
|
+
if (this.pauseEmu) {
|
|
184
|
+
if (code === LOWERCASE_G) {
|
|
185
|
+
this.resumeEmulation();
|
|
186
|
+
return;
|
|
187
|
+
} else if (code === LOWERCASE_N) {
|
|
188
|
+
this.requestStep();
|
|
189
|
+
this.emit("resume");
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Pass any other keys to the debugger if it's enabled
|
|
195
|
+
if (this.dbgr.enabled()) {
|
|
196
|
+
const handled = this.dbgr.keyPress(this.keyCode(evt));
|
|
197
|
+
if (handled) evt.preventDefault();
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Handles a key down event
|
|
203
|
+
* @param {KeyboardEvent} evt - The keyboard event
|
|
204
|
+
*/
|
|
205
|
+
keyDown(evt) {
|
|
206
|
+
// Early returns for common scenarios
|
|
207
|
+
if (this.inputEnabledFunction()) return;
|
|
208
|
+
if (!this.running) return;
|
|
209
|
+
|
|
210
|
+
const code = this.keyCode(evt);
|
|
211
|
+
evt.preventDefault();
|
|
212
|
+
|
|
213
|
+
// Special handling cases that we always want to keep within keyboard.js
|
|
214
|
+
const isSpecialHandled = this._handleSpecialKeys(code);
|
|
215
|
+
if (isSpecialHandled) return;
|
|
216
|
+
|
|
217
|
+
// Always pass the key to the BBC Micro (unless it was a special key)
|
|
218
|
+
this.processor.sysvia.keyDown(code, evt.shiftKey);
|
|
219
|
+
|
|
220
|
+
// Check for registered handlers
|
|
221
|
+
const handler = this._findKeyHandler(code, evt.altKey, evt.ctrlKey);
|
|
222
|
+
if (handler) {
|
|
223
|
+
handler.handler(true, code);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Handle special keys that must remain in keyboard.js
|
|
229
|
+
* @param {number} code - The key code
|
|
230
|
+
* @returns {boolean} True if the key was handled specially
|
|
231
|
+
* @private
|
|
232
|
+
*/
|
|
233
|
+
_handleSpecialKeys(code) {
|
|
234
|
+
if (code === utils.keyCodes.F12 || code === utils.keyCodes.BREAK) {
|
|
235
|
+
this.emit("break", true);
|
|
236
|
+
this.processor.setReset(true);
|
|
237
|
+
return true;
|
|
238
|
+
} else if (isMac && code === utils.keyCodes.CAPSLOCK) {
|
|
239
|
+
// Special CapsLock handling for Mac
|
|
240
|
+
this.handleMacCapsLock();
|
|
241
|
+
return true;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
return false;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Handles a key up event
|
|
249
|
+
* @param {KeyboardEvent} evt - The keyboard event
|
|
250
|
+
*/
|
|
251
|
+
keyUp(evt) {
|
|
252
|
+
// Early return for text input
|
|
253
|
+
if (this.inputEnabledFunction()) return;
|
|
254
|
+
|
|
255
|
+
// Always let the key ups come through to avoid sticky keys in the debugger
|
|
256
|
+
const code = this.keyCode(evt);
|
|
257
|
+
this.processor.sysvia.keyUp(code);
|
|
258
|
+
|
|
259
|
+
// No further special handling needed if not running
|
|
260
|
+
if (!this.running) return;
|
|
261
|
+
|
|
262
|
+
evt.preventDefault();
|
|
263
|
+
|
|
264
|
+
// Handle special key cases
|
|
265
|
+
if (code === utils.keyCodes.F12 || code === utils.keyCodes.BREAK) {
|
|
266
|
+
this.emit("break", false);
|
|
267
|
+
this.processor.setReset(false);
|
|
268
|
+
return;
|
|
269
|
+
} else if (isMac && code === utils.keyCodes.CAPSLOCK) {
|
|
270
|
+
// Special CapsLock handling for Mac
|
|
271
|
+
this.handleMacCapsLock();
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// Check for registered handlers
|
|
276
|
+
const handler = this._findKeyHandler(code, evt.altKey, evt.ctrlKey);
|
|
277
|
+
if (handler) {
|
|
278
|
+
handler.handler(false, code);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Special handling for Mac's Caps Lock key behavior
|
|
284
|
+
*/
|
|
285
|
+
handleMacCapsLock() {
|
|
286
|
+
const CAPS_LOCK_DELAY = 100;
|
|
287
|
+
|
|
288
|
+
// Mac browsers seem to model caps lock as a physical key that's down when capslock is on, and up when it's off.
|
|
289
|
+
// No event is generated when it is physically released on the keyboard. So, we simulate a "tap" here.
|
|
290
|
+
this.processor.sysvia.keyDown(utils.keyCodes.CAPSLOCK);
|
|
291
|
+
|
|
292
|
+
// Simulate a key release after a short delay
|
|
293
|
+
setTimeout(() => this.processor.sysvia.keyUp(utils.keyCodes.CAPSLOCK), CAPS_LOCK_DELAY);
|
|
294
|
+
|
|
295
|
+
if (isMac && window.localStorage && !window.localStorage.getItem("warnedAboutRubbishMacs")) {
|
|
296
|
+
this.emit("showError", {
|
|
297
|
+
context: "handling caps lock on Mac OS X",
|
|
298
|
+
error: `Mac OS X does not generate key up events for caps lock presses.
|
|
299
|
+
jsbeeb can only simulate a 'tap' of the caps lock key. This means it doesn't work well for games
|
|
300
|
+
that use caps lock for left or fire, as we can't tell if it's being held down. If you need to play
|
|
301
|
+
such a game, please see the documentation about remapping keys.
|
|
302
|
+
Close this window to continue (you won't see this error again)`,
|
|
303
|
+
});
|
|
304
|
+
window.localStorage.setItem("warnedAboutRubbishMacs", "true");
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Send raw keyboard input to the BBC
|
|
310
|
+
* @param {Array} keysToSend - Array of keys to send
|
|
311
|
+
* @param {boolean} checkCapsAndShiftLocks - Whether to check caps and shift locks
|
|
312
|
+
*/
|
|
313
|
+
sendRawKeyboardToBBC(keysToSend, checkCapsAndShiftLocks) {
|
|
314
|
+
let lastChar;
|
|
315
|
+
let nextKeyMillis = 0;
|
|
316
|
+
this.processor.sysvia.disableKeyboard();
|
|
317
|
+
const clocksPerSecond = Math.floor(this.processor.cpuMultiplier * 2000000);
|
|
318
|
+
|
|
319
|
+
if (checkCapsAndShiftLocks) {
|
|
320
|
+
let toggleKey = null;
|
|
321
|
+
if (!this.processor.sysvia.capsLockLight) toggleKey = utils.BBC.CAPSLOCK;
|
|
322
|
+
else if (this.processor.sysvia.shiftLockLight) toggleKey = utils.BBC.SHIFTLOCK;
|
|
323
|
+
if (toggleKey) {
|
|
324
|
+
keysToSend.unshift(toggleKey);
|
|
325
|
+
keysToSend.push(toggleKey);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
const sendCharHook = this.processor.debugInstruction.add(() => {
|
|
330
|
+
const millis = this.processor.cycleSeconds * 1000 + this.processor.currentCycles / (clocksPerSecond / 1000);
|
|
331
|
+
if (millis < nextKeyMillis) {
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
if (lastChar && lastChar !== utils.BBC.SHIFT) {
|
|
336
|
+
this.processor.sysvia.keyToggleRaw(lastChar);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
if (keysToSend.length === 0) {
|
|
340
|
+
// Finished
|
|
341
|
+
this.processor.sysvia.enableKeyboard();
|
|
342
|
+
sendCharHook.remove();
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
const ch = keysToSend[0];
|
|
347
|
+
const debounce = lastChar === ch;
|
|
348
|
+
lastChar = ch;
|
|
349
|
+
if (debounce) {
|
|
350
|
+
lastChar = undefined;
|
|
351
|
+
nextKeyMillis = millis + 30;
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
let time = 50;
|
|
356
|
+
if (typeof lastChar === "number") {
|
|
357
|
+
time = lastChar;
|
|
358
|
+
lastChar = undefined;
|
|
359
|
+
} else {
|
|
360
|
+
this.processor.sysvia.keyToggleRaw(lastChar);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// remove first character
|
|
364
|
+
keysToSend.shift();
|
|
365
|
+
|
|
366
|
+
nextKeyMillis = millis + time;
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* Clears all pressed keys
|
|
372
|
+
*/
|
|
373
|
+
clearKeys() {
|
|
374
|
+
this.processor.sysvia.clearKeys();
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* Called after each frame to determine if emulation should pause
|
|
379
|
+
* @returns {boolean} - True if emulation should pause
|
|
380
|
+
*/
|
|
381
|
+
postFrameShouldPause() {
|
|
382
|
+
if (this.stepEmuWhenPaused) {
|
|
383
|
+
this.stepEmuWhenPaused = false;
|
|
384
|
+
return true;
|
|
385
|
+
}
|
|
386
|
+
return false;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Request a single step of the emulator
|
|
391
|
+
*/
|
|
392
|
+
requestStep() {
|
|
393
|
+
this.stepEmuWhenPaused = true;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
/**
|
|
397
|
+
* Pause the emulator
|
|
398
|
+
*/
|
|
399
|
+
pauseEmulation() {
|
|
400
|
+
this.pauseEmu = true;
|
|
401
|
+
this.emit("pause");
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* Resume the emulator
|
|
406
|
+
*/
|
|
407
|
+
resumeEmulation() {
|
|
408
|
+
this.pauseEmu = false;
|
|
409
|
+
this.emit("resume");
|
|
410
|
+
}
|
|
411
|
+
}
|
package/src/lib/README
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
webgl-debug is from Khronos
|