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 main() { // Connect to the X server using the DISPLAY environment variable. X, err := xgbutil.NewConn() if err != nil { log.Fatal(err) } // Nice names for the modifier keys (same ones used by xmodmap). // This slice corresponds to the keybind.Modifiers slice (except for // the last 'Any' modifier element). nice := []string{ "shift", "lock", "control", "mod1", "mod2", "mod3", "mod4", "mod5", } // Whenever one uses the keybind package, Initialize should always be // called first. In this case, it initializes the key and modifier maps. keybind.Initialize(X) // Get the current modifier map. // The map is actually a table, where rows correspond to modifiers, and // columns correspond to the keys that activate that modifier. modMap := keybind.ModMapGet(X) // The number of keycodes allowed per modifier (i.e., the number of // columns in the modifier map). kPerMod := int(modMap.KeycodesPerModifier) // Get the number of allowable keysyms per keycode. // This is used to search for a valid keysym for a particular keycode. symsPerKc := int(keybind.KeyMapGet(X).KeysymsPerKeycode) // Imitate everything... fmt.Printf("xmodmap: up to %d keys per modifier, "+ "(keycodes in parentheses):\n\n", kPerMod) // Iterate through all keyboard modifiers defined in xgb/xproto // except the 'Any' modifier (which is last). for mmi := range keybind.Modifiers[:len(keybind.Modifiers)-1] { niceName := nice[mmi] keys := make([]string, 0, kPerMod) // row is the row for the 'mmi' modifier in the modifier mapping table. row := mmi * kPerMod // Iterate over each keycode in the modifier map for this modifier. for _, kc := range modMap.Keycodes[row : row+kPerMod] { // If this entry doesn't have a keycode (i.e., it's zero), we // have to skip it. if kc == 0 { continue } // Look for the first valid keysym in the keyboard map corresponding // to this keycode. If one can't be found, output "BadKey." var ksym xproto.Keysym = 0 for column := 0; column < symsPerKc; column++ { ksym = keybind.KeysymGet(X, kc, byte(column)) if ksym != 0 { break } } if ksym == 0 { keys = append(keys, fmt.Sprintf("BadKey (0x%x)", kc)) } else { keys = append(keys, fmt.Sprintf("%s (0x%x)", keybind.KeysymToStr(ksym), kc)) } } fmt.Printf("%-12s%s\n", niceName, strings.Join(keys, ", ")) } fmt.Println("") }