start of input logger
This commit is contained in:
37
examples/inputlog/README.md
Normal file
37
examples/inputlog/README.md
Normal file
@@ -0,0 +1,37 @@
|
||||
# Input Logger Example
|
||||
|
||||
This example demonstrates how to capture and log all pointer and key events in a Gio application.
|
||||
|
||||
## Features
|
||||
|
||||
- Captures all pointer events (press, release, move, drag, scroll)
|
||||
- Captures all key events (press, release) with modifiers
|
||||
- Logs event details including:
|
||||
- Key name and state (press/release)
|
||||
- Pointer position and button states
|
||||
- Scroll amounts
|
||||
- Modifier keys (Ctrl, Shift, Alt, etc.)
|
||||
- Simple flex layout with a gray background area for interaction
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
cd examples/inputlog
|
||||
go run .
|
||||
```
|
||||
|
||||
Move your mouse around the window and press keys to see the events logged to the console.
|
||||
|
||||
## Event Details
|
||||
|
||||
The application logs:
|
||||
- **Key Events**: Name, State (Press/Release), Modifiers
|
||||
- **Pointer Events**: Kind, Source (Mouse/Touch), Position, Buttons, Scroll, Modifiers
|
||||
- **Focus Events**: When the window gains/loses focus
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
- Uses `event.Op()` to register event handlers
|
||||
- Uses `gtx.Source.Event()` to retrieve events
|
||||
- Implements proper event filtering for both key and pointer events
|
||||
- Uses material theme for consistent styling
|
||||
142
examples/inputlog/main.go
Normal file
142
examples/inputlog/main.go
Normal file
@@ -0,0 +1,142 @@
|
||||
// SPDX-License-Identifier: Unlicense OR MIT
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"image/color"
|
||||
"os"
|
||||
|
||||
"github.com/mleku/fromage/app"
|
||||
"github.com/mleku/fromage/io/event"
|
||||
"github.com/mleku/fromage/io/key"
|
||||
"github.com/mleku/fromage/io/pointer"
|
||||
"github.com/mleku/fromage/layout"
|
||||
"github.com/mleku/fromage/op"
|
||||
"github.com/mleku/fromage/op/clip"
|
||||
"github.com/mleku/fromage/op/paint"
|
||||
"github.com/mleku/fromage/unit"
|
||||
"github.com/mleku/fromage/widget/material"
|
||||
)
|
||||
|
||||
func main() {
|
||||
go func() {
|
||||
w := &app.Window{}
|
||||
if err := run(w); err != nil {
|
||||
fmt.Printf("Error: %v\n", err)
|
||||
}
|
||||
os.Exit(0)
|
||||
}()
|
||||
app.Main()
|
||||
}
|
||||
|
||||
func run(w *app.Window) error {
|
||||
var ops op.Ops
|
||||
var th = material.NewTheme()
|
||||
var inputHandler = &InputHandler{}
|
||||
|
||||
for {
|
||||
switch e := w.Event().(type) {
|
||||
case app.DestroyEvent:
|
||||
return e.Err
|
||||
case app.FrameEvent:
|
||||
gtx := app.NewContext(&ops, e)
|
||||
inputHandler.Layout(gtx, th)
|
||||
e.Frame(&ops)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type InputHandler struct {
|
||||
keyTag event.Tag
|
||||
pointerTag event.Tag
|
||||
}
|
||||
|
||||
func (h *InputHandler) Layout(gtx layout.Context, th *material.Theme) {
|
||||
// Initialize tags if not set
|
||||
if h.keyTag == nil {
|
||||
h.keyTag = &h.keyTag
|
||||
}
|
||||
if h.pointerTag == nil {
|
||||
h.pointerTag = &h.pointerTag
|
||||
}
|
||||
|
||||
// Create a flex layout that fills the entire window
|
||||
flex := layout.Flex{
|
||||
Axis: layout.Vertical,
|
||||
}
|
||||
|
||||
// Create a simple box that captures all input events
|
||||
box := layout.Flexed(1, func(gtx layout.Context) layout.Dimensions {
|
||||
// Draw a background rectangle
|
||||
paint.FillShape(gtx.Ops, color.NRGBA{R: 0x80, G: 0x80, B: 0x80, A: 0xFF},
|
||||
clip.Rect{Max: gtx.Constraints.Max}.Op())
|
||||
|
||||
// Set up event handlers
|
||||
h.setupEventHandlers(gtx)
|
||||
|
||||
return layout.Dimensions{Size: gtx.Constraints.Max}
|
||||
})
|
||||
|
||||
// Add some text at the top
|
||||
label := layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||
return material.Label(th, unit.Sp(16),
|
||||
"Input Logger - Move mouse and press keys to see events logged").Layout(gtx)
|
||||
})
|
||||
|
||||
flex.Layout(gtx, label, box)
|
||||
|
||||
// Handle events after layout
|
||||
h.handleEvents(gtx)
|
||||
}
|
||||
|
||||
func (h *InputHandler) setupEventHandlers(gtx layout.Context) {
|
||||
// Set up a hit area for pointer events
|
||||
area := clip.Rect{Max: gtx.Constraints.Max}.Push(gtx.Ops)
|
||||
|
||||
// Set up pointer event handler
|
||||
event.Op(gtx.Ops, h.pointerTag)
|
||||
|
||||
// Set up key event handler
|
||||
event.Op(gtx.Ops, h.keyTag)
|
||||
|
||||
// Request focus for key events
|
||||
gtx.Execute(key.FocusCmd{Tag: h.keyTag})
|
||||
|
||||
area.Pop()
|
||||
}
|
||||
|
||||
func (h *InputHandler) handleEvents(gtx layout.Context) {
|
||||
// Handle key events
|
||||
keyFilter := key.Filter{Focus: h.keyTag}
|
||||
for {
|
||||
ev, ok := gtx.Event(keyFilter)
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
switch ev := ev.(type) {
|
||||
case key.Event:
|
||||
fmt.Printf("Key Event: Name=%s, State=%s, Modifiers=%s\n",
|
||||
ev.Name, ev.State, ev.Modifiers)
|
||||
case key.FocusEvent:
|
||||
fmt.Printf("Focus Event: Focus=%t\n", ev.Focus)
|
||||
}
|
||||
}
|
||||
|
||||
// Handle pointer events
|
||||
pointerFilter := pointer.Filter{
|
||||
Target: h.pointerTag,
|
||||
Kinds: pointer.Press | pointer.Release | pointer.Move | pointer.Drag | pointer.Scroll,
|
||||
}
|
||||
for {
|
||||
ev, ok := gtx.Event(pointerFilter)
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
switch ev := ev.(type) {
|
||||
case pointer.Event:
|
||||
fmt.Printf("Pointer Event: Kind=%s, Source=%s, PointerID=%d, Position=(%.1f,%.1f), Buttons=%s, Scroll=(%.1f,%.1f), Modifiers=%s\n",
|
||||
ev.Kind, ev.Source, ev.PointerID, ev.Position.X, ev.Position.Y, ev.Buttons, ev.Scroll.X, ev.Scroll.Y, ev.Modifiers)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user