Joystick support in Fyne with glfw

This commit is contained in:
Ivan Izaguirre 2020-10-12 17:19:51 +02:00 committed by Iván Izaguirre
parent 17f1121980
commit 9395c2ffb3
3 changed files with 134 additions and 16 deletions

1
go.mod
View File

@ -4,6 +4,7 @@ go 1.12
require (
fyne.io/fyne v1.3.3
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200625191551-73d3c3675aa3
github.com/pkg/profile v1.4.0
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 // indirect
github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd

View File

@ -0,0 +1,109 @@
package main
import (
"fmt"
"runtime"
"time"
"github.com/go-gl/glfw/v3.3/glfw"
)
/*
Apple 2 supports four paddles and 3 pushbuttons. The first two paddles are
the X, Y axis of the first joystick. The second two correspond the the second
joystick.
Button 0 is the primary button of joystick 0.
Button 1 is the secondary button of joystick 0 but also the primary button of
joystick 1.
Button 2 is the secondary button of Joystick 1.
*/
// TODO: key as buttons as on the IIe and mouse as joystick
type joystickInfo struct {
present bool
name string
paddles [2]uint8
buttons [2]bool
}
type joysticks struct {
info [2]*joystickInfo
}
const unplugged = uint8(255) // Max resistance when unplugged
func newJoysticks() *joysticks {
var j joysticks
return &j
}
func (j *joysticks) start() {
pool := time.NewTicker(time.Second / 50)
go func() {
runtime.LockOSThread()
for {
select {
case <-pool.C:
j.info[0] = j.queryJoystick(glfw.Joystick1)
j.info[1] = j.queryJoystick(glfw.Joystick2)
}
}
}()
}
func (j *joysticks) queryJoystick(joy glfw.Joystick) *joystickInfo {
if !joy.Present() {
return nil
}
var info joystickInfo
info.name = joy.GetName()
buttons := joy.GetButtons()
for i, b := range buttons {
if b == glfw.Press {
info.buttons[i%2] = true
}
}
axes := joy.GetAxes()
for i := 0; i < len(info.paddles); i++ {
info.paddles[i] = unplugged
if i < len(axes) {
v := uint16((axes[i] + 1.0) / 2.0 * 256.0)
if v > 255 {
v = 255
}
info.paddles[i] = uint8(v)
}
}
return &info
}
func (j *joysticks) ReadButton(i int) bool {
var value bool
i0 := j.info[0]
i1 := j.info[1]
switch i {
case 0:
value = (i0 != nil) && i0.buttons[0]
case 1:
// It can be secondary of first or primary of second
value = ((i0 != nil) && i0.buttons[1]) ||
(i1 != nil) && i1.buttons[0]
case 2:
value = (i1 != nil) && i1.buttons[0]
}
return value
}
func (j *joysticks) ReadPaddle(i int) (uint8, bool) {
var value = unplugged
info := j.info[i/2]
if info != nil {
value = info.paddles[i%2]
}
fmt.Printf("%v, %v, %v\n", i, j.info[0], value)
return value, value != unplugged
}

View File

@ -19,7 +19,9 @@ import (
)
type state struct {
a *izapple2.Apple2
a *izapple2.Apple2
app fyne.App
win fyne.Window
showPages bool
}
@ -39,9 +41,9 @@ func main() {
}
func fyneRun(s *state) {
app := app.New()
s.app = app.New()
// app.SetIcon(xxx)
window := app.NewWindow("iz-" + s.a.Name)
s.win = s.app.NewWindow("iz-" + s.a.Name)
// window.SetIcon(xxx)
bottom := widget.NewToolbar(
@ -66,23 +68,25 @@ func fyneRun(s *state) {
theme.NewThemedResource(resourceLayersTripleSvg, nil), func() {
s.showPages = !s.showPages
if !s.showPages {
window.SetTitle("iz-" + s.a.Name)
s.win.SetTitle("iz-" + s.a.Name)
}
}),
widget.NewToolbarAction(
theme.NewThemedResource(resourceCameraSvg, nil), func() {
err := izapple2.SaveSnapshot(s.a, "snapshot.png")
if err != nil {
app.SendNotification(fyne.NewNotification(window.Title(),
s.app.SendNotification(fyne.NewNotification(
s.win.Title(),
fmt.Sprintf("Error saving snapshoot: %v.\n.", err)))
} else {
app.SendNotification(fyne.NewNotification(window.Title(),
s.app.SendNotification(fyne.NewNotification(
s.win.Title(),
"Saving snapshot on 'snapshot.png'"))
}
}),
widget.NewToolbarSpacer(),
widget.NewToolbarAction(theme.ViewFullScreenIcon(), func() {
window.SetFullScreen(!window.FullScreen())
s.win.SetFullScreen(!s.win.FullScreen())
}),
)
@ -92,10 +96,13 @@ func fyneRun(s *state) {
layout.NewBorderLayout(nil, bottom, nil, nil),
screen, bottom,
)
window.SetContent(container)
window.SetPadded(false)
s.win.SetContent(container)
s.win.SetPadded(false)
registerKeyboardEvents(s, window.Canvas())
registerKeyboardEvents(s)
j := newJoysticks()
j.start()
s.a.SetJoysticksProvider(j)
go s.a.Run()
@ -111,7 +118,7 @@ func fyneRun(s *state) {
var img *image.RGBA
if s.showPages {
img = s.a.SnapshotParts()
window.SetTitle(fmt.Sprintf("%v %v %vx%v", s.a.Name, s.a.VideoModeName(), img.Rect.Dx()/2, img.Rect.Dy()/2))
s.win.SetTitle(fmt.Sprintf("%v %v %vx%v", s.a.Name, s.a.VideoModeName(), img.Rect.Dx()/2, img.Rect.Dy()/2))
} else {
img = s.a.Snapshot()
}
@ -122,19 +129,20 @@ func fyneRun(s *state) {
}
}()
window.SetOnClosed(func() {
s.win.SetOnClosed(func() {
done <- true
})
window.Show()
app.Run()
s.win.Show()
s.app.Run()
}
func registerKeyboardEvents(s *state, canvas fyne.Canvas) {
func registerKeyboardEvents(s *state) {
kp := newKeyboard(s)
canvas := s.win.Canvas()
// Koyboard events
// Events
canvas.SetOnTypedKey(func(ke *fyne.KeyEvent) {
//fmt.Printf("Event: %v\n", ke.Name)
kp.putKey(ke)