diff --git a/examples/keypress/main.go b/examples/keypress/main.go new file mode 100644 index 0000000..3a2c8cc --- /dev/null +++ b/examples/keypress/main.go @@ -0,0 +1,100 @@ +// 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 "github.com/jezek/xgbutil/xevent" +import "github.com/jezek/xgbutil/xwindow" +import "github.com/jezek/xgbutil/keybind" +import "git.tebibyte.media/sashakoshka/xgbkb" + +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) + if unicode.IsPrint(character) { + log.Printf("0x%04X | '%s'\n", symbol, string(character)) + } else { + log.Printf("0x%04X |\n", symbol) + } + + 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) +}