From 48a724931f15d18def7d80841ac89f3880f83458 Mon Sep 17 00:00:00 2001 From: Jeff Parsons Date: Mon, 15 Dec 2014 17:23:10 -0800 Subject: [PATCH] Fixed a problem with the right SHIFT key, and with webkit browsers when pressing/releasing both SHIFT keys together --- modules/htmlout/lib/httpapi.js | 23 ++++++++++++++++++++++- modules/pcjs/lib/disk.js | 4 ++-- modules/pcjs/lib/keyboard.js | 32 +++++++++++++++++++++++++++----- modules/shared/lib/diskapi.js | 2 +- 4 files changed, 52 insertions(+), 9 deletions(-) diff --git a/modules/htmlout/lib/httpapi.js b/modules/htmlout/lib/httpapi.js index 3f4ad37b1..fc163e08e 100644 --- a/modules/htmlout/lib/httpapi.js +++ b/modules/htmlout/lib/httpapi.js @@ -440,6 +440,9 @@ HTTPAPI.readUserVolume = function(sPath, fd, aCHS, aAddr, done) fs.read(fd, buf, 0, len, pos, function(err, cbRead, buffer) { var nResponse = 200; var sResponse = null; + // + // TODO: The callback should be asserting/verifying that cbRead equals the requested length. + // if (err) { nResponse = 400; sResponse = err.message; @@ -499,7 +502,24 @@ HTTPAPI.writeUserVolume = function(sPath, fd, aCHS, aAddr, sData, done) if (abData.length == len) { var buf = new Buffer(abData); + /* + * I have some concerns about asynchronous writes being performed out of order; however, + * even after changing fs.write() to fs.writeSync(), I'm still getting a corrupted 20mb disk + * image after running PKXARC B:DOCS.ARC into C:\TMP. TODO: Investigate. + */ + var nResponse = 200; + var sResponse = null; + var cbWrite = fs.writeSync(fd, buf, 0, len, pos); + if (cbWrite != len) { + nResponse = 400; + sResponse = "write length (" + cbWrite + ") does not equal buffer length (" + len + ")" + } + done(nResponse, sResponse); + /* fs.write(fd, buf, 0, len, pos, function(err, cbWrite, buffer) { + // + // TODO: The callback should be asserting/verifying that cbWrite equals the requested length. + // var nResponse = 200; var sResponse = null; if (err) { @@ -508,8 +528,9 @@ HTTPAPI.writeUserVolume = function(sPath, fd, aCHS, aAddr, sData, done) } done(nResponse, sResponse); }); + */ } else { - done(-1, "buffer length (" + abData.length + ") does not equal write length (" + len + ")"); + done(-1, "buffer length (" + abData.length + ") does not equal requested length (" + len + ")"); } }; diff --git a/modules/pcjs/lib/disk.js b/modules/pcjs/lib/disk.js index 807c26d12..158f58376 100644 --- a/modules/pcjs/lib/disk.js +++ b/modules/pcjs/lib/disk.js @@ -1052,8 +1052,8 @@ Disk.prototype.writeRemoteSectors = function(iCylinder, iHead, iSector, nSectors /** * disconnectRemoteDisk() * - * This is called by our powerDown() notification handler. If fRemote is true, we issue the disconnect request and - * then immediately set fRemote to false; we don't wait for (or test) the response. + * This is called by our powerDown() notification handler. If fRemote is true, we issue the disconnect + * request and then immediately set fRemote to false; we don't wait for (or test) the response. * * @this {Disk} */ diff --git a/modules/pcjs/lib/keyboard.js b/modules/pcjs/lib/keyboard.js index d9b748436..9980001ae 100644 --- a/modules/pcjs/lib/keyboard.js +++ b/modules/pcjs/lib/keyboard.js @@ -508,12 +508,13 @@ Keyboard.STATE = { RCMD: 0x0040, // 101-key keyboard only CMD: 0x0080, // 101-key keyboard only CMDS: 0x00c0, - SHIFTS: 0x00ff, // SHIFT | RSHIFT | CTRL | RCTRL | ALT | RALT | CMD | RCMD + ALL_RIGHT: 0x0055, // RSHIFT | RCTRL | RALT | RCMD + ALL_SHIFT: 0x00ff, // SHIFT | RSHIFT | CTRL | RCTRL | ALT | RALT | CMD | RCMD INSERT: 0x0100, // TODO: Placeholder (we currently have no notion of any "insert" states) CAPS_LOCK: 0x0200, NUM_LOCK: 0x0400, SCROLL_LOCK: 0x0800, - LOCKS: 0x0e00 // CAPS_LOCK | NUM_LOCK | SCROLL_LOCK + ALL_LOCKS: 0x0e00 // CAPS_LOCK | NUM_LOCK | SCROLL_LOCK }; /** @@ -1604,14 +1605,35 @@ Keyboard.prototype.updateShiftState = function(simCode, fSim, fDown) var fRight = (Math.floor(simCode / 1000) & 2); var bitState = Keyboard.KEYSTATES[simCode] || 0; if (bitState) { - if (fRight) bitState >>= 1; - if (bitState & Keyboard.STATE.LOCKS) { + if (fRight && !(bitState & Keyboard.STATE.ALL_RIGHT)) { + bitState >>= 1; + } + if (bitState & Keyboard.STATE.ALL_LOCKS) { if (fDown === false) return true; fDown = null; } if (fDown == null) { // ie, null or undefined fDown = !((fSim? this.bitsStateSim : this.bitsState) & bitState); } + else if (!fDown) { + /* + * In current webkit browsers, pressing and then releasing both left and right shift keys together + * (or both alt keys, or both cmd/windows keys, or presumably both ctrl keys) results in 4 events, as + * you would expect, but 3 of the 4 are "down" events; only the last of the 4 is an "up" event. + * + * Perhaps this is a browser accessibility feature (ie, deliberately suppressing the "up" event + * of one of the shift keys to implement a "sticky shift mode"?), but in any case, to maintain our + * internal consistency, if this is an "up" event and the shift state bit is any of ALL_SHIFT, then + * we set it to ALL_SHIFT, so that we'll automatically clear ALL shift states. + * + * TODO: The only downside to this work-around is that the simulation will still think a shift key is + * down. So in effect, we have enabled a "sticky shift mode" inside the simulation, whether or not that + * was the browser's intent. To fix that, we would have to identify the shift key that never went up + * and simulate the "up". That's more work than I think the problem merits. The user just needs to tap + * a single shift key to get out that mode. + */ + if (bitState & Keyboard.STATE.ALL_SHIFT) bitState = Keyboard.STATE.ALL_SHIFT; + } if (!fSim) { this.bitsState &= ~bitState; if (fDown) this.bitsState |= bitState; @@ -1903,7 +1925,7 @@ Keyboard.prototype.onFocusChange = function(fFocus) /* * Since we can't be sure of any shift states after losing focus, we clear them all. */ - if (!fFocus) this.bitsState &= ~Keyboard.STATE.SHIFTS; + if (!fFocus) this.bitsState &= ~Keyboard.STATE.ALL_SHIFT; }; /** diff --git a/modules/shared/lib/diskapi.js b/modules/shared/lib/diskapi.js index e25515e8f..14af760d4 100644 --- a/modules/shared/lib/diskapi.js +++ b/modules/shared/lib/diskapi.js @@ -97,7 +97,7 @@ DiskAPI.BPB = { RESERVED_SECS: 0x0E, // 2 bytes: reserved sectors; ie, # sectors preceding the first FAT--usually just the boot sector (eg, 1) FAT_TOTAL: 0x10, // 1 byte: FAT copies (eg, 2) ROOT_ENTRIES: 0x11, // 2 bytes: root directory entries (eg, 0x40 or 64) 0x40 * 0x20 = 0x800 (1 sector is 0x200 bytes, total of 4 sectors) - SECTOR_TOTAL: 0x13, // 2 bytes: number of sectors (eg, 0x140 or 320) + SECTOR_TOTAL: 0x13, // 2 bytes: number of sectors (eg, 0x140 or 320); if zero, refer to LARGE_SECS MEDIA_TYPE: 0x15, // 1 byte: media type (eg, 0xFF: 320Kb, 0xFE: 160Kb, 0xFD: 360Kb, 0xFC: 180Kb) FAT_SECS: 0x16, // 2 bytes: sectors per FAT (eg, 1) TRACK_SECS: 0x18, // 2 bytes: sectors per track (eg, 8)