Added support for keyboard lock LEDs
This commit is contained in:
parent
7737a9ca0a
commit
501649f67b
37 changed files with 1970 additions and 1829 deletions
|
|
@ -10,6 +10,9 @@
|
||||||
<video id="videoMDA" screenwidth="720" screenheight="350" scale="true" charset="/devices/pc/video/ibm-mda-cga.json" pos="center" padding="8px">
|
<video id="videoMDA" screenwidth="720" screenheight="350" scale="true" charset="/devices/pc/video/ibm-mda-cga.json" pos="center" padding="8px">
|
||||||
<menu>
|
<menu>
|
||||||
<title>Monochrome Display</title>
|
<title>Monochrome Display</title>
|
||||||
|
<control type="led" class="output" label="Scroll" binding="scroll-lock" pos="right" padleft="8px"/>
|
||||||
|
<control type="led" class="output" label="Num" binding="num-lock" pos="right" padleft="8px"/>
|
||||||
|
<control type="led" class="output" label="Caps" binding="caps-lock" pos="right" padleft="8px"/>
|
||||||
</menu>
|
</menu>
|
||||||
</video>
|
</video>
|
||||||
<keyboard ref="/devices/pc/keyboard/us83.xml"/>
|
<keyboard ref="/devices/pc/keyboard/us83.xml"/>
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,9 @@
|
||||||
<video id="videoMDA" screenwidth="720" screenheight="350" scale="true" charset="/devices/pc/video/ibm-mda-cga.json" padding="8px">
|
<video id="videoMDA" screenwidth="720" screenheight="350" scale="true" charset="/devices/pc/video/ibm-mda-cga.json" padding="8px">
|
||||||
<menu>
|
<menu>
|
||||||
<title>Monochrome Display</title>
|
<title>Monochrome Display</title>
|
||||||
|
<control type="led" class="output" label="Scroll" binding="scroll-lock" pos="right" padleft="8px"/>
|
||||||
|
<control type="led" class="output" label="Num" binding="num-lock" pos="right" padleft="8px"/>
|
||||||
|
<control type="led" class="output" label="Caps" binding="caps-lock" pos="right" padleft="8px"/>
|
||||||
</menu>
|
</menu>
|
||||||
</video>
|
</video>
|
||||||
<cpu id="cpu8088" model="8088" autostart="true" pos="left" padleft="8px" padbottom="8px">
|
<cpu id="cpu8088" model="8088" autostart="true" pos="left" padleft="8px" padbottom="8px">
|
||||||
|
|
@ -22,6 +25,7 @@
|
||||||
<control type="list" class="input" binding="listDrives"/>
|
<control type="list" class="input" binding="listDrives"/>
|
||||||
<control type="list" class="input" binding="listDisks">
|
<control type="list" class="input" binding="listDisks">
|
||||||
<disk path="">None</disk>
|
<disk path="">None</disk>
|
||||||
|
<manifest ref="/disks/pc/dos/ibm/2.00/manifest.xml" disk="*"/>
|
||||||
<manifest ref="/disks/pc/diags/ibm/2.20/manifest.xml" disk="*"/>
|
<manifest ref="/disks/pc/diags/ibm/2.20/manifest.xml" disk="*"/>
|
||||||
</control>
|
</control>
|
||||||
<control type="button" class="input" binding="loadDrive">Load Drive</control>
|
<control type="button" class="input" binding="loadDrive">Load Drive</control>
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -1,17 +0,0 @@
|
||||||
Installation Notes
|
|
||||||
---
|
|
||||||
|
|
||||||
Boot from disk "N1" (must not be write-protected).
|
|
||||||
|
|
||||||
Serial number: sco005312
|
|
||||||
activation key: thmjvbqz
|
|
||||||
|
|
||||||
Note: this Xenix version can't run with a VGA card.
|
|
||||||
You can use a Hercules monochrome card or a CGA/EGA card.
|
|
||||||
|
|
||||||
Manifest Details
|
|
||||||
---
|
|
||||||
|
|
||||||
[Manifest](manifest.xml) update using:
|
|
||||||
|
|
||||||
find -L private -name "*" -type f -exec node ../../../../../modules/diskdump/bin/diskdump --format=json --output=. --manifest --title="SCO Xenix 8086 Operating System v2.1.3" --disk={} \;
|
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -1,53 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<?xml-stylesheet type="text/xsl" href="/versions/pcjs/1.16.0/manifest.xsl"?>
|
|
||||||
<manifest type="software">
|
|
||||||
<title>SCO Xenix 8086 Operating System v2.1.3</title>
|
|
||||||
<disk id="disk01" size="368640" chs="40:2:9" img="private/B1" href="/disks/pc/xenix/8086/2.1.3/B1.json" md5="f14b42cc487c43892a98a7429f406b2c" md5json="ddcbf13e539aaa77ec311b8a390b919a">
|
|
||||||
<name>B1</name>
|
|
||||||
</disk>
|
|
||||||
<disk id="disk02" size="368640" chs="40:2:9" img="private/B2" href="/disks/pc/xenix/8086/2.1.3/B2.json" md5="d43f006038c66cf442e1fb0b7d94c889" md5json="9f1b830c15442ac7cbf56cda585f2d69">
|
|
||||||
<name>B2</name>
|
|
||||||
</disk>
|
|
||||||
<disk id="disk03" size="368640" chs="40:2:9" img="private/B3" href="/disks/pc/xenix/8086/2.1.3/B3.json" md5="7a0e593bb15eaa0fa56a7ef9f72e0b8d" md5json="2406f520bdb52fd7b498b7db68aef6b3">
|
|
||||||
<name>B3</name>
|
|
||||||
</disk>
|
|
||||||
<disk id="disk04" size="368640" chs="40:2:9" img="private/GAMES" href="/disks/pc/xenix/8086/2.1.3/GAMES.json" md5="0be7c5213dc1d540c4019e130f533835" md5json="2dac3fffe51f3200f3b8f2a5cebcf5a2">
|
|
||||||
<name>GAMES</name>
|
|
||||||
</disk>
|
|
||||||
<disk id="disk05" size="368640" chs="40:2:9" img="private/N1" href="/disks/pc/xenix/8086/2.1.3/N1.json" md5="f3abb0fbee6a60d925cbd81a31e9f2a5" md5json="d84c47d7fa2e14f00f76dabed23a3b58">
|
|
||||||
<name>N1</name>
|
|
||||||
</disk>
|
|
||||||
<disk id="disk06" size="368640" chs="40:2:9" img="private/N2" href="/disks/pc/xenix/8086/2.1.3/N2.json" md5="f3c8234732431e0fb29fea3c70f01be2" md5json="38b9a234911757176e437abff2173d02">
|
|
||||||
<name>N2</name>
|
|
||||||
</disk>
|
|
||||||
<disk id="disk07" size="368640" chs="40:2:9" img="private/N3" href="/disks/pc/xenix/8086/2.1.3/N3.json" md5="fb94524d93934e05615d29d618e426bf" md5json="49537e4c3601cb95e807b763fca2eb59">
|
|
||||||
<name>N3</name>
|
|
||||||
</disk>
|
|
||||||
<disk id="disk08" size="368640" chs="40:2:9" img="private/N4" href="/disks/pc/xenix/8086/2.1.3/N4.json" md5="93b380d3bfe3d720f4b14f1078119125" md5json="3e5e568e3eecf7c3673a68442065ed85">
|
|
||||||
<name>N4</name>
|
|
||||||
</disk>
|
|
||||||
<disk id="disk09" size="368640" chs="40:2:9" img="private/N5" href="/disks/pc/xenix/8086/2.1.3/N5.json" md5="5f9361267fea2565561e187896d0b437" md5json="74e4ff69686cc45932424d02e9f5e5eb">
|
|
||||||
<name>N5</name>
|
|
||||||
</disk>
|
|
||||||
<disk id="disk10" size="368640" chs="40:2:9" img="private/N6" href="/disks/pc/xenix/8086/2.1.3/N6.json" md5="fa649506a8d03d6b620a543b947f7b4a" md5json="7e7fbf7288b432c377653a5e1b2ceb8b">
|
|
||||||
<name>N6</name>
|
|
||||||
</disk>
|
|
||||||
<disk id="disk11" size="368640" chs="40:2:9" img="private/X1" href="/disks/pc/xenix/8086/2.1.3/X1.json" md5="0d456f3ff755fb0b3c9244abd6e946ed" md5json="dfcee09880e36afff1c579dc4d35c3c6">
|
|
||||||
<name>X1</name>
|
|
||||||
</disk>
|
|
||||||
<disk id="disk12" size="368640" chs="40:2:9" img="private/X2" href="/disks/pc/xenix/8086/2.1.3/X2.json" md5="62c2c7de8af9b742c552e118049f1f53" md5json="c3b05fb2f8ffc91e3c70ebfdd07dc8fd">
|
|
||||||
<name>X2</name>
|
|
||||||
</disk>
|
|
||||||
<disk id="disk13" size="368640" chs="40:2:9" img="private/X3" href="/disks/pc/xenix/8086/2.1.3/X3.json" md5="3f113fbade21054c5405ce89ada06c7a" md5json="57299f97b269ad62b5d1c6e73afa811d">
|
|
||||||
<name>X3</name>
|
|
||||||
</disk>
|
|
||||||
<disk id="disk14" size="368640" chs="40:2:9" img="private/X4" href="/disks/pc/xenix/8086/2.1.3/X4.json" md5="f14e3828cc4dc55d5c6b3c538f1532b1" md5json="2ec909508308505b1af7cf8e37598be6">
|
|
||||||
<name>X4</name>
|
|
||||||
</disk>
|
|
||||||
<disk id="disk15" size="368640" chs="40:2:9" img="private/X5" href="/disks/pc/xenix/8086/2.1.3/X5.json" md5="19e99431c8a44d78d50b12e524861eb9" md5json="e3bf413459e789e70979114ff3626944">
|
|
||||||
<name>X5</name>
|
|
||||||
</disk>
|
|
||||||
<disk id="disk16" size="368640" chs="40:2:9" img="private/X6" href="/disks/pc/xenix/8086/2.1.3/X6.json" md5="228b4b09421a46931d8976b5dd2b0bb9" md5json="970d62a77b268a532300c15bd6be7150">
|
|
||||||
<name>X6</name>
|
|
||||||
</disk>
|
|
||||||
</manifest>
|
|
||||||
|
|
@ -94,6 +94,16 @@
|
||||||
line-height: 34px;
|
line-height: 34px;
|
||||||
background-color: #ffffff;
|
background-color: #ffffff;
|
||||||
}
|
}
|
||||||
|
.pcjs-led {
|
||||||
|
float: left;
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
margin: 4px;
|
||||||
|
border: 1px solid black;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 19px;
|
||||||
|
background-color: #000000;
|
||||||
|
}
|
||||||
.pcjs-reference {
|
.pcjs-reference {
|
||||||
float: left;
|
float: left;
|
||||||
font-size: x-small;
|
font-size: x-small;
|
||||||
|
|
|
||||||
|
|
@ -377,6 +377,9 @@
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</form>
|
</form>
|
||||||
</xsl:when>
|
</xsl:when>
|
||||||
|
<xsl:when test="@type = 'led'">
|
||||||
|
<div class="{$APPCLASS}-{@class} {$APPCLASS}-{@type}" data-value="{$type},{$binding}"><xsl:value-of select="."/></div>
|
||||||
|
</xsl:when>
|
||||||
<xsl:when test="@type = 'separator'">
|
<xsl:when test="@type = 'separator'">
|
||||||
<hr/>
|
<hr/>
|
||||||
</xsl:when>
|
</xsl:when>
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -150,7 +150,7 @@ function ChipSet(parmsChipSet)
|
||||||
Component.call(this, "ChipSet", parmsChipSet, ChipSet);
|
Component.call(this, "ChipSet", parmsChipSet, ChipSet);
|
||||||
|
|
||||||
this.model = parmsChipSet['model'];
|
this.model = parmsChipSet['model'];
|
||||||
this.model = (this.model !== undefined? parseInt(this.model, 10) : ChipSet.MODEL_5150);
|
this.model = (this.model? parseInt(this.model, 10) : ChipSet.MODEL_5150);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SW1 describes the number of floppy drives, the amount of base memory, the primary monitor type,
|
* SW1 describes the number of floppy drives, the amount of base memory, the primary monitor type,
|
||||||
|
|
@ -173,7 +173,7 @@ function ChipSet(parmsChipSet)
|
||||||
} else {
|
} else {
|
||||||
this.aFloppyDrives = [360, 360];
|
this.aFloppyDrives = [360, 360];
|
||||||
var aFloppyDrives = parmsChipSet['floppies'];
|
var aFloppyDrives = parmsChipSet['floppies'];
|
||||||
if (aFloppyDrives && aFloppyDrives.length !== undefined) this.aFloppyDrives = aFloppyDrives;
|
if (aFloppyDrives && aFloppyDrives.length) this.aFloppyDrives = aFloppyDrives;
|
||||||
var nDrives = this.aFloppyDrives.length;
|
var nDrives = this.aFloppyDrives.length;
|
||||||
if (nDrives) {
|
if (nDrives) {
|
||||||
this.sw1Init |= ChipSet.PPI_SW.FDRIVE.IPL;
|
this.sw1Init |= ChipSet.PPI_SW.FDRIVE.IPL;
|
||||||
|
|
@ -1030,19 +1030,23 @@ ChipSet.prototype.reset = function(fHard)
|
||||||
* DMA Controller initialization
|
* DMA Controller initialization
|
||||||
*/
|
*/
|
||||||
this.aDMACs = new Array(this.cDMACs);
|
this.aDMACs = new Array(this.cDMACs);
|
||||||
for (i = 0; i < this.cDMACs; i++) this.initDMAController(i);
|
for (i = 0; i < this.cDMACs; i++) {
|
||||||
|
this.initDMAController(i);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* PIC initialization
|
* PIC initialization
|
||||||
*/
|
*/
|
||||||
this.aPICs = new Array(this.cPICs);
|
this.aPICs = new Array(this.cPICs);
|
||||||
this.initPIC(ChipSet.PIC0.INDEX, ChipSet.PIC0.PORT_LO);
|
this.initPIC(ChipSet.PIC0.INDEX, ChipSet.PIC0.PORT_LO);
|
||||||
if (this.cPICs > 1) this.initPIC(ChipSet.PIC1.INDEX, ChipSet.PIC1.PORT_LO);
|
if (this.cPICs > 1) {
|
||||||
|
this.initPIC(ChipSet.PIC1.INDEX, ChipSet.PIC1.PORT_LO);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Timer initialization
|
* Timer initialization
|
||||||
*/
|
*/
|
||||||
this.bTimerCtrl = undefined; // tracks writes to port 0x43
|
this.bTimerCtrl = null; // tracks writes to port 0x43
|
||||||
this.aTimers = new Array(3);
|
this.aTimers = new Array(3);
|
||||||
for (i = 0; i < this.aTimers.length; i++) {
|
for (i = 0; i < this.aTimers.length; i++) {
|
||||||
this.initTimer(i);
|
this.initTimer(i);
|
||||||
|
|
@ -1051,10 +1055,10 @@ ChipSet.prototype.reset = function(fHard)
|
||||||
/*
|
/*
|
||||||
* PPI and other misc ports
|
* PPI and other misc ports
|
||||||
*/
|
*/
|
||||||
this.bPPIA = undefined; // tracks writes to port 0x60, in case PPI_CTRL.A_IN is not set
|
this.bPPIA = null; // tracks writes to port 0x60, in case PPI_CTRL.A_IN is not set
|
||||||
this.bPPIB = undefined; // tracks writes to port 0x61, in case PPI_CTRL.B_IN is not set
|
this.bPPIB = null; // tracks writes to port 0x61, in case PPI_CTRL.B_IN is not set
|
||||||
this.bPPIC = undefined; // tracks writes to port 0x62, in case PPI_CTRL.C_IN_LO or PPI_CTRL.C_IN_HI is not set
|
this.bPPIC = null; // tracks writes to port 0x62, in case PPI_CTRL.C_IN_LO or PPI_CTRL.C_IN_HI is not set
|
||||||
this.bPPICtrl = undefined; // tracks writes to port 0x63 (eg, 0x99); read-only
|
this.bPPICtrl = null; // tracks writes to port 0x63 (eg, 0x99); read-only
|
||||||
this.bNMI = ChipSet.NMI.DISABLE;// tracks writes to the NMI Mask Register
|
this.bNMI = ChipSet.NMI.DISABLE;// tracks writes to the NMI Mask Register
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -1522,20 +1526,17 @@ ChipSet.prototype.restore = function(data)
|
||||||
this.sw2 = a[3];
|
this.sw2 = a[3];
|
||||||
|
|
||||||
a = data[1];
|
a = data[1];
|
||||||
this.aDMACs = new Array(this.cDMACs);
|
|
||||||
for (i = 0; i < this.cDMACs; i++) {
|
for (i = 0; i < this.cDMACs; i++) {
|
||||||
this.initDMAController(i, a.length == 1? a[0][i] : a);
|
this.initDMAController(i, a.length == 1? a[0][i] : a);
|
||||||
}
|
}
|
||||||
|
|
||||||
a = data[2];
|
a = data[2];
|
||||||
this.aPICs = new Array(this.cPICs);
|
|
||||||
for (i = 0; i < this.cPICs; i++) {
|
for (i = 0; i < this.cPICs; i++) {
|
||||||
this.initPIC(i, i === 0? ChipSet.PIC0.PORT_LO : ChipSet.PIC1.PORT_LO, a[0][i]);
|
this.initPIC(i, i === 0? ChipSet.PIC0.PORT_LO : ChipSet.PIC1.PORT_LO, a[0][i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
a = data[3];
|
a = data[3];
|
||||||
this.bTimerCtrl = a[0];
|
this.bTimerCtrl = a[0];
|
||||||
this.aTimers = new Array(3);
|
|
||||||
for (i = 0; i < this.aTimers.length; i++) {
|
for (i = 0; i < this.aTimers.length; i++) {
|
||||||
this.initTimer(i, a[1][i]);
|
this.initTimer(i, a[1][i]);
|
||||||
}
|
}
|
||||||
|
|
@ -1591,9 +1592,12 @@ ChipSet.aDMAControllerInit = [0, null, null, 0, new Array(4)];
|
||||||
ChipSet.prototype.initDMAController = function(iDMAC, aState)
|
ChipSet.prototype.initDMAController = function(iDMAC, aState)
|
||||||
{
|
{
|
||||||
var controller = this.aDMACs[iDMAC];
|
var controller = this.aDMACs[iDMAC];
|
||||||
if (!controller) controller = {
|
if (!controller) {
|
||||||
|
Component.assert(!aState);
|
||||||
|
controller = {
|
||||||
aChannels: new Array(4)
|
aChannels: new Array(4)
|
||||||
};
|
};
|
||||||
|
}
|
||||||
var a = aState && aState.length == 5? aState : ChipSet.aDMAControllerInit;
|
var a = aState && aState.length == 5? aState : ChipSet.aDMAControllerInit;
|
||||||
controller.bStatus = a[0];
|
controller.bStatus = a[0];
|
||||||
controller.bCmd = a[1];
|
controller.bCmd = a[1];
|
||||||
|
|
@ -1618,19 +1622,17 @@ ChipSet.aDMAChannelInit = [true, [0,0], [0,0], [0,0], [0,0]];
|
||||||
*/
|
*/
|
||||||
ChipSet.prototype.initDMAChannel = function(controller, iChannel, aState)
|
ChipSet.prototype.initDMAChannel = function(controller, iChannel, aState)
|
||||||
{
|
{
|
||||||
var a = ChipSet.aDMAChannelInit;
|
|
||||||
var channel = controller.aChannels[iChannel];
|
var channel = controller.aChannels[iChannel];
|
||||||
if (!channel) {
|
if (!channel) {
|
||||||
Component.assert(!aState);
|
Component.assert(!aState);
|
||||||
channel = {
|
channel = {
|
||||||
masked: true,
|
|
||||||
addrInit: [0,0],
|
addrInit: [0,0],
|
||||||
countInit: [0,0],
|
countInit: [0,0],
|
||||||
addrCurrent: [0,0],
|
addrCurrent: [0,0],
|
||||||
countCurrent: [0,0]
|
countCurrent: [0,0]
|
||||||
};
|
};
|
||||||
} else {
|
}
|
||||||
if (aState && aState.length == 8) a = aState;
|
var a = aState && aState.length == 8? aState : ChipSet.aDMAChannelInit;
|
||||||
channel.masked = a[0];
|
channel.masked = a[0];
|
||||||
channel.addrInit[0] = a[1][0]; channel.addrInit[1] = a[1][1];
|
channel.addrInit[0] = a[1][0]; channel.addrInit[1] = a[1][1];
|
||||||
channel.countInit[0] = a[2][0]; channel.countInit[1] = a[2][1];
|
channel.countInit[0] = a[2][0]; channel.countInit[1] = a[2][1];
|
||||||
|
|
@ -1639,7 +1641,6 @@ ChipSet.prototype.initDMAChannel = function(controller, iChannel, aState)
|
||||||
channel.mode = a[5];
|
channel.mode = a[5];
|
||||||
channel.bPage = a[6];
|
channel.bPage = a[6];
|
||||||
// a[7] is deprecated
|
// a[7] is deprecated
|
||||||
}
|
|
||||||
channel.controller = controller;
|
channel.controller = controller;
|
||||||
channel.iChannel = iChannel;
|
channel.iChannel = iChannel;
|
||||||
this.initDMAFunction(channel, a[8], a[9]);
|
this.initDMAFunction(channel, a[8], a[9]);
|
||||||
|
|
@ -1650,8 +1651,8 @@ ChipSet.prototype.initDMAChannel = function(controller, iChannel, aState)
|
||||||
* initDMAFunction(channel)
|
* initDMAFunction(channel)
|
||||||
*
|
*
|
||||||
* @param {Object} channel
|
* @param {Object} channel
|
||||||
* @param {Component|string|undefined} component
|
* @param {Component|string} [component]
|
||||||
* @param {string|undefined} sFunction
|
* @param {string} [sFunction]
|
||||||
* @param {Object} [obj]
|
* @param {Object} [obj]
|
||||||
* @return {*}
|
* @return {*}
|
||||||
*/
|
*/
|
||||||
|
|
@ -1723,7 +1724,7 @@ ChipSet.prototype.saveDMAChannels = function(controller)
|
||||||
ChipSet.aPICInit = [0, new Array(4)];
|
ChipSet.aPICInit = [0, new Array(4)];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* initPIC(iPIC, aState)
|
* initPIC(iPIC, port, aState)
|
||||||
*
|
*
|
||||||
* @this {ChipSet}
|
* @this {ChipSet}
|
||||||
* @param {number} iPIC
|
* @param {number} iPIC
|
||||||
|
|
@ -1733,12 +1734,16 @@ ChipSet.aPICInit = [0, new Array(4)];
|
||||||
ChipSet.prototype.initPIC = function(iPIC, port, aState)
|
ChipSet.prototype.initPIC = function(iPIC, port, aState)
|
||||||
{
|
{
|
||||||
var pic = this.aPICs[iPIC];
|
var pic = this.aPICs[iPIC];
|
||||||
if (!pic) pic = {};
|
if (!pic) {
|
||||||
|
pic = {
|
||||||
|
aICW: [null,null,null,null]
|
||||||
|
};
|
||||||
|
}
|
||||||
var a = aState && aState.length == 8? aState : ChipSet.aPICInit;
|
var a = aState && aState.length == 8? aState : ChipSet.aPICInit;
|
||||||
pic.port = port;
|
pic.port = port;
|
||||||
pic.nIRQBase = iPIC << 3;
|
pic.nIRQBase = iPIC << 3;
|
||||||
pic.nDelay = a[0];
|
pic.nDelay = a[0];
|
||||||
pic.aICW = a[1];
|
pic.aICW[0] = a[1][0]; pic.aICW[1] = a[1][1]; pic.aICW[2] = a[1][2]; pic.aICW[3] = a[1][3];
|
||||||
pic.nICW = a[2];
|
pic.nICW = a[2];
|
||||||
pic.bIMR = a[3];
|
pic.bIMR = a[3];
|
||||||
pic.bIRR = a[4];
|
pic.bIRR = a[4];
|
||||||
|
|
@ -1785,12 +1790,14 @@ ChipSet.aTimerInit = [[0,0], [0,0], [0,0], [0,0]];
|
||||||
ChipSet.prototype.initTimer = function(iTimer, aState)
|
ChipSet.prototype.initTimer = function(iTimer, aState)
|
||||||
{
|
{
|
||||||
var timer = this.aTimers[iTimer];
|
var timer = this.aTimers[iTimer];
|
||||||
if (!timer) timer = {
|
if (!timer) {
|
||||||
|
timer = {
|
||||||
countInit: [0,0],
|
countInit: [0,0],
|
||||||
countStart: [0,0],
|
countStart: [0,0],
|
||||||
countCurrent: [0,0],
|
countCurrent: [0,0],
|
||||||
countLatched: [0,0]
|
countLatched: [0,0]
|
||||||
};
|
};
|
||||||
|
}
|
||||||
var a = aState && aState.length == 13? aState : ChipSet.aTimerInit;
|
var a = aState && aState.length == 13? aState : ChipSet.aTimerInit;
|
||||||
timer.countInit[0] = a[0][0]; timer.countInit[1] = a[0][1];
|
timer.countInit[0] = a[0][0]; timer.countInit[1] = a[0][1];
|
||||||
timer.countStart[0] = a[1][0]; timer.countStart[1] = a[1][1];
|
timer.countStart[0] = a[1][0]; timer.countStart[1] = a[1][1];
|
||||||
|
|
@ -1842,7 +1849,7 @@ ChipSet.prototype.saveTimers = function()
|
||||||
* getSWMemorySize(fInit)
|
* getSWMemorySize(fInit)
|
||||||
*
|
*
|
||||||
* @this {ChipSet}
|
* @this {ChipSet}
|
||||||
* @param {boolean|undefined} [fInit] is true for init switch value(s) only, current value(s) otherwise
|
* @param {boolean} [fInit] is true for init switch value(s) only, current value(s) otherwise
|
||||||
* @return {number} number of Kb of specified memory (NOT necessarily the same as installed memory; see RAM component)
|
* @return {number} number of Kb of specified memory (NOT necessarily the same as installed memory; see RAM component)
|
||||||
*/
|
*/
|
||||||
ChipSet.prototype.getSWMemorySize = function(fInit)
|
ChipSet.prototype.getSWMemorySize = function(fInit)
|
||||||
|
|
@ -1856,7 +1863,7 @@ ChipSet.prototype.getSWMemorySize = function(fInit)
|
||||||
* getSWFloppyDrives(fInit)
|
* getSWFloppyDrives(fInit)
|
||||||
*
|
*
|
||||||
* @this {ChipSet}
|
* @this {ChipSet}
|
||||||
* @param {boolean|undefined} [fInit] is true for init switch value(s) only, current value(s) otherwise
|
* @param {boolean} [fInit] is true for init switch value(s) only, current value(s) otherwise
|
||||||
* @return {number} number of floppy drives specified by SW1 (range is 0 to 4)
|
* @return {number} number of floppy drives specified by SW1 (range is 0 to 4)
|
||||||
*/
|
*/
|
||||||
ChipSet.prototype.getSWFloppyDrives = function(fInit)
|
ChipSet.prototype.getSWFloppyDrives = function(fInit)
|
||||||
|
|
@ -1923,7 +1930,7 @@ ChipSet.prototype.getSWFloppyDriveSize = function(iDrive)
|
||||||
* getSWVideoMonitor(fInit)
|
* getSWVideoMonitor(fInit)
|
||||||
*
|
*
|
||||||
* @this {ChipSet}
|
* @this {ChipSet}
|
||||||
* @param {boolean|undefined} [fInit] is true for init switch value(s) only, current value(s) otherwise
|
* @param {boolean} [fInit] is true for init switch value(s) only, current value(s) otherwise
|
||||||
* @return {number} one of ChipSet.MONITOR.*
|
* @return {number} one of ChipSet.MONITOR.*
|
||||||
*/
|
*/
|
||||||
ChipSet.prototype.getSWVideoMonitor = function(fInit)
|
ChipSet.prototype.getSWVideoMonitor = function(fInit)
|
||||||
|
|
@ -1956,7 +1963,7 @@ ChipSet.prototype.addSwitches = function(s, control, n, v, oTips)
|
||||||
var aeCells = Component.getElementsByClass(control, sCellClass);
|
var aeCells = Component.getElementsByClass(control, sCellClass);
|
||||||
var sTip = null;
|
var sTip = null;
|
||||||
for (i = 0; i < aeCells.length; i++) {
|
for (i = 0; i < aeCells.length; i++) {
|
||||||
if (oTips !== undefined && oTips[i] !== undefined) {
|
if (oTips != null && oTips[i] != null) {
|
||||||
sTip = oTips[i];
|
sTip = oTips[i];
|
||||||
}
|
}
|
||||||
if (sTip) aeCells[i].setAttribute("title", sTip);
|
if (sTip) aeCells[i].setAttribute("title", sTip);
|
||||||
|
|
@ -1992,7 +1999,7 @@ ChipSet.prototype.getSwitch = function(control)
|
||||||
*
|
*
|
||||||
* @this {ChipSet}
|
* @this {ChipSet}
|
||||||
* @param {Object} control is an HTML control DOM object
|
* @param {Object} control is an HTML control DOM object
|
||||||
* @param {boolean} f is true if the switch represented by e should be "on", false if "off"
|
* @param {boolean} f is true if the switch represented by control should be "on", false if "off"
|
||||||
*/
|
*/
|
||||||
ChipSet.prototype.setSwitch = function(control, f)
|
ChipSet.prototype.setSwitch = function(control, f)
|
||||||
{
|
{
|
||||||
|
|
@ -2047,12 +2054,12 @@ ChipSet.prototype.updateSwitchDesc = function()
|
||||||
2: "Color",
|
2: "Color",
|
||||||
3: "Monochrome"
|
3: "Monochrome"
|
||||||
};
|
};
|
||||||
if (controlDesc !== undefined) {
|
if (controlDesc != null) {
|
||||||
var sHTML = "";
|
var sHTML = "";
|
||||||
sHTML += this.getSWMemorySize(true) + "Kb";
|
sHTML += this.getSWMemorySize(true) + "Kb";
|
||||||
sHTML += ", " + asMonitorTypes[this.getSWVideoMonitor(true)] + " Monitor";
|
sHTML += ", " + asMonitorTypes[this.getSWVideoMonitor(true)] + " Monitor";
|
||||||
sHTML += ", " + this.getSWFloppyDrives(true) + " Floppy Drives";
|
sHTML += ", " + this.getSWFloppyDrives(true) + " Floppy Drives";
|
||||||
if (this.sw1 !== undefined && this.sw1 != this.sw1Init || this.sw2 !== undefined && this.sw2 != this.sw2Init)
|
if (this.sw1 != null && this.sw1 != this.sw1Init || this.sw2 != null && this.sw2 != this.sw2Init)
|
||||||
sHTML += " (Reset required)";
|
sHTML += " (Reset required)";
|
||||||
controlDesc.innerHTML = sHTML;
|
controlDesc.innerHTML = sHTML;
|
||||||
}
|
}
|
||||||
|
|
@ -2092,7 +2099,7 @@ ChipSet.prototype.dumpTimer = function()
|
||||||
var timer = this.aTimers[iTimer];
|
var timer = this.aTimers[iTimer];
|
||||||
var sDump = "TIMER" + iTimer + ":";
|
var sDump = "TIMER" + iTimer + ":";
|
||||||
var count = 0;
|
var count = 0;
|
||||||
if (timer.countBytes !== undefined) {
|
if (timer.countBytes != null) {
|
||||||
for (var i = 0; i <= timer.countBytes; i++) {
|
for (var i = 0; i <= timer.countBytes; i++) {
|
||||||
count |= (timer.countCurrent[i] << (i * 8));
|
count |= (timer.countCurrent[i] << (i * 8));
|
||||||
}
|
}
|
||||||
|
|
@ -2735,7 +2742,7 @@ ChipSet.prototype.inPICLo = function(iPIC, addrFrom)
|
||||||
{
|
{
|
||||||
var b = 0;
|
var b = 0;
|
||||||
var pic = this.aPICs[iPIC];
|
var pic = this.aPICs[iPIC];
|
||||||
if (pic.bOCW3 !== undefined) {
|
if (pic.bOCW3 != null) {
|
||||||
var bReadReg = pic.bOCW3 & ChipSet.PIC_LO.OCW3_READ_CMD;
|
var bReadReg = pic.bOCW3 & ChipSet.PIC_LO.OCW3_READ_CMD;
|
||||||
switch (bReadReg) {
|
switch (bReadReg) {
|
||||||
case ChipSet.PIC_LO.OCW3_READ_IRR:
|
case ChipSet.PIC_LO.OCW3_READ_IRR:
|
||||||
|
|
@ -3425,7 +3432,7 @@ ChipSet.prototype.resetTimerIndex = function(iTimer)
|
||||||
* 0: Time-of-Day interrupt (~18.2 interrupts/second)
|
* 0: Time-of-Day interrupt (~18.2 interrupts/second)
|
||||||
* 1: DMA refresh
|
* 1: DMA refresh
|
||||||
* 2: Sound/Cassette
|
* 2: Sound/Cassette
|
||||||
* @param {boolean|undefined} [fCycleReset] is true if a cycle-count reset is about to occur
|
* @param {boolean} [fCycleReset] is true if a cycle-count reset is about to occur
|
||||||
* @return {Object} timer
|
* @return {Object} timer
|
||||||
*/
|
*/
|
||||||
ChipSet.prototype.updateTimer = function(iTimer, fCycleReset)
|
ChipSet.prototype.updateTimer = function(iTimer, fCycleReset)
|
||||||
|
|
@ -3593,7 +3600,7 @@ ChipSet.prototype.updateTimer = function(iTimer, fCycleReset)
|
||||||
* updateAllTimers(fCycleReset)
|
* updateAllTimers(fCycleReset)
|
||||||
*
|
*
|
||||||
* @this {ChipSet}
|
* @this {ChipSet}
|
||||||
* @param {boolean|undefined} [fCycleReset] is true if a cycle-count reset is about to occur
|
* @param {boolean} [fCycleReset] is true if a cycle-count reset is about to occur
|
||||||
*/
|
*/
|
||||||
ChipSet.prototype.updateAllTimers = function(fCycleReset)
|
ChipSet.prototype.updateAllTimers = function(fCycleReset)
|
||||||
{
|
{
|
||||||
|
|
@ -4483,7 +4490,7 @@ ChipSet.prototype.setSpeaker = function(fOn)
|
||||||
* @this {ChipSet}
|
* @this {ChipSet}
|
||||||
* @param {string} sMessage is any caller-defined message string
|
* @param {string} sMessage is any caller-defined message string
|
||||||
* @param {number} [bitsMessage] is one or more Debugger MESSAGE_* category flag(s)
|
* @param {number} [bitsMessage] is one or more Debugger MESSAGE_* category flag(s)
|
||||||
* @param {number|undefined} [nIRQ] if the message is associated with a particular IRQ #
|
* @param {number} [nIRQ] if the message is associated with a particular IRQ #
|
||||||
*
|
*
|
||||||
* This is a combination of the Debugger's messageEnabled() and message() functions, for convenience.
|
* This is a combination of the Debugger's messageEnabled() and message() functions, for convenience.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -172,6 +172,12 @@ function FDC(parmsFDC) {
|
||||||
*/
|
*/
|
||||||
this.aDiskHistory = [];
|
this.aDiskHistory = [];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If setBinding() sees a binding for loading local disks, it will set this flag, and then initBus()
|
||||||
|
* can intelligently update the "listDisks" control accordingly.
|
||||||
|
*/
|
||||||
|
this.fLocalDisks = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The remainder of FDC initialization now takes place in our initBus() handler, largely because we
|
* The remainder of FDC initialization now takes place in our initBus() handler, largely because we
|
||||||
* want initController() to have access to the ChipSet component, so that it can query switches and/or CMOS
|
* want initController() to have access to the ChipSet component, so that it can query switches and/or CMOS
|
||||||
|
|
@ -419,9 +425,6 @@ FDC.prototype.setBinding = function(sHTMLClass, sHTMLType, sBinding, control)
|
||||||
case "listDisks":
|
case "listDisks":
|
||||||
this.bindings[sBinding] = control;
|
this.bindings[sBinding] = control;
|
||||||
|
|
||||||
this.addDiskette("Local Disk", "?");
|
|
||||||
this.addDiskette("Remote Disk", "??");
|
|
||||||
|
|
||||||
control.onchange = function onChangeListDisks(event) {
|
control.onchange = function onChangeListDisks(event) {
|
||||||
var controlDesc = fdc.bindings["descDisk"];
|
var controlDesc = fdc.bindings["descDisk"];
|
||||||
var controlOption = control.options[control.selectedIndex];
|
var controlOption = control.options[control.selectedIndex];
|
||||||
|
|
@ -475,6 +478,7 @@ FDC.prototype.setBinding = function(sHTMLClass, sHTMLType, sBinding, control)
|
||||||
* Check for availability of FileReader
|
* Check for availability of FileReader
|
||||||
*/
|
*/
|
||||||
if (window && 'FileReader' in window) {
|
if (window && 'FileReader' in window) {
|
||||||
|
this.fLocalDisks = true;
|
||||||
this.bindings[sBinding] = control;
|
this.bindings[sBinding] = control;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -540,6 +544,11 @@ FDC.prototype.initBus = function(cmp, bus, cpu, dbg)
|
||||||
bus.addPortInputTable(this, FDC.aPortInput);
|
bus.addPortInputTable(this, FDC.aPortInput);
|
||||||
bus.addPortOutputTable(this, FDC.aPortOutput);
|
bus.addPortOutputTable(this, FDC.aPortOutput);
|
||||||
|
|
||||||
|
if (this.fLocalDisks) {
|
||||||
|
this.addDiskette("Local Disk", "?");
|
||||||
|
}
|
||||||
|
this.addDiskette("Remote Disk", "??");
|
||||||
|
|
||||||
if (!this.autoMount()) this.setReady();
|
if (!this.autoMount()) this.setReady();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -1190,7 +1199,7 @@ FDC.prototype.loadSelectedDrive = function(sDisketteName, sDiskettePath, file)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sDiskettePath == "?") {
|
if (sDiskettePath == "?") {
|
||||||
this.notice("Use 'Load' to load local disks");
|
this.notice('Use "Choose File" and "Load" to select and load a local disk.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -173,6 +173,8 @@ Keyboard.KEYCODE = {
|
||||||
/* 0x79 */ F10: 121,
|
/* 0x79 */ F10: 121,
|
||||||
/* 0x7A */ F11: 122,
|
/* 0x7A */ F11: 122,
|
||||||
/* 0x7B */ F12: 123,
|
/* 0x7B */ F12: 123,
|
||||||
|
/* 0x90 */ NUM_LOCK: 144,
|
||||||
|
/* 0x91 */ SCROLL_LOCK:145,
|
||||||
//
|
//
|
||||||
// ONDOWN is a bias we add to browser keyCodes that we want to handle on "down" rather than "press".
|
// ONDOWN is a bias we add to browser keyCodes that we want to handle on "down" rather than "press".
|
||||||
//
|
//
|
||||||
|
|
@ -208,12 +210,12 @@ Keyboard.LOCATION = {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* These internal "shift key" states are stored in bitsShift, as well as in aKeyCodes; note that the
|
* These internal "shift key" states are used to indicate the current simulated shift/modifier key states
|
||||||
* right-hand versions of selected shift bits are shifted 1 bit right.
|
* in shiftStates; note that right-hand shift bits match the corresponding left-hand bit shifted 1 bit right.
|
||||||
*
|
*
|
||||||
* @enum {number}
|
* @enum {number}
|
||||||
*/
|
*/
|
||||||
Keyboard.STATE = {
|
Keyboard.STATES = {
|
||||||
RSHIFT: 0x0001,
|
RSHIFT: 0x0001,
|
||||||
SHIFT: 0x0002,
|
SHIFT: 0x0002,
|
||||||
RCTRL: 0x0004, // 101-key keyboard only
|
RCTRL: 0x0004, // 101-key keyboard only
|
||||||
|
|
@ -223,21 +225,34 @@ Keyboard.STATE = {
|
||||||
COMMAND: 0x0040, // 101-key keyboard only (TODO: Treat this like the 'Windows' key)
|
COMMAND: 0x0040, // 101-key keyboard only (TODO: Treat this like the 'Windows' key)
|
||||||
INSERT: 0x0080, // TODO: Placeholder
|
INSERT: 0x0080, // TODO: Placeholder
|
||||||
CAPS_LOCK: 0x0100,
|
CAPS_LOCK: 0x0100,
|
||||||
NUM_LOCK: 0x0200, // TODO: Placeholder
|
NUM_LOCK: 0x0200,
|
||||||
SCROLL_LOCK: 0x0400, // TODO: Placeholder
|
SCROLL_LOCK: 0x0400,
|
||||||
SIMULATE: 0x003f // STATE.RSHIFT | STATE.SHIFT | STATE.RCTRL | STATE.CTRL | STATE.RALT | STATE.ALT
|
LOCK: 0x0700, // STATES.CAPS_LOCK | STATES.NUM_LOCK | STATES.SCROLL_LOCK
|
||||||
|
SIMULATE: 0x003f // STATES.RSHIFT | STATES.SHIFT | STATES.RCTRL | STATES.CTRL | STATES.RALT | STATES.ALT
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maps the KEYCODE of a "shift key" to its corresponding (default) STATE bit above
|
* Maps KEYCODES of shift/modifier keys to their corresponding (default) STATES bit above
|
||||||
*
|
*
|
||||||
* @enum {number}
|
* @enum {number}
|
||||||
*/
|
*/
|
||||||
Keyboard.STATEKEYS = {
|
Keyboard.KEYSTATES = {};
|
||||||
16: Keyboard.STATE.SHIFT,
|
Keyboard.KEYSTATES[Keyboard.KEYCODE.SHIFT] = Keyboard.STATES.SHIFT;
|
||||||
17: Keyboard.STATE.CTRL,
|
Keyboard.KEYSTATES[Keyboard.KEYCODE.CTRL] = Keyboard.STATES.CTRL;
|
||||||
18: Keyboard.STATE.ALT,
|
Keyboard.KEYSTATES[Keyboard.KEYCODE.ALT] = Keyboard.STATES.ALT;
|
||||||
20: Keyboard.STATE.CAPS_LOCK
|
Keyboard.KEYSTATES[Keyboard.KEYCODE.CAPS_LOCK] = Keyboard.STATES.CAPS_LOCK;
|
||||||
|
Keyboard.KEYSTATES[Keyboard.KEYCODE.NUM_LOCK] = Keyboard.STATES.NUM_LOCK;
|
||||||
|
Keyboard.KEYSTATES[Keyboard.KEYCODE.SCROLL_LOCK]= Keyboard.STATES.SCROLL_LOCK;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps "soft-key" definitions of shift/modifier keys to their corresponding (default) STATES bit above
|
||||||
|
*
|
||||||
|
* @enum {number}
|
||||||
|
*/
|
||||||
|
Keyboard.LEDSTATES = {
|
||||||
|
'caps-lock': Keyboard.STATES.CAPS_LOCK,
|
||||||
|
'num-lock': Keyboard.STATES.NUM_LOCK,
|
||||||
|
'scroll-lock': Keyboard.STATES.SCROLL_LOCK
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -257,10 +272,6 @@ Keyboard.STATEKEYS = {
|
||||||
Keyboard.aButtonCodes = {
|
Keyboard.aButtonCodes = {
|
||||||
'tab': Keyboard.KEYCODE.TAB + Keyboard.KEYCODE.ONDOWN,
|
'tab': Keyboard.KEYCODE.TAB + Keyboard.KEYCODE.ONDOWN,
|
||||||
'esc': Keyboard.KEYCODE.ESC + Keyboard.KEYCODE.ONDOWN,
|
'esc': Keyboard.KEYCODE.ESC + Keyboard.KEYCODE.ONDOWN,
|
||||||
'right-shift': Keyboard.KEYCODE.SHIFT + Keyboard.KEYCODE.ONDOWN + Keyboard.KEYCODE.ONRIGHT,
|
|
||||||
'shift': Keyboard.KEYCODE.SHIFT + Keyboard.KEYCODE.ONDOWN,
|
|
||||||
'ctrl': Keyboard.KEYCODE.CTRL + Keyboard.KEYCODE.ONDOWN,
|
|
||||||
'alt': Keyboard.KEYCODE.ALT + Keyboard.KEYCODE.ONDOWN,
|
|
||||||
'caps-lock': Keyboard.KEYCODE.CAPS_LOCK + Keyboard.KEYCODE.ONDOWN,
|
'caps-lock': Keyboard.KEYCODE.CAPS_LOCK + Keyboard.KEYCODE.ONDOWN,
|
||||||
'f1': Keyboard.KEYCODE.F1 + Keyboard.KEYCODE.ONDOWN,
|
'f1': Keyboard.KEYCODE.F1 + Keyboard.KEYCODE.ONDOWN,
|
||||||
'f2': Keyboard.KEYCODE.F2 + Keyboard.KEYCODE.ONDOWN,
|
'f2': Keyboard.KEYCODE.F2 + Keyboard.KEYCODE.ONDOWN,
|
||||||
|
|
@ -546,8 +557,8 @@ Keyboard.aSoftCodes = {
|
||||||
* The other problem (which is more of a problem with keyboards like the C1P than any IBM keyboards) is
|
* The other problem (which is more of a problem with keyboards like the C1P than any IBM keyboards) is
|
||||||
* that the shift/modifier state for a character on the "source" keyboard may not match the shift/modifier
|
* that the shift/modifier state for a character on the "source" keyboard may not match the shift/modifier
|
||||||
* state for the same character on the "target" keyboard. And since this code is inherited from C1Pjs,
|
* state for the same character on the "target" keyboard. And since this code is inherited from C1Pjs,
|
||||||
* we've inherited the same solution: keySimulateUpOrDown() has the ability to "undo" any states in bitsShift
|
* we've inherited the same solution: keySimulateUpOrDown() has the ability to "undo" any states in
|
||||||
* that conflict with the state(s) required for the character in question.
|
* shiftStates that conflict with the state(s) required for the character in question.
|
||||||
*
|
*
|
||||||
* @enum {number}
|
* @enum {number}
|
||||||
*/
|
*/
|
||||||
|
|
@ -667,7 +678,9 @@ Keyboard.aKeyCodes[Keyboard.KEYCODE.F7 + Keyboard.KEYCODE.ONDOWN] = Keyboard
|
||||||
Keyboard.aKeyCodes[Keyboard.KEYCODE.F8 + Keyboard.KEYCODE.ONDOWN] = Keyboard.SCANCODE.F8;
|
Keyboard.aKeyCodes[Keyboard.KEYCODE.F8 + Keyboard.KEYCODE.ONDOWN] = Keyboard.SCANCODE.F8;
|
||||||
Keyboard.aKeyCodes[Keyboard.KEYCODE.F9 + Keyboard.KEYCODE.ONDOWN] = Keyboard.SCANCODE.F9;
|
Keyboard.aKeyCodes[Keyboard.KEYCODE.F9 + Keyboard.KEYCODE.ONDOWN] = Keyboard.SCANCODE.F9;
|
||||||
Keyboard.aKeyCodes[Keyboard.KEYCODE.F10 + Keyboard.KEYCODE.ONDOWN] = Keyboard.SCANCODE.F10;
|
Keyboard.aKeyCodes[Keyboard.KEYCODE.F10 + Keyboard.KEYCODE.ONDOWN] = Keyboard.SCANCODE.F10;
|
||||||
// TODO: 0x45 ('num-lock'), 0x46 ('scroll-lock'), 0x4a ('num-sub') and 0x4e ('num-add')
|
Keyboard.aKeyCodes[Keyboard.KEYCODE.NUM_LOCK + Keyboard.KEYCODE.ONDOWN] = Keyboard.SCANCODE.NUM_LOCK;
|
||||||
|
Keyboard.aKeyCodes[Keyboard.KEYCODE.SCROLL_LOCK + Keyboard.KEYCODE.ONDOWN] = Keyboard.SCANCODE.SCROLL_LOCK;
|
||||||
|
// TODO: 0x4a ('num-sub') and 0x4e ('num-add')
|
||||||
Keyboard.aKeyCodes[Keyboard.KEYCODE.HOME + Keyboard.KEYCODE.ONDOWN] = Keyboard.SCANCODE.NUM_HOME;
|
Keyboard.aKeyCodes[Keyboard.KEYCODE.HOME + Keyboard.KEYCODE.ONDOWN] = Keyboard.SCANCODE.NUM_HOME;
|
||||||
Keyboard.aKeyCodes[Keyboard.KEYCODE.UP + Keyboard.KEYCODE.ONDOWN] = Keyboard.SCANCODE.NUM_UP;
|
Keyboard.aKeyCodes[Keyboard.KEYCODE.UP + Keyboard.KEYCODE.ONDOWN] = Keyboard.SCANCODE.NUM_UP;
|
||||||
Keyboard.aKeyCodes[Keyboard.KEYCODE.PGUP + Keyboard.KEYCODE.ONDOWN] = Keyboard.SCANCODE.NUM_PGUP;
|
Keyboard.aKeyCodes[Keyboard.KEYCODE.PGUP + Keyboard.KEYCODE.ONDOWN] = Keyboard.SCANCODE.NUM_PGUP;
|
||||||
|
|
@ -788,6 +801,7 @@ Keyboard.prototype.setBinding = function(sHTMLClass, sHTMLType, sBinding, contro
|
||||||
*/
|
*/
|
||||||
var kbd = this;
|
var kbd = this;
|
||||||
var id = sHTMLType + '-' + sBinding;
|
var id = sHTMLType + '-' + sBinding;
|
||||||
|
|
||||||
if (this.bindings[id] === undefined) {
|
if (this.bindings[id] === undefined) {
|
||||||
switch (sBinding) {
|
switch (sBinding) {
|
||||||
case "kbd":
|
case "kbd":
|
||||||
|
|
@ -802,6 +816,28 @@ Keyboard.prototype.setBinding = function(sHTMLClass, sHTMLType, sBinding, contro
|
||||||
return kbd.keyUpDown(event, false);
|
return kbd.keyUpDown(event, false);
|
||||||
};
|
};
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
case "caps-lock":
|
||||||
|
this.bindings[id] = control;
|
||||||
|
control.onclick = function onClickCapsLock(event) {
|
||||||
|
return kbd.toggleCapsLock(event);
|
||||||
|
};
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case "num-lock":
|
||||||
|
this.bindings[id] = control;
|
||||||
|
control.onclick = function onClickNumLock(event) {
|
||||||
|
return kbd.toggleNumLock(event);
|
||||||
|
};
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case "scroll-lock":
|
||||||
|
this.bindings[id] = control;
|
||||||
|
control.onclick = function onClickScrollLock(event) {
|
||||||
|
return kbd.toggleScrollLock(event);
|
||||||
|
};
|
||||||
|
return true;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (Keyboard.aButtonCodes[sBinding] !== undefined && sHTMLType == "button") {
|
if (Keyboard.aButtonCodes[sBinding] !== undefined && sHTMLType == "button") {
|
||||||
this.bindings[id] = control;
|
this.bindings[id] = control;
|
||||||
|
|
@ -809,6 +845,7 @@ Keyboard.prototype.setBinding = function(sHTMLClass, sHTMLType, sBinding, contro
|
||||||
return function onClickKeyboard(event) {
|
return function onClickKeyboard(event) {
|
||||||
if (DEBUG) kbd.messageDebugger(sKey + " clicked", Debugger.MESSAGE.KEYS);
|
if (DEBUG) kbd.messageDebugger(sKey + " clicked", Debugger.MESSAGE.KEYS);
|
||||||
if (kbd.cpu) kbd.cpu.setFocus();
|
if (kbd.cpu) kbd.cpu.setFocus();
|
||||||
|
kbd.checkShiftState(keyCode);
|
||||||
return !kbd.keySimulatePress(keyCode);
|
return !kbd.keySimulatePress(keyCode);
|
||||||
};
|
};
|
||||||
}(this, sBinding, Keyboard.aButtonCodes[sBinding]);
|
}(this, sBinding, Keyboard.aButtonCodes[sBinding]);
|
||||||
|
|
@ -841,28 +878,28 @@ Keyboard.prototype.setBinding = function(sHTMLClass, sHTMLType, sBinding, contro
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* findBinding(bKey, t, fDown)
|
* findBinding(bKey, sType, fDown)
|
||||||
*
|
*
|
||||||
* @this {Keyboard}
|
* @this {Keyboard}
|
||||||
* @param {number} bKey
|
* @param {number} bKey
|
||||||
* @param {string} t is the type of control (eg, "button" or "key")
|
* @param {string} sType is the type of control (eg, "button" or "key")
|
||||||
* @param {boolean} [fDown] is true if the key is going down, false if up, or undefined if unchanged
|
* @param {boolean} [fDown] is true if the key is going down, false if up, or undefined if unchanged
|
||||||
* @return {Object} is the HTML control DOM object (eg, HTMLButtonElement), or undefined if no such control exists
|
* @return {Object} is the HTML control DOM object (eg, HTMLButtonElement), or undefined if no such control exists
|
||||||
*/
|
*/
|
||||||
Keyboard.prototype.findBinding = function(bKey, t, fDown)
|
Keyboard.prototype.findBinding = function(bKey, sType, fDown)
|
||||||
{
|
{
|
||||||
var e;
|
var control;
|
||||||
for (var s in Keyboard.aSoftCodes) {
|
for (var sBinding in Keyboard.aSoftCodes) {
|
||||||
if (Keyboard.aSoftCodes[s] == bKey) {
|
if (Keyboard.aSoftCodes[sBinding] == bKey) {
|
||||||
var id = t + '-' + s;
|
var id = sType + '-' + sBinding;
|
||||||
e = this.bindings[id];
|
control = this.bindings[id];
|
||||||
if (e && fDown !== undefined) {
|
if (control && fDown !== undefined) {
|
||||||
this.setSoftKeyState(e, fDown);
|
this.setSoftKeyState(control, fDown);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return e;
|
return control;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -1108,11 +1145,11 @@ Keyboard.prototype.reset = function()
|
||||||
this.initState();
|
this.initState();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The physical (not virtual) state of various shift/lock keys.
|
* The current (assumed) physical state of the various shift/lock keys.
|
||||||
*
|
*
|
||||||
* TODO: Determine how (or whether) we can query the browser's initial shift/lock key states.
|
* TODO: Determine how (or whether) we can query the browser's initial shift/lock key states.
|
||||||
*/
|
*/
|
||||||
this.bitsShift = 0;
|
this.shiftStates = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* New scan codes are "pushed" onto abScanBuffer and then "shifted" off.
|
* New scan codes are "pushed" onto abScanBuffer and then "shifted" off.
|
||||||
|
|
@ -1344,6 +1381,100 @@ Keyboard.prototype.injectKeysFromBuffer = function(msDelay)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* setLED(control, f)
|
||||||
|
*
|
||||||
|
* @this {Keyboard}
|
||||||
|
* @param {Object} control is an HTML control DOM object
|
||||||
|
* @param {boolean} f is true if the LED represented by control should be "on", false if "off"
|
||||||
|
*/
|
||||||
|
Keyboard.prototype.setLED = function(control, f)
|
||||||
|
{
|
||||||
|
control.style.backgroundColor = (f? "#00ff00" : "#000000");
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* updateLEDs(bitState)
|
||||||
|
*
|
||||||
|
* Updates any and all shift-related LEDs with the corresponding state in shiftStates.
|
||||||
|
*
|
||||||
|
* @this {Keyboard}
|
||||||
|
* @param {number} [bitState] is the bit in shiftStates that may have changed, if known; undefined if not
|
||||||
|
*/
|
||||||
|
Keyboard.prototype.updateLEDs = function(bitState)
|
||||||
|
{
|
||||||
|
var control;
|
||||||
|
for (var sBinding in Keyboard.LEDSTATES) {
|
||||||
|
var id = "led-" + sBinding;
|
||||||
|
var bitLED = Keyboard.LEDSTATES[sBinding];
|
||||||
|
if ((!bitState || bitState == bitLED) && (control = this.bindings[id])) {
|
||||||
|
this.setLED(control, !!(this.shiftStates & bitLED));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* toggleCapsLock(event)
|
||||||
|
*
|
||||||
|
* @this {Keyboard}
|
||||||
|
* @param {Object} event
|
||||||
|
*/
|
||||||
|
Keyboard.prototype.toggleCapsLock = function(event)
|
||||||
|
{
|
||||||
|
if (this.cpu) this.cpu.setFocus();
|
||||||
|
this.keySimulatePress(Keyboard.KEYCODE.CAPS_LOCK + Keyboard.KEYCODE.ONDOWN, true);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* toggleNumLock(event)
|
||||||
|
*
|
||||||
|
* @this {Keyboard}
|
||||||
|
* @param {Object} event
|
||||||
|
*/
|
||||||
|
Keyboard.prototype.toggleNumLock = function(event)
|
||||||
|
{
|
||||||
|
if (this.cpu) this.cpu.setFocus();
|
||||||
|
this.keySimulatePress(Keyboard.KEYCODE.NUM_LOCK + Keyboard.KEYCODE.ONDOWN, true);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* toggleScrollLock(event)
|
||||||
|
*
|
||||||
|
* @this {Keyboard}
|
||||||
|
* @param {Object} event
|
||||||
|
*/
|
||||||
|
Keyboard.prototype.toggleScrollLock = function(event)
|
||||||
|
{
|
||||||
|
if (this.cpu) this.cpu.setFocus();
|
||||||
|
this.keySimulatePress(Keyboard.KEYCODE.SCROLL_LOCK + Keyboard.KEYCODE.ONDOWN, true);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* checkShiftState(keyCode, fDown)
|
||||||
|
*
|
||||||
|
* @this {Keyboard}
|
||||||
|
* @param {number} keyCode (should already include any ONDOWN and/or ONRIGHT modifiers)
|
||||||
|
* @param {boolean} [fDown] is true for down, false for up, undefined for TBD
|
||||||
|
*/
|
||||||
|
Keyboard.prototype.checkShiftState = function(keyCode, fDown)
|
||||||
|
{
|
||||||
|
if (Keyboard.aKeyCodes[keyCode]) {
|
||||||
|
var bCode = Math.floor(keyCode % 1000);
|
||||||
|
var fRight = (Math.floor(keyCode / 1000) & 2);
|
||||||
|
var bitState = Keyboard.KEYSTATES[bCode] || 0;
|
||||||
|
if (bitState) {
|
||||||
|
if (fRight) bitState >>= 1;
|
||||||
|
if (bitState & Keyboard.STATES.LOCK) {
|
||||||
|
fDown = !(this.shiftStates & bitState);
|
||||||
|
}
|
||||||
|
this.shiftStates &= ~bitState;
|
||||||
|
if (fDown) this.shiftStates |= bitState;
|
||||||
|
|
||||||
|
this.updateLEDs(bitState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* keyUpDown(event, fDown)
|
* keyUpDown(event, fDown)
|
||||||
*
|
*
|
||||||
|
|
@ -1365,20 +1496,26 @@ Keyboard.prototype.keyUpDown = function(event, fDown)
|
||||||
if (Keyboard.aKeyCodes[keyCode + Keyboard.KEYCODE.ONDOWN]) {
|
if (Keyboard.aKeyCodes[keyCode + Keyboard.KEYCODE.ONDOWN]) {
|
||||||
|
|
||||||
keyCodeSim += Keyboard.KEYCODE.ONDOWN;
|
keyCodeSim += Keyboard.KEYCODE.ONDOWN;
|
||||||
var bShift = Keyboard.STATEKEYS[keyCode] || 0;
|
var bitState = Keyboard.KEYSTATES[keyCode] || 0;
|
||||||
|
|
||||||
if (bShift) {
|
if (bitState) {
|
||||||
if (event.location == Keyboard.LOCATION.RIGHT) {
|
if (event.location == Keyboard.LOCATION.RIGHT) {
|
||||||
bShift >>= 1;
|
bitState >>= 1;
|
||||||
keyCodeSim += Keyboard.KEYCODE.ONRIGHT;
|
keyCodeSim += Keyboard.KEYCODE.ONRIGHT;
|
||||||
}
|
}
|
||||||
this.bitsShift &= ~bShift;
|
this.shiftStates &= ~bitState;
|
||||||
if (fDown) this.bitsShift |= bShift;
|
if (fDown) this.shiftStates |= bitState;
|
||||||
if (keyCode == Keyboard.KEYCODE.CAPS_LOCK) {
|
|
||||||
|
this.updateLEDs(bitState);
|
||||||
|
|
||||||
|
if (keyCode == Keyboard.KEYCODE.CAPS_LOCK || keyCode == Keyboard.KEYCODE.NUM_LOCK || keyCode == Keyboard.KEYCODE.SCROLL_LOCK) {
|
||||||
/*
|
/*
|
||||||
* FYI, CAPS_LOCK generates a "down" event ONLY when getting locked, and an "up" event ONLY
|
* FYI, "lock" keys generate a "down" event ONLY when getting locked, and an "up" event ONLY
|
||||||
* when getting unlocked--which is exactly what I want, even though that may seem a little
|
* when getting unlocked--which is exactly what I want, even though that may seem a little
|
||||||
* counter-intuitive (since the key itself actually went down AND up for each event).
|
* counter-intuitive.
|
||||||
|
*
|
||||||
|
* However, since the key DID actually go down AND up on each event, we must make sure both make
|
||||||
|
* and break scan codes are delivered; keySimulatePress() will take care of that.
|
||||||
*/
|
*/
|
||||||
fPass = this.keySimulatePress(keyCodeSim);
|
fPass = this.keySimulatePress(keyCodeSim);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1389,7 +1526,7 @@ Keyboard.prototype.keyUpDown = function(event, fDown)
|
||||||
/*
|
/*
|
||||||
* HACK for simulating Ctrl-Break using Ctrl-Del (Mac) / Ctrl-Backspace (Windows)
|
* HACK for simulating Ctrl-Break using Ctrl-Del (Mac) / Ctrl-Backspace (Windows)
|
||||||
*/
|
*/
|
||||||
if (keyCode == Keyboard.KEYCODE.BS && (this.bitsShift & (Keyboard.STATE.CTRL|Keyboard.STATE.ALT)) == Keyboard.STATE.CTRL) {
|
if (keyCode == Keyboard.KEYCODE.BS && (this.shiftStates & (Keyboard.STATES.CTRL|Keyboard.STATES.ALT)) == Keyboard.STATES.CTRL) {
|
||||||
keyCodeSim = Keyboard.KEYCODE.FAKE_CTRLBREAK;
|
keyCodeSim = Keyboard.KEYCODE.FAKE_CTRLBREAK;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
|
|
@ -1427,8 +1564,8 @@ Keyboard.prototype.keyUpDown = function(event, fDown)
|
||||||
/*
|
/*
|
||||||
* Avoid interfering with useful Browser key commands, like COMMAND-Q, COMMAND-T, etc.
|
* Avoid interfering with useful Browser key commands, like COMMAND-Q, COMMAND-T, etc.
|
||||||
*/
|
*/
|
||||||
this.bitsShift &= ~Keyboard.STATE.COMMAND;
|
this.shiftStates &= ~Keyboard.STATES.COMMAND;
|
||||||
if (fDown) this.bitsShift |= Keyboard.STATE.COMMAND;
|
if (fDown) this.shiftStates |= Keyboard.STATES.COMMAND;
|
||||||
fAutoClear = false;
|
fAutoClear = false;
|
||||||
fPass = true;
|
fPass = true;
|
||||||
}
|
}
|
||||||
|
|
@ -1476,7 +1613,7 @@ Keyboard.prototype.keyUpDown = function(event, fDown)
|
||||||
* above that explicitly clear fAutoClear -- such as the COMMAND key itself -- are exceptions
|
* above that explicitly clear fAutoClear -- such as the COMMAND key itself -- are exceptions
|
||||||
* to the rule).
|
* to the rule).
|
||||||
*/
|
*/
|
||||||
this.bitsShift &= ~Keyboard.STATE.COMMAND;
|
this.shiftStates &= ~Keyboard.STATES.COMMAND;
|
||||||
/*
|
/*
|
||||||
* I don't reliably get keyDown/keyUp events for all keys on all devices, but for those devices that
|
* I don't reliably get keyDown/keyUp events for all keys on all devices, but for those devices that
|
||||||
* I DO, it seems like a good idea to cancel any pending key "up" simulation on receipt of the actual
|
* I DO, it seems like a good idea to cancel any pending key "up" simulation on receipt of the actual
|
||||||
|
|
@ -1529,11 +1666,11 @@ Keyboard.prototype.keyPress = function(event)
|
||||||
*/
|
*/
|
||||||
fPass = false;
|
fPass = false;
|
||||||
} else {
|
} else {
|
||||||
if (this.bitsShift & Keyboard.STATE.COMMAND) {
|
if (this.shiftStates & Keyboard.STATES.COMMAND) {
|
||||||
this.bitsShift &= ~Keyboard.STATE.COMMAND;
|
this.shiftStates &= ~Keyboard.STATES.COMMAND;
|
||||||
} else {
|
} else {
|
||||||
// if (DEBUG && event.altKey) this.messageDebugger("ALT press: keyCode " + keyCode, Debugger.MESSAGE.KEYS);
|
// if (DEBUG && event.altKey) this.messageDebugger("ALT press: keyCode " + keyCode, Debugger.MESSAGE.KEYS);
|
||||||
if (this.bitsShift & (Keyboard.STATE.CTRL | Keyboard.STATE.ALT)) {
|
if (this.shiftStates & (Keyboard.STATES.CTRL | Keyboard.STATES.ALT)) {
|
||||||
fPass = false;
|
fPass = false;
|
||||||
} else {
|
} else {
|
||||||
if (this.fEscapeDisabled && keyCode == Keyboard.ASCII['`']) keyCode = Keyboard.KEYCODE.ESC;
|
if (this.fEscapeDisabled && keyCode == Keyboard.ASCII['`']) keyCode = Keyboard.KEYCODE.ESC;
|
||||||
|
|
@ -1547,14 +1684,15 @@ Keyboard.prototype.keyPress = function(event)
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* keySimulatePress(keyCode)
|
* keySimulatePress(keyCode, fCheckShift, fQuickRelease)
|
||||||
*
|
*
|
||||||
* @this {Keyboard}
|
* @this {Keyboard}
|
||||||
* @param {number} keyCode
|
* @param {number} keyCode
|
||||||
|
* @param {boolean} [fCheckShift]
|
||||||
* @param {boolean} [fQuickRelease] is true to simulate the press and release immediately
|
* @param {boolean} [fQuickRelease] is true to simulate the press and release immediately
|
||||||
* @return {boolean} true if successfully simulated, false if unrecognized/unsupported key
|
* @return {boolean} true if successfully simulated, false if unrecognized/unsupported key
|
||||||
*/
|
*/
|
||||||
Keyboard.prototype.keySimulatePress = function(keyCode, fQuickRelease)
|
Keyboard.prototype.keySimulatePress = function(keyCode, fCheckShift, fQuickRelease)
|
||||||
{
|
{
|
||||||
var fSimulated = false;
|
var fSimulated = false;
|
||||||
|
|
||||||
|
|
@ -1563,6 +1701,8 @@ Keyboard.prototype.keySimulatePress = function(keyCode, fQuickRelease)
|
||||||
*/
|
*/
|
||||||
this.autoClear(keyCode);
|
this.autoClear(keyCode);
|
||||||
|
|
||||||
|
if (fCheckShift) this.checkShiftState(keyCode);
|
||||||
|
|
||||||
if (this.keySimulateUpOrDown(keyCode, true, Keyboard.SIMCODE.KEYPRESS)) {
|
if (this.keySimulateUpOrDown(keyCode, true, Keyboard.SIMCODE.KEYPRESS)) {
|
||||||
/*
|
/*
|
||||||
* If fQuickRelease is set, we switch to an alternate approach, which is to immediately queue a
|
* If fQuickRelease is set, we switch to an alternate approach, which is to immediately queue a
|
||||||
|
|
@ -1627,7 +1767,7 @@ Keyboard.prototype.keySimulateUpOrDown = function(keyCode, fDown, simCode)
|
||||||
* whenever both CTRL and ALT are pressed as well, so that it's easier to simulate that old favorite: CTRL-ALT-DEL
|
* whenever both CTRL and ALT are pressed as well, so that it's easier to simulate that old favorite: CTRL-ALT-DEL
|
||||||
*/
|
*/
|
||||||
if (wCode == Keyboard.SCANCODE.BS) {
|
if (wCode == Keyboard.SCANCODE.BS) {
|
||||||
if ((this.bitsShift & (Keyboard.STATE.CTRL | Keyboard.STATE.ALT)) == (Keyboard.STATE.CTRL | Keyboard.STATE.ALT)) {
|
if ((this.shiftStates & (Keyboard.STATES.CTRL | Keyboard.STATES.ALT)) == (Keyboard.STATES.CTRL | Keyboard.STATES.ALT)) {
|
||||||
wCode = Keyboard.SCANCODE.NUM_DEL;
|
wCode = Keyboard.SCANCODE.NUM_DEL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1651,17 +1791,17 @@ Keyboard.prototype.keySimulateUpOrDown = function(keyCode, fDown, simCode)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (bScan == Keyboard.SCANCODE.SHIFT) {
|
if (bScan == Keyboard.SCANCODE.SHIFT) {
|
||||||
if (!(this.bitsShift & (Keyboard.STATE.SHIFT | Keyboard.STATE.RSHIFT))) {
|
if (!(this.shiftStates & (Keyboard.STATES.SHIFT | Keyboard.STATES.RSHIFT))) {
|
||||||
if (!(this.bitsShift & Keyboard.STATE.CAPS_LOCK) || !fAlpha) {
|
if (!(this.shiftStates & Keyboard.STATES.CAPS_LOCK) || !fAlpha) {
|
||||||
bShift = bScan;
|
bShift = bScan;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (bScan == Keyboard.SCANCODE.CTRL) {
|
} else if (bScan == Keyboard.SCANCODE.CTRL) {
|
||||||
if (!(this.bitsShift & (Keyboard.STATE.CTRL | Keyboard.STATE.RCTRL))) {
|
if (!(this.shiftStates & (Keyboard.STATES.CTRL | Keyboard.STATES.RCTRL))) {
|
||||||
bShift = bScan;
|
bShift = bScan;
|
||||||
}
|
}
|
||||||
} else if (bScan == Keyboard.SCANCODE.ALT) {
|
} else if (bScan == Keyboard.SCANCODE.ALT) {
|
||||||
if (!(this.bitsShift & (Keyboard.STATE.ALT | Keyboard.STATE.RALT))) {
|
if (!(this.shiftStates & (Keyboard.STATES.ALT | Keyboard.STATES.RALT))) {
|
||||||
bShift = bScan;
|
bShift = bScan;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -87,8 +87,9 @@ if (typeof module !== 'undefined') {
|
||||||
* or setPixel().
|
* or setPixel().
|
||||||
*
|
*
|
||||||
* Thanks to the CPU's new block-based memory manager that allows us to sparse-allocate memory
|
* Thanks to the CPU's new block-based memory manager that allows us to sparse-allocate memory
|
||||||
* in 4K increments, updateScreen() can also ask the CPU for the "dirty" state of all the blocks
|
* (in 4Kb increments on 20-bit buses, 16Kb increments on 24-bit buses), updateScreen()
|
||||||
* underlying the video buffer, bypassing the update completely if the buffer is still clean.
|
* can also ask the CPU for the "dirty" state of all the blocks underlying the video buffer,
|
||||||
|
* bypassing the update completely if the buffer is still clean.
|
||||||
*
|
*
|
||||||
* Unfortunately, that optimization is defeated if our count of active blink elements is non-zero,
|
* Unfortunately, that optimization is defeated if our count of active blink elements is non-zero,
|
||||||
* because we must rescan the entire buffer to locate and redraw them all; I'm assuming for now
|
* because we must rescan the entire buffer to locate and redraw them all; I'm assuming for now
|
||||||
|
|
@ -499,8 +500,8 @@ Video.MODES.UNKNOWN = 0xFF;
|
||||||
* Supported Fonts
|
* Supported Fonts
|
||||||
*
|
*
|
||||||
* Once we've finished loading the standard 8K font file, aFonts[] should contain one or more of the
|
* Once we've finished loading the standard 8K font file, aFonts[] should contain one or more of the
|
||||||
* fonts listed below. For the standard MDA/CGA font ROM, the first (MDA) font resides in the first 4K,
|
* fonts listed below. For the standard MDA/CGA font ROM, the first (MDA) font resides in the first 4Kb,
|
||||||
* and the second and third (CGA) fonts reside in the two 2K halves of the second 4K.
|
* and the second and third (CGA) fonts reside in the two 2K halves of the second 4Kb.
|
||||||
*
|
*
|
||||||
* It may seem odd that the cell size for FONT_CGAD is *larger* than the cell size for FONT_CGA,
|
* It may seem odd that the cell size for FONT_CGAD is *larger* than the cell size for FONT_CGA,
|
||||||
* since 40-column mode is actually lower resolution, but since we don't shrink the window when we shrink
|
* since 40-column mode is actually lower resolution, but since we don't shrink the window when we shrink
|
||||||
|
|
@ -1018,7 +1019,7 @@ Card.MISC.IO_SELECT = 0x01; // 0 sets CRT ports to 0x3Bn, 1 sets CRT
|
||||||
Card.MISC.ENABLE_RAM = 0x02; // 0 disables video RAM, 1 enables
|
Card.MISC.ENABLE_RAM = 0x02; // 0 disables video RAM, 1 enables
|
||||||
Card.MISC.CLK_SELECT = 0x0C; // 0x0: 14Mhz I/O clock, 0x4: 16Mhz on-board clock, 0x8: external clock, 0xC: unused
|
Card.MISC.CLK_SELECT = 0x0C; // 0x0: 14Mhz I/O clock, 0x4: 16Mhz on-board clock, 0x8: external clock, 0xC: unused
|
||||||
Card.MISC.DISABLE_DRV = 0x10; // 0 activates internal video drivers, 1 activates feature connector direct drive outputs
|
Card.MISC.DISABLE_DRV = 0x10; // 0 activates internal video drivers, 1 activates feature connector direct drive outputs
|
||||||
Card.MISC.PAGE_ODD_EVEN = 0x20; // 0 selects the low 64K page of video RAM for text modes, 1 selects the high page
|
Card.MISC.PAGE_ODD_EVEN = 0x20; // 0 selects the low 64Kb page of video RAM for text modes, 1 selects the high page
|
||||||
Card.MISC.HORZ_POLARITY = 0x40; // 0 selects positive horizontal retrace
|
Card.MISC.HORZ_POLARITY = 0x40; // 0 selects positive horizontal retrace
|
||||||
Card.MISC.VERT_POLARITY = 0x80; // 0 selects positive vertical retrace
|
Card.MISC.VERT_POLARITY = 0x80; // 0 selects positive vertical retrace
|
||||||
|
|
||||||
|
|
@ -1981,6 +1982,9 @@ Video.prototype.initBus = function(cmp, bus, cpu, dbg)
|
||||||
*/
|
*/
|
||||||
this.kbd = cmp.getComponentByType("Keyboard");
|
this.kbd = cmp.getComponentByType("Keyboard");
|
||||||
if (this.kbd && this.canvasScreen) {
|
if (this.kbd && this.canvasScreen) {
|
||||||
|
for (var s in this.bindings) {
|
||||||
|
if (s.indexOf("lock") > 0) this.kbd.setBinding("input", "led", s, this.bindings[s]);
|
||||||
|
}
|
||||||
this.kbd.setBinding("input", this.textareaScreen? "textarea" : "canvas", "kbd", this.textareaScreen || this.canvasScreen);
|
this.kbd.setBinding("input", this.textareaScreen? "textarea" : "canvas", "kbd", this.textareaScreen || this.canvasScreen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2008,10 +2012,17 @@ Video.prototype.setBinding = function(sHTMLClass, sHTMLType, sBinding, control)
|
||||||
var video = this;
|
var video = this;
|
||||||
var canvas, lockPointer;
|
var canvas, lockPointer;
|
||||||
|
|
||||||
|
if (!this.bindings[sBinding]) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We now save every binding that comes in, so that if there are bindings for "caps-lock' and the like,
|
||||||
|
* we can forward them to the Keyboard.
|
||||||
|
*/
|
||||||
|
this.bindings[sBinding] = control;
|
||||||
|
|
||||||
switch (sBinding) {
|
switch (sBinding) {
|
||||||
|
|
||||||
case "lockPointer":
|
case "lockPointer":
|
||||||
this.bindings[sBinding] = control;
|
|
||||||
this.sLockMessage = control.innerHTML;
|
this.sLockMessage = control.innerHTML;
|
||||||
if (this.canvasScreen && this.canvasScreen.lockPointer) {
|
if (this.canvasScreen && this.canvasScreen.lockPointer) {
|
||||||
control.onclick = function onClickLockPointer() {
|
control.onclick = function onClickLockPointer() {
|
||||||
|
|
@ -2025,7 +2036,6 @@ Video.prototype.setBinding = function(sHTMLClass, sHTMLType, sBinding, control)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case "refresh":
|
case "refresh":
|
||||||
this.bindings[sBinding] = control;
|
|
||||||
control.onclick = function onClickRefresh() {
|
control.onclick = function onClickRefresh() {
|
||||||
if (DEBUG) video.messageDebugger("refreshScreen()");
|
if (DEBUG) video.messageDebugger("refreshScreen()");
|
||||||
video.updateScreen(true);
|
video.updateScreen(true);
|
||||||
|
|
@ -2035,6 +2045,7 @@ Video.prototype.setBinding = function(sHTMLClass, sHTMLType, sBinding, control)
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -99,6 +99,16 @@
|
||||||
line-height: 34px; /* the equivalent of "vertical-align: middle" for single-line elements */
|
line-height: 34px; /* the equivalent of "vertical-align: middle" for single-line elements */
|
||||||
background-color: #ffffff;
|
background-color: #ffffff;
|
||||||
}
|
}
|
||||||
|
.pcjs-led {
|
||||||
|
float: left;
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
margin: 4px;
|
||||||
|
border: 1px solid black;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 19px; /* the equivalent of "vertical-align: middle" for single-line elements */
|
||||||
|
background-color: #000000;
|
||||||
|
}
|
||||||
.pcjs-reference {
|
.pcjs-reference {
|
||||||
float: left;
|
float: left;
|
||||||
font-size: x-small;
|
font-size: x-small;
|
||||||
|
|
|
||||||
|
|
@ -378,6 +378,9 @@
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</form>
|
</form>
|
||||||
</xsl:when>
|
</xsl:when>
|
||||||
|
<xsl:when test="@type = 'led'">
|
||||||
|
<div class="{$APPCLASS}-{@class} {$APPCLASS}-{@type}" data-value="{$type},{$binding}"><xsl:value-of select="."/></div>
|
||||||
|
</xsl:when>
|
||||||
<xsl:when test="@type = 'separator'">
|
<xsl:when test="@type = 'separator'">
|
||||||
<hr/>
|
<hr/>
|
||||||
</xsl:when>
|
</xsl:when>
|
||||||
|
|
|
||||||
|
|
@ -509,21 +509,21 @@ if (window && !window.document.ELEMENT_NODE) window.document.ELEMENT_NODE = 1;
|
||||||
*/
|
*/
|
||||||
Component.bindComponentControls = function(component, element, sAppClass)
|
Component.bindComponentControls = function(component, element, sAppClass)
|
||||||
{
|
{
|
||||||
var iControl, aeControls;
|
var aeControls = Component.getElementsByClass(element.parentNode, sAppClass + "-control");
|
||||||
aeControls = Component.getElementsByClass(element.parentNode, sAppClass + "-control");
|
|
||||||
for (iControl = 0; iControl < aeControls.length; iControl++) {
|
for (var iControl = 0; iControl < aeControls.length; iControl++) {
|
||||||
var iNode, aeChildNodes;
|
|
||||||
aeChildNodes = aeControls[iControl].childNodes;
|
var aeChildNodes = aeControls[iControl].childNodes;
|
||||||
for (iNode = 0; iNode < aeChildNodes.length; iNode++) {
|
|
||||||
|
for (var iNode = 0; iNode < aeChildNodes.length; iNode++) {
|
||||||
var control = aeChildNodes[iNode];
|
var control = aeChildNodes[iNode];
|
||||||
if (control.nodeType !== window.document.ELEMENT_NODE) {
|
if (control.nodeType !== window.document.ELEMENT_NODE) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
var sClass = control.getAttribute("class");
|
var sClass = control.getAttribute("class");
|
||||||
if (!sClass) continue;
|
if (!sClass) continue;
|
||||||
var iClass, aClasses;
|
var aClasses = sClass.split(" ");
|
||||||
aClasses = sClass.split(" ");
|
for (var iClass = 0; iClass < aClasses.length; iClass++) {
|
||||||
for (iClass = 0; iClass < aClasses.length; iClass++) {
|
|
||||||
var parms;
|
var parms;
|
||||||
sClass = aClasses[iClass];
|
sClass = aClasses[iClass];
|
||||||
switch (sClass) {
|
switch (sClass) {
|
||||||
|
|
@ -535,7 +535,7 @@ Component.bindComponentControls = function(component, element, sAppClass)
|
||||||
} else {
|
} else {
|
||||||
Component.log('Component.bindComponentControls("' + component.toString() + '"): missing binding' + (parms? ' for ' + parms['type'] : ''), "warning");
|
Component.log('Component.bindComponentControls("' + component.toString() + '"): missing binding' + (parms? ' for ' + parms['type'] : ''), "warning");
|
||||||
}
|
}
|
||||||
aClasses = [];
|
iClass = aClasses.length;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// Component.log("Component.bindComponentControls(" + component.toString() + "): unrecognized control class \"" + sClass + "\"", "warning");
|
// Component.log("Component.bindComponentControls(" + component.toString() + "): unrecognized control class \"" + sClass + "\"", "warning");
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -94,6 +94,16 @@
|
||||||
line-height: 34px;
|
line-height: 34px;
|
||||||
background-color: #ffffff;
|
background-color: #ffffff;
|
||||||
}
|
}
|
||||||
|
.pcjs-led {
|
||||||
|
float: left;
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
margin: 4px;
|
||||||
|
border: 1px solid black;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 19px;
|
||||||
|
background-color: #000000;
|
||||||
|
}
|
||||||
.pcjs-reference {
|
.pcjs-reference {
|
||||||
float: left;
|
float: left;
|
||||||
font-size: x-small;
|
font-size: x-small;
|
||||||
|
|
|
||||||
|
|
@ -377,6 +377,9 @@
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</form>
|
</form>
|
||||||
</xsl:when>
|
</xsl:when>
|
||||||
|
<xsl:when test="@type = 'led'">
|
||||||
|
<div class="{$APPCLASS}-{@class} {$APPCLASS}-{@type}" data-value="{$type},{$binding}"><xsl:value-of select="."/></div>
|
||||||
|
</xsl:when>
|
||||||
<xsl:when test="@type = 'separator'">
|
<xsl:when test="@type = 'separator'">
|
||||||
<hr/>
|
<hr/>
|
||||||
</xsl:when>
|
</xsl:when>
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue