giu icon indicating copy to clipboard operation
giu copied to clipboard

Help capturing keyboard inputs

Open jasmeer opened this issue 2 months ago • 5 comments

Hi I want to capture key strokes only when canvas is clicked/active. I tried this and does't work.

var texture *g.Texture
var text = "Hello, Gopher!"
var canvasClicked bool

func loop() {
	g.SingleWindow().Layout(
		g.Label("Canvas demo"),
		g.Custom(func() {
			canvasClicked = g.IsItemClicked(g.MouseButtonLeft)
			canvas := g.GetCanvas()
			pos := g.GetCursorScreenPos()
			p1 := image.Point{X: pos.X + 0, Y: pos.Y + 0}
			p2 := image.Point{X: pos.X + 600, Y: pos.Y + 100}
			canvas.AddRectFilled(p1, p2, color.RGBA{R: 200, G: 200, B: 200, A: 255}, 0.2, g.DrawFlagsNone)
			g.SetCursorScreenPos(image.Point{X: pos.X, Y: pos.Y + 100})

		}),
		g.InputTextMultiline(&text).Size(-1, 100),
	)
}

func main() {
	wnd := g.NewMasterWindow("Canvas", 600, 600, g.MasterWindowFlagsNotResizable)

	img, _ := g.LoadImage("gopher.png")
	g.EnqueueNewTextureFromRgba(img, func(tex *g.Texture) {
		texture = tex
	})
	wnd.SetAdditionalInputHandlerCallback(func(key g.Key, mod g.Modifier, act g.Action) {
		if canvasClicked {
			fmt.Println(key, mod, act)
		}
	})
	wnd.Run(loop)
}

Thanks Jasmeer

jasmeer avatar Oct 24 '25 13:10 jasmeer

I think there are several problems in your solution:

  1. Canvas is not a "physical" object (well. I mean things like Button/TextBox/even a label) ar considered widgets by imgui and canvas simply isn't)
  2. IsItemClicked actually applies to the previous widget (in your case youll probably trigger things when the label is clicked)

What you would like to do is something like that:

//code deleted; see EDIT

also note that IsMouseClicked happens only in one frame so technically you'd need to do the keyboard input simultaneously with a keybaord input.

EDIT sorry - copy-paste issues 😄

package main

import (
	"fmt"
	"image"
	"image/color"

	g "github.com/AllenDang/giu"
)

var (
	texture       *g.Texture
	text          = "Hello, Gopher!"
	canvasClicked bool
)

func loop() {
	g.SingleWindow().Layout(
		g.Label("Canvas demo"),
		g.Custom(func() {
			canvas := g.GetCanvas()
			pos := g.GetCursorScreenPos()
			p1 := image.Point{X: pos.X + 0, Y: pos.Y + 0}
			p2 := image.Point{X: pos.X + 600, Y: pos.Y + 100}
			canvas.AddRectFilled(p1, p2, color.RGBA{R: 200, G: 200, B: 200, A: 255}, 0.2, g.DrawFlagsNone)
			g.SetCursorScreenPos(image.Point{X: pos.X, Y: pos.Y + 100})
			mousePos := g.GetMousePos()
			if mousePos.Y > pos.Y && mousePos.Y < pos.Y+100 {
				canvasClicked = g.IsMouseClicked(g.MouseButtonLeft)
			}
		}),
		g.InputTextMultiline(&text).Size(-1, 100),
	)
}

func main() {
	wnd := g.NewMasterWindow("Canvas", 600, 600, g.MasterWindowFlagsNotResizable)

	img, _ := g.LoadImage("gopher.png")
	g.EnqueueNewTextureFromRgba(img, func(tex *g.Texture) {
		texture = tex
	})
	wnd.SetAdditionalInputHandlerCallback(func(key g.Key, mod g.Modifier, act g.Action) {
		if canvasClicked {
			fmt.Println(key, mod, act)
		}
	})
	wnd.Run(loop)
}

gucio321 avatar Oct 24 '25 14:10 gucio321

Thank you @gucio321 for the quick response. That fixed the basic issue - but I still have the issue related what you said :

sMouseClicked happens only in one frame so technically you'd need to do the keyboard input simultaneously

What I need is a custom widget using Canvas that 'knows' when it has key board focus and more-or-less behave like a real widget w.r.t keyboard events? Is that possible? Thx jasmeer

jasmeer avatar Oct 24 '25 15:10 jasmeer

What I need is a custom widget using Canvas that 'knows' when it has key board focus and more-or-less behave like a real widget w.r.t keyboard events?

sorry but I don't understand what exactly do you mean. When exactly do you want to enable keyboard shortcuts on your canvas? when the mouse button is donw (then you can just use IsMouseDown) or when it is somehow "focused" (like a text box)?

gucio321 avatar Oct 24 '25 16:10 gucio321

I am trying to implement a very elementary terminal emulator. I want it as a custom widget using canvas. All key stokes will be forwarded to the running program via PTY when this widget.

There is a project https://github.com/liamg/darktile - it is using github.com/hajimehoshi/ebiten/v2 for the GUI. I want to port it to giu;

I can use InputTextMultiline; but it would be much easier if I can create a similar one using Canvas. Thanks Jasmeer

jasmeer avatar Oct 24 '25 16:10 jasmeer

I can use InputTextMultiline; but it would be much easier if I can create a similar one using Canvas.

well, let me note that it is a really brave statement...

I am trying to implement a very elementary terminal emulator. I want it as a custom widget using canvas. All key stokes will be forwarded to the running program via PTY when this widget.

you'd need to figure out how does the keyboard focus work in general but... this is not something giu has api for. You'd need to dig in cimgui-go/dear imgui a bit.

gucio321 avatar Oct 24 '25 17:10 gucio321