Skip to content
This repository was archived by the owner on Apr 23, 2025. It is now read-only.

Conversation

@koxu1996
Copy link

@koxu1996 koxu1996 commented Jul 6, 2021

Base API

Functions:

  • p5.KeyIsDown(code string) bool - checks if given key is already pressed

Variables:

  • p5.KeyIsPressed bool - whether any key is pressed now
  • p5.Key string - name of last pressed/typed key

Callbacks

Callbacks can be set with following functions:

  • p5.SetKeyPressedCallback(f KeyEventFunc)
  • p5.SetKeyTypedCallback(f KeyEventFunc)
  • p5.SetKeyReleasedCallback(f KeyEventFunc)

Caveats:

  • There is no way to detect lower case characters, so we always use upper case. Bear that in mind, especially when working with KeyTyped event.

@sbinet I am not sure if the code is safe, so please take a look. I used your examples key-snake and key-pressed from #52. Feel free to suggest changes, this is just proposal 😀

@codecov
Copy link

codecov bot commented Jul 7, 2021

Codecov Report

Merging #53 (11a665b) into main (cbaf5d8) will decrease coverage by 4.78%.
The diff coverage is 11.11%.

Impacted file tree graph

@@            Coverage Diff             @@
##             main      #53      +/-   ##
==========================================
- Coverage   80.62%   75.84%   -4.79%     
==========================================
  Files           9       10       +1     
  Lines         609      654      +45     
==========================================
+ Hits          491      496       +5     
- Misses         96      133      +37     
- Partials       22       25       +3     
Impacted Files Coverage Δ
api.go 60.71% <0.00%> (-2.25%) ⬇️
keyboard.go 0.00% <0.00%> (ø)
p5.go 0.00% <0.00%> (ø)
proc.go 63.28% <13.88%> (-8.09%) ⬇️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update cbaf5d8...11a665b. Read the comment docs.

@sbinet
Copy link
Contributor

sbinet commented Jul 7, 2021

thanks for the PR.

I like you map-based approach. (I was initially thinking of using a uint32 mask, but, well, if the map approach is efficient enough, who cares)

I think I'd rather have only one struct that holds all the callbacks than increasing the number of globals.
e.g.:

package p5

type Keyboard struct {
    down    map[string]struct{}
    release map[key.Event]struct{}
    last    string

    Pressed  KeyCallback
    Typed    KeyCallback
    Released KeyCallback
}

func WithKeyCallback(cbk Keyboard) Option {
    return func(p *Proc) { p.Key = cbk }
}

and:

package main

func main() {
    p5.Run(setup, draw, p5.WithKeyCallback(p5.Keyboard{
        Pressed: keyPressed,
        ...
    })
}

what do you think?

@koxu1996
Copy link
Author

koxu1996 commented Jul 8, 2021

  1. I made little refactoring, now callbacks and global variables are moved to single struct.

  2. Regarding your callback approach, user have to pass all 3 callbacks otherwise SIGSEGV is thrown. I would rather allow setting each individually. Additionally your example is using Proc.Key which is missing, and I am confused if you want to store callbacks in Keyboard or Proc structure.

  3. I don't see how uint32 mask could be used; for storing keys map is suitable and efficient container. Regarding following code:

down map[string]struct{}
release map[key.Event]struct{}

  • map with bool is recommended for set-like data - see https://blog.golang.org/maps#TOC_4
  • we cannot use key.Event as key, because we could not search this map in simple way

@sbinet
Copy link
Contributor

sbinet commented Jul 9, 2021

Regarding your callback approach, user have to pass all 3 callbacks otherwise SIGSEGV is thrown.

not necessarily.
this would need some plumbing in p5.Run(...), though:

func Run(setup, draw Func, opts ...Option) {
...
    for _, opt := range opts {
        opt(gproc)
    }
    if gproc.Key.Pressed == nil {
        gproc.Key.Pressed = func() {}
    }
    ...
}

Additionally your example is using Proc.Key which is missing

I was indeed using notation from my previous PR :)
I was also probably beeing overeager and starting to reduce the number of globals being used in the p5 package.

map with bool is recommended for set-like data - see https://blog.golang.org/maps#TOC_4

