Improved keyboard support wih SDL

This commit is contained in:
Ivan Izaguirre 2019-04-13 20:29:31 +02:00
parent 2ca630ddfc
commit b775526b34
7 changed files with 174 additions and 10 deletions

View File

@ -42,7 +42,7 @@ func (fe *ansiConsoleFrontend) subscribeToTextPages() {
const refreshDelayMs = 100
func (fe *ansiConsoleFrontend) getKey() (key uint8, ok bool) {
func (fe *ansiConsoleFrontend) GetKey() (key uint8, ok bool) {
stdinReader := func(c chan uint8) {
reader := bufio.NewReader(os.Stdin)
for {

View File

@ -44,10 +44,12 @@ func (a *Apple2) AddDisk2(diskRomFile string, diskImage string) {
}
// Run starts the Apple2 emulation
func (a *Apple2) Run(log bool) {
func (a *Apple2) Run(log bool, consoleKeyboard bool) {
// Init frontend
fe := newAnsiConsoleFrontend(a)
a.io.setKeyboardProvider(fe)
if consoleKeyboard {
a.io.setKeyboardProvider(fe)
}
if !log {
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.
const (
apple2RomSize = 12 * 1024

View File

@ -8,15 +8,15 @@ type ioC0Page struct {
softSwitchesR [256]softSwitchR
softSwitchesW [256]softSwitchW
softSwitchesData [128]uint8
keyboard keyboardProvider
keyboard KeyboardProvider
apple2 *Apple2
}
type softSwitchR func(io *ioC0Page) uint8
type softSwitchW func(io *ioC0Page, value uint8)
type keyboardProvider interface {
getKey() (key uint8, ok bool)
type KeyboardProvider interface {
GetKey() (key uint8, ok bool)
}
// 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
}
func (p *ioC0Page) setKeyboardProvider(kb keyboardProvider) {
func (p *ioC0Page) setKeyboardProvider(kb KeyboardProvider) {
p.keyboard = kb
}

View File

@ -95,7 +95,7 @@ func getSoftSwitch(ioFlag uint8, isSet bool) softSwitchR {
func getKeySoftSwitch(io *ioC0Page) uint8 {
strobed := (io.softSwitchesData[ioDataKeyboard] & (1 << 7)) == 0
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)
}
}

44
apple2sdl/run.go Normal file
View File

@ -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)
}
}

105
apple2sdl/sdlKeyboard.go Normal file
View File

@ -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
View File

@ -1,6 +1,9 @@
package main
import "go6502/apple2"
import (
"go6502/apple2"
"go6502/apple2sdl"
)
func main() {
//romFile := "apple2/romdumps/Apple2.rom"
@ -10,7 +13,12 @@ func main() {
diskImage := "../dos33.dsk"
log := false
sdl := true
a := apple2.NewApple2(romFile)
a.AddDisk2(disk2RomFile, diskImage)
a.Run(log)
if sdl {
apple2sdl.SDLRun(a)
} else {
a.Run(log, true)
}
}