mirror of
https://github.com/irmen/ksim65.git
synced 2024-09-28 14:54:53 +00:00
Custom c64 key mapping to make typing on a modern keyboard tolerable. Connected Restore key (backslash) to NMI.
This commit is contained in:
parent
bfdd9aa656
commit
88c1688a41
@ -15,6 +15,7 @@
|
|||||||
<option value="$PROJECT_DIR$" />
|
<option value="$PROJECT_DIR$" />
|
||||||
</set>
|
</set>
|
||||||
</option>
|
</option>
|
||||||
|
<option name="useAutoImport" value="true" />
|
||||||
<option name="useQualifiedModuleNames" value="true" />
|
<option name="useQualifiedModuleNames" value="true" />
|
||||||
</GradleProjectSettings>
|
</GradleProjectSettings>
|
||||||
</option>
|
</option>
|
||||||
|
@ -9,11 +9,13 @@ import java.awt.event.KeyEvent
|
|||||||
* Minimal simulation of the MOS 6526 CIA chip.
|
* Minimal simulation of the MOS 6526 CIA chip.
|
||||||
* Depending on what CIA it is (1 or 2), some registers do different things on the C64.
|
* Depending on what CIA it is (1 or 2), some registers do different things on the C64.
|
||||||
*/
|
*/
|
||||||
class Cia(val number: Int, startAddress: Address, endAddress: Address): MemMappedComponent(startAddress, endAddress) {
|
class Cia(val number: Int, startAddress: Address, endAddress: Address) : MemMappedComponent(startAddress, endAddress) {
|
||||||
private var ramBuffer = Array<UByte>(endAddress - startAddress + 1) { 0x00 }
|
private var ramBuffer = Array<UByte>(endAddress - startAddress + 1) { 0x00 }
|
||||||
private var pra = 0xff
|
private var pra = 0xff
|
||||||
|
|
||||||
private val hostKeyPresses = mutableSetOf<Int>()
|
private data class HostKeyPress(val code: Int, val rightSide: Boolean, val numpad: Boolean)
|
||||||
|
|
||||||
|
private val hostKeyPresses = mutableSetOf<HostKeyPress>()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
require(endAddress - startAddress + 1 == 256) { "cia requires exactly 256 memory bytes (16*16 mirrored)" }
|
require(endAddress - startAddress + 1 == 256) { "cia requires exactly 256 memory bytes (16*16 mirrored)" }
|
||||||
@ -24,134 +26,165 @@ class Cia(val number: Int, startAddress: Address, endAddress: Address): MemMappe
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun reset() {
|
override fun reset() {
|
||||||
|
hostKeyPresses.clear()
|
||||||
// TODO: reset TOD timer, timer A and B
|
// TODO: reset TOD timer, timer A and B
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun get(address: Address): UByte {
|
override fun get(address: Address): UByte {
|
||||||
|
fun scanColumn(keys: List<HostKeyPress>): UByte {
|
||||||
|
var bits = 0b10000000
|
||||||
|
var presses = 0
|
||||||
|
for (key in keys) {
|
||||||
|
if (key in hostKeyPresses) presses = presses or bits
|
||||||
|
bits = bits ushr 1
|
||||||
|
}
|
||||||
|
return (presses.inv() and 255).toShort()
|
||||||
|
}
|
||||||
|
|
||||||
val register = (address - startAddress) and 15
|
val register = (address - startAddress) and 15
|
||||||
if(number==1) {
|
if (number == 1) {
|
||||||
return if (register == 0x01) {
|
return if (register == 0x01) {
|
||||||
// register 1 on CIA#1 is the keyboard data port
|
// register 1 on CIA#1 is the keyboard data port
|
||||||
// if bit is cleared in PRA, contains keys pressed in that column of the matrix
|
// if bit is cleared in PRA, contains keys pressed in that column of the matrix
|
||||||
// TODO tweak the keyboard mapping so that keys like '=' can be pressed,
|
when (pra) {
|
||||||
// RESTORE works (this is not a normal key but connected to the cpu's NMI line),
|
|
||||||
// Cursor up/down/left/right all work and left/right shift are different.
|
|
||||||
when(pra) {
|
|
||||||
0b00000000 -> {
|
0b00000000 -> {
|
||||||
// check if any keys are pressed at all (by checking all columns at once)
|
// check if any keys are pressed at all (by checking all columns at once)
|
||||||
if(hostKeyPresses.isEmpty()) 0xff.toShort() else 0x00.toShort()
|
if (hostKeyPresses.isEmpty()) 0xff.toShort() else 0x00.toShort()
|
||||||
}
|
}
|
||||||
0b11111110 -> {
|
0b11111110 -> {
|
||||||
// read column 0
|
// read column 0
|
||||||
val presses =
|
scanColumn(
|
||||||
(if (KeyEvent.VK_DOWN in hostKeyPresses) 0b10000000 else 0) or
|
listOf(
|
||||||
(if (KeyEvent.VK_F5 in hostKeyPresses) 0b01000000 else 0) or
|
HostKeyPress(KeyEvent.VK_DOWN, rightSide = false, numpad = false),
|
||||||
(if (KeyEvent.VK_F3 in hostKeyPresses) 0b00100000 else 0) or
|
HostKeyPress(KeyEvent.VK_F5, rightSide = false, numpad = false),
|
||||||
(if (KeyEvent.VK_F1 in hostKeyPresses) 0b00010000 else 0) or
|
HostKeyPress(KeyEvent.VK_F3, rightSide = false, numpad = false),
|
||||||
(if (KeyEvent.VK_F7 in hostKeyPresses) 0b00001000 else 0) or
|
HostKeyPress(KeyEvent.VK_F1, rightSide = false, numpad = false),
|
||||||
(if (KeyEvent.VK_RIGHT in hostKeyPresses) 0b00000100 else 0) or
|
HostKeyPress(KeyEvent.VK_F7, rightSide = false, numpad = false),
|
||||||
(if (KeyEvent.VK_ENTER in hostKeyPresses) 0b00000010 else 0) or
|
HostKeyPress(KeyEvent.VK_RIGHT, rightSide = false, numpad = false),
|
||||||
(if (KeyEvent.VK_BACK_SPACE in hostKeyPresses) 0b00000001 else 0)
|
HostKeyPress(KeyEvent.VK_ENTER, rightSide = false, numpad = false),
|
||||||
(presses.inv() and 255).toShort()
|
HostKeyPress(KeyEvent.VK_BACK_SPACE, rightSide = false, numpad = false)
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
0b11111101 -> {
|
0b11111101 -> {
|
||||||
// read column 1
|
// read column 1
|
||||||
val presses =
|
scanColumn(
|
||||||
(if(KeyEvent.VK_SHIFT in hostKeyPresses) 0b10000000 else 0) or // TODO make it LEFT shift only
|
listOf(
|
||||||
(if(KeyEvent.VK_E in hostKeyPresses) 0b01000000 else 0) or
|
HostKeyPress(KeyEvent.VK_SHIFT, rightSide = false, numpad = false), // left shift
|
||||||
(if(KeyEvent.VK_S in hostKeyPresses) 0b00100000 else 0) or
|
HostKeyPress(KeyEvent.VK_E, rightSide = false, numpad = false),
|
||||||
(if(KeyEvent.VK_Z in hostKeyPresses) 0b00010000 else 0) or
|
HostKeyPress(KeyEvent.VK_S, rightSide = false, numpad = false),
|
||||||
(if(KeyEvent.VK_4 in hostKeyPresses) 0b00001000 else 0) or
|
HostKeyPress(KeyEvent.VK_Z, rightSide = false, numpad = false),
|
||||||
(if(KeyEvent.VK_A in hostKeyPresses) 0b00000100 else 0) or
|
HostKeyPress(KeyEvent.VK_4, rightSide = false, numpad = false),
|
||||||
(if(KeyEvent.VK_W in hostKeyPresses) 0b00000010 else 0) or
|
HostKeyPress(KeyEvent.VK_A, rightSide = false, numpad = false),
|
||||||
(if(KeyEvent.VK_3 in hostKeyPresses) 0b00000001 else 0)
|
HostKeyPress(KeyEvent.VK_W, rightSide = false, numpad = false),
|
||||||
(presses.inv() and 255).toShort()
|
HostKeyPress(KeyEvent.VK_3, rightSide = false, numpad = false)
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
0b11111011 -> {
|
0b11111011 -> {
|
||||||
// read column 2
|
// read column 2
|
||||||
val presses =
|
scanColumn(
|
||||||
(if (KeyEvent.VK_X in hostKeyPresses) 0b10000000 else 0) or
|
listOf(
|
||||||
(if (KeyEvent.VK_T in hostKeyPresses) 0b01000000 else 0) or
|
HostKeyPress(KeyEvent.VK_X, rightSide = false, numpad = false),
|
||||||
(if (KeyEvent.VK_F in hostKeyPresses) 0b00100000 else 0) or
|
HostKeyPress(KeyEvent.VK_T, rightSide = false, numpad = false),
|
||||||
(if (KeyEvent.VK_C in hostKeyPresses) 0b00010000 else 0) or
|
HostKeyPress(KeyEvent.VK_F, rightSide = false, numpad = false),
|
||||||
(if (KeyEvent.VK_6 in hostKeyPresses) 0b00001000 else 0) or
|
HostKeyPress(KeyEvent.VK_C, rightSide = false, numpad = false),
|
||||||
(if (KeyEvent.VK_D in hostKeyPresses) 0b00000100 else 0) or
|
HostKeyPress(KeyEvent.VK_6, rightSide = false, numpad = false),
|
||||||
(if (KeyEvent.VK_R in hostKeyPresses) 0b00000010 else 0) or
|
HostKeyPress(KeyEvent.VK_D, rightSide = false, numpad = false),
|
||||||
(if (KeyEvent.VK_5 in hostKeyPresses) 0b00000001 else 0)
|
HostKeyPress(KeyEvent.VK_R, rightSide = false, numpad = false),
|
||||||
(presses.inv() and 255).toShort()
|
HostKeyPress(KeyEvent.VK_5, rightSide = false, numpad = false)
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
0b11110111 -> {
|
0b11110111 -> {
|
||||||
// read column 3
|
// read column 3
|
||||||
val presses =
|
scanColumn(
|
||||||
(if (KeyEvent.VK_V in hostKeyPresses) 0b10000000 else 0) or
|
listOf(
|
||||||
(if (KeyEvent.VK_U in hostKeyPresses) 0b01000000 else 0) or
|
HostKeyPress(KeyEvent.VK_V, rightSide = false, numpad = false),
|
||||||
(if (KeyEvent.VK_H in hostKeyPresses) 0b00100000 else 0) or
|
HostKeyPress(KeyEvent.VK_U, rightSide = false, numpad = false),
|
||||||
(if (KeyEvent.VK_B in hostKeyPresses) 0b00010000 else 0) or
|
HostKeyPress(KeyEvent.VK_H, rightSide = false, numpad = false),
|
||||||
(if (KeyEvent.VK_8 in hostKeyPresses) 0b00001000 else 0) or
|
HostKeyPress(KeyEvent.VK_B, rightSide = false, numpad = false),
|
||||||
(if (KeyEvent.VK_G in hostKeyPresses) 0b00000100 else 0) or
|
HostKeyPress(KeyEvent.VK_8, rightSide = false, numpad = false),
|
||||||
(if (KeyEvent.VK_Y in hostKeyPresses) 0b00000010 else 0) or
|
HostKeyPress(KeyEvent.VK_G, rightSide = false, numpad = false),
|
||||||
(if (KeyEvent.VK_7 in hostKeyPresses) 0b00000001 else 0)
|
HostKeyPress(KeyEvent.VK_Y, rightSide = false, numpad = false),
|
||||||
(presses.inv() and 255).toShort()
|
HostKeyPress(KeyEvent.VK_7, rightSide = false, numpad = false)
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
0b11101111 -> {
|
0b11101111 -> {
|
||||||
// read column 4
|
// read column 4
|
||||||
val presses =
|
scanColumn(
|
||||||
(if (KeyEvent.VK_N in hostKeyPresses) 0b10000000 else 0) or
|
listOf(
|
||||||
(if (KeyEvent.VK_O in hostKeyPresses) 0b01000000 else 0) or
|
HostKeyPress(KeyEvent.VK_N, rightSide = false, numpad = false),
|
||||||
(if (KeyEvent.VK_K in hostKeyPresses) 0b00100000 else 0) or
|
HostKeyPress(KeyEvent.VK_O, rightSide = false, numpad = false),
|
||||||
(if (KeyEvent.VK_M in hostKeyPresses) 0b00010000 else 0) or
|
HostKeyPress(KeyEvent.VK_K, rightSide = false, numpad = false),
|
||||||
(if (KeyEvent.VK_0 in hostKeyPresses) 0b00001000 else 0) or
|
HostKeyPress(KeyEvent.VK_M, rightSide = false, numpad = false),
|
||||||
(if (KeyEvent.VK_J in hostKeyPresses) 0b00000100 else 0) or
|
HostKeyPress(KeyEvent.VK_0, rightSide = false, numpad = false),
|
||||||
(if (KeyEvent.VK_I in hostKeyPresses) 0b00000010 else 0) or
|
HostKeyPress(KeyEvent.VK_J, rightSide = false, numpad = false),
|
||||||
(if (KeyEvent.VK_9 in hostKeyPresses) 0b00000001 else 0)
|
HostKeyPress(KeyEvent.VK_I, rightSide = false, numpad = false),
|
||||||
(presses.inv() and 255).toShort()
|
HostKeyPress(KeyEvent.VK_9, rightSide = false, numpad = false)
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
0b11011111 -> {
|
0b11011111 -> {
|
||||||
// read column 5
|
// read column 5
|
||||||
val presses =
|
scanColumn(
|
||||||
(if (KeyEvent.VK_COMMA in hostKeyPresses) 0b10000000 else 0) or
|
listOf(
|
||||||
(if (KeyEvent.VK_OPEN_BRACKET in hostKeyPresses) 0b01000000 else 0) or // '[' = @
|
HostKeyPress(KeyEvent.VK_COMMA, rightSide = false, numpad = false),
|
||||||
(if (KeyEvent.VK_SEMICOLON in hostKeyPresses) 0b00100000 else 0) or // ';' -> :
|
HostKeyPress(KeyEvent.VK_AT, rightSide = false, numpad = false),
|
||||||
(if (KeyEvent.VK_PERIOD in hostKeyPresses) 0b00010000 else 0) or
|
HostKeyPress(KeyEvent.VK_COLON, rightSide = false, numpad = false),
|
||||||
(if (KeyEvent.VK_MINUS in hostKeyPresses) 0b00001000 else 0) or
|
HostKeyPress(KeyEvent.VK_PERIOD, rightSide = false, numpad = false),
|
||||||
(if (KeyEvent.VK_L in hostKeyPresses) 0b00000100 else 0) or
|
HostKeyPress(KeyEvent.VK_MINUS, rightSide = false, numpad = false),
|
||||||
(if (KeyEvent.VK_P in hostKeyPresses) 0b00000010 else 0) or
|
HostKeyPress(KeyEvent.VK_L, rightSide = false, numpad = false),
|
||||||
(if (KeyEvent.VK_PLUS in hostKeyPresses) 0b00000001 else 0)
|
HostKeyPress(KeyEvent.VK_P, rightSide = false, numpad = false),
|
||||||
(presses.inv() and 255).toShort()
|
HostKeyPress(KeyEvent.VK_PLUS, rightSide = false, numpad = false)
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
0b10111111 -> {
|
0b10111111 -> {
|
||||||
// read column 6
|
// read column 6
|
||||||
val presses =
|
scanColumn(
|
||||||
(if (KeyEvent.VK_SLASH in hostKeyPresses) 0b10000000 else 0) or
|
listOf(
|
||||||
(if (KeyEvent.VK_BACK_SLASH in hostKeyPresses) 0b01000000 else 0) or // '\' -> up arrow
|
HostKeyPress(KeyEvent.VK_SLASH, rightSide = false, numpad = false),
|
||||||
(if (KeyEvent.VK_EQUALS in hostKeyPresses) 0b00100000 else 0) or
|
HostKeyPress(KeyEvent.VK_CIRCUMFLEX, rightSide = false, numpad = false),
|
||||||
(if (KeyEvent.VK_SHIFT in hostKeyPresses) 0b00010000 else 0) or // TODO RIGHT shift only
|
HostKeyPress(KeyEvent.VK_EQUALS, rightSide = false, numpad = false),
|
||||||
(if (KeyEvent.VK_HOME in hostKeyPresses) 0b00001000 else 0) or
|
HostKeyPress(
|
||||||
(if (KeyEvent.VK_QUOTE in hostKeyPresses) 0b00000100 else 0) or // ' -> ;
|
KeyEvent.VK_SHIFT,
|
||||||
(if (KeyEvent.VK_CLOSE_BRACKET in hostKeyPresses) 0b00000010 else 0) or // ']' = *
|
rightSide = true,
|
||||||
(if (KeyEvent.VK_END in hostKeyPresses) 0b00000001 else 0) // END -> pound key
|
numpad = false
|
||||||
(presses.inv() and 255).toShort()
|
), // right shift
|
||||||
|
HostKeyPress(KeyEvent.VK_HOME, rightSide = false, numpad = false),
|
||||||
|
HostKeyPress(KeyEvent.VK_SEMICOLON, rightSide = false, numpad = false),
|
||||||
|
HostKeyPress(KeyEvent.VK_ASTERISK, rightSide = false, numpad = false),
|
||||||
|
HostKeyPress(
|
||||||
|
KeyEvent.VK_DEAD_TILDE,
|
||||||
|
rightSide = false,
|
||||||
|
numpad = false
|
||||||
|
) // pound sign
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
0b01111111 -> {
|
0b01111111 -> {
|
||||||
// read column 7
|
// read column 7
|
||||||
val presses =
|
scanColumn(
|
||||||
(if (KeyEvent.VK_ESCAPE in hostKeyPresses) 0b10000000 else 0) or // esc -> STOP
|
listOf(
|
||||||
(if (KeyEvent.VK_Q in hostKeyPresses) 0b01000000 else 0) or
|
HostKeyPress(KeyEvent.VK_ESCAPE, rightSide = false, numpad = false),
|
||||||
(if (KeyEvent.VK_ALT in hostKeyPresses) 0b00100000 else 0) or // alt -> Commodore
|
HostKeyPress(KeyEvent.VK_Q, rightSide = false, numpad = false),
|
||||||
(if (KeyEvent.VK_SPACE in hostKeyPresses) 0b00010000 else 0) or
|
HostKeyPress(KeyEvent.VK_ALT, rightSide = false, numpad = false),
|
||||||
(if (KeyEvent.VK_2 in hostKeyPresses) 0b00001000 else 0) or
|
HostKeyPress(KeyEvent.VK_SPACE, rightSide = false, numpad = false),
|
||||||
(if (KeyEvent.VK_CONTROL in hostKeyPresses) 0b00000100 else 0) or
|
HostKeyPress(KeyEvent.VK_2, rightSide = false, numpad = false),
|
||||||
(if (KeyEvent.VK_BACK_QUOTE in hostKeyPresses) 0b00000010 else 0) or // '`' -> left arrow
|
HostKeyPress(KeyEvent.VK_CONTROL, rightSide = false, numpad = false),
|
||||||
(if (KeyEvent.VK_1 in hostKeyPresses) 0b00000001 else 0)
|
HostKeyPress(KeyEvent.VK_BACK_QUOTE, rightSide = false, numpad = false),
|
||||||
(presses.inv() and 255).toShort()
|
HostKeyPress(KeyEvent.VK_1, rightSide = false, numpad = false)
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
// invalid column selection
|
// invalid column selection
|
||||||
0xff
|
0xff
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else ramBuffer[register]
|
||||||
else ramBuffer[register]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CIA #2 is not emulated yet
|
// CIA #2 is not emulated yet
|
||||||
@ -161,7 +194,7 @@ class Cia(val number: Int, startAddress: Address, endAddress: Address): MemMappe
|
|||||||
override fun set(address: Address, data: UByte) {
|
override fun set(address: Address, data: UByte) {
|
||||||
val register = (address - startAddress) and 15
|
val register = (address - startAddress) and 15
|
||||||
ramBuffer[register] = data
|
ramBuffer[register] = data
|
||||||
if(number==1) {
|
if (number == 1) {
|
||||||
when (register) {
|
when (register) {
|
||||||
0x00 -> {
|
0x00 -> {
|
||||||
// PRA data port A (select keyboard matrix column)
|
// PRA data port A (select keyboard matrix column)
|
||||||
@ -173,9 +206,127 @@ class Cia(val number: Int, startAddress: Address, endAddress: Address): MemMappe
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun hostKeyPressed(event: KeyEvent) {
|
fun hostKeyPressed(event: KeyEvent) {
|
||||||
if(event.id==KeyEvent.KEY_PRESSED)
|
val rightSide = event.keyLocation == KeyEvent.KEY_LOCATION_RIGHT
|
||||||
hostKeyPresses.add(event.keyCode)
|
val numpad = event.keyLocation == KeyEvent.KEY_LOCATION_NUMPAD
|
||||||
else if(event.id==KeyEvent.KEY_RELEASED)
|
val shift = HostKeyPress(KeyEvent.VK_SHIFT, rightSide = true, numpad = false)
|
||||||
hostKeyPresses.remove(event.keyCode)
|
|
||||||
|
fun register(eventId: Int, vararg keys: HostKeyPress) {
|
||||||
|
if (eventId == KeyEvent.KEY_PRESSED) keys.forEach { hostKeyPresses.add(it) }
|
||||||
|
else keys.forEach { hostKeyPresses.remove(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun unregister(keyCode: Int) {
|
||||||
|
hostKeyPresses.removeAll { it.code == keyCode }
|
||||||
|
}
|
||||||
|
|
||||||
|
// to avoid some 'stuck' keys, if we receive a shift/control/alt RELEASE, we wipe the keyboard buffer
|
||||||
|
// (this can happen becase we're changing the keycode for some pressed keys below,
|
||||||
|
// and a released key doesn't always match the pressed keycode anymore then)
|
||||||
|
if (event.id == KeyEvent.KEY_RELEASED && event.keyCode in listOf(
|
||||||
|
KeyEvent.VK_SHIFT,
|
||||||
|
KeyEvent.VK_CONTROL,
|
||||||
|
KeyEvent.VK_ALT,
|
||||||
|
KeyEvent.VK_ALT_GRAPH
|
||||||
|
)
|
||||||
|
) hostKeyPresses.clear()
|
||||||
|
|
||||||
|
// try to remap the keys a bit so a modern PC keyboard maps better to the keys of the C64
|
||||||
|
when {
|
||||||
|
event.keyChar == '@' -> {
|
||||||
|
unregister(KeyEvent.VK_SHIFT)
|
||||||
|
register(event.id, HostKeyPress(KeyEvent.VK_AT, rightSide = false, numpad = false))
|
||||||
|
}
|
||||||
|
event.keyChar == '^' -> {
|
||||||
|
unregister(KeyEvent.VK_SHIFT)
|
||||||
|
register(event.id, HostKeyPress(KeyEvent.VK_CIRCUMFLEX, rightSide = false, numpad = false))
|
||||||
|
}
|
||||||
|
event.keyChar == '&' -> {
|
||||||
|
register(event.id, shift, HostKeyPress(KeyEvent.VK_6, rightSide = false, numpad = false))
|
||||||
|
}
|
||||||
|
event.keyChar == '*' -> {
|
||||||
|
unregister(KeyEvent.VK_SHIFT)
|
||||||
|
register(event.id, HostKeyPress(KeyEvent.VK_ASTERISK, rightSide = false, numpad = false))
|
||||||
|
}
|
||||||
|
event.keyChar == '(' -> {
|
||||||
|
register(event.id, shift, HostKeyPress(KeyEvent.VK_8, rightSide = false, numpad = false))
|
||||||
|
}
|
||||||
|
event.keyChar == ')' -> {
|
||||||
|
register(event.id, shift, HostKeyPress(KeyEvent.VK_9, rightSide = false, numpad = false))
|
||||||
|
}
|
||||||
|
event.keyChar == '[' -> {
|
||||||
|
register(event.id, shift, HostKeyPress(KeyEvent.VK_COLON, rightSide = false, numpad = false))
|
||||||
|
}
|
||||||
|
event.keyChar == ']' -> {
|
||||||
|
register(event.id, shift, HostKeyPress(KeyEvent.VK_SEMICOLON, rightSide = false, numpad = false))
|
||||||
|
}
|
||||||
|
event.keyChar == '+' -> {
|
||||||
|
unregister(KeyEvent.VK_SHIFT)
|
||||||
|
register(event.id, HostKeyPress(KeyEvent.VK_PLUS, rightSide = false, numpad = false))
|
||||||
|
}
|
||||||
|
event.keyChar == '"' -> {
|
||||||
|
register(event.id, HostKeyPress(KeyEvent.VK_2, rightSide = false, numpad = false))
|
||||||
|
}
|
||||||
|
event.keyChar == ':' -> {
|
||||||
|
unregister(KeyEvent.VK_SHIFT)
|
||||||
|
register(event.id, HostKeyPress(KeyEvent.VK_COLON, rightSide = false, numpad = false))
|
||||||
|
}
|
||||||
|
event.keyChar == '~' -> {
|
||||||
|
unregister(KeyEvent.VK_SHIFT)
|
||||||
|
register(event.id, HostKeyPress(KeyEvent.VK_DEAD_TILDE, rightSide = false, numpad = false))
|
||||||
|
}
|
||||||
|
event.keyChar == '\'' -> {
|
||||||
|
register(event.id, shift, HostKeyPress(KeyEvent.VK_7, rightSide = false, numpad = false))
|
||||||
|
}
|
||||||
|
else -> when (event.keyCode) {
|
||||||
|
KeyEvent.VK_CONTROL, KeyEvent.VK_TAB -> {
|
||||||
|
// both controls and the tab key map to the 'single left control'
|
||||||
|
register(event.id, HostKeyPress(KeyEvent.VK_CONTROL, rightSide = false, numpad = false))
|
||||||
|
}
|
||||||
|
KeyEvent.VK_ALT, KeyEvent.VK_ALT_GRAPH -> {
|
||||||
|
// both alts map to the 'commodore key' (same left alt)
|
||||||
|
register(event.id, HostKeyPress(KeyEvent.VK_ALT, rightSide = false, numpad = false))
|
||||||
|
}
|
||||||
|
KeyEvent.VK_F2 -> {
|
||||||
|
// F2 = shift+F1
|
||||||
|
val func = HostKeyPress(KeyEvent.VK_F1, rightSide = false, numpad = false)
|
||||||
|
register(event.id, shift, func)
|
||||||
|
}
|
||||||
|
KeyEvent.VK_F4 -> {
|
||||||
|
// F4 = shift+F3
|
||||||
|
val func = HostKeyPress(KeyEvent.VK_F3, rightSide = false, numpad = false)
|
||||||
|
register(event.id, shift, func)
|
||||||
|
}
|
||||||
|
KeyEvent.VK_F6 -> {
|
||||||
|
// F6 = shift+F5
|
||||||
|
val func = HostKeyPress(KeyEvent.VK_F5, rightSide = false, numpad = false)
|
||||||
|
register(event.id, shift, func)
|
||||||
|
}
|
||||||
|
KeyEvent.VK_F8 -> {
|
||||||
|
// F8 = shift+F7
|
||||||
|
val func = HostKeyPress(KeyEvent.VK_F7, rightSide = false, numpad = false)
|
||||||
|
register(event.id, shift, func)
|
||||||
|
}
|
||||||
|
KeyEvent.VK_INSERT -> {
|
||||||
|
// insert = shift+backspace(del)
|
||||||
|
val backspace = HostKeyPress(KeyEvent.VK_BACK_SPACE, rightSide = false, numpad = false)
|
||||||
|
register(event.id, shift, backspace)
|
||||||
|
}
|
||||||
|
KeyEvent.VK_UP -> {
|
||||||
|
// up = shift+down
|
||||||
|
val cursor = HostKeyPress(KeyEvent.VK_DOWN, rightSide = false, numpad = false)
|
||||||
|
register(event.id, shift, cursor)
|
||||||
|
}
|
||||||
|
KeyEvent.VK_LEFT -> {
|
||||||
|
// left = shift+right
|
||||||
|
val cursor = HostKeyPress(KeyEvent.VK_RIGHT, rightSide = false, numpad = false)
|
||||||
|
register(event.id, shift, cursor)
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
// just map the key as usual
|
||||||
|
val hostkey = HostKeyPress(event.keyCode, rightSide, numpad)
|
||||||
|
register(event.id, hostkey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package razorvine.c64emu
|
package razorvine.c64emu
|
||||||
|
|
||||||
|
import razorvine.ksim65.Cpu6502
|
||||||
import razorvine.ksim65.components.MemoryComponent
|
import razorvine.ksim65.components.MemoryComponent
|
||||||
import java.awt.*
|
import java.awt.*
|
||||||
import java.awt.image.BufferedImage
|
import java.awt.image.BufferedImage
|
||||||
@ -60,13 +61,13 @@ private class BitmapScreenPanel(val chargenData: ByteArray, val ram: MemoryCompo
|
|||||||
|
|
||||||
private fun loadCharacters(shifted: Boolean): Array<BufferedImage> {
|
private fun loadCharacters(shifted: Boolean): Array<BufferedImage> {
|
||||||
val chars = Array(256) { BufferedImage(8, 8, BufferedImage.TYPE_BYTE_BINARY) }
|
val chars = Array(256) { BufferedImage(8, 8, BufferedImage.TYPE_BYTE_BINARY) }
|
||||||
val offset = if(shifted) 256*8 else 0
|
val offset = if (shifted) 256 * 8 else 0
|
||||||
// val color = ScreenDefs.colorPalette[14].rgb
|
// val color = ScreenDefs.colorPalette[14].rgb
|
||||||
for(char in 0..255) {
|
for (char in 0..255) {
|
||||||
for(line in 0..7) {
|
for (line in 0..7) {
|
||||||
val charbyte = chargenData[offset + char*8 + line].toInt()
|
val charbyte = chargenData[offset + char * 8 + line].toInt()
|
||||||
for(x in 0..7) {
|
for (x in 0..7) {
|
||||||
if(charbyte and (0b10000000 ushr x) !=0 )
|
if (charbyte and (0b10000000 ushr x) != 0)
|
||||||
chars[char].setRGB(x, line, 0xffffff)
|
chars[char].setRGB(x, line, 0xffffff)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -92,10 +93,10 @@ private class BitmapScreenPanel(val chargenData: ByteArray, val ram: MemoryCompo
|
|||||||
val shifted = (ram[0xd018].toInt() and 0b00000010) != 0
|
val shifted = (ram[0xd018].toInt() and 0b00000010) != 0
|
||||||
g2d.background = ScreenDefs.colorPalette[ram[0xd021].toInt() and 15]
|
g2d.background = ScreenDefs.colorPalette[ram[0xd021].toInt() and 15]
|
||||||
g2d.clearRect(0, 0, ScreenDefs.SCREEN_WIDTH, ScreenDefs.SCREEN_HEIGHT)
|
g2d.clearRect(0, 0, ScreenDefs.SCREEN_WIDTH, ScreenDefs.SCREEN_HEIGHT)
|
||||||
for(y in 0 until ScreenDefs.SCREEN_HEIGHT_CHARS) {
|
for (y in 0 until ScreenDefs.SCREEN_HEIGHT_CHARS) {
|
||||||
for(x in 0 until ScreenDefs.SCREEN_WIDTH_CHARS) {
|
for (x in 0 until ScreenDefs.SCREEN_WIDTH_CHARS) {
|
||||||
val char = ram[screen + x + y*ScreenDefs.SCREEN_WIDTH_CHARS].toInt()
|
val char = ram[screen + x + y * ScreenDefs.SCREEN_WIDTH_CHARS].toInt()
|
||||||
val color = ram[colors + x + y*ScreenDefs.SCREEN_WIDTH_CHARS].toInt()
|
val color = ram[colors + x + y * ScreenDefs.SCREEN_WIDTH_CHARS].toInt()
|
||||||
drawColoredChar(x, y, char, color and 15, shifted)
|
drawColoredChar(x, y, char, color and 15, shifted)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -105,18 +106,18 @@ private class BitmapScreenPanel(val chargenData: ByteArray, val ram: MemoryCompo
|
|||||||
|
|
||||||
private fun drawColoredChar(x: Int, y: Int, char: Int, color: Int, shifted: Boolean) {
|
private fun drawColoredChar(x: Int, y: Int, char: Int, color: Int, shifted: Boolean) {
|
||||||
var cached = coloredCharacters[Triple(char, color, shifted)]
|
var cached = coloredCharacters[Triple(char, color, shifted)]
|
||||||
if(cached==null) {
|
if (cached == null) {
|
||||||
cached = if(shifted) shiftedCharacters[char] else normalCharacters[char]
|
cached = if (shifted) shiftedCharacters[char] else normalCharacters[char]
|
||||||
val colored = g2d.deviceConfiguration.createCompatibleImage(8, 8, BufferedImage.BITMASK)
|
val colored = g2d.deviceConfiguration.createCompatibleImage(8, 8, BufferedImage.BITMASK)
|
||||||
val sourceRaster = cached.raster
|
val sourceRaster = cached.raster
|
||||||
val coloredRaster = colored.raster
|
val coloredRaster = colored.raster
|
||||||
val pixelArray = IntArray(4)
|
val pixelArray = IntArray(4)
|
||||||
val javaColor = ScreenDefs.colorPalette[color]
|
val javaColor = ScreenDefs.colorPalette[color]
|
||||||
val coloredPixel = listOf(javaColor.red, javaColor.green, javaColor.blue, javaColor.alpha).toIntArray()
|
val coloredPixel = listOf(javaColor.red, javaColor.green, javaColor.blue, javaColor.alpha).toIntArray()
|
||||||
for(pixelY in 0..7) {
|
for (pixelY in 0..7) {
|
||||||
for(pixelX in 0..7) {
|
for (pixelX in 0..7) {
|
||||||
val source = sourceRaster.getPixel(pixelX, pixelY, pixelArray)
|
val source = sourceRaster.getPixel(pixelX, pixelY, pixelArray)
|
||||||
if(source[0]!=0) {
|
if (source[0] != 0) {
|
||||||
coloredRaster.setPixel(pixelX, pixelY, coloredPixel)
|
coloredRaster.setPixel(pixelX, pixelY, coloredPixel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -132,6 +133,7 @@ class MainC64Window(
|
|||||||
title: String,
|
title: String,
|
||||||
chargenData: ByteArray,
|
chargenData: ByteArray,
|
||||||
val ram: MemoryComponent,
|
val ram: MemoryComponent,
|
||||||
|
val cpu: Cpu6502,
|
||||||
val keypressCia: Cia
|
val keypressCia: Cia
|
||||||
) : JFrame(title), KeyListener {
|
) : JFrame(title), KeyListener {
|
||||||
private val canvas = BitmapScreenPanel(chargenData, ram)
|
private val canvas = BitmapScreenPanel(chargenData, ram)
|
||||||
@ -195,7 +197,7 @@ class MainC64Window(
|
|||||||
addKeyListener(this)
|
addKeyListener(this)
|
||||||
pack()
|
pack()
|
||||||
setLocationRelativeTo(null)
|
setLocationRelativeTo(null)
|
||||||
location = Point(location.x/2, location.y)
|
location = Point(location.x / 2, location.y)
|
||||||
setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, mutableSetOf())
|
setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, mutableSetOf())
|
||||||
setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, mutableSetOf())
|
setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, mutableSetOf())
|
||||||
requestFocusInWindow()
|
requestFocusInWindow()
|
||||||
@ -218,8 +220,14 @@ class MainC64Window(
|
|||||||
override fun keyTyped(event: KeyEvent) {}
|
override fun keyTyped(event: KeyEvent) {}
|
||||||
|
|
||||||
override fun keyPressed(event: KeyEvent) {
|
override fun keyPressed(event: KeyEvent) {
|
||||||
|
// '\' is mapped as RESTORE, this causes a NMI on the cpu
|
||||||
|
if (event.keyChar == '\\') {
|
||||||
|
cpu.nmi()
|
||||||
|
} else {
|
||||||
keypressCia.hostKeyPressed(event)
|
keypressCia.hostKeyPressed(event)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun keyReleased(event: KeyEvent) {
|
override fun keyReleased(event: KeyEvent) {
|
||||||
keypressCia.hostKeyPressed(event)
|
keypressCia.hostKeyPressed(event)
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@ class C64Machine(title: String) : IVirtualMachine {
|
|||||||
// TODO: implement something so that RND(0) actually works in basic. (cia timer?)
|
// TODO: implement something so that RND(0) actually works in basic. (cia timer?)
|
||||||
|
|
||||||
private val debugWindow = DebugWindow(this)
|
private val debugWindow = DebugWindow(this)
|
||||||
private val hostDisplay = MainC64Window(title, chargenData, ram, cia1)
|
private val hostDisplay = MainC64Window(title, chargenData, ram, cpu, cia1)
|
||||||
private var paused = false
|
private var paused = false
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
Loading…
Reference in New Issue
Block a user