102 lines
3.2 KiB
Go
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)
|
|
}
|