Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 123 additions & 0 deletions driver/embedded/efi.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
//go:build tamago

package fynex

import (
"image"
"io"
"log"
"time"

"github.com/usbarmory/go-boot/uefi"
"github.com/usbarmory/go-boot/uefi/x64"

"fyne.io/fyne/v2"
"fyne.io/fyne/v2/driver/embedded"
)

type efi struct {
buf []byte
queue chan embedded.Event
}

func NewUEFIDriver() embedded.Driver {
return &efi{queue: make(chan embedded.Event)}
}

func (u *efi) Queue() chan embedded.Event {
return u.queue
}

func (u *efi) Run(mainLoop func()) {
err := u.runLoop(mainLoop, u.queue)
if err != nil {
u.handleError(err)
} else {
_ = x64.UEFI.Runtime.ResetSystem(uefi.EfiResetShutdown)
}
}

func (u *efi) handleError(err error) {
log.Println("> ", err)
time.Sleep(time.Second * 3)

_ = x64.UEFI.Runtime.ResetSystem(uefi.EfiResetWarm)
}

func (u *efi) Render(img image.Image) {
gop, _ := x64.UEFI.Boot.GetGraphicsOutput()
i := 0

width := img.Bounds().Dx()
height := img.Bounds().Dy()

for y := 0; y < height; y++ {
for x := 0; x < width; x++ {
pix := img.At(x, y)

r, g, b, _ := pix.RGBA()
u.buf[i+0] = byte(b)
u.buf[i+1] = byte(g)
u.buf[i+2] = byte(r)
u.buf[i+3] = 0

i += 4
}
}

_ = gop.Blt(u.buf, uefi.EfiBltBufferToVideo, 0, 0, 0, 0, uint64(width), uint64(height), 0)
}

func (u *efi) runLoop(mainLoop func(), queue chan embedded.Event) error {
// we have to Run on a goroutine because the UEFI.Console is used on main in other code...
wait := make(chan struct{})
go func() {
mainLoop()
wait <- struct{}{}
}()

defer func() {
fyne.CurrentApp().Quit()
<-wait
}()

data := make([]byte, 4)
for {
n, err := x64.UEFI.Console.Read(data)
if err == io.EOF {
return err
}
if err != nil {
fyne.LogError("failed to read", err)
continue
}

for i := 0; i < n && i < len(data); i++ {
switch data[i] {
case 0:
continue
case 17, 23: // ctrl+Q or Esc
return nil
}

triggerKey(uint16(data[i]), embedded.KeyPressed, queue)
triggerKey(uint16(data[i]), embedded.KeyReleased, queue)
}
}
}

func (u *efi) ScreenSize() fyne.Size {
gop, err := x64.UEFI.Boot.GetGraphicsOutput()
if err != nil {
u.handleError(err)
return fyne.NewSize(0, 0)
}

mode, _ := gop.GetMode()
info, _ := mode.GetInfo()
ww, hh := uint64(info.HorizontalResolution),
uint64(info.VerticalResolution)

u.buf = make([]byte, ww*hh*4)
return fyne.NewSize(float32(ww), float32(hh))
}
49 changes: 49 additions & 0 deletions driver/embedded/key.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//go:build tamago || tinygo || noos

package fynex

import (
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/driver/embedded"
)

func triggerKey(key uint16, dir embedded.KeyDirection, queue chan embedded.Event) {
name := fyne.KeyName("")
switch key {
case 1:
name = fyne.KeyUp
case 2:
name = fyne.KeyDown
case 3:
name = fyne.KeyRight
case 4:
name = fyne.KeyLeft
case 27: // esc
name = fyne.KeyEscape
case 13: // ret
name = fyne.KeyReturn
case 8: // backspace
name = fyne.KeyBackspace
case 9: // tab
name = fyne.KeyTab
case ' ':
name = fyne.KeySpace
default:
if key > ' ' && key < '~' {
name = fyne.KeyName(rune(key))
if key >= 'a' && key <= 'z' {
name = fyne.KeyName(rune(key) - 'a' + 'A')
}
}
}
queue <- &embedded.KeyEvent{Name: name, Direction: dir}

// visible characters
if key >= ' ' && key <= '~' {
if dir == embedded.KeyReleased {
return
}

queue <- &embedded.CharacterEvent{Rune: rune(key)}
}
}
32 changes: 32 additions & 0 deletions driver/embedded/tinygo-display.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//go:build (tinygo || noos) && !nodisplay

package fynex

import (
"image"
"image/draw"

"fyne.io/fyne/v2"
"github.com/sago35/tinydisplay"
)

var display *tinydisplay.Client

func nextKey() uint16 {
return display.GetPressedKey()
}

func (t *tinygo) Render(img image.Image) {
// tinydisplay does not like our *image.NRGBA, so copy it
out := image.NewRGBA(img.Bounds())
draw.Draw(out, out.Bounds(), img, image.ZP, draw.Src)

display.SetImage(out)
}

func (t *tinygo) ScreenSize() fyne.Size {
display, _ = tinydisplay.NewClient("127.0.0.1", 9812, 0, 0)
w, h := display.Size()

return fyne.NewSize(float32(w), float32(h))
}
20 changes: 20 additions & 0 deletions driver/embedded/tinygo-nodisplay.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//go:build (tinygo || noos) && nodisplay

package fynex

import (
"image"

"fyne.io/fyne/v2"
)

func nextKey() uint16 {
return noKey
}

func (t *tinygo) Render(_ image.Image) {
}

func (t *tinygo) ScreenSize() fyne.Size {
return fyne.NewSize(320, 240)
}
87 changes: 87 additions & 0 deletions driver/embedded/tinygo.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
//go:build tinygo || noos

package fynex

import (
"time"

"fyne.io/fyne/v2"
"fyne.io/fyne/v2/driver/embedded"
)

const noKey = uint16(0xFFFF)

type tinygo struct {
queue chan embedded.Event
}

func NewTinyGoDriver() embedded.Driver {
return &tinygo{queue: make(chan embedded.Event)}
}

func (t *tinygo) Queue() chan embedded.Event {
return t.queue
}

func (t *tinygo) Run(mainLoop func()) {
go runEvents(t.queue)
mainLoop()
}

func runEvents(queue chan embedded.Event) {
key := noKey
for {
time.Sleep(time.Millisecond * 10) // don't poll too fast

newKey := nextKey()
if newKey == key {
continue
}

if newKey == noKey {
triggerKey(key, embedded.KeyReleased, queue)
key = newKey
} else {
if newKey == 0x100 { // escape
break
}

typed := mapKey(newKey)
triggerKey(typed, embedded.KeyPressed, queue)
key = newKey
}
}

fyne.Do(fyne.CurrentApp().Quit)
}

func mapKey(key uint16) uint16 {
// TODO handle shift...
if key >= 'A' && key <= 'Z' {
return key + 'a' - 'A'
}

switch key {
case 0x100:
return 27 // esc
case 0x101:
return 13 // ret
case 0x103:
return 8 // backspace
case 0x102:
return 9 // tab
case 0x105:
return 127 // delete

case 265:
return 1
case 264:
return 2
case 263:
return 4
case 262:
return 3
}

return key
}
33 changes: 24 additions & 9 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,28 +1,33 @@
module fyne.io/x/fyne

go 1.19
go 1.24.2

toolchain go1.24.6

require (
fyne.io/fyne/v2 v2.6.0
github.com/Andrew-M-C/go.jsonvalue v1.4.1
github.com/eclipse/paho.mqtt.golang v1.3.5
github.com/gorilla/websocket v1.5.3
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
github.com/sago35/tinydisplay v0.0.0-20220715023138-477e392e8cc6
github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef
github.com/stretchr/testify v1.10.0
github.com/twpayne/go-geom v1.0.0
github.com/usbarmory/go-boot v0.0.0-20250519071039-682fd55bc6ca
github.com/wagslane/go-password-validator v0.3.0
golang.org/x/image v0.24.0
)

require (
fyne.io/systray v1.11.0 // indirect
github.com/BurntSushi/toml v1.4.0 // indirect
fyne.io/systray v1.11.1-0.20250603113521-ca66a66d8b58 // indirect
github.com/BurntSushi/toml v1.5.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fredbi/uri v1.1.0 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/fyne-io/gl-js v0.1.0 // indirect
github.com/fyne-io/glfw-js v0.2.0 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/fredbi/uri v1.1.1 // indirect
github.com/fsnotify/fsnotify v1.9.0 // indirect
github.com/fyne-io/gl-js v0.2.0 // indirect
github.com/fyne-io/glfw-js v0.3.0 // indirect
github.com/fyne-io/image v0.1.1 // indirect
github.com/fyne-io/oksvg v0.1.0 // indirect
github.com/go-gl/gl v0.0.0-20231021071112-07e5d0ea2e71 // indirect
Expand All @@ -33,17 +38,27 @@ require (
github.com/gopherjs/gopherjs v1.17.2 // indirect
github.com/hack-pad/go-indexeddb v0.3.2 // indirect
github.com/hack-pad/safejs v0.1.0 // indirect
github.com/jeandeaual/go-locale v0.0.0-20241217141322-fcc2cadd6f08 // indirect
github.com/jeandeaual/go-locale v0.0.0-20250612000132-0ef82f21eade // indirect
github.com/jsummers/gobmp v0.0.0-20230614200233-a9de23ed2e25 // indirect
github.com/klauspost/compress v1.17.4 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/nicksnyder/go-i18n/v2 v2.5.1 // indirect
github.com/pierrec/lz4/v4 v4.1.14 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rymdport/portal v0.4.1 // indirect
github.com/shopspring/decimal v1.4.0 // indirect
github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c // indirect
github.com/therootcompany/xz v1.0.1 // indirect
github.com/u-root/u-root v0.14.1-0.20250211171033-17c75c6542a1 // indirect
github.com/u-root/uio v0.0.0-20240209044354-b3d14b93376a // indirect
github.com/ulikunitz/xz v0.5.11 // indirect
github.com/usbarmory/tamago v0.0.0-20250506193353-852659b3a9d6 // indirect
github.com/yuin/goldmark v1.7.8 // indirect
golang.org/x/net v0.35.0 // indirect
golang.org/x/sys v0.30.0 // indirect
golang.org/x/sys v0.32.0 // indirect
golang.org/x/text v0.22.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
tinygo.org/x/drivers v0.29.1-0.20250118064509-00578a3a81f3 // indirect
)

replace fyne.io/fyne/v2 => github.com/andydotxyz/fyne/v2 v2.2.0-rc1.0.20250906184609-25c7154dc182
Loading
Loading