Example #1
0
func initKeyboardMapping() {
	const (
		keyLo = 8
		keyHi = 255
	)
	km, err := xp.GetKeyboardMapping(xConn, keyLo, keyHi-keyLo+1).Reply()
	if err != nil {
		log.Fatal(err)
	}
	if km == nil {
		log.Fatal("couldn't get keyboard mapping")
	}
	n := int(km.KeysymsPerKeycode)
	if n < 2 {
		log.Fatalf("too few keysyms per keycode: %d", n)
	}
	for i := keyLo; i <= keyHi; i++ {
		keysyms[i][0] = km.Keysyms[(i-keyLo)*n+0]
		keysyms[i][1] = km.Keysyms[(i-keyLo)*n+1]
	}

	toGrabs := []xp.Keysym{wmKeysym}
	if doAudioActions {
		toGrabs = append(toGrabs, xkAudioLowerVolume, xkAudioMute, xkAudioRaiseVolume)
	}
	for _, toGrab := range toGrabs {
		keycode := xp.Keycode(0)
		for i := keyLo; i <= keyHi; i++ {
			if keysyms[i][0] == toGrab || keysyms[i][1] == toGrab {
				keycode = xp.Keycode(i)
			}
		}
		if keycode == 0 {
			if toGrab != wmKeysym {
				continue
			}
			log.Fatalf("could not find the window manager key %s", keysymString(toGrab))
		}
		if err := xp.GrabKeyChecked(xConn, false, rootXWin, xp.ModMaskAny, keycode,
			xp.GrabModeAsync, xp.GrabModeAsync).Check(); err != nil {
			log.Fatal(err)
		}
	}

	// Disable Caps Lock if it is the wmKeysym.
	if wmKeysym == xkCapsLock {
		// On Ubuntu 12.04, disabling Caps Lock involved the equivalent of
		// `xmodmap -e "clear lock"`. On Ubuntu 14.04, XKB has replaced xmodmap,
		// possibly because this facilitates per-window keyboard layouts, so the
		// equivalent of `xmodmap -e "clear lock"` doesn't work. As of October
		// 2014, github.com/BurntSushi/xgb doesn't support XKB, so we exec the
		// setxkbmap program instead of speaking the X11 protocol directly to
		// disable Caps Lock.
		if err := exec.Command("setxkbmap", "-option", "caps:none").Run(); err != nil {
			log.Fatalf("setxkbmap failed: %v", err)
		}
	}
}
Example #2
0
func findKeycode(keysym xp.Keysym) (keycode xp.Keycode, shift bool) {
	for i, k := range keysyms {
		if k[0] == keysym {
			return xp.Keycode(i), false
		}
		if k[1] == keysym {
			return xp.Keycode(i), true
		}
	}
	return 0, false
}
Example #3
0
// Given a keysym, find the keycode mapped to it in the current X environment.
// keybind.Initialize MUST have been called before using this function.
func keycodeGet(xu *xgbutil.XUtil, keysym xproto.Keysym) xproto.Keycode {
	min, max := minMaxKeycodeGet(xu)
	keyMap := KeyMapGet(xu)
	if keyMap == nil {
		panic("keybind.Initialize must be called before using the keybind " +
			"package.")
	}

	var c byte
	for kc := int(min); kc <= int(max); kc++ {
		for c = 0; c < keyMap.KeysymsPerKeycode; c++ {
			if keysym == KeysymGet(xu, xproto.Keycode(kc), c) {
				return xproto.Keycode(kc)
			}
		}
	}
	return 0
}
Example #4
0
func ByteToString(k *Keyboard, b1 byte, b2 byte) string {
	if b1 != 0 {
		return k.KeycodeToString(xproto.Keycode(b1))
	}
	if b2 != 0 {
		return fmt.Sprintf("button%d", b2)
	}
	return ""
}
Example #5
0
func (k *Keyboard) Keycodes(keysym xproto.Keysym) []xproto.Keycode {
	var c byte
	var keycode xproto.Keycode
	keycodes := make([]xproto.Keycode, 0)
	set := make(map[xproto.Keycode]bool, 0)

	for kc := int(k.Min); kc <= int(k.Max); kc++ {
		keycode = xproto.Keycode(kc)
		for c = 0; c < k.KeysymsPerKeycode; c++ {
			if keysym == k.Keysymget(keycode, c) && !set[keycode] {
				keycodes = append(keycodes, keycode)
				set[keycode] = true
			}
		}
	}
	return keycodes
}
Example #6
0
// StrToKeycode is a wrapper around keycodeGet meant to make our search
// a bit more flexible if needed. (i.e., case-insensitive)
func StrToKeycode(xu *xgbutil.XUtil, str string) xproto.Keycode {
	// Do some fancy case stuff before we give up.
	sym, ok := keysyms[str]
	if !ok {
		sym, ok = keysyms[strings.Title(str)]
	}
	if !ok {
		sym, ok = keysyms[strings.ToLower(str)]
	}
	if !ok {
		sym, ok = keysyms[strings.ToUpper(str)]
	}

	// If we don't know what 'str' is, return 0.
	// There will probably be a bad access. We should do better than that...
	if !ok {
		return xproto.Keycode(0)
	}
	return keycodeGet(xu, sym)
}
Example #7
0
// ParseString takes a string of the format '[Mod[-Mod[...]]]-KEY',
// i.e., 'Mod4-j', and returns a modifiers/keycode combo.
// An error is returned if the string is malformed, or if no valid KEY can
// be found.
// Valid values of KEY should include almost anything returned by pressing
// keys with the 'xev' program. Alternatively, you may reference the keys
// of the 'keysyms' map defined in keybind/keysymdef.go.
func ParseString(xu *xgbutil.XUtil, s string) (uint16, xproto.Keycode, error) {
	mods, kc := uint16(0), xproto.Keycode(0)
	for _, part := range strings.Split(s, "-") {
		switch strings.ToLower(part) {
		case "shift":
			mods |= xproto.ModMaskShift
		case "lock":
			mods |= xproto.ModMaskLock
		case "control":
			mods |= xproto.ModMaskControl
		case "mod1":
			mods |= xproto.ModMask1
		case "mod2":
			mods |= xproto.ModMask2
		case "mod3":
			mods |= xproto.ModMask3
		case "mod4":
			mods |= xproto.ModMask4
		case "mod5":
			mods |= xproto.ModMask5
		case "any":
			mods |= xproto.ModMaskAny
		default: // a key code!
			if kc == 0 { // only accept the first keycode we see
				kc = StrToKeycode(xu, part)
			}
		}
	}

	if kc == 0 {
		return 0, 0, fmt.Errorf("Could not find a valid keycode in the "+
			"string '%s'. Key binding failed.", s)
	}

	return mods, kc, nil
}
Example #8
0
// Given a keysym, find all keycodes mapped to it in the current X environment.
// keybind.Initialize MUST have been called before using this function.
func keycodesGet(xu *xgbutil.XUtil, keysym xproto.Keysym) []xproto.Keycode {
	min, max := minMaxKeycodeGet(xu)
	keyMap := KeyMapGet(xu)
	if keyMap == nil {
		panic("keybind.Initialize must be called before using the keybind " +
			"package.")
	}

	var c byte
	var keycode xproto.Keycode
	keycodes := make([]xproto.Keycode, 0)
	set := make(map[xproto.Keycode]bool, 0)

	for kc := int(min); kc <= int(max); kc++ {
		keycode = xproto.Keycode(kc)
		for c = 0; c < keyMap.KeysymsPerKeycode; c++ {
			if keysym == KeysymGet(xu, keycode, c) && !set[keycode] {
				keycodes = append(keycodes, keycode)
				set[keycode] = true
			}
		}
	}
	return keycodes
}
Example #9
0
// updateMaps runs in response to MappingNotify events.
// It is responsible for making sure our view of the world's keyboard
// and modifier maps is correct. (Pointer mappings should be handled in
// a similar callback in the mousebind package.)
func updateMaps(xu *xgbutil.XUtil, e xevent.MappingNotifyEvent) {
	keyMap, modMap := MapsGet(xu)

	// Hold up... If this is MappingKeyboard, then we may have some keycode
	// changes. This is GROSS. We basically need to go through each keycode
	// in the map, look up the keysym using the new map and use that keysym
	// to look up the keycode in our current map. If the current keycode
	// does not equal the old keycode, then we log the change in a map of
	// old keycode -> new keycode.
	// Once the map is constructed, we look through all of our keybindings
	// and updated appropriately. *puke*
	// I am only somewhat confident that this is correct.
	if e.Request == xproto.MappingKeyboard {
		changes := make(map[xproto.Keycode]xproto.Keycode, 0)
		xuKeyMap := &xgbutil.KeyboardMapping{keyMap}

		min, max := minMaxKeycodeGet(xu)

		// let's not do too much allocation in our loop, shall we?
		var newSym, oldSym xproto.Keysym
		var oldKc xproto.Keycode
		var column byte

		// wrap 'int(..)' around bytes min and max to avoid overflow. Hideous.
		for newKc := int(min); newKc <= int(max); newKc++ {
			for column = 0; byte(column) < keyMap.KeysymsPerKeycode; column++ {
				// use new key map
				newSym = KeysymGetWithMap(xu, xuKeyMap, xproto.Keycode(newKc),
					column)

				// uses old key map
				oldKc = keycodeGet(xu, newSym)
				oldSym = KeysymGet(xu, xproto.Keycode(newKc), column)

				// If the old and new keysyms are the same, ignore!
				// Also ignore if either keysym is VoidSymbol
				if oldSym == newSym || oldSym == 0 || newSym == 0 {
					continue
				}

				// these should match if there are NO changes
				if oldKc != xproto.Keycode(newKc) {
					changes[oldKc] = xproto.Keycode(newKc)
				}
			}
		}

		// Now use 'changes' to do some regrabbing
		// Loop through all key bindings and check if we have any affected
		// key codes. (Note that each key binding may be associated with
		// multiple callbacks.)
		// We must ungrab everything first, in case two keys are being swapped.
		for _, key := range keyKeys(xu) {
			if _, ok := changes[key.Code]; ok {
				Ungrab(xu, key.Win, key.Mod, key.Code)
			}
		}
		// Okay, now grab.
		for _, key := range keyKeys(xu) {
			if newKc, ok := changes[key.Code]; ok {
				Grab(xu, key.Win, key.Mod, newKc)
				updateKeyBindKey(xu, key, newKc)
			}
		}
	}

	// We don't have to do something with MappingModifier like we do with
	// MappingKeyboard. This is due to us requiring that key strings use
	// modifier names built into X. (i.e., the names seen in the output of
	// `xmodmap`.) This means that the modifier mappings happen on the X server
	// side, so we don't *typically* have to care what key is actually being
	// pressed to trigger a modifier. (There are some exceptional cases, and
	// when that happens, we simply query on-demand which keys are modifiers.
	// See the RunKey{Press,Release}Callbacks functions in keybind/callback.go
	// for the deets.)

	// Finally update our view of the mappings.
	KeyMapSet(xu, keyMap)
	ModMapSet(xu, modMap)
}
Example #10
0
func (w *Window) handleEvents() {
	var noX int32 = 1<<31 - 1
	noX++
	var lastX, lastY int32 = noX, 0
	var button wde.Button

	downKeys := map[string]bool{}

	for {
		e, err := w.conn.WaitForEvent()

		if err != nil {
			fmt.Fprintln(os.Stderr, "[go.wde X error] ", err)
			continue
		}

		switch e := e.(type) {

		case xproto.ButtonPressEvent:
			button = button | buttonForDetail(e.Detail)
			var bpe wde.MouseDownEvent
			bpe.Which = buttonForDetail(e.Detail)
			bpe.Where.X = int(e.EventX)
			bpe.Where.Y = int(e.EventY)
			lastX = int32(e.EventX)
			lastY = int32(e.EventY)
			w.events <- bpe

		case xproto.ButtonReleaseEvent:
			button = button & ^buttonForDetail(e.Detail)
			var bue wde.MouseUpEvent
			bue.Which = buttonForDetail(e.Detail)
			bue.Where.X = int(e.EventX)
			bue.Where.Y = int(e.EventY)
			lastX = int32(e.EventX)
			lastY = int32(e.EventY)
			w.events <- bue

		case xproto.LeaveNotifyEvent:
			var wee wde.MouseExitedEvent
			wee.Where.X = int(e.EventX)
			wee.Where.Y = int(e.EventY)
			if lastX != noX {
				wee.From.X = int(lastX)
				wee.From.Y = int(lastY)
			} else {
				wee.From.X = wee.Where.X
				wee.From.Y = wee.Where.Y
			}
			lastX = int32(e.EventX)
			lastY = int32(e.EventY)
			w.events <- wee
		case xproto.EnterNotifyEvent:
			var wee wde.MouseEnteredEvent
			wee.Where.X = int(e.EventX)
			wee.Where.Y = int(e.EventY)
			if lastX != noX {
				wee.From.X = int(lastX)
				wee.From.Y = int(lastY)
			} else {
				wee.From.X = wee.Where.X
				wee.From.Y = wee.Where.Y
			}
			lastX = int32(e.EventX)
			lastY = int32(e.EventY)
			w.events <- wee

		case xproto.MotionNotifyEvent:
			var mme wde.MouseMovedEvent
			mme.Where.X = int(e.EventX)
			mme.Where.Y = int(e.EventY)
			if lastX != noX {
				mme.From.X = int(lastX)
				mme.From.Y = int(lastY)
			} else {
				mme.From.X = mme.Where.X
				mme.From.Y = mme.Where.Y
			}
			lastX = int32(e.EventX)
			lastY = int32(e.EventY)
			if button == 0 {
				w.events <- mme
			} else {
				var mde wde.MouseDraggedEvent
				mde.MouseMovedEvent = mme
				mde.Which = button
				w.events <- mde
			}

		case xproto.KeyPressEvent:
			var ke wde.KeyEvent
			code := keybind.LookupString(w.xu, e.State, e.Detail)
			ke.Key = keyForCode(code)
			w.events <- wde.KeyDownEvent(ke)
			downKeys[ke.Key] = true
			kpe := wde.KeyTypedEvent{
				KeyEvent: ke,
				Glyph:    letterForCode(code),
				Chord:    wde.ConstructChord(downKeys),
			}
			w.events <- kpe

		case xproto.KeyReleaseEvent:
			var ke wde.KeyUpEvent
			ke.Key = keyForCode(keybind.LookupString(w.xu, e.State, e.Detail))
			delete(downKeys, ke.Key)
			w.events <- ke

		case xproto.KeymapNotifyEvent:
			newDownKeys := make(map[string]bool)
			for i := 0; i < len(e.Keys); i++ {
				mask := e.Keys[i]
				for j := 0; j < 8; j++ {
					if mask&(1<<uint(j)) != 0 {
						keycode := xproto.Keycode(8*(i+1) + j)
						key := keyForCode(keybind.LookupString(w.xu, 0, keycode))
						newDownKeys[key] = true
					}
				}
			}
			/* remove keys that are no longer pressed */
			for key := range downKeys {
				if _, ok := newDownKeys[key]; !ok {
					var ke wde.KeyUpEvent
					ke.Key = key
					delete(downKeys, key)
					w.events <- ke
				}
			}
			/* add keys that are newly pressed */
			for key := range newDownKeys {
				if _, ok := downKeys[key]; !ok {
					var ke wde.KeyDownEvent
					ke.Key = key
					downKeys[key] = true
					w.events <- ke
				}
			}

		case xproto.ConfigureNotifyEvent:
			var re wde.ResizeEvent
			re.Width = int(e.Width)
			re.Height = int(e.Height)
			if re.Width != w.width || re.Height != w.height {
				w.width, w.height = re.Width, re.Height

				w.bufferLck.Lock()
				w.buffer.Destroy()
				w.buffer = xgraphics.New(w.xu, image.Rect(0, 0, re.Width, re.Height))
				w.bufferLck.Unlock()

				w.events <- re
			}

		case xproto.ClientMessageEvent:
			if icccm.IsDeleteProtocol(w.xu, xevent.ClientMessageEvent{&e}) {
				w.events <- wde.CloseEvent{}
			}
		case xproto.DestroyNotifyEvent:
		case xproto.ReparentNotifyEvent:
		case xproto.MapNotifyEvent:
		case xproto.UnmapNotifyEvent:
		case xproto.PropertyNotifyEvent:

		default:
			fmt.Fprintf(os.Stderr, "unhandled event: type %T\n%+v\n", e, e)
		}

	}

	close(w.events)
}