xgbkb/examples/keypress/main.go
2023-06-30 17:22:20 -04:00

102 lines
3.2 KiB
Go

// Example keypress is xgbutil/_examples/keypress-english modified to
// demonstrate the functionality in this module.
package main
import "log"
import "flag"
import "unicode"
import "github.com/jezek/xgbutil"
import "github.com/jezek/xgb/xproto"
import "git.tebibyte.media/tomo/xgbkb"
import "github.com/jezek/xgbutil/xevent"
import "github.com/jezek/xgbutil/xwindow"
import "github.com/jezek/xgbutil/keybind"
var flagRoot = false
func init() {
log.SetFlags(0)
flag.BoolVar(&flagRoot, "root", flagRoot,
"When set, the keyboard will be grabbed on the root window. "+
"Make sure you have a way to kill the window created with "+
"the mouse.")
flag.Parse()
}
func main() {
// Connect to the X server using the DISPLAY environment variable.
X, err := xgbutil.NewConn()
if err != nil {
log.Fatal(err)
}
// Anytime the keybind (mousebind) package is used, keybind.Initialize
// *should* be called once. It isn't strictly necessary, but allows your
// keybindings to persist even if the keyboard mapping is changed during
// run-time. (Assuming you're using the xevent package's event loop.)
// It also handles the case when your modifier map is changed.
keybind.Initialize(X)
// xgbkb must also be initialized before use, but only after keybind has
// been initialized.
xgbkb.Initialize(X)
// Create a new window. We will listen for key presses and translate them
// only when this window is in focus. (Similar to how `xev` works.)
win, err := xwindow.Generate(X)
if err != nil {
log.Fatalf("Could not generate a new window X id: %s", err)
}
win.Create(X.RootWin(), 0, 0, 500, 500, xproto.CwBackPixel, 0xffffffff)
// Listen for Key{Press,Release} events.
win.Listen(xproto.EventMaskKeyPress, xproto.EventMaskKeyRelease)
// Map the window.
win.Map()
// Notice that we use xevent.KeyPressFun instead of keybind.KeyPressFun,
// because we aren't trying to make a grab *and* because we want to listen
// to *all* key press events, rather than just a particular key sequence
// that has been pressed.
wid := win.Id
if flagRoot {
wid = X.RootWin()
}
xevent.KeyPressFun(
func(X *xgbutil.XUtil, e xevent.KeyPressEvent) {
symbol, character := xgbkb.KeycodeToKeysym( e.Detail, e.State)
modifiers := xgbkb.StateToModifiers(e.State)
if unicode.IsPrint(character) {
log.Printf("0x%04X | '%s' %v\n", symbol, string(character), modifiers)
} else {
log.Printf("0x%04X | %v\n", symbol, modifiers)
}
if keybind.KeyMatch(X, "Escape", e.State, e.Detail) {
if e.State&xproto.ModMaskControl > 0 {
log.Println("Control-Escape detected. Quitting...")
xevent.Quit(X)
}
}
}).Connect(X, wid)
// If we want root, then we take over the entire keyboard.
if flagRoot {
if err := keybind.GrabKeyboard(X, X.RootWin()); err != nil {
log.Fatalf("Could not grab keyboard: %s", err)
}
log.Println("WARNING: We are taking *complete* control of the root " +
"window. The only way out is to press 'Control + Escape' or to " +
"close the window with the mouse.")
}
// Finally, start the main event loop. This will route any appropriate
// KeyPressEvents to your callback function.
log.Println("Program initialized. Start pressing keys!")
log.Println("Keysym | Rune")
log.Println("------ | ----")
xevent.Main(X)
}