func (self *Window) bindKeys() { // navigate self.freqLimitedFunc(func(X *xgbutil.XUtil, ev xevent.KeyPressEvent) { file := self.set.Next() if file != nil { self.currentFile = file file.Draw() } }).Connect(X, self.Id, "Space", false) self.freqLimitedFunc(func(X *xgbutil.XUtil, ev xevent.KeyPressEvent) { file := self.set.Prev() if file != nil { self.currentFile = file file.Draw() } }).Connect(X, self.Id, "c", false) self.freqLimitedFunc(func(X *xgbutil.XUtil, ev xevent.KeyPressEvent) { file := self.set.Rand() if file != nil { self.currentFile = file file.Draw() } }).Connect(X, self.Id, "f", false) // image operations self.freqLimitedFunc(func(X *xgbutil.XUtil, ev xevent.KeyPressEvent) { self.currentFile.ZoomIn() self.currentFile.Draw() }).Connect(X, self.Id, "z", false) self.freqLimitedFunc(func(X *xgbutil.XUtil, ev xevent.KeyPressEvent) { self.currentFile.ZoomOut() self.currentFile.Draw() }).Connect(X, self.Id, "x", false) keybind.KeyPressFun(func(X *xgbutil.XUtil, ev xevent.KeyPressEvent) { self.currentFile.Move(0, MOVE_STEP) self.currentFile.Draw() }).Connect(X, self.Id, "w", false) keybind.KeyPressFun(func(X *xgbutil.XUtil, ev xevent.KeyPressEvent) { self.currentFile.Move(0, -MOVE_STEP) self.currentFile.Draw() }).Connect(X, self.Id, "s", false) keybind.KeyPressFun(func(X *xgbutil.XUtil, ev xevent.KeyPressEvent) { self.currentFile.Move(MOVE_STEP, 0) self.currentFile.Draw() }).Connect(X, self.Id, "a", false) keybind.KeyPressFun(func(X *xgbutil.XUtil, ev xevent.KeyPressEvent) { self.currentFile.Move(-MOVE_STEP, 0) self.currentFile.Draw() }).Connect(X, self.Id, "d", false) }
func keyHandlers(X *xgbutil.XUtil, cycle *prompt.Cycle, items []*prompt.CycleItem) { geom := headGeom(X) keybind.KeyPressFun( func(X *xgbutil.XUtil, ev xevent.KeyPressEvent) { shown := cycle.Show(geom, cycleNext, items) if !shown { log.Fatal("Did not show cycle prompt.") } cycle.Next() }).Connect(X, X.RootWin(), cycleNext, true) keybind.KeyPressFun( func(X *xgbutil.XUtil, ev xevent.KeyPressEvent) { cycle.Next() }).Connect(X, cycle.GrabId(), cycleNext, true) keybind.KeyPressFun( func(X *xgbutil.XUtil, ev xevent.KeyPressEvent) { shown := cycle.Show(geom, cyclePrev, items) if !shown { log.Fatal("Did not show cycle prompt.") } cycle.Prev() }).Connect(X, X.RootWin(), cyclePrev, true) keybind.KeyPressFun( func(X *xgbutil.XUtil, ev xevent.KeyPressEvent) { cycle.Prev() }).Connect(X, cycle.GrabId(), cyclePrev, true) }
func main() { X, err := xgbutil.NewConn() if err != nil { log.Fatal(err) } keybind.Initialize(X) // call once before using keybind package // Read an example gopher image into a regular png image. img, _, err := image.Decode(bytes.NewBuffer(gopher.GopherPng())) if err != nil { log.Fatal(err) } // Now convert it into an X image. ximg := xgraphics.NewConvert(X, img) // Now show it in a new window. // We set the window title and tell the program to quit gracefully when // the window is closed. // There is also a convenience method, XShow, that requires no parameters. win := showImage(ximg, "The Go Gopher!", true) // Listen for key press events. win.Listen(xproto.EventMaskKeyPress) err = keybind.KeyPressFun( func(X *xgbutil.XUtil, ev xevent.KeyPressEvent) { println("fullscreen!") err := ewmh.WmStateReq(X, win.Id, ewmh.StateToggle, "_NET_WM_STATE_FULLSCREEN") if err != nil { log.Fatal(err) } }).Connect(X, win.Id, "f", false) if err != nil { log.Fatal(err) } err = keybind.KeyPressFun( func(X *xgbutil.XUtil, ev xevent.KeyPressEvent) { println("quit fullscreen!") err := ewmh.WmStateReq(X, win.Id, ewmh.StateToggle, "_NET_WM_STATE_FULLSCREEN") if err != nil { log.Fatal(err) } }).Connect(X, win.Id, "Escape", false) if err != nil { log.Fatal(err) } // If we don't block, the program will end and the window will disappear. // We could use a 'select{}' here, but xevent.Main will emit errors if // something went wrong, so use that instead. xevent.Main(X) }
func (hotkey Hotkey) attach(X *xgbutil.XUtil) { log.Println(hotkey.Key) err := keybind.KeyPressFun( func(X *xgbutil.XUtil, e xevent.KeyPressEvent) { go exec.Command("/bin/sh", "-c", hotkey.Cmd).Run() }).Connect(X, X.RootWin(), hotkey.Key, true) if err != nil { log.Fatalf("Could not bind %s: %s", hotkey.Key, err.Error()) } }
// API func (ct *CommandTray) Bind(key string) { if ct.mod != "" { return } ct.mod = key utils.FailMeMaybe(keybind.KeyPressFun(func(_ *xgbutil.XUtil, _ xevent.KeyPressEvent) { ct.Focus() }).Connect(ct.X, ct.X.RootWin(), ct.mod, true)) }
func (self *Window) freqLimitedFunc(fun func(*xgbutil.XUtil, xevent.KeyPressEvent)) keybind.KeyPressFun { return keybind.KeyPressFun(func(X *xgbutil.XUtil, ev xevent.KeyPressEvent) { if self.forbidCommand { return } fun(X, ev) self.forbidCommand = true go func() { <-time.After(CMD_FREQ) self.forbidCommand = false }() }) }
func (kcmd keyCommand) attach(run func()) { if run == nil { return } if kcmd.cmd == "PromptCyclePrev" || kcmd.cmd == "PromptCycleNext" { // We've got to parse the key string first and make sure // there are some modifiers; otherwise this utterly fails! mods, _, _ := keybind.ParseString(X, kcmd.keyStr) if mods == 0 { logger.Warning.Printf("Sorry but the key binding '%s' for the %s "+ "command is invalid. It must have a modifier "+ "to work properly. i.e., Mod1-tab where 'Mod1' "+ "is the modifier.", kcmd.keyStr, kcmd.cmd) return } keybind.KeyPressFun( func(X *xgbutil.XUtil, ev xevent.KeyPressEvent) { run() }).Connect(X, wingo.root.Id, kcmd.keyStr, true) keybind.KeyPressFun( func(X *xgbutil.XUtil, ev xevent.KeyPressEvent) { run() }).Connect(X, X.Dummy(), kcmd.keyStr, true) } else { if kcmd.down { keybind.KeyPressFun( func(X *xgbutil.XUtil, ev xevent.KeyPressEvent) { run() }).Connect(X, wingo.root.Id, kcmd.keyStr, true) } else { keybind.KeyReleaseFun( func(X *xgbutil.XUtil, ev xevent.KeyReleaseEvent) { run() }).Connect(X, wingo.root.Id, kcmd.keyStr, true) } } }
func main() { X, err := xgbutil.NewConn() if err != nil { log.Fatalf("Could not connect to X: %v", err) } keybind.Initialize(X) keybind.KeyPressFun( func(X *xgbutil.XUtil, e xevent.KeyPressEvent) { fmt.Println("Key press!") }).Connect(X, X.RootWin(), "Mod4-j") xevent.Main(X) }
func main() { X, err := xgbutil.NewConn() fatal(err) keybind.Initialize(X) slct := prompt.NewSelect(X, prompt.DefaultSelectTheme, prompt.DefaultSelectConfig) // Create some artifical groups to use. artGroups := []prompt.SelectGroup{ slct.NewStaticGroup("Group 1"), slct.NewStaticGroup("Group 2"), slct.NewStaticGroup("Group 3"), slct.NewStaticGroup("Group 4"), slct.NewStaticGroup("Group 5"), } // And now create some artificial items. items := []*item{ newItem("andrew", 1), newItem("bruce", 2), newItem("kaitlyn", 3), newItem("cauchy", 4), newItem("plato", 1), newItem("platonic", 2), newItem("andrew gallant", 3), newItem("Andrew Gallant", 4), newItem("Andrew", 1), newItem("jim", 1), newItem("jimmy", 2), newItem("jimbo", 3), } groups := make([]*prompt.SelectGroupItem, len(artGroups)) for i, artGroup := range artGroups { groups[i] = slct.AddGroup(artGroup) } for _, item := range items { item.promptItem = slct.AddChoice(item) } geom := headGeom(X) keybind.KeyPressFun( func(X *xgbutil.XUtil, ev xevent.KeyPressEvent) { showGroups := newGroups(groups, items) slct.Show(geom, prompt.TabCompletePrefix, showGroups) }).Connect(X, X.RootWin(), selectActivate, true) println("Loaded...") xevent.Main(X) }
// setupEventHandlers attaches the canvas' channels to the window and // sets the appropriate callbacks to some events: // ConfigureNotify events will cause the window to update its state of geometry. // Expose events will cause the window to repaint the current image. // Button events to allow panning. // Key events to perform various tasks when certain keys are pressed. func (w *Window) setupEventHandlers(chans chans) { w.Listen(xproto.EventMaskStructureNotify | xproto.EventMaskExposure | xproto.EventMaskButtonPress | xproto.EventMaskButtonRelease | xproto.EventMaskKeyPress) // Get the current geometry in case we don't get a ConfigureNotify event // (or have already missed it). if _, err := w.Geometry(); err != nil { errLg.Fatal(err) } // Keep a state of window geometry. xevent.ConfigureNotifyFun( func(X *xgbutil.XUtil, ev xevent.ConfigureNotifyEvent) { w.Geom.WidthSet(int(ev.Width)) w.Geom.HeightSet(int(ev.Height)) }).Connect(w.X, w.Id) // Repaint the window on expose events. xevent.ExposeFun( func(X *xgbutil.XUtil, ev xevent.ExposeEvent) { chans.ctl <- []string{"pan", "origin"} }).Connect(w.X, w.Id) // Setup a drag handler to allow panning. mousebind.Drag(w.X, w.Id, w.Id, "1", false, func(X *xgbutil.XUtil, rx, ry, ex, ey int) (bool, xproto.Cursor) { chans.panStartChan <- image.Point{ex, ey} return true, 0 }, func(X *xgbutil.XUtil, rx, ry, ex, ey int) { chans.panStepChan <- image.Point{ex, ey} }, // We do nothing on mouse release func(X *xgbutil.XUtil, rx, ry, ex, ey int) { return }) for _, kb := range keybinds { k := kb // Needed because the callback closure will capture kb err := keybind.KeyPressFun( func(X *xgbutil.XUtil, ev xevent.KeyPressEvent) { chans.ctl <- k.command }).Connect(w.X, w.Id, k.key, false) if err != nil { errLg.Println(err) } } }
func BindKeys(keymap map[string]string) { X, err := xgbutil.NewConn() if err != nil { log.Fatal(err) } keybind.Initialize(X) for k, v := range keymap { v := v err = keybind.KeyPressFun(func(X *xgbutil.XUtil, e xevent.KeyPressEvent) { h.broadcast <- v }).Connect(X, X.RootWin(), k, true) if err != nil { log.Fatal(err) } } log.Println("Program initialized. Start pressing keys!") xevent.Main(X) }
// setupEventHandlers attaches the canvas' channels to the window and // sets the appropriate callbacks to some events: // ConfigureNotify events will cause the window to update its state of geometry. // Expose events will cause the window to repaint the current image. // Button events to allow panning. // Key events to perform various tasks when certain keys are pressed. Should // these be configurable? Meh. func (w *window) setupEventHandlers(chans chans) { w.chans = chans w.Listen(xproto.EventMaskStructureNotify | xproto.EventMaskExposure | xproto.EventMaskButtonPress | xproto.EventMaskButtonRelease | xproto.EventMaskKeyPress) // Get the current geometry in case we don't get a ConfigureNotify event // (or have already missed it). _, err := w.Geometry() if err != nil { errLg.Fatal(err) } // And ask the canvas to draw the first image when it gets around to it. go func() { w.chans.drawChan <- func(origin image.Point) image.Point { return image.Point{} } }() // Keep a state of window geometry. xevent.ConfigureNotifyFun( func(X *xgbutil.XUtil, ev xevent.ConfigureNotifyEvent) { w.Geom.WidthSet(int(ev.Width)) w.Geom.HeightSet(int(ev.Height)) }).Connect(w.X, w.Id) // Repaint the window on expose events. xevent.ExposeFun( func(X *xgbutil.XUtil, ev xevent.ExposeEvent) { w.chans.drawChan <- func(origin image.Point) image.Point { return origin } }).Connect(w.X, w.Id) // Setup a drag handler to allow panning. mousebind.Drag(w.X, w.Id, w.Id, "1", false, func(X *xgbutil.XUtil, rx, ry, ex, ey int) (bool, xproto.Cursor) { w.chans.panStartChan <- image.Point{ex, ey} return true, 0 }, func(X *xgbutil.XUtil, rx, ry, ex, ey int) { w.chans.panStepChan <- image.Point{ex, ey} }, func(X *xgbutil.XUtil, rx, ry, ex, ey int) { w.chans.panEndChan <- image.Point{ex, ey} }) // Set up a map of keybindings to avoid a lot of boiler plate. // for keystring, fun := range kbs { for _, keyb := range keybinds { keyb := keyb err := keybind.KeyPressFun( func(X *xgbutil.XUtil, ev xevent.KeyPressEvent) { keyb.action(w) }).Connect(w.X, w.Id, keyb.key, false) if err != nil { errLg.Println(err) } } }
func main() { X, err := xgbutil.NewConn() fatal(err) // Whenever the mousebind package is used, you must call Initialize. // Similarly for the keybind package. keybind.Initialize(X) mousebind.Initialize(X) // Easter egg! Use a right click to draw a gopher. gopherPng, _, err := image.Decode(bytes.NewBuffer(gopher.GopherPng())) fatal(err) // Now scale it to a reasonable size. gopher := xgraphics.Scale(gopherPng, gopherWidth, gopherHeight) // Create a new xgraphics.Image. It automatically creates an X pixmap for // you, and handles drawing to windows in the XDraw, XPaint and // XSurfaceSet functions. // N.B. An error is possible since X pixmap allocation can fail. canvas := xgraphics.New(X, image.Rect(0, 0, width, height)) // Color in the background color. canvas.For(func(x, y int) xgraphics.BGRA { return bg }) // Use the convenience function XShowExtra to create and map the // canvas window. // XShowExtra will also set the surface window of canvas for us. // We also use XShowExtra to set the name of the window and to quit the // main event loop when the window is closed. win := canvas.XShowExtra("Pointer painting", true) // Listen for pointer motion events and key press events. win.Listen(xproto.EventMaskButtonPress | xproto.EventMaskButtonRelease | xproto.EventMaskKeyPress) // The mousebind drag function runs three callbacks: one when the drag is // first started, another at each "step" in the drag, and a final one when // the drag is done. // The button sequence (in this case '1') is pressed, the first callback // is executed. If the first return value is true, the drag continues // and a pointer grab is initiated with the cursor id specified in the // second return value (use 0 to keep the cursor unchanged). // If it's false, the drag stops. // Note that Drag will automatically compress MotionNotify events. mousebind.Drag(X, win.Id, win.Id, "1", false, func(X *xgbutil.XUtil, rx, ry, ex, ey int) (bool, xproto.Cursor) { drawPencil(canvas, win, ex, ey) return true, 0 }, func(X *xgbutil.XUtil, rx, ry, ex, ey int) { drawPencil(canvas, win, ex, ey) }, func(X *xgbutil.XUtil, rx, ry, ex, ey int) {}) mousebind.Drag(X, win.Id, win.Id, "3", false, func(X *xgbutil.XUtil, rx, ry, ex, ey int) (bool, xproto.Cursor) { drawGopher(canvas, gopher, win, ex, ey) return true, 0 }, func(X *xgbutil.XUtil, rx, ry, ex, ey int) { drawGopher(canvas, gopher, win, ex, ey) }, func(X *xgbutil.XUtil, rx, ry, ex, ey int) {}) // Bind to the clear key specified, and just redraw the bg color. keybind.KeyPressFun( func(X *xgbutil.XUtil, ev xevent.KeyPressEvent) { clearCanvas(canvas, win) }).Connect(X, win.Id, clearKey, false) // Bind a callback to each key specified in the 'pencils' color map. // The response is to simply switch the pencil color. for key, clr := range pencils { c := clr keybind.KeyPressFun( func(X *xgbutil.XUtil, ev xevent.KeyPressEvent) { log.Printf("Changing pencil color to: %#v", c) pencil = c }).Connect(X, win.Id, key, false) } // Output some basic directions. fmt.Println("Use the left or right buttons on your mouse to paint " + "squares and gophers.") fmt.Println("Pressing numbers 1, 2, 3, 4, 5 or 6 will switch your pencil " + "color.") fmt.Println("Pressing 'c' will clear the canvas.") xevent.Main(X) }
func (kcmd keyCommand) attach() { if kcmd.cmdName == "CycleClientPrev" || kcmd.cmdName == "CycleClientNext" { // We've got to parse the key string first and make sure // there are some modifiers; otherwise this utterly fails! mods, _, _ := keybind.ParseString(X, kcmd.keyStr) if mods == 0 { logger.Warning.Printf("Sorry but the key binding '%s' for the %s "+ "command is invalid. It must have a modifier "+ "to work properly. i.e., Mod1-tab where 'Mod1' "+ "is the modifier.", kcmd.keyStr, kcmd.cmdName) return } run, err := cmdHacks.CycleClientRunWithKeyStr(kcmd.keyStr, kcmd.cmdStr) if err != nil { logger.Warning.Printf("Could not setup %s: %s", kcmd.cmdName, err) return } err = keybind.KeyPressFun( func(X *xgbutil.XUtil, ev xevent.KeyPressEvent) { go run() }).Connect(X, Root.Id, kcmd.keyStr, true) if err != nil { logger.Warning.Printf("Could not bind '%s': %s", kcmd.keyStr, err) } err = keybind.KeyPressFun( func(X *xgbutil.XUtil, ev xevent.KeyPressEvent) { go run() }).Connect(X, X.Dummy(), kcmd.keyStr, true) if err != nil { logger.Warning.Printf("Could not bind '%s': %s", kcmd.keyStr, err) } } else { run := func() { go func() { _, err := gribbleEnv.Run(kcmd.cmdStr) if err != nil { logger.Warning.Println(err) } }() } if kcmd.down { err := keybind.KeyPressFun( func(X *xgbutil.XUtil, ev xevent.KeyPressEvent) { run() }).Connect(X, Root.Id, kcmd.keyStr, true) if err != nil { logger.Warning.Printf("Could not bind '%s': %s", kcmd.keyStr, err) } } else { err := keybind.KeyReleaseFun( func(X *xgbutil.XUtil, ev xevent.KeyReleaseEvent) { run() }).Connect(X, Root.Id, kcmd.keyStr, true) if err != nil { logger.Warning.Printf("Could not bind '%s': %s", kcmd.keyStr, err) } } } }
func makeWindow(ximage *xgraphics.Image) (*xwindow.Window, *bool) { w, h := ximage.Rect.Dx(), ximage.Rect.Dy() window, err := xwindow.Generate(ximage.X) if err != nil { xgbutil.Logger.Printf("Could not generate new window id: %s", err) return nil, nil } window.Create(ximage.X.RootWin(), 0, 0, w, h, xproto.CwBackPixel, 0x00000000) window.Listen(xproto.EventMaskExposure, xproto.EventMaskKeyPress, xproto.EventMaskStructureNotify, xproto.EventMaskVisibilityChange) window.WMGracefulClose(func(w *xwindow.Window) { xevent.Detach(w.X, w.Id) keybind.Detach(w.X, w.Id) mousebind.Detach(w.X, w.Id) w.Destroy() xevent.Quit(w.X) }) err = icccm.WmStateSet(ximage.X, window.Id, &icccm.WmState{ State: icccm.StateNormal, }) if err != nil { xgbutil.Logger.Printf("Could not set WM_STATE: %s", err) } err = ewmh.WmNameSet(ximage.X, window.Id, "Computer System Monitor") if err != nil { xgbutil.Logger.Printf("Could not set _NET_WM_NAME: %s", err) } err = keybind.KeyPressFun( func(X *xgbutil.XUtil, ev xevent.KeyPressEvent) { err := ewmh.WmStateReq(ximage.X, window.Id, ewmh.StateToggle, "_NET_WM_STATE_FULLSCREEN") if err != nil { log.Fatal(err) } }).Connect(ximage.X, window.Id, "f", false) if err != nil { log.Fatal(err) } xevent.ExposeFun( func(xu *xgbutil.XUtil, event xevent.ExposeEvent) { ximage.XExpPaint(window.Id, 0, 0) }).Connect(ximage.X, window.Id) obscured := false xevent.VisibilityNotifyFun( func(xu *xgbutil.XUtil, event xevent.VisibilityNotifyEvent) { obscured = event.State == xproto.VisibilityFullyObscured }).Connect(ximage.X, window.Id) window.Map() return window, &obscured }
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.) keybind.Initialize(X) // Before attaching callbacks, wrap them in a callback function type. // The keybind package exposes two such callback types: keybind.KeyPressFun // and keybind.KeyReleaseFun. cb1 := keybind.KeyPressFun( func(X *xgbutil.XUtil, e xevent.KeyPressEvent) { log.Println("Key press!") }) // We can now attach the callback to a particular window and key // combination. This particular example grabs a key on the root window, // which makes it a global keybinding. // Also, "Mod4-j" typically corresponds to pressing down the "Super" or // "Windows" key on your keyboard, and then pressing the letter "j". // N.B. This approach works by issuing a passive grab on the window // specified. To respond to Key{Press,Release} events without a grab, use // the xevent.Key{Press,Release}Fun callback function types instead. err = cb1.Connect(X, X.RootWin(), "Mod4-j", true) // A keybinding can fail if the key string could not be parsed, or if you're // trying to bind a key that has already been grabbed by another client. if err != nil { log.Fatal(err) } // We can even attach multiple callbacks to the same key. err = keybind.KeyPressFun( func(X *xgbutil.XUtil, e xevent.KeyPressEvent) { log.Println("A second handler always happens after the first.") }).Connect(X, X.RootWin(), "Mod4-j", true) if err != nil { log.Fatal(err) } // Finally, if we want this client to stop responding to key events, we // can attach another handler that, when run, detaches all previous // handlers. // This time, we'll show an example of a KeyRelease binding. err = keybind.KeyReleaseFun( func(X *xgbutil.XUtil, e xevent.KeyReleaseEvent) { // Use keybind.Detach to detach the root window // from all KeyPress *and* KeyRelease handlers. keybind.Detach(X, X.RootWin()) log.Printf("Detached all Key{Press,Release}Events from the "+ "root window (%d).", X.RootWin()) }).Connect(X, X.RootWin(), "Mod4-Shift-q", true) if err != nil { log.Fatal(err) } // Finally, start the main event loop. This will route any appropriate // KeyPressEvents to your callback function. log.Println("Program initialized. Start pressing keys!") xevent.Main(X) }