this blog entry is a bit old :)
I think nowadays the map[T]struct{} is prefered as it brings the same semantics than a map[T]bool without the extra memory foot print of the useless boolean associated value (the empty struct struct{} will be optimized away).

we cannot use key.Event as key, because we could not search this map in simple way

you're right.

(I am sorry I'll have to disappear for a week w/o much internet connectivity and leave this PR unreviewed for the time being. I'll review it further coming back from holidays)

@koxu1996
Copy link
Author

koxu1996 commented Jul 12, 2021

Okay, I replaced map[string]bool with map[string]struct{}. I moved callbacks into Proc as you wished and now they are passed via single Option:

func main() {
	p5.Run(setup, draw, p5.WithKeyCallback(p5.KeyCb{
		Pressed:  keyPressed,
		Typed:    keyTyped,
	}))
	...

Is it fine?

@koxu1996
Copy link
Author

@sbinet Do you have time to look at it?

Copy link
Contributor

@sbinet sbinet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hi,

apologies for the belated answer.
please find my comments inlined.

do you have an idea on a testing strategy for this new feature?
(something testable through the usual go test scaffolding)

also: could you rebase off the latest main?

thanks.

@@ -0,0 +1,33 @@
// Copyright ©2020 The go-p5 Authors. All rights reserved.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Copyright ©2020 The go-p5 Authors. All rights reserved.
// Copyright ©2021 The go-p5 Authors. All rights reserved.

Comment on lines +299 to +301
if e.State == key.Press {
p.onKeyPressed(e)
} else if e.State == key.Release {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if e.State == key.Press {
p.onKeyPressed(e)
} else if e.State == key.Release {
switch e.State {
case key.Press:
p.onKeyPressed(e)
case key.Release:


import "gioui.org/io/key"

var Keyboard struct {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

perhaps move this as an anonymous field of the global Event variable, much like we did for Mouse ?

p5/event.go

Line 9 in 6b7ccd9

Mouse struct {

ie:

var Event struct {
    Mouse struct { ... }
    Key struct { ... }
}

Comment on lines +85 to +87
KeyPressed KeyEventFunc
KeyTyped KeyEventFunc
KeyReleased KeyEventFunc
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instead of "exploding" the KeyCb fields into 3 different fields in Proc, perhaps just add a Key KeyCb field to Proc ?

// KeyEventFunc is the type of key functions users provide to p5.
type KeyEventFunc func(key.Event)

type KeyCb struct {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this new type probably needs a bit of documentation.
also, as we spelled out the func-option WithKeyCallback, what about renaming this type KeyCallback ?
(alternatively, we could go with WithKeyCbk / KeyCbk)

the meaning of (and their semantical nuance) the Pressed and Typed probably need to be documented and/or explained.
this can be done as part of the documentation of each of these fields.

gproc.DrawImage(img, x, y)
}

// KeyIsDown checks if given key is already pressed.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// KeyIsDown checks if given key is already pressed.
// KeyIsDown checks whether a given key is already pressed.

}

// KeyIsDown checks if given key is already pressed.
func KeyIsDown(code string) bool {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
func KeyIsDown(code string) bool {
func KeyIsDown(name string) bool {

Comment on lines +18 to +19
// KeyIsDown checks if given key is already pressed.
func (p *Proc) KeyIsDown(code string) bool {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// KeyIsDown checks if given key is already pressed.
func (p *Proc) KeyIsDown(code string) bool {
// KeyIsDown checks whether a given key is already pressed.
func (p *Proc) KeyIsDown(name string) bool {

Comment on lines +20 to +23
if _, ok := Keyboard.downKeys[code]; ok {
return true
}
return false
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if _, ok := Keyboard.downKeys[code]; ok {
return true
}
return false
_, ok := Keyboard.downKeys[code]
return ok

@sbinet
Copy link
Contributor

sbinet commented Aug 16, 2021

ping?

@koxu1996
Copy link
Author

Sorry, I am quite busy nowadays and I am no longer interested in using go-p5.

@koxu1996 koxu1996 closed this Aug 16, 2021
@sbinet sbinet mentioned this pull request Nov 12, 2021
@koxu1996 koxu1996 mentioned this pull request Nov 10, 2023
15 tasks
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants