Improved keyboard support wih SDL
This commit is contained in:
parent
2ca630ddfc
commit
b775526b34
|
@ -42,7 +42,7 @@ func (fe *ansiConsoleFrontend) subscribeToTextPages() {
|
||||||
|
|
||||||
const refreshDelayMs = 100
|
const refreshDelayMs = 100
|
||||||
|
|
||||||
func (fe *ansiConsoleFrontend) getKey() (key uint8, ok bool) {
|
func (fe *ansiConsoleFrontend) GetKey() (key uint8, ok bool) {
|
||||||
stdinReader := func(c chan uint8) {
|
stdinReader := func(c chan uint8) {
|
||||||
reader := bufio.NewReader(os.Stdin)
|
reader := bufio.NewReader(os.Stdin)
|
||||||
for {
|
for {
|
||||||
|
|
|
@ -44,10 +44,12 @@ func (a *Apple2) AddDisk2(diskRomFile string, diskImage string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run starts the Apple2 emulation
|
// Run starts the Apple2 emulation
|
||||||
func (a *Apple2) Run(log bool) {
|
func (a *Apple2) Run(log bool, consoleKeyboard bool) {
|
||||||
// Init frontend
|
// Init frontend
|
||||||
fe := newAnsiConsoleFrontend(a)
|
fe := newAnsiConsoleFrontend(a)
|
||||||
a.io.setKeyboardProvider(fe)
|
if consoleKeyboard {
|
||||||
|
a.io.setKeyboardProvider(fe)
|
||||||
|
}
|
||||||
if !log {
|
if !log {
|
||||||
go fe.textModeGoRoutine()
|
go fe.textModeGoRoutine()
|
||||||
}
|
}
|
||||||
|
@ -59,6 +61,11 @@ func (a *Apple2) Run(log bool) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetKeyboardProvider attaches an external keyboard provider
|
||||||
|
func (a *Apple2) SetKeyboardProvider(kb KeyboardProvider) {
|
||||||
|
a.io.setKeyboardProvider(kb)
|
||||||
|
}
|
||||||
|
|
||||||
// LoadRom loads a binary file to the top of the memory.
|
// LoadRom loads a binary file to the top of the memory.
|
||||||
const (
|
const (
|
||||||
apple2RomSize = 12 * 1024
|
apple2RomSize = 12 * 1024
|
||||||
|
|
|
@ -8,15 +8,15 @@ type ioC0Page struct {
|
||||||
softSwitchesR [256]softSwitchR
|
softSwitchesR [256]softSwitchR
|
||||||
softSwitchesW [256]softSwitchW
|
softSwitchesW [256]softSwitchW
|
||||||
softSwitchesData [128]uint8
|
softSwitchesData [128]uint8
|
||||||
keyboard keyboardProvider
|
keyboard KeyboardProvider
|
||||||
apple2 *Apple2
|
apple2 *Apple2
|
||||||
}
|
}
|
||||||
|
|
||||||
type softSwitchR func(io *ioC0Page) uint8
|
type softSwitchR func(io *ioC0Page) uint8
|
||||||
type softSwitchW func(io *ioC0Page, value uint8)
|
type softSwitchW func(io *ioC0Page, value uint8)
|
||||||
|
|
||||||
type keyboardProvider interface {
|
type KeyboardProvider interface {
|
||||||
getKey() (key uint8, ok bool)
|
GetKey() (key uint8, ok bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
// See https://www.kreativekorp.com/miscpages/a2info/iomemory.shtml
|
// See https://www.kreativekorp.com/miscpages/a2info/iomemory.shtml
|
||||||
|
@ -64,7 +64,7 @@ func (p *ioC0Page) isSoftSwitchExtActive(ioFlag uint8) bool {
|
||||||
return (p.softSwitchesData[ioFlag] & ssOn) == ssOn
|
return (p.softSwitchesData[ioFlag] & ssOn) == ssOn
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *ioC0Page) setKeyboardProvider(kb keyboardProvider) {
|
func (p *ioC0Page) setKeyboardProvider(kb KeyboardProvider) {
|
||||||
p.keyboard = kb
|
p.keyboard = kb
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -95,7 +95,7 @@ func getSoftSwitch(ioFlag uint8, isSet bool) softSwitchR {
|
||||||
func getKeySoftSwitch(io *ioC0Page) uint8 {
|
func getKeySoftSwitch(io *ioC0Page) uint8 {
|
||||||
strobed := (io.softSwitchesData[ioDataKeyboard] & (1 << 7)) == 0
|
strobed := (io.softSwitchesData[ioDataKeyboard] & (1 << 7)) == 0
|
||||||
if strobed && io.keyboard != nil {
|
if strobed && io.keyboard != nil {
|
||||||
if key, ok := io.keyboard.getKey(); ok {
|
if key, ok := io.keyboard.GetKey(); ok {
|
||||||
io.softSwitchesData[ioDataKeyboard] = key + (1 << 7)
|
io.softSwitchesData[ioDataKeyboard] = key + (1 << 7)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
package apple2sdl
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/veandco/go-sdl2/sdl"
|
||||||
|
|
||||||
|
"go6502/apple2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SDLRun starts the Apple2 emulator on SDL
|
||||||
|
func SDLRun(a *apple2.Apple2) {
|
||||||
|
window, renderer, err := sdl.CreateWindowAndRenderer(800, 600, sdl.WINDOW_SHOWN)
|
||||||
|
if err != nil {
|
||||||
|
panic("Failed to create window")
|
||||||
|
}
|
||||||
|
defer window.Destroy()
|
||||||
|
defer renderer.Destroy()
|
||||||
|
window.SetTitle("Apple2")
|
||||||
|
renderer.Clear()
|
||||||
|
renderer.Present()
|
||||||
|
|
||||||
|
kp := newSDLKeyBoard()
|
||||||
|
a.SetKeyboardProvider(&kp)
|
||||||
|
go a.Run(false, false)
|
||||||
|
|
||||||
|
running := true
|
||||||
|
for running {
|
||||||
|
for event := sdl.PollEvent(); event != nil; event = sdl.PollEvent() {
|
||||||
|
switch t := event.(type) {
|
||||||
|
case *sdl.QuitEvent:
|
||||||
|
running = false
|
||||||
|
case *sdl.KeyboardEvent:
|
||||||
|
//fmt.Printf("[%d ms] Keyboard\ttype:%d\tsym:%c\tmodifiers:%d\tstate:%d\trepeat:%d\n",
|
||||||
|
// t.Timestamp, t.Type, t.Keysym.Sym, t.Keysym.Mod, t.State, t.Repeat)
|
||||||
|
kp.putKey(t)
|
||||||
|
case *sdl.TextInputEvent:
|
||||||
|
//fmt.Printf("[%d ms] TextInput\ttype:%d\texts:%s\n",
|
||||||
|
// t.Timestamp, t.Type, t.GetText())
|
||||||
|
kp.putText(t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sdl.Delay(1000 / 60)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,105 @@
|
||||||
|
package apple2sdl
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unicode/utf8"
|
||||||
|
|
||||||
|
"github.com/veandco/go-sdl2/sdl"
|
||||||
|
)
|
||||||
|
|
||||||
|
type sdlKeyboard struct {
|
||||||
|
keyChannel chan uint8
|
||||||
|
}
|
||||||
|
|
||||||
|
func newSDLKeyBoard() sdlKeyboard {
|
||||||
|
var k sdlKeyboard
|
||||||
|
k.keyChannel = make(chan uint8, 100)
|
||||||
|
return k
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k *sdlKeyboard) putText(textEvent *sdl.TextInputEvent) {
|
||||||
|
text := textEvent.GetText()
|
||||||
|
|
||||||
|
for _, ch := range text {
|
||||||
|
// We will use computed text only for printable ASCII chars
|
||||||
|
if ch < ' ' || ch > '~' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := make([]uint8, 1)
|
||||||
|
utf8.EncodeRune(buf, ch)
|
||||||
|
|
||||||
|
k.putChar(buf[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k *sdlKeyboard) putKey(keyEvent *sdl.KeyboardEvent) {
|
||||||
|
/* To get keys as understood by the Apple2 hardware run:
|
||||||
|
10 A=PEEK(49152)
|
||||||
|
20 B = A - 128
|
||||||
|
30 PRINT A, B
|
||||||
|
40 GOTO 10
|
||||||
|
*/
|
||||||
|
if keyEvent.Type != sdl.KEYDOWN {
|
||||||
|
// Process only key pushes
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
key := keyEvent.Keysym
|
||||||
|
ctrl := key.Mod&sdl.KMOD_CTRL != 0
|
||||||
|
|
||||||
|
if ctrl {
|
||||||
|
if key.Sym >= 'a' && key.Sym <= 'z' {
|
||||||
|
k.putChar(uint8(key.Sym) - 97 + 1)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result := uint8(0)
|
||||||
|
|
||||||
|
switch key.Sym {
|
||||||
|
case sdl.K_ESCAPE:
|
||||||
|
result = 27
|
||||||
|
case sdl.K_BACKSPACE:
|
||||||
|
result = 24
|
||||||
|
case sdl.K_RETURN:
|
||||||
|
result = 13
|
||||||
|
case sdl.K_RETURN2:
|
||||||
|
result = 13
|
||||||
|
case sdl.K_LEFT:
|
||||||
|
if ctrl {
|
||||||
|
result = 31 // Base64A
|
||||||
|
}
|
||||||
|
result = 8
|
||||||
|
case sdl.K_RIGHT:
|
||||||
|
result = 21
|
||||||
|
|
||||||
|
// Base64A clone particularities
|
||||||
|
case sdl.K_F2:
|
||||||
|
result = 127
|
||||||
|
case sdl.K_UP:
|
||||||
|
result = 31
|
||||||
|
case sdl.K_DOWN:
|
||||||
|
result = 10
|
||||||
|
}
|
||||||
|
|
||||||
|
// Missing values 91 to 95. Usually control for [\]^_
|
||||||
|
// On the Base64A it's control for \]./
|
||||||
|
|
||||||
|
if result != 0 {
|
||||||
|
k.putChar(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k *sdlKeyboard) putChar(ch uint8) {
|
||||||
|
k.keyChannel <- ch
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k *sdlKeyboard) GetKey() (key uint8, ok bool) {
|
||||||
|
select {
|
||||||
|
case key = <-k.keyChannel:
|
||||||
|
ok = true
|
||||||
|
default:
|
||||||
|
ok = false
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
12
main.go
12
main.go
|
@ -1,6 +1,9 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import "go6502/apple2"
|
import (
|
||||||
|
"go6502/apple2"
|
||||||
|
"go6502/apple2sdl"
|
||||||
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
//romFile := "apple2/romdumps/Apple2.rom"
|
//romFile := "apple2/romdumps/Apple2.rom"
|
||||||
|
@ -10,7 +13,12 @@ func main() {
|
||||||
diskImage := "../dos33.dsk"
|
diskImage := "../dos33.dsk"
|
||||||
|
|
||||||
log := false
|
log := false
|
||||||
|
sdl := true
|
||||||
a := apple2.NewApple2(romFile)
|
a := apple2.NewApple2(romFile)
|
||||||
a.AddDisk2(disk2RomFile, diskImage)
|
a.AddDisk2(disk2RomFile, diskImage)
|
||||||
a.Run(log)
|
if sdl {
|
||||||
|
apple2sdl.SDLRun(a)
|
||||||
|
} else {
|
||||||
|
a.Run(log, true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue