diff --git a/.gitmodules b/.gitmodules index 12941230..513d3a91 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,9 +1,6 @@ [submodule "javatari.js"] path = javatari.js url = https://github.com/sehugg/javatari.js -[submodule "dasm"] - path = dasm - url = https://github.com/sehugg/dasm [submodule "codemirror"] path = codemirror url = https://github.com/codemirror/CodeMirror diff --git a/doc/notes.txt b/doc/notes.txt index 79f5851c..0bedfc4f 100644 --- a/doc/notes.txt +++ b/doc/notes.txt @@ -28,7 +28,7 @@ TODO: - kbd shortcuts - PC x86 support - show errors in list (maybe window list?) -- can't see 1st line in editor sometimes +- can't see 1st line in editor sometimes (when scrolling cursor past bottom of screen) - online help - show self-modifying code insns left of editor - facade/kbd shortcuts for emulators, focus diff --git a/presets/apple2/cosmic.c b/presets/apple2/cosmic.c index 2300ab9b..938183a0 100644 --- a/presets/apple2/cosmic.c +++ b/presets/apple2/cosmic.c @@ -3,24 +3,29 @@ #include #include +// type aliases for byte/signed byte/unsigned 16-bit typedef unsigned char byte; typedef signed char sbyte; typedef unsigned short word; +// peeks, pokes, and strobes #define POKE(addr,val) (*(unsigned char*) (addr) = (val)) #define POKEW(addr,val) (*(unsigned*) (addr) = (val)) #define PEEK(addr) (*(unsigned char*) (addr)) #define PEEKW(addr) (*(unsigned*) (addr)) #define STROBE(addr) __asm__ ("sta %w", addr) +// speaker click #define CLICK STROBE(0xc030) /// HIRES LOOKUP TABLE -#define VHEIGHT 192 -#define VBWIDTH 40 +#define VHEIGHT 192 // number of scanlines +#define VBWIDTH 40 // number of bytes per scanline +#define PIXWIDTH 280 // 7 pixels per byte #define LUT(x) (byte*)(0x2000|x) +// starting address of each scanline static byte* const vidmem[VHEIGHT] = { LUT(0x0000), LUT(0x0400), LUT(0x0800), LUT(0x0c00), LUT(0x1000), LUT(0x1400), LUT(0x1800), LUT(0x1c00), LUT(0x0080), LUT(0x0480), LUT(0x0880), LUT(0x0c80), LUT(0x1080), LUT(0x1480), LUT(0x1880), LUT(0x1c80), @@ -48,20 +53,7 @@ static byte* const vidmem[VHEIGHT] = { LUT(0x03d0), LUT(0x07d0), LUT(0x0bd0), LUT(0x0fd0), LUT(0x13d0), LUT(0x17d0), LUT(0x1bd0), LUT(0x1fd0) }; -const byte DIV7_140[140] = { - 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 8, 8, 8, 8, - 9, 9, 9,10,10,10,10,11,11,11,12,12,12,12,13,13,13,14,14,14,14,15,15,15,16,16,16,16,17,17,17,18, -18,18,18,19,19,19,20,20,20,20,21,21,21,22,22,22,22,23,23,23,24,24,24,24,25,25,25,26,26,26,26,27, -27,27,28,28,28,28,29,29,29,30,30,30,30,31,31,31,32,32,32,32,33,33,33,34,34,34,34,35,35,35,36,36, -36,36,37,37,37,38,38,38,38,39,39,39}; - -const byte MOD7_140[140] = { - 0, 2, 4, 6, 1, 3, 5, 0, 2, 4, 6, 1, 3, 5, 0, 2, 4, 6, 1, 3, 5, 0, 2, 4, 6, 1, 3, 5, 0, 2, 4, 6, - 1, 3, 5, 0, 2, 4, 6, 1, 3, 5, 0, 2, 4, 6, 1, 3, 5, 0, 2, 4, 6, 1, 3, 5, 0, 2, 4, 6, 1, 3, 5, 0, - 2, 4, 6, 1, 3, 5, 0, 2, 4, 6, 1, 3, 5, 0, 2, 4, 6, 1, 3, 5, 0, 2, 4, 6, 1, 3, 5, 0, 2, 4, 6, 1, - 3, 5, 0, 2, 4, 6, 1, 3, 5, 0, 2, 4, 6, 1, 3, 5, 0, 2, 4, 6, 1, 3, 5, 0, 2, 4, 6, 1, 3, 5, 0, 2, - 4, 6, 1, 3, 5, 0, 2, 4, 6, 1, 3, 5}; - +// divide-by 7 table const byte DIV7[256] = { 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 9, @@ -72,6 +64,7 @@ const byte DIV7[256] = { 27,27,27,27,28,28,28,28,28,28,28,29,29,29,29,29,29,29,30,30,30,30,30,30,30,31,31,31,31,31,31,31, 32,32,32,32,32,32,32,33,33,33,33,33,33,33,34,34,34,34,34,34,34,35,35,35,35,35,35,35,36,36,36,36}; +// modulo-by-7 table const byte MOD7[256] = { 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, @@ -82,18 +75,19 @@ const byte MOD7[256] = { 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3}; +// bitmask table const byte BIT7[7] = { 1, 2, 4, 8, 16, 32, 64 }; #pragma static-locals(on) /// SOUND FUNCTIONS -void tone(byte freq, byte dur, sbyte mod) { +void tone(byte period, byte dur, sbyte mod) { word i; while (dur--) { - for (i=0; i> (7-xs); + rest = data >> (7-xs); // save leftover bits } + // compute final byte operation switch (op) { - case OP_DRAW: *dest = rest; break; - case OP_XOR: result |= (*dest ^= rest); break; + case OP_DRAW: *dest = rest; break; + case OP_XOR: result |= (*dest ^= rest); break; case OP_ERASE: *dest &= ~rest; break; } } @@ -168,6 +154,7 @@ void draw_sprite(const byte* src, byte x, byte y) { render_sprite(src, x, y, OP_DRAW); } +// XOR returns non-zero if any pixels were overlapped byte xor_sprite(const byte* src, byte x, byte y) { return render_sprite(src, x, y, OP_XOR); } @@ -176,6 +163,7 @@ void erase_sprite(const byte* src, byte x, byte y) { render_sprite(src, x, y, OP_ERASE); } +// clear just sets all bytes to 0, and is fast void clear_sprite(const byte* src, byte x, byte y) { byte i,j; byte w = *src++; @@ -189,36 +177,49 @@ void clear_sprite(const byte* src, byte x, byte y) { } } -void draw_char(char ch, byte x, byte y) { +// FONT FUNCTIONS + +#define LOCHAR 0x20 // lowest character value in font +#define HICHAR 0x7f // highest character value in font + +const byte font8x8[HICHAR-LOCHAR+1][8] = {/*{w:8,h:8,bpp:1,count:96}*/ +{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x18,0x18,0x18,0x18,0x00,0x00,0x18,0x00 }, { 0x66,0x66,0x66,0x00,0x00,0x00,0x00,0x00 }, { 0x66,0x66,0xff,0x66,0xff,0x66,0x66,0x00 }, { 0x18,0x7c,0x06,0x3c,0x60,0x3e,0x18,0x00 }, { 0x46,0x66,0x30,0x18,0x0c,0x66,0x62,0x00 }, { 0x3c,0x66,0x3c,0x1c,0xe6,0x66,0xfc,0x00 }, { 0x60,0x30,0x18,0x00,0x00,0x00,0x00,0x00 }, { 0x30,0x18,0x0c,0x0c,0x0c,0x18,0x30,0x00 }, { 0x0c,0x18,0x30,0x30,0x30,0x18,0x0c,0x00 }, { 0x00,0x66,0x3c,0xff,0x3c,0x66,0x00,0x00 }, { 0x00,0x18,0x18,0x7e,0x18,0x18,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x0c }, { 0x00,0x00,0x00,0x7e,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00 }, { 0x00,0xc0,0x60,0x30,0x18,0x0c,0x06,0x00 }, { 0x3c,0x66,0x76,0x6e,0x66,0x66,0x3c,0x00 }, { 0x18,0x18,0x1c,0x18,0x18,0x18,0x7e,0x00 }, { 0x3c,0x66,0x60,0x30,0x0c,0x06,0x7e,0x00 }, { 0x3c,0x66,0x60,0x38,0x60,0x66,0x3c,0x00 }, { 0x60,0x70,0x78,0x66,0xfe,0x60,0x60,0x00 }, { 0x7e,0x06,0x3e,0x60,0x60,0x66,0x3c,0x00 }, { 0x3c,0x66,0x06,0x3e,0x66,0x66,0x3c,0x00 }, { 0x7e,0x66,0x30,0x18,0x18,0x18,0x18,0x00 }, { 0x3c,0x66,0x66,0x3c,0x66,0x66,0x3c,0x00 }, { 0x3c,0x66,0x66,0x7c,0x60,0x66,0x3c,0x00 }, { 0x00,0x00,0x18,0x00,0x00,0x18,0x00,0x00 }, { 0x00,0x00,0x18,0x00,0x00,0x18,0x18,0x0c }, { 0x70,0x18,0x0c,0x06,0x0c,0x18,0x70,0x00 }, { 0x00,0x00,0x7e,0x00,0x7e,0x00,0x00,0x00 }, { 0x0e,0x18,0x30,0x60,0x30,0x18,0x0e,0x00 }, { 0x3c,0x66,0x60,0x30,0x18,0x00,0x18,0x00 }, { 0x3c,0x66,0x76,0x76,0x06,0x46,0x3c,0x00 }, { 0x18,0x3c,0x66,0x7e,0x66,0x66,0x66,0x00 }, { 0x3e,0x66,0x66,0x3e,0x66,0x66,0x3e,0x00 }, { 0x3c,0x66,0x06,0x06,0x06,0x66,0x3c,0x00 }, { 0x1e,0x36,0x66,0x66,0x66,0x36,0x1e,0x00 }, { 0x7e,0x06,0x06,0x1e,0x06,0x06,0x7e,0x00 }, { 0x7e,0x06,0x06,0x1e,0x06,0x06,0x06,0x00 }, { 0x3c,0x66,0x06,0x76,0x66,0x66,0x3c,0x00 }, { 0x66,0x66,0x66,0x7e,0x66,0x66,0x66,0x00 }, { 0x3c,0x18,0x18,0x18,0x18,0x18,0x3c,0x00 }, { 0x78,0x30,0x30,0x30,0x30,0x36,0x1c,0x00 }, { 0x66,0x36,0x1e,0x0e,0x1e,0x36,0x66,0x00 }, { 0x06,0x06,0x06,0x06,0x06,0x06,0x7e,0x00 }, { 0xc6,0xee,0xfe,0xd6,0xc6,0xc6,0xc6,0x00 }, { 0x66,0x6e,0x7e,0x7e,0x76,0x66,0x66,0x00 }, { 0x3c,0x66,0x66,0x66,0x66,0x66,0x3c,0x00 }, { 0x3e,0x66,0x66,0x3e,0x06,0x06,0x06,0x00 }, { 0x3c,0x66,0x66,0x66,0x66,0x3c,0x70,0x00 }, { 0x3e,0x66,0x66,0x3e,0x1e,0x36,0x66,0x00 }, { 0x3c,0x66,0x06,0x3c,0x60,0x66,0x3c,0x00 }, { 0x7e,0x18,0x18,0x18,0x18,0x18,0x18,0x00 }, { 0x66,0x66,0x66,0x66,0x66,0x66,0x3c,0x00 }, { 0x66,0x66,0x66,0x66,0x66,0x3c,0x18,0x00 }, { 0xc6,0xc6,0xc6,0xd6,0xfe,0xee,0xc6,0x00 }, { 0x66,0x66,0x3c,0x18,0x3c,0x66,0x66,0x00 }, { 0x66,0x66,0x66,0x3c,0x18,0x18,0x18,0x00 }, { 0x7e,0x60,0x30,0x18,0x0c,0x06,0x7e,0x00 }, { 0x3c,0x0c,0x0c,0x0c,0x0c,0x0c,0x3c,0x00 }, { 0x00,0x06,0x0c,0x18,0x30,0x60,0xc0,0x00 }, { 0x3c,0x30,0x30,0x30,0x30,0x30,0x3c,0x00 }, { 0x00,0x18,0x3c,0x7e,0x18,0x18,0x18,0x18 }, { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff }, { 0x06,0x0c,0x18,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x3c,0x60,0x7c,0x66,0x7c,0x00 }, { 0x00,0x06,0x06,0x3e,0x66,0x66,0x3e,0x00 }, { 0x00,0x00,0x3c,0x06,0x06,0x06,0x3c,0x00 }, { 0x00,0x60,0x60,0x7c,0x66,0x66,0x7c,0x00 }, { 0x00,0x00,0x3c,0x66,0x7e,0x06,0x3c,0x00 }, { 0x00,0x70,0x18,0x7c,0x18,0x18,0x18,0x00 }, { 0x00,0x00,0x7c,0x66,0x66,0x7c,0x60,0x3e }, { 0x00,0x06,0x06,0x3e,0x66,0x66,0x66,0x00 }, { 0x00,0x18,0x00,0x1c,0x18,0x18,0x3c,0x00 }, { 0x00,0x60,0x00,0x60,0x60,0x60,0x60,0x3c }, { 0x00,0x06,0x06,0x36,0x1e,0x36,0x66,0x00 }, { 0x00,0x1c,0x18,0x18,0x18,0x18,0x3c,0x00 }, { 0x00,0x00,0x66,0xfe,0xfe,0xd6,0xc6,0x00 }, { 0x00,0x00,0x3e,0x66,0x66,0x66,0x66,0x00 }, { 0x00,0x00,0x3c,0x66,0x66,0x66,0x3c,0x00 }, { 0x00,0x00,0x3e,0x66,0x66,0x3e,0x06,0x06 }, { 0x00,0x00,0x7c,0x66,0x66,0x7c,0x60,0x60 }, { 0x00,0x00,0x3e,0x66,0x06,0x06,0x06,0x00 }, { 0x00,0x00,0x7c,0x06,0x3c,0x60,0x3e,0x00 }, { 0x00,0x18,0x7e,0x18,0x18,0x18,0x70,0x00 }, { 0x00,0x00,0x66,0x66,0x66,0x66,0x7c,0x00 }, { 0x00,0x00,0x66,0x66,0x66,0x3c,0x18,0x00 }, { 0x00,0x00,0xc6,0xd6,0xfe,0x7c,0x6c,0x00 }, { 0x00,0x00,0x66,0x3c,0x18,0x3c,0x66,0x00 }, { 0x00,0x00,0x66,0x66,0x66,0x7c,0x30,0x1e }, { 0x00,0x00,0x7e,0x30,0x18,0x0c,0x7e,0x00 }, { 0x38,0x0c,0x0c,0x06,0x0c,0x0c,0x38,0x00 }, { 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18 }, { 0x1c,0x30,0x30,0x60,0x30,0x30,0x1c,0x00 }, { 0x00,0x4c,0x32,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, +}; + +// draw character from column 0..39, row 0..23 +void draw_char(char ch, byte col, byte row) { byte i; const byte* src = &font8x8[(ch-LOCHAR)][0]; - x *= 8; + byte y = row*8; for (i=0; i<8; i++) { - byte* dest = &vidmem[x++][y]; + byte* dest = &vidmem[y++][col]; *dest = *src; src += 1; } } -void draw_string(const char* str, byte x, byte y) { +// draw string starting at row/col (vert 1 = draw vertical) +void draw_string(const char* str, byte col, byte row, byte vert) { do { byte ch = *str++; if (!ch) break; - draw_char(ch, x, y); - x++; + draw_char(ch, col, row); + if (vert) row++; else col++; } while (1); } -void draw_bcd_word(word bcd, byte x, byte y) { +// draw 4-digit BCD word +void draw_bcd_word(word bcd, byte col, byte row, byte vert) { byte j; - x += 3; + if (vert) row+=3; else col+=3; // move to rightmost digit for (j=0; j<4; j++) { - draw_char('0'+(bcd&0xf), x, y); - x--; + draw_char('0'+(bcd&0xf), col, row); + if (vert) row--; else col--; bcd >>= 4; } } +// add two 4-digit BCD words word bcd_add(word a, word b) { word result; __asm__ ("sed"); // set decimal (BCD) mode @@ -258,9 +259,6 @@ const byte* const enemy_bitmaps[4] = { // byte attract; -byte credits; -byte curplayer; - word score; byte lives; @@ -290,26 +288,51 @@ typedef struct { MarchMode this_mode, next_mode; -void draw_lives(byte player) { +void draw_lives() { byte i; byte n = lives; - byte x = player ? (22-MAXLIVES) : 6; - byte y = VBWIDTH-3; + byte y = 18; + byte x = VBWIDTH-1; for (i=0; ix = x; e->y = y; e->shape = enemy_bitmaps[bm]; - x += 28; - if (x >= 28*7) { + x += 29; + if (x >= 200) { x = 0; y += 20; bm++; @@ -403,32 +426,6 @@ void update_next_enemy() { enemy_index++; } -void draw_bunker(byte x, byte y, byte y2, byte h, byte w) { - byte i,a,b; - for (i=0; ishape[0]*8; byte eh = e->shape[1]; @@ -482,7 +479,7 @@ void drop_bomb() { void move_bomb() { byte leftover = xor_sprite(bomb_bitmap, bomb_x, bomb_y); // erase - if (bomb_y < 192-10) { + if (bomb_y > 192-12) { bomb_y = 0; } else if (leftover) { erase_sprite(bomb_bitmap, bomb_x, bomb_y); // erase bunker @@ -510,13 +507,13 @@ void move_player() { if (kbhit()) { key = cgetc(); switch (key) { - case 'Z': + case 8: // left arrow player_dir = player_dir < 0 ? 0 : -2; break; - case 'X': + case 21: // right arrow player_dir = player_dir > 0 ? 0 : 2; break; - case ' ': + case ' ': // space if (bullet_y == 0) { fire_bullet(); } @@ -558,17 +555,18 @@ void play_round() { void init_game() { score = 0; lives = 5; - curplayer = 0; } void game_over_msg() { byte i; + byte x=11; + byte y=10; for (i=0; i<50; i++) { - draw_string(" *************** ", 5, 15); - draw_string("*** ***", 5, 16); - draw_string("** GAME OVER **", 5, 17); - draw_string("*** ***", 5, 18); - draw_string(" *************** ", 5, 19); + draw_string(" *************** ", x, y+0, 0); + draw_string("*** ***", x, y+1, 0); + draw_string("** GAME OVER **", x, y+2, 0); + draw_string("*** ***", x, y+3, 0); + draw_string(" *************** ", x, y+4, 0); } } @@ -595,7 +593,6 @@ void attract_mode() { void main() { // NOTE: initializers don't get run, so we init here - credits = 0; while (1) { //attract_mode(); play_game(); diff --git a/presets/apple2/siegegame.c b/presets/apple2/siegegame.c index 00d0327f..00bc8a4e 100644 --- a/presets/apple2/siegegame.c +++ b/presets/apple2/siegegame.c @@ -3,7 +3,6 @@ #include #include #include -#include #define COLS 40 #define ROWS 24 @@ -12,13 +11,14 @@ typedef unsigned char byte; typedef signed char sbyte; typedef unsigned short word; +// BASL = text address of cursor position static byte** BASL = (byte**) 0x28; byte getchar(byte x, byte y) { // JSR VTABZ // LDA (BASL) ($28) - gotoxy(x,y); - return (*BASL)[x]; + gotoxy(x,y); // set cursor position + return (*BASL)[x]; // lookup value @ cursor address } void delay(byte count) { @@ -45,6 +45,7 @@ Player players[2]; byte credits = 0; byte frames_per_move; +byte gameover; #define START_SPEED 12 #define MAX_SPEED 5 @@ -73,22 +74,22 @@ void draw_box(byte x, byte y, byte x2, byte y2, const char* chars) { void draw_playfield() { draw_box(0,1,COLS-1,ROWS-1,BOX_CHARS); - cputsxy(0,0,"Plyr1:"); - cputsxy(20,0,"Plyr2:"); - cputcxy(7,0,players[0].score+'0'); - cputcxy(27,0,players[1].score+'0'); + cputsxy( 0, 0, "Plyr1:"); + cputsxy(20, 0, "Plyr2:"); + cputcxy( 7, 0, players[0].score+'0'); + cputcxy(27, 0, players[1].score+'0'); } typedef enum { D_RIGHT, D_DOWN, D_LEFT, D_UP } dir_t; -const char DIR_X[4] = { 1, 0, -1, 0 }; -const char DIR_Y[4] = { 0, 1, 0, -1 }; +const sbyte DIR_X[4] = { 1, 0, -1, 0 }; +const sbyte DIR_Y[4] = { 0, 1, 0, -1 }; void init_game() { memset(players, 0, sizeof(players)); players[0].head_attr = '1'; players[1].head_attr = '2'; - players[0].tail_attr = 1; - players[1].tail_attr = 9; + players[0].tail_attr = '#'; + players[1].tail_attr = '*'; frames_per_move = START_SPEED; } @@ -120,13 +121,14 @@ void human_control(Player* p) { if (!p->human) return; if (!kbhit()) return; key = cgetc(); + // I/J/K/M cursor movement switch (key) { case 'I': dir = D_UP; break; case 'J': dir = D_LEFT; break; case 'K': dir = D_RIGHT; break; case 'M': dir = D_DOWN; break; } - // don't let the player reverse + // don't let the player reverse direction if (dir < 0x80 && dir != (p->dir ^ 2)) { p->dir = dir; } @@ -159,21 +161,17 @@ void ai_control(Player* p) { } } -byte gameover; - void flash_colliders() { byte i; // flash players that collided for (i=0; i<56; i++) { - //cv_set_frequency(CV_SOUNDCHANNEL_0, 1000+i*8); - //cv_set_attenuation(CV_SOUNDCHANNEL_0, i/2); - if (players[0].collided) players[0].head_attr ^= 0x80; - if (players[1].collided) players[1].head_attr ^= 0x80; delay(2); + revers(players[0].collided && (i&1)); draw_player(&players[0]); + revers(players[1].collided && (i&1)); draw_player(&players[1]); } - //cv_set_attenuation(CV_SOUNDCHANNEL_0, 28); + revers(0); } void make_move() { @@ -237,6 +235,5 @@ void play_game() { } void main() { - joy_install (joy_static_stddrv); play_game(); } diff --git a/src/platform/apple2.js b/src/platform/apple2.js index 5d6c2ecb..d5ef9a21 100644 --- a/src/platform/apple2.js +++ b/src/platform/apple2.js @@ -152,13 +152,19 @@ var Apple2Platform = function(mainElement) { audio = new SampleAudio(cpuFrequency); video.create(); video.setKeyboardEvents(function(key,code,flags) { - // since we're an Apple II+, we don't do lowercase if (flags & 1) { if (code) { + // convert to uppercase for Apple ][ if (code >= 0x61 && code <= 0x7a) - code -= 0x20; + code -= 0x20; kbdlatch = (code | 0x80) & 0xff; } else if (key) { + switch (key) { + case 37: key=8; break; // left + case 39: key=21; break; // right + case 38: key=11; break; // up + case 40: key=10; break; // down + } kbdlatch = (key | 0x80) & 0xff; } }